Спросите свой вопрос и получите сводку документа, используя эту страницу и выбранного вами поставщика AI
Содержимое этой страницы было переведено с помощью ИИ.
Смотреть последнюю версию оригинального контента на английскомЕсли у вас есть идея по улучшению этой документации, не стесняйтесь внести свой вклад, подав запрос на вытягивание на GitHub.
Ссылка на документацию GitHubКопировать Markdown документа в буфер обмена
Форматирование дат и чисел по локалям с помощью Intl
Перевод строк — это лишь видимая верхушка айсберга интернационализации. Вторая половина, порождающая регулярные баг-репорты, это форматирование: когда пользователь из Германии видит 1,234.56 вместо 1.234,56, пользователь из Японии видит 08/02/2026 и читает это как август, или когда дата по-разному отображается на сервере и клиенте, ломая гидратацию React.
Ни для чего из этого не нужны сторонние библиотеки. Стандартный Intl встроен в любую современную среду исполнения.
Содержание
Начните с удаления самописных хелперов для дат
Практически в любой кодовой базе найдется функция formatDate, написанная задолго до того, как кто-то задумался о локализации. В ней захардкожен жесткий порядок, разделитель и, как правило, английские названия месяцев.
Копировать код в буфер обмена
Intl.DateTimeFormat заменяет ее полностью и работает корректно для любой локали:
Копировать код в буфер обмена
То же самое касается чисел. Метод toFixed(2) повсеместно выдает 1234.56, что является ошибкой для большей части Европы.
Что охватывает Intl
Открыть таблицу в модальном окне для четкого просмотра всех данных
| API | Для чего использовать |
|---|---|
Intl.DateTimeFormat | Даты и время с пресетами dateStyle / timeStyle |
Intl.NumberFormat | Дроби, валюты, проценты, единицы измерения, компактный вид |
Intl.RelativeTimeFormat | "3 дня назад", "через 2 часа" |
Intl.ListFormat | "a, b и c" против "a, b, and c" |
Intl.PluralRules | Определение грамматической категории плюрализации чисел |
Intl.Collator | Корректная сортировка строк с учетом правил языка |
Intl.Collator часто несправедливо забывают. Обычный array.sort() на строках сортирует по кодовым точкам Unicode, из-за чего буквы с диакритикой улетают в конец за букву z, а шведская ö оказывается не на своем месте. Если вы сортируете видимые пользователю списки, делайте это через коллатор.
Копировать код в буфер обмена
Предпочитайте пресеты ручной сборке параметров
dateStyle и timeStyle позволяют самой локали определить правильный порядок полей и разделители. Перечисление year, month и day по отдельности дает избыточный контроль, который чаще вредит, так как принятый порядок элементов различается в зависимости от страны, и вы рискуете перезаписать правила CLDR своими ошибочными догадками.
Копировать код в буфер обмена
Указывайте отдельные поля явным образом только тогда, когда строгая фиксированная ширина продиктована дизайном, например в узкой колонке таблицы.
Создание форматтеров ресурсоемко
Это ключевой нюанс производительности. Инициализация объекта Intl.NumberFormat загружает увесистые локализационные данные, и эта операция значительно дороже последующего вызова .format(). Вызов конструктора внутри цикла рендеринга на тысячу строк приводит к ощутимым задержкам.
Копировать код в буфер обмена
Методы toLocaleDateString() и toLocaleString() страдают той же скрытой проблемой: каждый их вызов под капотом конструирует новый форматтер. Это незаметно для единичного значения, но недопустимо для списков.
Кэшируйте форматтеры по комбинации локали и параметров:
Копировать код в буфер обмена
Баг с часовым поясом, возникающий только в продакшене
Этот сценарий отнял у разработчиков множество рабочих часов. Сервер рендерит дату при SSR, браузер выполняет гидратацию на клиенте, и React выбрасывает ошибку hydration mismatch, так как на сервере и в браузере получились разные текстовые строки.
Причина в том, что Intl.DateTimeFormat использует текущий часовой пояс операционной системы, если он не указан явно. Сервер продакшена работает по UTC, а ноутбук разработчика — в домашнем часовом поясе. В результате баг невозможно воспроизвести локально, и он стреляет только в продакшене.
Копировать код в буфер обмена
Три рабочих подхода:
- Зафиксировать часовой пояс на сервере и передавать его явно. Надежно и детерминированно, но все видят время по UTC.
- Рендерить только на клиенте, оставляя нейтральный плейсхолдер во время серверного прохода. Точно для каждого пользователя, но дает небольшой визуальный сдвиг.
- Сохранять часовой пояс пользователя и прокидывать его на сервер и клиент. Идеальный результат, требующий чуть больше подготовительной работы.
Какой бы путь вы ни выбрали, всегда передавайте timeZone явно для любых дат, участвующих в SSR и гидратации. Дата без указания часового пояса — это дата с двумя несовпадающими значениями.
Валюте нужна валюта, а не локаль
Локаль и валюта независимы друг от друга. fr-FR не означает евро по умолчанию: французский пользователь вполне может просматривать инвойс в долларах США.
Копировать код в буфер обмена
Локаль управляет разделителями, группировкой разрядов и положением символа. Валюта берется из ваших прикладных данных. Попытка вывести одно из другого неизбежно приведет к ошибкам в бухгалтерии.
Обратите внимание на параметр currencyDisplay. В интерфейсах, где сосуществуют разные валюты со знаком доллара, значение "code" исключает путаницу между долларами США, Канады и Австралии.
Относительное время воспринимается лучше абсолютного
Для недавних событий текст "2 часа назад" воспринимается гораздо легче точной временной метки, и Intl.RelativeTimeFormat берет это на себя.
Копировать код в буфер обмена
Параметр numeric: "auto" как раз и возвращает "вчера" вместо сухого "1 день назад". Без него вы получите механический числовой формат.
Что добавляет Intlayer
Intlayer оборачивает эти возможности в легковесные хелперы с автоматическим кэшированием, избавляя вас от ручного поддержания Map, и автоматически подставляет активную локаль из контекста.
Копировать код в буфер обмена
Функция date() также поддерживает пресеты ("short", "long", "dateOnly", "timeOnly", "full"). Для React и Vue доступны готовые хуки и composables, получающие активный язык непосредственно из контекста приложения.
Это слой кэширования и подстановки локали по умолчанию над стандартным API платформы. Сама логика форматирования полностью опирается на нативный Intl. Все сигнатуры описаны в документации форматтеров.
Частые ошибки
toLocaleDateString()без указания локали. Берет локаль операционной системы, которая на сервере зависит от настроек контейнера.- Форматирование в цикле без кэширования. Создание форматтера забирает львиную долю процессорного времени.
- Отсутствие
timeZoneна изоморфных датах. Гарантирует ошибки гидратации, которые не воспроизводятся локально. - Определение валюты по локали.
fr-FRне гарантирует расчеты в евро. - Обычный
sort()для видимых списков. Всегда применяйтеIntl.Collator. - Ручной хардкод названий месяцев или дней. Они уже содержатся в базе CLDR для всех языков.
- Отказ от
numeric: "auto"для относительного времени. Приводит к фразам вроде "1 день назад" там, где есть слово вчера.
Полезные материалы
- Форматтеры и утилиты локалей:
number,currency,date,relativeTime,list - Справочник конфигурации
- Бенчмарки производительности фреймворков
- Адаптер совместимости react-intl
- Формат сообщений ICU: множественные формы, селекторы и числовые скелетоны
- Как тестировать переводы, включая форматтеры и плюрализацию
- Что на самом деле охватывает интернационализация
Комментарии
Пока нет комментариев. Будьте первым, кто поделится своими мыслями.
