Intl API: как форматировать даты, числа и валюты по локали

Что такое Intl API и зачем он нужен
Intl API — это стандартизованный интерфейс в JavaScript для форматирования строк, чисел, дат и валют с учётом локали пользователя. Это позволяет автоматически применить нужный порядок даты, разделители тысяч и десятичные разделители, локальные названия валют и единиц.
Кратко:
- Intl.DateTimeFormat — форматирование дат и времени.
- Intl.NumberFormat — форматирование чисел, процентов, валют и единиц.
Важно: Intl опирается на реализацию движка (ICU) в браузере и операционной системе, поэтому вывод может немного отличаться между средами.
Как получить локаль пользователя
Лучший практический способ — проверить navigator.languages и navigator.language. navigator.languages возвращает массив предпочтений пользователя, отсортированный по приоритету.
Код для получения локали:
const getUserLocale = () => {
if (navigator.languages && navigator.languages.length) {
return navigator.languages[0];
}
return navigator.language;
};
console.log(getUserLocale());Пояснение: возвращается BCP 47 тэг, например “en-US” или “ru-RU”. Используйте его в конструкторе Intl.
Форматирование дат: Intl.DateTimeFormat
Intl.DateTimeFormat принимает локаль и объект опций, где можно задать формат для weekday, year, month, day и других компонент.
Простой пример:
const date = Date.now();
const locale = getUserLocale();
const options = {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
};
const formatter = new Intl.DateTimeFormat(locale, options);
console.log(formatter.format(date)); // пример: "пятница, 24 марта 2023 г."Советы:
- Для компактного формата используйте { year: “2-digit”, month: “short”, day: “2-digit” }.
- Для времени добавьте hour, minute, second и параметр hour12 для 12/24-часового формата.
- Для временных зон используйте timeZone: “Europe/Moscow” или Intl API по умолчанию возьмёт системную зону.
Ограничения:
- Не все браузеры поддерживают все опции одинаково (например, форматирование временных зон или узкие названия дней).
Форматирование чисел: Intl.NumberFormat
Intl.NumberFormat форматирует десятичные числа, проценты, валюты и единицы. Вы задаёте локаль и options.
Десятичные числа и проценты
Пример форматирования десятичного числа:
const num = 123456;
const locale = getUserLocale(); // например "en-US"
const options = {
style: "decimal",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
useGrouping: true,
};
const formatter = new Intl.NumberFormat(locale, options);
console.log(formatter.format(num)); // "123,456.00" в en-USПроценты:
const num = 0.1234; // 12.34%
const locale = getUserLocale();
const options = { style: "percent", maximumFractionDigits: 2 };
const pct = new Intl.NumberFormat(locale, options);
console.log(pct.format(num)); // "12.34%" (в зависимости от локали)Примечание: передавать 123456 как процент даёт 12 345 600% — обычно проценты задают как дробь от 1.
Валюты
Для валют укажите style: “currency” и currency: “USD”/“EUR” и т.д. currencyDisplay контролирует отображение (symbol, code, name).
const num = 123456;
const locale = getUserLocale(); // "ru-RU" или "en-US"
const options = {
style: "currency",
currency: "USD",
currencyDisplay: "code", // "USD 123,456.00" или локальная форма
};
const money = new Intl.NumberFormat(locale, options);
console.log(money.format(num));Советы по валютам:
- Всегда указывайте currency, если ожидаете конкретную валюту.
- Для пользовательских локалей можно выбирать currency по стране пользователя как дефолт, но лучше показывать выбор валюты в интерфейсе.
Единицы измерения
Intl.NumberFormat поддерживает style: “unit” и unit: “liter”/“meter”/“kilogram” и т.д. unitDisplay: “long”|”short”|”narrow”.
const num = 123456;
const locale = getUserLocale();
const options = { style: "unit", unit: "liter", unitDisplay: "long" };
const fmt = new Intl.NumberFormat(locale, options);
console.log(fmt.format(num)); // "123 456 liters" или локальная формаУчтите, что многие единицы имеют разные формы в зависимости от локали и языка.
Когда Intl может не подойти (контрпримеры)
- Если вам нужны одинаковые вывода на всех платформах (byte-for-byte) — Intl даст разные строки в разных реализациях. В этом случае лучше использовать библиотеку с собственным шаблоном вывода.
- Если целевая среда — очень старые браузеры без Intl (IE < 11) — потребуется полифилл или сторонняя библиотека.
- Если вы должны переводить и управлять форматами извне (например, CMS) — возможно, удобнее хранить форматные строки на сервере.
Альтернативы и полифиллы
- Luxon — современная библиотека для дат (использует Intl когда доступен).
- Day.js — лёгкая замена Moment.js, плагинная архитектура.
- date-fns — набор утилит для дат, не всегда локализует вывод автоматически.
- Polyfill: “Intl.js” или пакет “@formatjs/intl” для старых окружений.
Выбор зависит от требований: нужна ли поддержка i18n из коробки, размер бандла, и поведение в разных средах.
Руководство по внедрению (мини-методология)
- Определите требуемые локали и бизнес-правила (валюта пользователя, формат даты в UI, округление).
- Используйте navigator.languages[0] с фоллбеком на navigator.language.
- Централизуйте форматтеры в утилитный модуль (например, utils/formatters.js) и переиспользуйте их.
- Покройте юнит-тестами критичные форматы (набор примеров вход/ожидаемый вывод для ключевых локалей).
- Для старых браузеров добавьте полифилл и протестируйте в CI с эмуляцией окружений.
- Документируйте правила отображения для локализаторов.
Совместимость и миграция
Таблица совместимости (общая):
- Современные версии Chrome, Firefox, Safari и Edge имеют хорошую поддержку Intl.
- Node.js поддерживает Intl, но поведение зависит от сборки и ICU.
- Для старых браузеров (IE11 и ниже) потребуется полифилл.
Миграционные советы:
- Вынесите вызовы Intl в один слой — это упростит подмену реализации.
- Добавьте feature-detection: if (typeof Intl === “undefined”) { / подгрузить полифилл / }.
Проверки и тесты (кейсы приёмки)
Критерии приёмки:
- Для каждой критичной локали проверяется формат даты, времени, валюты и процента.
- Для валюты: корректная валюта и отображение символа/кода.
- Для процентов: входные значения интерпретируются как доля (0.5 => 50%).
Примеры тест-кейсов:
- Формат даты для “en-US” и “ru-RU” для одной и той же отметки времени.
- Формат валюты USD для пользователей в разных локалях.
- Отладка: если locales содержит несуществующий тэг — Intl должен фоллбекнуть на «en» или системную локаль.
Чеклист ролей
Для разработчика:
- Централизуйте форматтеры.
- Добавьте unit-тесты для ключевых локалей.
- Обеспечьте фоллбеки и полифиллы.
Для продукт-менеджера:
- Утвердите список обязательных локалей.
- Решите политику по валютам и округлению.
Для локализатора:
- Проверьте вывод дат и единиц в целевом языке.
- Подготовьте примеры с реальными значениями для проверки.
Decision tree: Intl или библиотека
flowchart TD
A[Нужна локализация форматов?] -->|Да| B{Целевые окружения}
B -->|Современные браузеры + Node| C[Использовать Intl]
B -->|Старые браузеры/IE| D[Intl + полифилл или библиотека]
B -->|Единый вывод на всех платформах| E[Использовать библиотеку с собственным шаблоном]
A -->|Нет| F[Обычный стринг-форматинг]Безопасность и приватность
Intl использует только локальные настройки браузера и не отправляет данные на сервер. Однако не полагайтесь на локаль как на источник чувствительной информации: локаль — это предпочтение интерфейса, а не доказательство геолокации.
Короткая галерея крайних случаев
- Локаль возвращает “und” или пустую строку — используйте дефолт “en” или ваш продуктовый дефолт.
- Пользователь выбрал язык, не поддерживаемый ваш интерфейс — предоставьте загрузку локализованных ресурсов и fallback-тексты.
Краткий глоссарий
- BCP 47: стандарт для меток локалей (например, “en-US”).
- ICU: библиотека для интернационализации, на которой основан Intl.
- Фоллбек: резервный вариант, если нужная локаль не поддерживается.
Итог и рекомендации
Важно: централизуйте логику форматирования, тестируйте для ключевых регионов и используйте полифиллы только при необходимости. Intl — предпочтительный инструмент для большинства задач по локализации форматов: он встроен, эффективен и покрывает основные кейсы.
Короткий чек-план внедрения:
- Добавьте getUserLocale().
- Вынесите formatter-обёртки.
- Напишите тесты для ключевых локалей.
- Добавьте полифилл для старых окружений.
Похожие материалы
Что автоматизировать в умном доме
Philips Hue Bridge — настройка и возможности
Adobe Camera Raw: полное руководство по RAW
Google Street View: как открыть на телефоне и ПК
Amazon Music Prime — как начать слушать