i18next предоставляет слой абстракции для работы с переводами и языковыми ресурсами, однако задачи форматирования дат, чисел, валют и сложных языковых конструкций чаще всего делегируются встроенному API среды выполнения — ECMAScript Internationalization API (Intl). Его использование в связке с системой интернационализации позволяет разделить ответственность: i18next управляет текстовыми ресурсами и ключами, а Intl отвечает за культурно-зависимое представление данных.
Intl API представляет собой стандартный набор объектов:
Intl.DateTimeFormat — форматирование дат и времениIntl.NumberFormat — форматирование чисел и валютIntl.RelativeTimeFormat — относительное времяIntl.PluralRules — правила множественного числаIntl.Collator — сортировка строк с учётом локалиВ контексте i18next это создаёт естественное разделение:
Такое разделение предотвращает дублирование логики форматирования в ресурсах переводов и уменьшает количество ошибок, связанных с ручной обработкой локалей.
i18next поддерживает форматирование значений через механизм
интерполяции. Встроенный интерполятор может быть расширен функцией
format, позволяющей подключить Intl API напрямую.
Пример базовой конфигурации:
import i18next from "i18next";
i18next.init({
lng: "ru",
resources: {
ru: {
translation: {
balance: "Баланс: {{value, currency}}",
today: "Сегодня: {{date, datetime}}"
}
}
},
interpolation: {
format: (value, format, lng) => {
if (format === "currency") {
return new Intl.NumberFormat(lng, {
style: "currency",
currency: "RUB"
}).format(value);
}
if (format === "datetime") {
return new Intl.DateTimeFormat(lng, {
year: "numeric",
month: "long",
day: "numeric"
}).format(value);
}
return value;
}
}
});
Механизм работает следующим образом:
{{value, format}}formatIntl.DateTimeFormat позволяет учитывать локальные
особенности отображения дат: порядок компонентов, разделители, названия
месяцев.
Пример использования в контексте i18next:
const formatDate = (value, lng) =>
new Intl.DateTimeFormat(lng, {
weekday: "long",
year: "numeric",
month: "short",
day: "numeric"
}).format(value);
Интеграция:
interpolation: {
format: (value, format, lng) => {
if (format === "date_full") {
return new Intl.DateTimeFormat(lng, {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
}).format(value);
}
return value;
}
}
Особенность использования заключается в том, что Intl автоматически адаптирует:
Intl.NumberFormat является ключевым инструментом для
финансовых интерфейсов и числовых данных.
Пример форматирования валюты:
const formatCurrency = (value, lng, currency = "USD") =>
new Intl.NumberFormat(lng, {
style: "currency",
currency
}).format(value);
Интеграция в i18next:
interpolation: {
format: (value, format, lng) => {
switch (format) {
case "usd":
return new Intl.NumberFormat(lng, {
style: "currency",
currency: "USD"
}).format(value);
case "percent":
return new Intl.NumberFormat(lng, {
style: "percent",
minimumFractionDigits: 2
}).format(value);
case "number":
return new Intl.NumberFormat(lng).format(value);
default:
return value;
}
}
}
Intl учитывает:
i18next уже содержит встроенную систему pluralization, однако
Intl.PluralRules позволяет унифицировать логику определения
формы множественного числа на уровне JavaScript.
const pluralRules = new Intl.PluralRules("ru");
pluralRules.select(1); // "one"
pluralRules.select(2); // "few"
pluralRules.select(5); // "many"
Использование в связке:
const getPluralKey = (value, lng) => {
const rules = new Intl.PluralRules(lng);
return rules.select(value);
};
Это может использоваться при динамическом выборе ключей переводов:
const key = `items_${getPluralKey(count, lng)}`;
i18next.t(key, { count });
При работе с локализованными списками важна корректная сортировка.
Обычный Array.sort() не учитывает языковые особенности.
const collator = new Intl.Collator("ru");
["я", "а", "ю"].sort(collator.compare);
Интеграция в приложение:
const sortLocalized = (array, lng) => {
const collator = new Intl.Collator(lng, {
sensitivity: "base"
});
return array.sort(collator.compare);
};
Это особенно важно для:
В архитектурно зрелых системах форматирование через Intl выделяется в отдельный слой.
Пример структуры:
const formatters = {
date: (value, lng) =>
new Intl.DateTimeFormat(lng, { dateStyle: "medium" }).format(value),
currency: (value, lng, currency) =>
new Intl.NumberFormat(lng, {
style: "currency",
currency
}).format(value),
number: (value, lng) =>
new Intl.NumberFormat(lng).format(value)
};
Интеграция:
i18next.init({
interpolation: {
format: (value, format, lng, options) => {
if (formatters[format]) {
return formatters[format](value, lng, options?.currency);
}
return value;
}
}
});
Такой подход позволяет:
Intl API использует нативные реализации движка JavaScript, что обеспечивает высокую производительность. Однако создание форматтеров — дорогая операция.
Оптимизация заключается в кешировании:
const dateFormatCache = new Map();
const getDateFormatter = (lng) => {
if (!dateFormatCache.has(lng)) {
dateFormatCache.set(
lng,
new Intl.DateTimeFormat(lng, { dateStyle: "long" })
);
}
return dateFormatCache.get(lng);
};
Аналогично кешируются:
Intl.NumberFormatIntl.CollatorIntl.RelativeTimeFormatПри использовании i18next вместе с React часто применяется
react-i18next, где Intl остаётся слоем форматирования.
Пример:
const { t, i18n } = useTranslation();
t("balance", {
value: 12345.67,
formatParams: {
value: { currency: "EUR" }
}
});
И интерполятор:
format: (value, format, lng, options) => {
if (format === "currency") {
return new Intl.NumberFormat(lng, {
style: "currency",
currency: options?.currency
}).format(value);
}
return value;
}
В некоторых системах используется ICU Message Format, где pluralization и форматирование встроены в строку.
Пример:
"There are {count, plural, one {# item} other {# items}}"
При этом Intl может использоваться параллельно:
Такое разделение снижает сложность шаблонов и повышает читаемость переводов.
Существуют три основных подхода:
Гибридная модель наиболее устойчива в крупных приложениях, где требования к локализации выходят за пределы простого перевода строк.