В реальных приложениях интернационализация почти никогда не ограничивается одной операцией форматирования. Дата, время, числа, валюты, списки, правила множественного числа и локализованная сортировка используются совместно, образуя связанный слой представления данных. Intl API в JavaScript проектировался как набор независимых, но согласованных инструментов, которые можно комбинировать без потери производительности и единообразия локали.
Ключевая идея комбинирования заключается в том, что все форматтеры должны опираться на один и тот же идентификатор локали.
const locale = 'ru-RU';
const dateFormatter = new Intl.DateTimeFormat(locale);
const numberFormatter = new Intl.NumberFormat(locale);
const collator = new Intl.Collator(locale);
Такой подход исключает расхождения в представлении данных: дата, число и сортировка используют одну и ту же культурную модель.
Особое значение имеет объект Intl.Locale, который
позволяет централизованно описывать параметры локали:
const locale = new Intl.Locale('ru-RU', {
hourCycle: 'h23',
calendar: 'gregory',
});
Этот объект может использоваться как источник конфигурации для других API, снижая дублирование настроек.
При комбинировании Intl.NumberFormat с другими
форматерами важно учитывать контекст числа: простое значение, денежная
величина, процент или индекс.
const locale = 'ru-RU';
const currencyFormatter = new Intl.NumberFormat(locale, {
style: 'currency',
currency: 'RUB',
});
const percentFormatter = new Intl.NumberFormat(locale, {
style: 'percent',
});
Комбинация с датами часто используется в отчётах и финансовых интерфейсах:
const dateFormatter = new Intl.DateTimeFormat(locale);
const currencyFormatter = new Intl.NumberFormat(locale, {
style: 'currency',
currency: 'RUB',
});
function formatTransaction(date, amount) {
return `${dateFormatter.format(date)} — ${currencyFormatter.format(amount)}`;
}
Здесь объединяются два независимых API, но результат воспринимается как единая семантическая строка.
Intl.RelativeTimeFormat дополняет
Intl.DateTimeFormat, позволяя выражать временные интервалы
в человеческой форме.
const locale = 'ru-RU';
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });
Комбинирование с абсолютными датами часто используется в интерфейсах уведомлений:
const dateFormatter = new Intl.DateTimeFormat(locale, {
day: 'numeric',
month: 'long',
});
function formatNotification(date, diffInDays) {
const absolute = dateFormatter.format(date);
const relative = rtf.format(diffInDays, 'day');
return `${absolute} (${relative})`;
}
В этом случае два разных представления времени дополняют друг друга: одно даёт точку на временной шкале, другое — интерпретацию относительно текущего момента.
Intl.Collator отвечает за культурно корректную
сортировку, а Intl.ListFormat — за представление наборов
данных в виде строки.
const locale = 'ru-RU';
const collator = new Intl.Collator(locale);
const listFormatter = new Intl.ListFormat(locale, {
style: 'long',
type: 'conjunction',
});
Типичный сценарий — сортировка и последующее отображение:
function formatUserList(users) {
const sorted = users.sort((a, b) => collator.compare(a, b));
return listFormatter.format(sorted);
}
Здесь используется последовательное применение API: сначала структурная операция (сортировка), затем семантическое представление (форматирование списка).
Intl.PluralRules часто комбинируется с
Intl.NumberFormat для построения грамматически корректных
сообщений.
const locale = 'ru-RU';
const pluralRules = new Intl.PluralRules(locale);
const numberFormatter = new Intl.NumberFormat(locale);
Пример построения сообщений:
const forms = {
one: 'файл',
few: 'файла',
many: 'файлов',
other: 'файла',
};
function formatFiles(count) {
const category = pluralRules.select(count);
const word = forms[category] || forms.other;
return `${numberFormatter.format(count)} ${word}`;
}
Здесь происходит связка трёх уровней:
Intl.Segmenter используется для корректной работы с
границами слов и предложений, особенно в многоязычных текстах.
const locale = 'ru-RU';
const segmenter = new Intl.Segmenter(locale, { granularity: 'word' });
const collator = new Intl.Collator(locale);
Пример комбинирования сегментации и сортировки:
function sortWords(text) {
const words = Array.from(segmenter.segment(text))
.filter(s => s.isWordLike)
.map(s => s.segment);
return words.sort((a, b) => collator.compare(a, b));
}
Здесь сегментация обеспечивает корректное разбиение текста, а collator — культурную сортировку.
При комбинировании нескольких Intl API критическим становится вопрос производительности. Конструкторы форматтеров достаточно тяжёлые, поэтому повторное создание объектов внутри функций приводит к лишним затратам.
Оптимальная стратегия — кэширование:
const cache = new Map();
function getFormatter(type, locale, options) {
const key = JSON.stringify({ type, locale, options });
if (!cache.has(key)) {
let formatter;
switch (type) {
case 'date':
formatter = new Intl.DateTimeFormat(locale, options);
break;
case 'number':
formatter = new Intl.NumberFormat(locale, options);
break;
case 'list':
formatter = new Intl.ListFormat(locale, options);
break;
}
cache.set(key, formatter);
}
return cache.get(key);
}
Такой подход особенно важен при построении сложных UI, где форматирование выполняется многократно.
При совместном использовании нескольких форматеров важно избегать рассинхронизации параметров локали.
Например, различие в hourCycle или calendar
может привести к несогласованному отображению данных:
const locale = new Intl.Locale('ru-RU', {
hourCycle: 'h23',
calendar: 'gregory',
});
const dateFormatter = new Intl.DateTimeFormat(locale.toString(), {
hour: '2-digit',
minute: '2-digit',
});
Использование одного объекта Intl.Locale как источника
конфигурации снижает риск расхождений между форматерами.
В реальных интерфейсах комбинирование Intl API проявляется в построении комплексных строк.
Пример формирования карточки события:
const locale = 'ru-RU';
const dateFormatter = new Intl.DateTimeFormat(locale, {
weekday: 'long',
day: 'numeric',
month: 'long',
});
const numberFormatter = new Intl.NumberFormat(locale);
const listFormatter = new Intl.ListFormat(locale, {
type: 'conjunction',
});
function formatEvent(event) {
const date = dateFormatter.format(event.date);
const attendees = listFormatter.format(event.participants);
return `${date}, участников: ${numberFormatter.format(event.count)} (${attendees})`;
}
Здесь одновременно используются три независимых API, но результат формируется как единая семантическая конструкция.
При композиции важно учитывать последовательность операций:
Нарушение этого порядка приводит к потере семантики или некорректному отображению.
Intl API можно рассматривать как набор независимых функций, которые становятся строительными блоками более сложных систем форматирования.
const formatters = {
date: new Intl.DateTimeFormat('ru-RU'),
number: new Intl.NumberFormat('ru-RU'),
list: new Intl.ListFormat('ru-RU'),
collator: new Intl.Collator('ru-RU'),
};
function formatDashboard(data) {
const sorted = [...data.items].sort((a, b) =>
formatters.collator.compare(a.name, b.name)
);
const names = formatters.list.format(sorted.map(i => i.name));
return `${formatters.date.format(data.date)}: ${names}`;
}
Такой подход позволяет строить переиспользуемые и расширяемые системы интернационализации без дублирования логики.