Переключение между локалями

В библиотеке Globalize локаль определяет набор правил форматирования дат, чисел, валют, сообщений и других культурно-зависимых данных. Переключение локали означает смену активного контекста форматирования без перезагрузки приложения и без пересборки данных.

Внутри Globalize отсутствует глобальная «магическая» локаль, которая автоматически меняет поведение всех функций. Вместо этого используется явное создание экземпляров, привязанных к конкретной локали.


Принцип локальности экземпляра Globalize

Каждый экземпляр Globalize создаётся на основе идентификатора локали:

import Globalize from "globalize";

const en = new Globalize("en");
const ru = new Globalize("ru");

Каждый объект содержит собственный контекст:

  • en — форматирование по правилам английской локали
  • ru — форматирование по правилам русской локали

Переключение между локалями в таком подходе сводится к выбору нужного экземпляра.


Переключение локали через создание нового экземпляра

Наиболее прямолинейный способ — создание нового объекта Globalize при смене языка интерфейса:

let currentLocale = "en";
let g = new Globalize(currentLocale);

function switchLocale(locale) {
  currentLocale = locale;
  g = new Globalize(locale);
}

Такой подход прост, но требует контроля состояния g во всём приложении.


Использование фабрики экземпляров

При большом количестве локалей удобнее централизовать создание экземпляров:

import Globalize from "globalize";

const cache = new Map();

function getGlobalize(locale) {
  if (!cache.has(locale)) {
    cache.set(locale, new Globalize(locale));
  }
  return cache.get(locale);
}

Использование:

const gRu = getGlobalize("ru");
const gEn = getGlobalize("en");

Кэширование снижает накладные расходы при частых переключениях локалей.


Переключение локали в рантайме приложения

При динамическом изменении языка интерфейса часто используется единая точка доступа:

import Globalize from "globalize";

let locale = "en";
let g = new Globalize(locale);

function setLocale(newLocale) {
  locale = newLocale;
  g = new Globalize(newLocale);
}

function formatNumber(value) {
  return g.numberFormatter()(value);
}

Любые форматтеры создаются из текущего экземпляра, что гарантирует консистентность вывода.


Влияние CLDR-данных на переключение локалей

Globalize опирается на данные CLDR (Unicode Common Locale Data Repository). Перед использованием локали необходимо загрузить соответствующие данные:

import Globalize from "globalize";

Globalize.load(
  require("cldr-data/main/ru/ca-gregorian.json"),
  require("cldr-data/main/ru/numbers.json"),
  require("cldr-data/supplemental/timeData.json"),
  require("cldr-data/supplemental/weekData.json")
);

После загрузки данных можно создавать экземпляры:

const ru = new Globalize("ru");

Если данные локали не загружены, переключение на неё приведёт к ошибкам форматирования или использованию неполных правил.


Переключение локалей для форматтеров чисел

Форматирование чисел зависит от текущего экземпляра:

const ru = new Globalize("ru");
const en = new Globalize("en");

console.log(ru.numberFormatter(2)(12345.678));
// 12 345,68

console.log(en.numberFormatter(2)(12345.678));
// 12,345.68

Переключение локали означает создание нового форматтера через другой экземпляр:

function formatPrice(value, locale) {
  const g = new Globalize(locale);
  return g.numberFormatter(2)(value);
}

Переключение локалей для дат

Форматирование дат также строго привязано к экземпляру:

const ru = new Globalize("ru");
const en = new Globalize("en");

const date = new Date(2026, 0, 15);

console.log(ru.dateFormatter({ datetime: "medium" })(date));
console.log(en.dateFormatter({ datetime: "medium" })(date));

При смене локали изменяются:

  • порядок компонентов даты
  • названия месяцев
  • формат времени
  • разделители

Переключение локали в UI-состоянии приложения

При архитектуре с состоянием (например, Redux-подобной) локаль часто хранится как часть глобального состояния:

const state = {
  locale: "en"
};

function setLocale(locale) {
  state.locale = locale;
}

function g() {
  return new Globalize(state.locale);
}

Использование:

function formatCurrency(value) {
  return g().currencyFormatter("USD")(value);
}

Такой подход исключает рассинхронизацию между UI и форматированием.


Динамическое обновление форматтеров

Форматтеры в Globalize являются функциями, привязанными к конкретному экземпляру. При смене локали ранее созданные форматтеры не обновляются автоматически:

const g = new Globalize("en");
const formatter = g.numberFormatter();

console.log(formatter(1000)); // 1,000

g = new Globalize("ru");

console.log(formatter(1000)); // всё ещё форматирует по en

Следствие — форматтеры должны пересоздаваться при смене локали.


Переиспользование и инвалидация кэша форматтеров

При оптимизации производительности используется кэш:

const formatterCache = new Map();

function getFormatter(locale) {
  if (!formatterCache.has(locale)) {
    const g = new Globalize(locale);
    formatterCache.set(locale, {
      number: g.numberFormatter(),
      date: g.dateFormatter()
    });
  }
  return formatterCache.get(locale);
}

При смене локали кэш либо расширяется, либо инвалидируется:

function clearFormatterCache() {
  formatterCache.clear();
}

Переключение локали и сообщения

Globalize поддерживает форматирование сообщений:

const ru = new Globalize("ru");

Globalize.loadMessages({
  ru: {
    greeting: "Привет, {name}!"
  }
});

console.log(ru.messageFormatter("greeting")({ name: "Иван" }));

При смене локали необходимо:

  • загрузить сообщения для новой локали
  • создать новый экземпляр Globalize

Ленивое переключение локалей

В условиях больших приложений локали часто подгружаются по требованию:

async function switchLocale(locale) {
  await loadLocaleData(locale);
  currentGlobalize = new Globalize(locale);
}

Функция загрузки может включать:

  • CLDR данные
  • переводы
  • дополнительные настройки форматирования

Фолбэк локалей

При отсутствии данных для выбранной локали используется fallback:

function createGlobalize(locale) {
  try {
    return new Globalize(locale);
  } catch (e) {
    return new Globalize("en");
  }
}

Также fallback может быть реализован на уровне сообщений:

  • ru-RUruen

Изоляция локалей в многомодульной архитектуре

В системах с несколькими модулями важно избегать глобального состояния:

export function createI18n(locale) {
  const g = new Globalize(locale);

  return {
    formatNumber: g.numberFormatter(),
    formatDate: g.dateFormatter(),
    formatCurrency: g.currencyFormatter("USD")
  };
}

Каждый модуль получает собственный изолированный контекст локали, что исключает побочные эффекты при переключении языка в других частях системы.