Intl API для форматирования дат, чисел, валют и единиц в JavaScript

Intl API упрощает форматирование и работу с международно ориентированными строками, числами, датами и валютами. Он позволяет корректно отображать данные в соответствии с локалью — например, применить правильный символ валюты, разделители тысяч, формат даты и порядковую форму дня.
Этот материал объясняет, как получить локаль пользователя, какие опции предоставляет Intl.DateTimeFormat и Intl.NumberFormat, показывает практические примеры и рекомендуемые подходы для тестирования и миграции.
Получение локали пользователя
Конструкторы Intl принимают локаль и объект опций. По локали они выбирают способ форматирования.
Для получения локали на клиенте обычно используют navigator.language и navigator.languages. navigator.language возвращает одиночный BCP 47 тег (например, “en-US”), а navigator.languages — массив предпочтительных локалей, отсортированный по приоритету.
Простой вспомогательный код для получения локали пользователя:
const getUserLocale = () => {
if (navigator.languages && navigator.languages.length) {
return navigator.languages[0];
}
return navigator.language;
};
console.log(getUserLocale());
Важно: при серверном рендеринге или в средах без объекта navigator локаль обычно нужно получать из заголовков запроса (Accept-Language) или из пользовательских настроек в профиле.
Форматирование дат
Intl.DateTimeFormat принимает локаль и набор опций. Помимо weekday, year, month и day есть расширенные опции для времени и временной зоны.
Ключевые опции:
- weekday: long, short, narrow
- year: numeric, 2-digit
- month: numeric, 2-digit, long, short, narrow
- day: numeric, 2-digit
- hour, minute, second: numeric, 2-digit
- timeZone: строка IANA, например “UTC” или “Europe/Moscow”
- timeZoneName: short, long
- hour12: true/false
- dateStyle / timeStyle: full, long, medium, short (удобно для быстрых настроек)
Пример форматирования даты с опциями:
const date = Date.now()
const locale = getUserLocale();
const options = {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
};
const formatter = new Intl.DateTimeFormat(locale, options);
// weekday, month date, year (Friday, March 24, 2023)
console.log(formatter.format(date));Дополнительные приёмы и полезные методы:
- formatToParts(date) возвращает массив частей (weekday, day, literal и т. д.), что удобно для составления пользовательских шаблонов.
- resolvedOptions() показывает фактические параметры форматтера после сопоставления с поддерживаемыми локалями.
Пример с временной зоной и форматированием времени:
const date = new Date();
const formatter = new Intl.DateTimeFormat('ru-RU', {
dateStyle: 'long',
timeStyle: 'short',
timeZone: 'Europe/Moscow'
});
console.log(formatter.format(date));Заметка: поведение dateStyle/timeStyle и поддержка форматных комбинаций могут отличаться между браузерами и версиями ICU, поэтому тесты по целевым локалям обязательны.
Форматирование чисел
Intl.NumberFormat форматирует числа с учётом локали и опций. Опции зависят от выбранного style.
Основные опции:
- style: decimal, percent, currency, unit
- minimumFractionDigits, maximumFractionDigits
- useGrouping: true/false — разделители тысяч
- notation: standard, scientific, engineering, compact
- compactDisplay: short, long
- signDisplay: auto, always, never, exceptZero
Десятичные числа и проценты
Пример форматирования десятичного числа:
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
Проценты:
const num = 123456;
const locale = getUserLocale();
const options = {
style: "percent",
useGrouping: true,
};
const formatter = new Intl.NumberFormat(locale, options);
console.log(formatter.format(num)); // 12,345,600%
Примечание: стиль percent умножает число на 100 и добавляет знак процента; будьте внимательны к входным данным.
Валюты
Для форматирования валют используйте style: “currency” и укажите currency (ISO 4217): “USD”, “EUR”, “RUB” и т. п. Рекомендуется всегда явно указывать currency — в разных средах отсутствие этого параметра может привести к ошибке или непредсказуемому результату.
Опция currencyDisplay управляет тем, как будет показана валюта: symbol, code или name.
Пример:
const num = 123456;
const locale = getUserLocale(); // en-US
const options = {
style: "currency",
currency: "USD",
currencyDisplay: "code",
};
const formatter = new Intl.NumberFormat(locale, options);
console.log(formatter.format(num)); // USD 123,456.00
Если нужно показать валюту в локальном формате с символом и двумя знаками после запятой, используйте currencyDisplay: “symbol” и minimumFractionDigits/maximumFractionDigits при необходимости.
Единицы измерения
Для форматирования единиц установите style: “unit” и укажите unit (например, “meter”, “kilogram”, “liter”, “second”). unitDisplay задаёт вид отображения: long, short, narrow.
Пример:
const num = 123456;
const locale = getUserLocale();
const options = {
style: "unit",
unit: "liter",
unitDisplay: "long",
};
const formatter = new Intl.NumberFormat(locale, options);
console.log(formatter.format(num)); //123,456 liters
Замечание: список поддерживаемых единиц и их имен зависит от реализации ICU в среде выполнения.
Полезные приёмы и шаблоны
- Выносите логику форматирования в отдельный слой (утилиты или сервис локализации). Это упрощает тестирование и замену реализации.
- Используйте formatToParts, если нужно встроить отформатированные числа/даты в сложные DOM-шаблоны с разной разметкой для цифр и символов.
- Для отображения дат/чисел в приложении выбирайте локаль по профилю пользователя, затем по Accept-Language, затем по настройкам браузера — в этом порядке.
- Для финансовых операций всегда храните суммы в минимальных единицах (копейки/центы) или в числовом типе с фиксированной точностью и форматируйте для показа.
Когда Intl не подходит
Важно понимать сценарии, где Intl может оказаться недостаточным:
- старые браузеры или минимальные сборки ICU в Node.js, где некоторые локали или опции не поддерживаются;
- требования к единообразному отображению между клиентом и сервером при SSR, если сервер использует другую версию ICU;
- специфические правила локализации, которых нет в стандартной базе (напр., нетипичные формы склонения валютных названий или кастомные шаблоны дат);
- корпоративные форматы для отчётов, которые не укладываются в стандартные опции.
В таких случаях рассмотрите полифилл Intl (например, intl-pluralrules/polyfill или полный ICU для Node.js) либо сторонние библиотеки (Luxon, date-fns, Day.js) с явной локализацией и более предсказуемой поддержкой.
Совместимость и миграция
- Node.js: Intl использует ICU. В некоторых сборках Node может быть включён урезанный набор локалей (small-icu). Для полного набора локалей требуется сборка с full-icu или установка соответствующих пакетов.
- Браузеры: современные версии Chrome, Firefox, Safari, Edge предоставляют широкую поддержку Intl, но детали (например, dateStyle/timeStyle, набор единиц) могут отличаться.
- SSR: при рендеринге на сервере убедитесь, что серверная среда поддерживает те же локали и правила форматирования, что и клиент.
Миграционные советы:
- Покройте тестами основные целевые локали.
- Включите проверку resolvedOptions() в тестах, чтобы убедиться, что форматтер использует ожидаемые параметры.
- При добавлении полифилла проверяйте размер бандла и impact на производительность.
Роль‑ориентированные чеклисты
Разработчик:
- Вынести форматтеры в утилиты.
- Всегда передавать локаль явно при вызове (если есть основной контекст локали).
- Использовать formatToParts при необходимости стилизовать части.
Дизайнер/UX:
- Убедиться, что макеты выдерживают разные длины строк для локалей (напр., немецкие слова длиннее).
- Проверить расположение символов валют и порядок элементов даты.
Тестировщик/Локализатор:
- Написать тесты для каждой целевой локали с контрольными примерами.
- Проверить поведение при нестандартных локалях (например, zh-Hant, ru-RU, ar-EG).
Критерии приёмки
- Дата отображается в формате, соответствующем выбранной локали и опциям.
- Числа отображаются с правильными разделителями и количеством знаков.
- Валюты показываются с ожидаемым символом/кодом/названием.
- Форматирование остаётся стабильным при смене локали и при SSR.
Тест‑кейсы и примеры проверки
- Проверка простого форматирования даты для ru-RU, en-US, ja-JP.
- Проверка форматирования валюты USD, EUR, RUB и поведение при отсутствии currency.
- Форматирование процентов: 0.123 => 12.3% (в зависимости от minimumFractionDigits).
- Отображение единиц: liter, meter, kilogram в нескольких локалях.
- formatToParts: собирать число и проверять, что части (integer, group, decimal, fraction, literal) соответствуют ожидаемым для локали.
Примеры кода: расширенные
Форматирование с notation и compact:
const numbers = [1000, 12_345_678];
const compactFormatter = new Intl.NumberFormat('en-US', { notation: 'compact', compactDisplay: 'short' });
console.log(numbers.map(n => compactFormatter.format(n))); // ['1K', '12M'] (зависит от локали)
const sciFormatter = new Intl.NumberFormat('en-US', { notation: 'scientific', maximumFractionDigits: 2 });
console.log(sciFormatter.format(12345)); // '1.23E4'Использование formatToParts для встраивания в DOM:
const formatter = new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB' });
const parts = formatter.formatToParts(123456.78);
// parts — массив объектов {type: 'integer'|'group'|'decimal'|'fraction'|'currency'|'literal', value: '...'}
// можно сгенерировать элементы для каждой части с отдельным классомМентальные модели и эвристики
- «Локаль определяет форму, опции — детализацию». Локаль задаёт порядок и символы, опции — сколько знаков и какой стиль.
- «Форматирование для показа != хранение»: храните данные в нейтральном формате, форматируйте только при отображении.
- «Fallback — явное, а не магический выбор»: лучше явно указывать currency и ключевые опции, чем полагаться на поведение реализации.
Мини‑методология внедрения Intl в проект
- Определить список целевых локалей и приоритеты.
- Вынести утилиты форматирования и централизовать доступ к текущей локали.
- Покрыть примерными тестами ключевые форматы (дата, валюта, процент, единицы).
- Провести smoke‑тесты в целевых браузерах и на сервере.
- При необходимости добавить полифилл или стороннюю библиотеку.
Безопасность и приватность
Intl не отправляет пользовательских данных наружу — это локальная библиотека. Однако при выборе локали из заголовков (Accept-Language) или профиля учитывайте потенциальные побочные каналы (фингерпринтинг): излишне детальные данные о локали могут дополняться сессиями аналитики.
Важно: храните пользовательские настройки локали в профиле только если это ожидаемое поведение, и давайте пользователю возможность изменить отображение.
Краткий словарь
- Локаль: BCP 47 тег, например ru-RU, en-US.
- ICU: библиотека для интернационализации, которую используют среды выполнения.
- formatToParts: метод для получения частей отформатированной строки.
- currencyDisplay: опция для управления показом валюты.
Альтернативы
- Luxon: современная библиотека для работы с датами/временем с хорошей поддержкой временных зон.
- Day.js и date-fns: компактные библиотеки для манипуляций с датами; локализация реализуется отдельными пакетами.
- Полифиллы Intl: для старых браузеров или когда нужно единообразие ICU.
Итог
Intl — это мощный и встроенный инструмент для локализованного форматирования дат, чисел, валют и единиц. Он хорошо подходит для большинства интерфейсных задач, но требует проверки поддержки локалей в целевых средах и аккуратного подхода при серверном рендеринге. Если проект предъявляет строгие требования к единообразию между средами или поддерживает очень старые браузеры, рассмотрите полифилл или стороннюю библиотеку.
Важно: тестируйте форматирование на реальных локалях и устройствах, документируйте используемые опции и централизуйте форматтеры в проекте.
Похожие материалы
Отключение PCA в Windows
Проблемы при обновлении до Windows 7 — решения
Переустановка Windows 7 без потери настроек
Windows 10 приложение для Arduino — пошагово
4×4×4 LED‑куб на Arduino — полное руководство