Международные API в JavaScript опираются на стандарты BCP 47, ICU и данные CLDR, из-за чего поведение форматирования зависит не только от кода приложения, но и от окружения выполнения. Различия между браузерами, версиями Node.js, операционными системами и установленными языковыми пакетами часто становятся причиной несоответствий в форматировании дат, чисел и текста.
Основные объекты Intl API: Intl.DateTimeFormat,
Intl.NumberFormat, Intl.Collator,
Intl.RelativeTimeFormat, Intl.PluralRules,
Intl.ListFormat — используют механизм выбора локали и её
«деградации» (locale fallback), который является ключевой зоной
возникновения проблем.
Выбор локали происходит через алгоритм разрешения BCP 47 тегов.
Например, строка ru-KZ, ru-RU, ru
рассматриваются как отдельные кандидаты с постепенным упрощением.
При создании форматтера:
const fmt = new Intl.DateTimeFormat("ru-KZ");
движок:
ru-KZruРезультат можно исследовать через:
fmt.resolvedOptions();
Ключевые поля:
locale — фактически выбранная локальcalendar — используемый календарьnumberingSystem — система счисленияtimeZone — временная зона (для DateTimeFormat)Расхождения между ожидаемой и фактической локалью часто возникают из-за того, что движок «упрощает» запрос до более общего варианта.
resolvedOptions() является основным инструментом
диагностики поведения Intl.
const nf = new Intl.NumberFormat("kk-KZ");
nf.resolvedOptions();
Типичные проблемы выявляются по следующим признакам:
ru-KZ →
ru-RU)При анализе следует учитывать, что итоговая локаль может быть нормализована движком ICU и не совпадать с входной строкой.
Различия между средами выполнения являются одной из основных причин неконсистентного форматирования.
зависит от сборки ICU
возможны режимы:
В режиме small ICU часть локалей отсутствует, что приводит к неожиданным fallback-цепочкам.
Пример:
Intl.NumberFormat("zh-Hant-HK")
в одной среде может давать традиционные китайские настройки, в другой — упрощённый китайский.
Node.js может использовать системный ICU, где набор локалей ограничен установленными пакетами ОС.
В Linux-средах часто встречается ситуация:
Результат — автоматический переход к en-US.
Метод Intl.supportedLocalesOf используется для
диагностики доступности локалей:
Intl.supportedLocalesOf(["ru-KZ", "kk-KZ", "fr-FR"]);
Возвращается массив локалей, реально поддерживаемых окружением.
Пустой результат указывает на отсутствие поддержки, а не на ошибку синтаксиса.
Intl.DateTimeFormat чувствителен к таймзоне, которая
может отличаться между:
new Intl.DateTimeFormat("ru-RU", {
timeZone: "Asia/Almaty"
});
Типичные проблемы:
timeZone при fallbackДиагностика:
new Intl.DateTimeFormat().resolvedOptions().timeZone;
BCP 47 теги могут содержать расширения:
-u-nu (система счисления)-u-ca (календарь)-u-hc (часовой формат)Пример:
new Intl.DateTimeFormat("ar-EG-u-nu-latn");
Проблемы возникают при:
Результатом может стать потеря ожидаемой системы счисления или формата времени.
Intl.NumberFormat зависит от:
new Intl.NumberFormat("de-DE").format(1234567.89);
Ожидается: 1.234.567,89
Однако возможны отклонения:
Причина часто связана с fallback локали или ограниченной ICU сборкой.
Intl.Collator зависит от локали сильнее остальных
API.
["ä", "a", "z"].sort(new Intl.Collator("de").compare);
Типовые ошибки:
usage: "sort" и
usage: "search"Диагностика:
const col = new Intl.Collator("de", { sensitivity: "base" });
col.resolvedOptions();
Intl объекты кэшируются внутри движка, но неправильное переиспользование приводит к ошибкам логики:
const fmt = new Intl.DateTimeFormat("ru-RU");
function format(date, locale) {
return fmt.format(date); // локаль игнорируется
}
Проблема проявляется как:
Intl объекты не сериализуются напрямую:
JSON.stringify(new Intl.NumberFormat("ru-RU"));
Результат:
{}
Диагностика требует использования:
formatter.resolvedOptions();
Логирование без resolvedOptions часто скрывает реальную локаль, выбранную движком.
ICU библиотека определяет:
Разные версии ICU приводят к:
В Node.js это особенно заметно при переходе между версиями runtime.
Некорректные теги автоматически приводятся к валидным:
new Intl.DateTimeFormat("russian");
Результат:
en-USКорректный формат:
ruru-RUДиагностический признак — неожиданный locale в
resolvedOptions.
При SSR часто возникает расхождение между сервером и клиентом:
Это приводит к:
Типичный источник:
new Intl.DateTimeFormat().format(new Date());
без явного указания локали.
Если локаль не указана:
new Intl.NumberFormat();
используется:
Intl.DateTimeFormat().resolvedOptions().locale
или системная локаль окружения.
Проблемы возникают при:
Комплексная диагностика включает:
Пример диагностического набора:
function debugLocale(locale) {
const dt = new Intl.DateTimeFormat(locale);
const nf = new Intl.NumberFormat(locale);
const col = new Intl.Collator(locale);
return {
date: dt.resolvedOptions(),
number: nf.resolvedOptions(),
collator: col.resolvedOptions()
};
}
enЕсли локаль не распознана:
Пример:
new Intl.NumberFormat("xx-YY");
Результат:
Диагностика возможна только через resolvedOptions.
Intl API не предоставляет событий изменения локали. Любые изменения окружения не отражаются автоматически.
Следовательно: