Intl API в JavaScript представляет собой стандартный набор инструментов для локализации: форматирования чисел, дат, времени, списков, сообщений и работы с языковыми особенностями. В современных браузерах и средах выполнения он реализован нативно через ICU (International Components for Unicode), однако исторически поддержка была неполной, а поведение — фрагментированным. Это привело к появлению полифилов, среди которых ключевую роль занимает экосистема FormatJS FormatJS.
Стандарт Intl включает набор конструкторов:
Intl.DateTimeFormatIntl.NumberFormatIntl.PluralRulesIntl.RelativeTimeFormatIntl.ListFormatIntl.SegmenterКаждый из них опирается на локализованные данные ICU и позволяет форматировать значения в соответствии с языковыми и региональными правилами.
Проблема возникает в следующих случаях:
RelativeTimeFormat или
ListFormat) в старых runtime.Полифил решает задачу унификации поведения: один и тот же код работает одинаково в разных средах.
FormatJS FormatJS представляет собой набор модульных пакетов, реализующих отдельные части Intl API. Вместо монолитного полифила используется композиционная модель: подключаются только необходимые части.
Официальная документация и исходные материалы доступны на FormatJS documentation.
Ключевые пакеты:
@formatjs/intl-numberformat@formatjs/intl-datetimeformat@formatjs/intl-pluralrules@formatjs/intl-relativetimeformat@formatjs/intl-listformat@formatjs/intl-segmenterКаждый пакет повторяет интерфейс соответствующего стандарта
Intl.*.
Механика работы строится вокруг подмены глобального объекта
Intl или его отдельных конструкторов.
Базовый сценарий:
Проверяется наличие нативной реализации:
if (!Intl.NumberFormat) {
// подключение полифила
}При отсутствии API подключается реализация из
@formatjs/*.
Данные локалей подгружаются отдельно (часто в виде JSON или встроенных таблиц).
Глобальный Intl дополняется или
переопределяется.
Модульный подход позволяет подключать только нужные компоненты.
Пример установки:
npm install @formatjs/intl-numberformat
Инициализация:
import '@formatjs/intl-numberformat/polyfill';
import '@formatjs/intl-numberformat/locale-data/ru';
После подключения код, использующий Intl.NumberFormat,
начинает работать одинаково во всех окружениях.
Intl.NumberFormat отвечает за форматирование чисел,
валют и процентов.
Пример использования:
const formatter = new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'KZT'
});
formatter.format(123456.78);
Полифил реализует:
, vs .);Intl.DateTimeFormat — один из наиболее сложных
компонентов.
const dt = new Intl.DateTimeFormat('ru-RU', {
dateStyle: 'full',
timeStyle: 'short'
});
dt.format(new Date());
Реализация FormatJS:
Intl.PluralRules критически важен для языков с развитой
морфологией (русский, арабский, польский).
const pr = new Intl.PluralRules('ru-RU');
pr.select(1); // one
pr.select(2); // few
pr.select(5); // many
Полифил реализует:
Используется для выражений типа «2 дня назад», «через 5 минут».
const rtf = new Intl.RelativeTimeFormat('ru', { numeric: 'auto' });
rtf.format(-2, 'day');
Особенности реализации:
Intl.ListFormat отвечает за форматирование списков:
const lf = new Intl.ListFormat('ru', {
style: 'long',
type: 'conjunction'
});
lf.format(['яблоки', 'груши', 'сливы']);
Результат зависит от локали:
Intl.Segmenter используется для разбиения текста на:
const segmenter = new Intl.Segmenter('ru', { granularity: 'word' });
[...segmenter.segment('Пример текста')];
Полифил реализует алгоритмы Unicode Text Segmentation.
В современных сборках важна оптимизация размера бандла.
Пример Webpack:
module.exports = {
resolve: {
alias: {
'@formatjs/intl-relativetimeformat': '@formatjs/intl-relativetimeformat/polyfill'
}
}
};
Подходы оптимизации:
await import('@formatjs/intl-datetimeformat/locale-data/ru');
Node.js может работать в разных режимах ICU:
full-icusmall-icusystem-icuВ случае small-icu часть локалей отсутствует, что
приводит к неполной локализации.
Полифил FormatJS компенсирует это:
Локали являются отдельным слоем данных.
Подходы:
import '@formatjs/intl-numberformat/locale-data/ru';
async function loadLocale(locale) {
await import(`@formatjs/intl-numberformat/locale-data/${locale}`);
}
import '@formatjs/intl-numberformat/locale-data/en';
import '@formatjs/intl-numberformat/locale-data/ru';
import '@formatjs/intl-numberformat/locale-data/de';
Типичная стратегия работы:
Intl, если он полностью
поддерживает нужные API;Проверки:
const hasRtf = typeof Intl.RelativeTimeFormat !== 'undefined';
Полифилы Intl могут быть тяжёлыми, так как включают:
Оптимизация:
@formatjs/intl.Нативная реализация:
Полифил FormatJS:
en_US вместо
en-US).В приложениях с динамическим языком интерфейса:
Типовая архитектура:
Современная версия FormatJS ориентирована на:
Каждый Intl API вынесен в отдельный пакет, что позволяет собирать только необходимую функциональность без лишнего веса.