ECMAScript Internationalization API

ECMAScript Internationalization API (Intl) представляет собой встроенный в JavaScript набор инструментов для локализации и культурно-зависимой обработки данных: чисел, дат, строк, списков и языковых форм. API стандартизирован спецификацией ECMA-402 и интегрирован в современные JavaScript-движки, обеспечивая единый подход к международной адаптации приложений без внешних библиотек.

Основная идея заключается в разделении данных и их представления: логика приложения оперирует абстрактными значениями, а слой Intl отвечает за форматирование с учётом локали пользователя, правил языка и региональных особенностей.


Ключевым понятием является локаль — строковый идентификатор языка и региона, соответствующий стандарту BCP 47.

Примеры:

  • en — английский язык
  • en-US — английский (США)
  • ru-RU — русский (Россия)
  • zh-Hans-CN — китайский (упрощённая письменность, Китай)

Локаль может включать:

  • язык
  • регион
  • вариант письменности
  • расширения (например, календарь или сортировка)

Разрешение локали происходит через механизм locale resolution, где движок сопоставляет запрошенную локаль с поддерживаемыми вариантами.


Объект Intl и базовая архитектура

Глобальный объект Intl служит контейнером для всех форматтеров и утилит:

  • Intl.NumberFormat
  • Intl.DateTimeFormat
  • Intl.Collator
  • Intl.PluralRules
  • Intl.RelativeTimeFormat
  • Intl.ListFormat
  • Intl.DisplayNames
  • Intl.Segmenter

Каждый из этих конструкторов создаёт специализированный форматтер, который инкапсулирует правила конкретной локали.

Общая архитектура основана на двух шагах:

  1. Создание экземпляра с заданной локалью и опциями
  2. Вызов метода форматирования (format, formatToParts, resolvedOptions)

Intl.NumberFormat: форматирование чисел

Используется для локализованного представления чисел, валют и процентов.

const nf = new Intl.NumberFormat('ru-RU');
nf.format(1234567.89); // "1 234 567,89"

Основные режимы

Валюта:

new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
}).format(1234.5); // "$1,234.50"

Проценты:

new Intl.NumberFormat('en-US', {
  style: 'percent'
}).format(0.25); // "25%"

Единицы измерения:

new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'kilometer-per-hour'
}).format(100);

Детализация форматирования

Опции управления:

  • minimumFractionDigits
  • maximumFractionDigits
  • useGrouping

Метод formatToParts() возвращает структуру токенов, полезную для кастомного UI.


Intl.DateTimeFormat: даты и время

Форматирование дат зависит от культурных правил: порядок компонентов, разделители, названия месяцев.

const dtf = new Intl.DateTimeFormat('ru-RU');
dtf.format(new Date()); 

Управление представлением

new Intl.DateTimeFormat('en-GB', {
  dateStyle: 'full',
  timeStyle: 'long'
});

Детализированные поля

  • year
  • month
  • day
  • hour
  • minute
  • second
  • weekday
new Intl.DateTimeFormat('en-US', {
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

Таймзоны

new Intl.DateTimeFormat('en-US', {
  timeZone: 'UTC'
});

Поддержка IANA time zone database обеспечивает корректное отображение времени независимо от локальной системы.


Intl.RelativeTimeFormat: относительное время

Используется для выражений вида «3 дня назад» или «через 2 часа».

const rtf = new Intl.RelativeTimeFormat('ru-RU');

rtf.format(-1, 'day'); // "1 день назад"
rtf.format(2, 'hour'); // "через 2 часа"

Поддерживаемые единицы:

  • second
  • minute
  • hour
  • day
  • week
  • month
  • quarter
  • year

Опция numeric позволяет управлять формой:

new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

Intl.PluralRules: множественные формы

Языки различают формы слов в зависимости от числа.

const pr = new Intl.PluralRules('ru-RU');

pr.select(1); // "one"
pr.select(2); // "few"
pr.select(5); // "many"

Используется для построения локализованных сообщений:

const forms = {
  one: 'яблоко',
  few: 'яблока',
  many: 'яблок'
};

Intl.Collator: сравнение строк

Предназначен для корректной сортировки строк с учётом языка.

const collator = new Intl.Collator('ru-RU');

['яблоко', 'арбуз', 'груша'].sort(collator.compare);

Опции сортировки

  • sensitivity (base, accent, case, variant)
  • numeric (учёт чисел в строках)
  • ignorePunctuation
new Intl.Collator('en', { numeric: true }).compare('file2', 'file10');

Intl.ListFormat: форматирование списков

Используется для корректного соединения элементов списка.

const lf = new Intl.ListFormat('ru-RU');

lf.format(['яблоки', 'груши', 'сливы']);
// "яблоки, груши и сливы"

Типы:

  • conjunction (и)
  • disjunction (или)
  • unit (единицы измерения)

Intl.DisplayNames: локализованные названия

Позволяет получать локализованные названия языков, регионов и валют.

const dn = new Intl.DisplayNames('ru-RU', { type: 'language' });

dn.of('en'); // "английский"
dn.of('fr'); // "французский"

Типы:

  • language
  • region
  • currency
  • script

Intl.Segmenter: сегментация текста

Используется для разбиения текста на границы: слова, предложения, графемы.

const segmenter = new Intl.Segmenter('en', { granularity: 'word' });

[...segmenter.segment('Hello world')].map(s => s.segment);

Гранулярность:

  • grapheme (символы)
  • word (слова)
  • sentence (предложения)

Особенно важно для языков без пробелов (например, китайский, японский).


Разрешение локали и fallback-логика

При создании любого форматтера происходит:

  1. Анализ списка локалей
  2. Выбор наиболее подходящей
  3. Применение fallback (например, en-USen)
new Intl.NumberFormat(['fr-CA', 'fr', 'en']);

Метод:

resolvedOptions()

возвращает фактически выбранные параметры:

nf.resolvedOptions();

Производительность и повторное использование

Создание экземпляров Intl является относительно дорогой операцией. Оптимизация строится на:

  • кешировании форматтеров
  • переиспользовании экземпляров
  • предварительной инициализации при загрузке приложения
const formatter = new Intl.NumberFormat('ru-RU');

function format(value) {
  return formatter.format(value);
}

Поддержка сред выполнения

Intl реализован в:

  • современных браузерах (Chrome, Firefox, Safari, Edge)
  • Node.js (через ICU-библиотеку)
  • некоторых ограниченных окружениях с урезанным ICU

Полнота функциональности зависит от версии ICU, встроенной в движок.


Опции расширенной настройки

Общие механизмы, встречающиеся в разных конструкторах:

  • localeMatcher: алгоритм выбора локали (best fit или lookup)
  • style: формат представления
  • notation: научная или инженерная нотация (NumberFormat)
  • signDisplay: управление знаком числа

Форматирование через parts API

Многие форматтеры поддерживают метод:

formatToParts()

Пример:

new Intl.NumberFormat('ru-RU').formatToParts(1234);

Результат представляет массив объектов:

  • { type: 'integer', value: '1' }
  • { type: 'group', value: ' ' }

Это позволяет строить кастомные интерфейсы, где каждая часть числа или даты стилизуется отдельно.


Unicode и культурная чувствительность

Intl опирается на стандарты Unicode:

  • CLDR (Common Locale Data Repository)
  • ICU (International Components for Unicode)

Это обеспечивает согласованность поведения между платформами и языками.

Особое внимание уделяется:

  • правилам множественных форм
  • порядку сортировки
  • форматированию дат
  • написанию чисел и валют

Интеграция с приложениями

Intl часто используется как базовый слой в:

  • системах локализации UI
  • финансовых приложениях
  • аналитических панелях
  • календарях и планировщиках
  • поисковых системах (сортировка и ранжирование)

Архитектурно он выступает как низкоуровневый форматтер, поверх которого строятся i18n-библиотеки более высокого уровня.