Angular i18n

Интернационализация в JavaScript в современном вебе опирается на встроенный стандарт ECMAScript Internationalization API (Intl), который предоставляет единый механизм форматирования дат, чисел, валют, единиц измерения и текстовых конструкций с учётом локали. В экосистеме Angular эта функциональность используется как на уровне платформы, так и через шаблонные инструменты и DI-механизмы, формируя связку между стандартным API браузера и фреймворком интернационализации.

Angular строит свою i18n-модель поверх двух уровней: compile-time интернационализации шаблонов и runtime-форматирования через JavaScript Intl API. Такое разделение позволяет одновременно оптимизировать производительность и обеспечить точность локализованного вывода.


Intl API как базовый слой локализации

ECMAScript Internationalization API предоставляет набор объектов-конструкторов:

  • Intl.DateTimeFormat — форматирование дат и времени
  • Intl.NumberFormat — форматирование чисел и валют
  • Intl.Collator — сортировка строк с учётом локали
  • Intl.PluralRules — правила множественного числа
  • Intl.RelativeTimeFormat — относительное время
  • Intl.ListFormat — форматирование списков

Каждый объект принимает локаль и параметры форматирования:

const formatter = new Intl.NumberFormat('ru-RU', {
  style: 'currency',
  currency: 'RUB'
});

formatter.format(12345.67);

Результат зависит от локали среды выполнения, что делает Intl API фундаментом для Angular pipe-инструментов.


Связь Angular pipes и Intl API

Angular предоставляет встроенные пайпы для локализации:

  • DatePipe
  • CurrencyPipe
  • DecimalPipe
  • PercentPipe

Эти пайпы используют Intl API в современных браузерах, а в некоторых случаях fallback-реализацию для старых окружений.

Пример DatePipe:

{{ today | date:'longDate' }}

Под капотом формируется объект Intl.DateTimeFormat с соответствующими параметрами локали.

Эквивалент на чистом Intl API:

new Intl.DateTimeFormat('ru-RU', {
  dateStyle: 'long'
}).format(new Date());

Angular абстрагирует создание formatter-объектов, управляет кешированием и реактивностью изменений локали.


Локаль и DI-механизм LOCALE_ID

В Angular локаль определяется через токен DI:

import { LOCALE_ID } from '@angular/core';

providers: [
  { provide: LOCALE_ID, useValue: 'ru' }
]

Эта настройка влияет на:

  • форматирование дат
  • отображение чисел
  • порядок элементов в шаблонах
  • выбор ICU-множественных форм

Intl API получает локаль либо напрямую, либо через Angular wrapper:

new Intl.NumberFormat('ru').format(1000);

При смене LOCALE_ID Angular пересоздаёт форматтеры, что приводит к изменению представления данных без изменения бизнес-логики.


ICU сообщения и расширенная интернационализация

Angular использует ICU Message Format для сложных языковых конструкций:

{itemsCount, plural,
  =0 {нет элементов}
  one {1 элемент}
  few {# элемента}
  many {# элементов}
}

Подобная логика частично пересекается с Intl.PluralRules:

new Intl.PluralRules('ru-RU').select(5);

Возвращаемое значение (one, few, many) используется для выбора правильной формы.

Angular компилирует ICU выражения на этапе сборки, превращая их в эффективные JS-конструкции, минимизируя runtime-накладные расходы.


Форматирование чисел через Intl.NumberFormat

Числовая локализация в Angular часто соответствует Intl.NumberFormat:

const nf = new Intl.NumberFormat('de-DE', {
  minimumFractionDigits: 2
});

nf.format(1234.5);

В Angular эквивалент:

{{ 1234.5 | number:'1.2-2' }}

Параметры пайпа интерпретируются и транслируются в настройки Intl:

  • 1.2-2 → минимальное и максимальное количество знаков
  • локаль берётся из LOCALE_ID

Особенности:

  • разделитель тысяч зависит от локали
  • десятичный разделитель различается (1,234.5 vs 1.234,5)
  • поддерживается scientific и compact notation через Intl API

Работа с валютами через CurrencyPipe и Intl

Форматирование валюты напрямую связано с Intl.NumberFormat:

new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
}).format(99.99);

Angular:

{{ 99.99 | currency:'USD' }}

Внутренние механизмы:

  • выбор символа валюты зависит от locale
  • позиция символа (до/после числа)
  • правила пробелов и разделителей
  • поддержка ISO 4217

Особенно важен режим display:

currencyDisplay: 'symbol' | 'code' | 'name'

Даты и время: Intl.DateTimeFormat vs Angular DatePipe

Intl API:

new Intl.DateTimeFormat('fr-FR', {
  dateStyle: 'full',
  timeStyle: 'short'
}).format(new Date());

Angular:

{{ now | date:'full' }}

Сравнение поведения:

  • Intl использует нативную реализацию ICU библиотек браузера
  • Angular DatePipe добавляет слой совместимости и форматирования шаблонов
  • Angular поддерживает строковые паттерны (yyyy-MM-dd)
  • Intl оперирует семантическими стилями (long, short, full)

В современных браузерах Angular старается делегировать форматирование Intl API для снижения сложности реализации.


Локализация списков через Intl.ListFormat

Списки часто требуют языковой корректности:

new Intl.ListFormat('en-GB', {
  style: 'long',
  type: 'conjunction'
}).format(['apples', 'bananas', 'oranges']);

Результат:

apples, bananas and oranges

В Angular это не всегда вынесено в отдельный pipe, но используется при построении UI-компонентов, особенно в:

  • динамических фильтрах
  • отображении тегов
  • формировании описаний

Сравнение строк через Intl.Collator

Сортировка зависит от локали:

['ä', 'a', 'z'].sort(
  new Intl.Collator('de').compare
);

В Angular это важно для:

  • таблиц данных
  • списков пользователей
  • dropdown-компонентов

Без Intl.Collator сортировка происходит по Unicode code points, что приводит к некорректному порядку в локализованных интерфейсах.


Runtime и compile-time i18n в Angular

Angular разделяет интернационализацию на два слоя:

Compile-time (шаблонная i18n)

  • извлечение строк во время сборки
  • генерация файлов XLIFF
  • создание отдельных билдов под локали

Runtime (Intl API)

  • форматирование чисел, дат, валют
  • plural rules
  • list formatting
  • dynamic UI strings

Такое разделение позволяет:

  • минимизировать размер runtime
  • избегать дублирования локализационных данных
  • использовать нативные возможности браузера

Интеграция с локалями браузера

Intl API опирается на данные окружения:

navigator.language

Angular может использовать:

  • DEFAULT_LOCALE_ID
  • browser locale detection
  • server-side rendering locale injection

SSR особенно чувствителен к различиям между окружениями:

  • Node.js использует ICU build
  • браузер использует системные локали
  • возможны расхождения форматирования

Производительность и кеширование форматтеров

Создание Intl объектов дорогостоящее:

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

Angular применяет стратегии:

  • кеширование formatter-объектов
  • переиспользование при неизменной локали
  • lazy creation внутри pipes

Это особенно критично для:

  • больших таблиц
  • виртуальных списков
  • частых change detection циклов

Polyfill-стратегии и поддержка окружений

Некоторые окружения требуют polyfill Intl API:

  • старые браузеры
  • специфические Node.js сборки
  • ограниченные embedded среды

Angular CLI может подключать:

  • @angular/localize
  • intl polyfills
  • ICU data builds

Важно учитывать, что неполный ICU dataset в Node.js влияет на доступные локали и корректность форматирования.


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

Множественность в языках не ограничивается английским one/many.

new Intl.PluralRules('ru-RU').select(3);

Результат может быть:

  • one
  • few
  • many
  • other

Angular ICU синтаксис напрямую отображает эти категории, обеспечивая точную грамматическую адаптацию текста.


Локализация единиц измерения через Intl

Современный Intl API поддерживает форматирование единиц:

new Intl.NumberFormat('ru-RU', {
  style: 'unit',
  unit: 'kilometer'
}).format(5);

Это используется в Angular приложениях для:

  • отображения расстояний
  • температуры
  • скорости
  • веса

Декларативная модель Angular и императивный Intl

Angular предоставляет декларативные механизмы через шаблоны, тогда как Intl API остаётся императивным инструментом:

  • шаблоны скрывают детали создания formatter
  • Intl предоставляет полный контроль над форматированием
  • pipes являются мостом между подходами

Такое разделение упрощает архитектуру:

  • бизнес-логика не зависит от локали
  • UI адаптируется через DI и pipes
  • форматирование стандартизировано через ECMAScript API