Поведение Intl API в значительной степени зависит от окружения, так
как список доступных локалей определяется ICU-библиотекой, встроенной в
браузер или Node.js. Это создаёт первую категорию проблем:
непредсказуемость поддержки локалей между средами.
Падение на ближайшую
доступную локаль
Если запрошенная локаль отсутствует, происходит fallback:
new Intl.DateTimeFormat("xx-YY").resolvedOptions().locale
Результат может неожиданно превратиться в "en" или
другую системную локаль. Это приводит к:
- различиям в форматировании между staging и production
- различиям между браузерами
- различиям между версиями Node.js
Ключевая проблема: отсутствие строгого контроля над
цепочкой fallback.
Расширенные теги BCP 47
и их деградация
Локали вида:
zh-Hant-HK
sr-Latn-RS
en-US-u-ca-buddhist
могут частично игнорироваться. Unicode extension subtags
(-u-) особенно подвержены:
- удалению при fallback
- игнорированию при отсутствии поддержки календаря/системы
счисления
Несовместимость ICU и
различия окружений
Intl API напрямую зависит от ICU версии.
Разные результаты
форматирования
Один и тот же код может выдавать разные строки:
- Node.js с полной ICU
- Node.js с small-icu
- браузеры разных версий
Особенно заметно в:
Intl.NumberFormat
Intl.DateTimeFormat
Intl.Collator
Типичный эффект: изменение формата даты без
изменения кода.
Проблема частичной сборки
ICU
Small-ICU часто содержит только базовые локали (en, some European
languages). Остальные локали:
- откатываются на en
- теряют поддержку календарей и систем счисления
Проблемы дат и временных зон
DST (переход на летнее/зимнее
время)
Самый частый источник ошибок:
new Date("2024-03-31T02:30:00")
В некоторых зонах это время не существует.
Результаты:
- автоматический сдвиг времени
- пропуск часов
- неожиданные сутки
Нестабильность временных зон
IANA timezone database регулярно обновляется:
- изменяются правила DST
- появляются новые зоны
- старые переименовываются
Это влияет на:
timeZone: "Europe/Moscow"
- исторические даты
- серверные расчёты
Границы Date и числовые
ограничения
Ограничения диапазона Date
JavaScript Date работает в диапазоне:
- приблизительно ±100 миллионов дней от epoch
При выходе за пределы:
- возвращается
Invalid Date
- Intl может вести себя непредсказуемо
NaN и Infinity в
форматировании
new Intl.NumberFormat().format(NaN)
new Intl.NumberFormat().format(Infinity)
Результаты зависят от локали:
- NaN → “NaN”, “не число”, “NaN” (разные языки)
- Infinity → “∞”, “Infinity”
Проблема: невозможность унифицировать отображение
без пост-обработки.
Числовые форматы и ошибки
округления
Потеря точности IEEE 754
0.1 + 0.2 // 0.30000000000000004
Intl может скрывать или усиливать эффект:
maximumFractionDigits
roundingMode (в новых реализациях)
Банковское округление и
локали
Разные локали применяют разные правила округления:
- half-up
- half-even
- truncation (редко)
Проблема: отсутствие гарантированного поведения без
явного задания roundingMode.
BigInt поддерживается не всегда одинаково:
- некоторые окружения конвертируют в string
- другие поддерживают напрямую
- возможны ошибки при очень больших числах
Культурные различия
форматирования
Порядок компонентов даты
new Intl.DateTimeFormat("en-US")
new Intl.DateTimeFormat("de-DE")
Результат:
Edge case: парсинг таких строк обратно невозможен
без контекста локали.
Различия систем счисления
Некоторые локали используют:
- арабские цифры
- восточно-арабские цифры
- индийские цифры
Это влияет на:
- отображение чисел
- сортировку строк
- UX в формах
Разные символы валют
new Intl.NumberFormat("en", {
style: "currency",
currency: "USD"
})
Возможные варианты:
- $1,000.00
- US$1,000.00
- $ 1.000,00 (в некоторых локалях)
Collator и
неожиданные результаты сортировки
Лексикографическая
нестабильность
["ä", "a", "z"].sort(new Intl.Collator("de").compare)
Результат зависит от:
- strength
- sensitivity
- ICU версии
Numeric sorting и строки
чисел
["2", "10", "1"].sort(collator.compare)
Без { numeric: true } результат:
С включённой опцией:
Case sensitivity и
диакритика
Опции sensitivity:
Ошибки возникают при:
- смешанных языках
- пользовательском вводе
- поисковых системах
new Intl.RelativeTimeFormat("en").format(-1, "day")
Проблемные случаи:
- “yesterday” vs “1 day ago”
- неоднозначность при границах суток
- локализация с отсутствием форм
new Intl.ListFormat("en", { type: "conjunction" })
Разные локали используют:
- запятую
- союзы (“and”, “und”, “и”)
- отсутствие Oxford comma
Edge case: автоматическое построение текста может
ломать UX-интонацию.
Потеря стабильности
структуры
new Intl.NumberFormat().formatToParts(1000)
Проблемы:
- разные части в разных локалях
- нестабильный порядок частей
- необходимость ручной сборки строки
Сложность восстановления
строки
Склеивание частей:
- требует учёта
literal
- требует локали-специфичной логики
Unicode и нормализация строк
Разные формы одного символа
"é" === "e\u0301"
Intl Collator может:
- считать равными
- считать различными (в зависимости от sensitivity)
Проблемы поиска
- визуально одинаковые строки не совпадают
- сортировка нарушается
- фильтрация данных становится нестабильной
RTL-языки и визуальные
артефакты
Локали типа:
создают проблемы:
- смешение направлений текста
- ошибки при вставке чисел
- некорректные разделители
Особенно в:
- таблицах
- финансовых интерфейсах
- логах
Гидратация и
SSR-рассинхронизация
Разные результаты на
сервере и клиенте
Сервер:
Intl.DateTimeFormat().format(new Date())
Клиент:
- другая локаль браузера
- другая временная зона
Результат:
- mismatch при hydration
- ошибки фреймворков
- повторный рендер
Проблемы кэширования Intl
объектов
Неожиданная дороговизна
создания
new Intl.NumberFormat(...)
Создание:
- дорого по CPU
- аллоцирует ICU структуры
Типичная ошибка:
- создание форматтера внутри цикла
Кэширование и его побочные
эффекты
- разные опции → разные экземпляры
- риск утечки памяти при динамических локалях
- необходимость централизованного пула форматтеров
Ограничения совместимости
API
Старые браузеры и полифилы
Некоторые функции:
Intl.PluralRules
Intl.RelativeTimeFormat
Intl.DisplayNames
Intl.Segmenter
могут отсутствовать или быть частично реализованы.
Частичная поддержка опций
Например:
roundingMode
trailingZeroDisplay
могут игнорироваться без ошибок, создавая иллюзию корректной
работы.
Неоднозначность
отображения календарей
Разные календарные системы
calendar: "gregory"
calendar: "islamic"
calendar: "buddhist"
Проблемы:
- отсутствие поддержки в локали
- fallback на Gregorian
- несоответствие ожиданиям пользователей
Intl API не предназначен для парсинга, но часто используется
косвенно:
- форматирование → обратный парсинг
- локализованные числа → преобразование в Number
- даты из строк
Проблемы:
- неоднозначные разделители
- разные порядки компонентов
- невозможность однозначного восстановления исходного значения
Итоговые классы проблем Intl
API
1. Зависимость от окружения
ICU, браузер, Node.js, версия системы.
2. Локализационная
неоднозначность
Fallback, BCP 47, Unicode extensions.
3. Временные зоны и
календарные эффекты
DST, IANA updates, invalid local times.
4. Числовая нестабильность
Floating point, rounding, currency rules.
5. Структурная сложность
вывода
formatToParts, RTL, collation differences.
6. Производственные ловушки
SSR mismatch, caching, performance costs.
7. Семантические ограничения
Отсутствие обратного парсинга и строгой обратимости
форматирования.