Интеграция с Intl API

i18next предоставляет слой абстракции для работы с переводами и языковыми ресурсами, однако задачи форматирования дат, чисел, валют и сложных языковых конструкций чаще всего делегируются встроенному API среды выполнения — ECMAScript Internationalization API (Intl). Его использование в связке с системой интернационализации позволяет разделить ответственность: i18next управляет текстовыми ресурсами и ключами, а Intl отвечает за культурно-зависимое представление данных.


Архитектурная роль Intl в экосистеме интернационализации

Intl API представляет собой стандартный набор объектов:

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

В контексте i18next это создаёт естественное разделение:

  • i18next управляет ключами переводов и контекстом
  • Intl управляет локализацией значений данных

Такое разделение предотвращает дублирование логики форматирования в ресурсах переводов и уменьшает количество ошибок, связанных с ручной обработкой локалей.


Базовая интеграция i18next с форматированием через Intl

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;
    }
  }
});

Механизм работает следующим образом:

  1. i18next обрабатывает строку перевода
  2. Находит интерполяцию {{value, format}}
  3. Передаёт значение в функцию format
  4. Intl API возвращает локализованное представление

Форматирование дат через Intl.DateTimeFormat

Intl.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

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 учитывает:

  • разделители тысяч
  • десятичные символы
  • позицию валютного знака
  • локальные правила округления

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

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 });

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

При работе с локализованными списками важна корректная сортировка. Обычный 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);
};

Это особенно важно для:

  • списков пользователей
  • каталогов
  • поисковых результатов

Использование форматтеров как слой поверх i18next

В архитектурно зрелых системах форматирование через 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;
    }
  }
});

Такой подход позволяет:

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

Обработка локалей и производительность Intl

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.NumberFormat
  • Intl.Collator
  • Intl.RelativeTimeFormat

Взаимодействие с React-экосистемой

При использовании 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;
}

Комбинирование Intl с ICU-стилем сообщений

В некоторых системах используется ICU Message Format, где pluralization и форматирование встроены в строку.

Пример:

"There are {count, plural, one {# item} other {# items}}"

При этом Intl может использоваться параллельно:

  • ICU — для структуры предложения
  • Intl — для форматирования значений внутри

Такое разделение снижает сложность шаблонов и повышает читаемость переводов.


Практика выбора стратегии форматирования

Существуют три основных подхода:

1. Полное использование Intl через i18next format

  • гибкость
  • контроль над форматами
  • минимальная зависимость от сторонних библиотек

2. ICU + i18next plugins

  • декларативные строки
  • сложная грамматика
  • меньше логики в коде

3. Гибридный подход

  • ICU для текстовой структуры
  • Intl для значений
  • i18next как координатор

Гибридная модель наиболее устойчива в крупных приложениях, где требования к локализации выходят за пределы простого перевода строк.