Интеграция библиотеки Globalize в приложения на Vue.js строится вокруг единого принципа: локализация должна быть реактивной, централизованной и отделённой от бизнес-логики компонентов. Globalize предоставляет набор инструментов для форматирования чисел, дат, валют, сообщений и единиц измерения, а Vue — реактивную систему, которая позволяет динамически переключать локаль без перезагрузки приложения.
Ключевая задача интеграции — связать состояние текущей локали с реактивным контекстом Vue и обеспечить автоматическое обновление отображаемых значений при её изменении.
Globalize требует наличия CLDR-данных (Unicode Common Locale Data Repository). Это принципиально отличает его от более лёгких решений: библиотека не содержит локали «из коробки» и работает только с внешними данными.
Установка:
npm install globalize cldr-data
Дополнительно часто используются загрузчики CLDR:
npm install cldrjs
Перед использованием форматирования необходимо загрузить данные локалей.
Пример базовой инициализации:
import Globalize from "globalize";
import Cldr from "cldrjs";
// загрузка CLDR JSON (пример условный)
import likelySubtags from "cldr-data/supplemental/likelySubtags.json";
import numbers from "cldr-data/main/ru/numbers.json";
import currencies from "cldr-data/main/ru/currencies.json";
import timeZoneNames from "cldr-data/main/ru/timeZoneNames.json";
import dateFields from "cldr-data/main/ru/dateFields.json";
// инициализация CLDR
Cldr.load(likelySubtags);
Cldr.load(numbers);
Cldr.load(currencies);
Cldr.load(timeZoneNames);
Cldr.load(dateFields);
// установка глобальной локали
Globalize.locale("ru");
Важно: Globalize не работает без предварительной загрузки данных. Ошибки на этом этапе — наиболее частая причина «пустого» форматирования.
В Vue-архитектуре Globalize обычно не используется напрямую в компонентах. Вместо этого создаётся сервис локализации, который инкапсулирует:
// i18n/globalizeService.js
import Globalize from "globalize";
class GlobalizeService {
constructor() {
this.locale = "ru";
this.instance = Globalize;
}
setLocale(locale) {
this.locale = locale;
this.instance.locale(locale);
}
formatNumber(value) {
return this.instance.numberFormatter()(value);
}
formatCurrency(value, currency) {
return this.instance.currencyFormatter(currency)(value);
}
formatDate(value) {
return this.instance.dateFormatter()(value);
}
formatMessage(message, params) {
return this.instance.messageFormatter(message)(params);
}
}
export const globalizeService = new GlobalizeService();
Чтобы локаль автоматически обновляла интерфейс, используется реактивное состояние.
Пример через reactive:
import { reactive } from "vue";
import { globalizeService } from "./globalizeService";
export const i18nState = reactive({
locale: "ru",
});
Переключение локали:
export function setLocale(locale) {
i18nState.locale = locale;
globalizeService.setLocale(locale);
}
Composable позволяет использовать форматирование в любом компоненте.
import { computed } from "vue";
import { i18nState } from "./state";
import { globalizeService } from "./globalizeService";
export function useGlobalize() {
const locale = computed(() => i18nState.locale);
const formatNumber = (value) => {
locale.value; // зависимость для реактивности
return globalizeService.formatNumber(value);
};
const formatCurrency = (value, currency) => {
locale.value;
return globalizeService.formatCurrency(value, currency);
};
const formatDate = (value) => {
locale.value;
return globalizeService.formatDate(value);
};
return {
locale,
formatNumber,
formatCurrency,
formatDate,
};
}
Особенность подхода: любое использование locale.value
внутри функций заставляет Vue пересчитывать зависимости при смене
языка.
<script setup>
import { useGlobalize } from "@/i18n/useGlobalize";
const { formatNumber, formatCurrency } = useGlobalize();
const price = 12999.5;
</script>
<template>
<div>
<p>Цена: {{ formatCurrency(price, "RUB") }}</p>
<p>Количество: {{ formatNumber(10234.56) }}</p>
</div>
</template>
Переключение локали должно обновлять весь интерфейс без перезагрузки.
import { setLocale } from "@/i18n/state";
function switchToEnglish() {
setLocale("en");
}
function switchToRussian() {
setLocale("ru");
}
После изменения локали Vue автоматически перерисует компоненты, где используются функции форматирования.
Globalize использует CLDR-правила для форматирования дат:
const date = new Date();
globalizeService.formatDate(date);
Расширенный вариант:
this.instance.dateFormatter({
date: "long",
time: "short",
})(date);
Поддерживаются уровни:
globalizeService.formatCurrency(1500, "USD");
Особенность Globalize — строгая привязка к ISO-кодам валют и локали. Отображение символов и позиционирование автоматически определяется CLDR.
MessageFormatter используется для интерполяции строк:
const msg = Globalize.messageFormatter("cart.items");
msg({ count: 3 });
Пример CLDR-совместимого шаблона:
{
"cart": {
"items": "В корзине {count} товаров"
}
}
Поддерживается pluralization:
{
"items": {
"one": "{count} товар",
"few": "{count} товара",
"many": "{count} товаров"
}
}
В крупных приложениях локали не загружаются сразу.
Пример ленивой загрузки:
async function loadLocale(locale) {
const data = await import(`cldr-data/main/${locale}/numbers.json`);
Globalize.load(data);
Globalize.locale(locale);
}
Такой подход уменьшает начальный бандл.
Для централизованного подключения создаётся плагин:
import { globalizeService } from "./globalizeService";
export default {
install(app) {
app.config.globalProperties.$g = globalizeService;
},
};
Использование:
this.$g.formatNumber(1000);
При серверном рендеринге важно:
Пример:
export function createGlobalize(locale) {
const g = Globalize;
g.locale(locale);
return g;
}
Globalize создаёт форматтеры, которые тяжёлые при частом создании. Оптимизация:
const numberFormatter = Globalize.numberFormatter();
const currencyFormatter = Globalize.currencyFormatter("USD");
Переиспользование экземпляров уменьшает нагрузку при рендере списков.
Без загрузки данных Globalize возвращает ошибки или пустые строки.
Неправильно:
formatCurrency(value) {
return Globalize.currencyFormatter("USD")(value);
}
При каждом вызове создаётся новый formatter.
Использование Globalize.locale() без реактивного слоя
приводит к отсутствию обновлений UI.
Рекомендуемая архитектура:
/i18n/cldr/ — данные локалей/i18n/service.js — Globalize wrapper/i18n/state.js — reactive locale/i18n/useGlobalize.js — composable/plugins/globalize.js — Vue pluginТакая структура отделяет форматирование от компонентов и сохраняет предсказуемость поведения интерфейса.