В международной локализации JavaScript под состоянием локали понимается совокупность параметров, определяющих язык, региональные настройки, правила форматирования и сопутствующие культурные особенности, применяемые при работе с API семейства Intl. Эти параметры не являются статичными: они участвуют в разрешении, наследовании, переопределении и кэшировании, формируя поведение форматтеров чисел, дат, строк и сравнений.
Ключевым элементом выступает строка локали в формате BCP 47
(например, en-US, ru-RU,
zh-Hans-CN), которая используется как входная точка для
построения внутренних объектов форматирования. Однако реальное состояние
локали в приложении выходит за пределы строки и включает результаты
нормализации, выбранные фолбэки и параметры, вычисленные движком
ICU.
Объект Intl.Locale представляет формализованное описание
локали, включая язык, письменность, регион, календарь и другие
расширения.
const locale = new Intl.Locale('ru-RU');
Структура локали включает несколько уровней:
ru)Cyrl)RU)nu,
ca, hc)Расширенные параметры позволяют описывать, например, тип календаря или систему нумерации:
const locale = new Intl.Locale('ar-EG-u-nu-arab-ca-islamic');
С точки зрения состояния приложения Intl.Locale является
неизменяемым объектом. Любая модификация приводит к созданию нового
экземпляра:
const base = new Intl.Locale('en-US');
const withRegion = base.setRegion('GB');
Такой подход делает локаль безопасной для передачи между слоями приложения и хранения в состоянии без риска мутации.
При создании форматтеров Intl выполняется процесс разрешения локали. Он включает:
const formatter = new Intl.DateTimeFormat('xx-XX');
console.log(formatter.resolvedOptions().locale);
Результирующая локаль часто отличается от запрошенной. Это значение становится фактическим состоянием, влияющим на поведение форматирования.
Механизм fallback особенно важен при работе с частично поддерживаемыми идентификаторами локалей, где движок ICU выбирает наиболее близкий доступный вариант.
В архитектуре приложений локаль рассматривается как глобальное или контекстное состояние. Она влияет на:
Intl.DateTimeFormat)Intl.NumberFormat)Intl.Collator)Базовый подход предполагает хранение текущей локали в одном источнике истины:
let currentLocale = 'en-US';
function setLocale(nextLocale) {
currentLocale = nextLocale;
}
Такой уровень управления часто становится точкой синхронизации между UI, API-слоем и форматированием данных.
Создание объектов Intl является относительно дорогой операцией, поскольку включает обращение к ICU-данным. Поэтому состояние локали тесно связано с стратегией кэширования.
Типичная ошибка — повторное создание форматтера без учета локали:
function formatDate(date) {
const formatter = new Intl.DateTimeFormat(currentLocale);
return formatter.format(date);
}
Более устойчивый подход использует кэш по локали:
const dateFormatCache = new Map();
function getDateFormatter(locale) {
if (!dateFormatCache.has(locale)) {
dateFormatCache.set(locale, new Intl.DateTimeFormat(locale));
}
return dateFormatCache.get(locale);
}
Такой подход связывает состояние локали с состоянием кэша, минимизируя пересоздание объектов при повторном использовании.
Изменение локали требует пересмотра всех зависимых Intl-объектов. При наличии кэша возникает проблема синхронизации состояния.
Стратегии управления включают:
Пример очистки:
function setLocale(nextLocale) {
currentLocale = nextLocale;
dateFormatCache.clear();
}
Более масштабируемая модель использует ключ вида
${locale}-${optionsHash}, позволяя учитывать не только
локаль, но и параметры форматирования.
Форматирование чисел напрямую зависит от локали, включая:
const nf = new Intl.NumberFormat('de-DE');
nf.format(1234567.89);
В состоянии приложения это означает, что любое числовое значение может иметь несколько представлений в зависимости от текущей локали. Поэтому форматирование часто отделяется от хранения данных.
Форматирование дат включает не только локаль, но и часовой пояс, что расширяет понятие состояния:
const dtf = new Intl.DateTimeFormat('ru-RU', {
timeZone: 'Europe/Moscow'
});
Комбинация локали и временной зоны формирует составное состояние, влияющее на итоговое представление времени.
Изменение одного из параметров требует пересоздания форматтера, что усиливает важность централизованного управления локализационным состоянием.
Сравнение строк зависит от локали и правил сортировки:
const collator = new Intl.Collator('tr-TR', { sensitivity: 'base' });
Сортировка в разных локалях приводит к различным порядкам символов, что делает локаль частью логики бизнес-данных, а не только UI.
Состояние коллатора часто кэшируется отдельно от форматтеров чисел и дат из-за различных опций конфигурации.
Если локаль не передана явно, используется локаль окружения выполнения. Это значение может поступать из:
const formatter = new Intl.NumberFormat();
В этом случае состояние локали становится неявным и зависит от среды, что усложняет воспроизводимость поведения.
Для детерминированных систем предпочтительно явное управление локалью, исключающее зависимость от внешнего окружения.
Все основные объекты Intl являются неизменяемыми. После создания их параметры не могут быть изменены. Это свойство делает их пригодными для безопасного хранения в состоянии приложения и повторного использования.
const nf = new Intl.NumberFormat('en-US');
// nf.format = изменяемый метод, но конфигурация неизменяема
Иммутабельность упрощает:
В сложных системах локаль становится частью глобального состояния, влияющего на множество модулей. Выделяются несколько подходов к управлению:
Локаль хранится в одном модуле и используется через доступ к функции получения текущего значения.
Локаль передается через контекст выполнения, что позволяет различным частям приложения использовать разные настройки одновременно.
Фабрики Intl-объектов зависят от локали и параметров:
function createFormatters(locale) {
return {
date: new Intl.DateTimeFormat(locale),
number: new Intl.NumberFormat(locale),
collator: new Intl.Collator(locale)
};
}
Такая группировка снижает избыточные пересоздания и синхронизирует состояние внутри одного набора форматтеров.
При динамической смене локали часто вводится версия состояния:
let localeState = {
locale: 'en-US',
version: 0
};
function updateLocale(nextLocale) {
localeState = {
locale: nextLocale,
version: localeState.version + 1
};
}
Версия позволяет автоматически инвалидировать кэши и пересчитывать зависимости без ручного управления списками объектов.
Intl-объекты зависят от ICU-данных, что делает их создание относительно дорогим по сравнению с обычными функциями. Поэтому управление состоянием локали тесно связано с оптимизацией производительности:
Баланс между актуальностью локали и затратами на пересоздание определяет архитектуру слоя локализации.
Корректное управление локалью обеспечивает стабильность отображения данных во всей системе. При одинаковом состоянии локали результат работы Intl-объектов становится полностью детерминированным, включая формат дат, чисел и порядок сортировки строк.