Международные возможности JavaScript исторически развивались вокруг фрагментированного набора решений: ручные функции форматирования, сторонние библиотеки и позднее — стандартизированный набор инструментов ECMAScript Internationalization API (Intl). Сравнение этих подходов раскрывает ключевые различия в архитектуре, производительности, поддержке локалей и уровне соответствия стандартам Unicode CLDR.
Intl API построен как тонкая обёртка над ICU (International Components for Unicode), предоставляя доступ к системным данным локализации без необходимости включать их в приложение. Это принципиально отличает его от большинства альтернатив, которые либо поставляют собственные таблицы локалей, либо реализуют форматирование вручную.
До появления зрелого Intl API значительная часть проектов использовала встроенные средства JavaScript напрямую.
Объект Date предоставляет базовую функциональность, но практически не содержит инструментов локализации:
toString() возвращает фиксированный форматtoISOString() ориентирован на ISO-8601getMonth(), getDate() требуют ручной
сборки строкФорматирование даты в локальном стиле требует ручного кода:
function formatDateRu(date) {
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0');
const year = date.getFullYear();
return `${day}.${month}.${year}`;
}
Такой подход:
Аналогичная ситуация наблюдается с числами:
function formatNumber(n) {
return n.toString().replace('.', ',');
}
Проблемы:
Intl.NumberFormat, Intl.DateTimeFormat и другие компоненты заменяют ручные решения декларативной моделью:
new Intl.NumberFormat('ru-RU').format(1234567.89);
или
new Intl.DateTimeFormat('en-US').format(new Date());
Ключевое отличие — перенос логики форматирования в движок JavaScript и ICU.
| Критерий | Ручной код | Intl API |
|---|---|---|
| Поддержка локалей | отсутствует | встроенная |
| Точность формата | низкая | высокая |
| Поддержка обновлений стандартов | отсутствует | автоматическая |
| Поддержка валют, дат, чисел | частичная | полная |
Moment.js долгое время был де-факто стандартом работы с датами.
Ключевые особенности:
Пример:
moment().locale('ru').format('LL');
Недостатки относительно Intl:
Intl DateTimeFormat:
new Intl.DateTimeFormat('ru-RU', { dateStyle: 'long' }).format(new Date());
Преимущества Intl:
date-fns представляет функциональный подход и модульность.
Особенности:
Пример:
import { format } from 'date-fns';
import { ru } from 'date-fns/locale';
format(new Date(), 'PPPP', { locale: ru });
Сравнение с Intl:
Проблемная зона date-fns — необходимость поддерживать собственную модель локализации, что приводит к рассинхронизации с обновлениями CLDR.
Luxon построен на Temporal-подобной модели и использует Intl внутри.
Пример:
DateTime.now().setLocale('ru').toLocaleString(DateTime.DATE_FULL);
Особенности:
Сравнение:
В большинстве случаев Luxon дублирует функциональность Intl, не добавляя принципиально новых возможностей, а лишь изменяя стиль API.
Ранние библиотеки форматирования чисел решали задачи:
Пример:
accounting.formatMoney(12345.67, "€", 2, " ", ",");
Проблемы:
Intl.NumberFormat:
new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR'
}).format(12345.67);
Ключевые различия:
Сравнение по памяти и загрузке:
| Решение | Размер | Зависимости | Время инициализации |
|---|---|---|---|
| Intl API | 0 KB (в bundle) | нет | мгновенно |
| Moment.js | большой | да | высокая |
| date-fns | средний | частично | средняя |
| Luxon | средний | Intl + JS | средняя |
Intl API строго следует Unicode CLDR и спецификациям ECMA-402.
Это означает:
Сторонние библиотеки:
Особенно заметно в:
Подход: декларативная конфигурация
new Intl.DateTimeFormat('ru-RU', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
});
Особенность:
Trade-off:
new Intl.DateTimeFormat('en-GB', {
timeZone: 'Asia/Almaty',
timeStyle: 'short'
});
Вывод: Intl предоставляет базовую функциональность, достаточную для большинства сценариев без дополнительных зависимостей.
Temporal API разрабатывается как замена Date и частично дополняет Intl.
Отличия:
Таким образом архитектура будущего JavaScript выглядит как связка:
| Критерий | Intl API | Библиотеки | Ручной код |
|---|---|---|---|
| Локализация | встроенная | частичная | отсутствует |
| Размер | нулевой | средний/большой | нулевой |
| Поддержка стандартов | высокая | средняя | низкая |
| Гибкость | средняя | высокая | максимальная (но дорогая) |
| Производительность | высокая | средняя | переменная |
| Поддержка обновлений | автоматическая | ручная | отсутствует |
Использование Intl API ведёт к архитектуре, где:
Использование сторонних библиотек формирует обратную модель: