Форматирование значений

Интерполяция как базовый механизм подстановки данных

В основе форматирования значений в i18next лежит интерполяция — механизм подстановки динамических данных в строки перевода. Он позволяет вставлять переменные в текстовые шаблоны и управлять их отображением.

Типичная структура перевода:

{
  "welcome": "Привет, {{name}}!"
}

Использование:

i18next.t('welcome', { name: 'Алексей' })

Результат:

Привет, Алексей!

Интерполяция поддерживает не только строки, но и числа, булевы значения, даты (после преобразования) и сложные объекты, если они приведены к строковому виду.


Экранирование и безопасный вывод значений

По умолчанию i18next экранирует значения для защиты от XSS-атак в веб-среде.

{
  "danger": "Hello {{value}}"
}
i18next.t('danger', { value: '<script>alert(1)</script>' })

Результат:

Hello &lt;script&gt;alert(1)&lt;/script&gt;

Отключение экранирования:

i18next.init({
  interpolation: {
    escapeValue: false
  }
})

Такой режим используется только в окружениях, где уже обеспечена защита (например, React).


Форматирование через функции интерполяции

i18next позволяет применять функции прямо в процессе подстановки значений. Это используется для преобразования данных перед выводом.

{
  "price": "Цена: {{value, formatPrice}}"
}

Регистрация форматтера:

i18next.init({
  interpolation: {
    format: (value, format) => {
      if (format === 'formatPrice') {
        return `${value.toFixed(2)} ₽`
      }
      return value
    }
  }
})

Использование:

i18next.t('price', { value: 1250 })

Результат:

Цена: 1250.00 ₽

Механизм format является центральной точкой расширения форматирования.


Форматирование чисел

Часто требуется локализованное отображение чисел: разделители тысяч, дробные знаки, валюта.

i18next.init({
  interpolation: {
    format: (value, format, lng) => {
      if (format === 'number') {
        return new Intl.NumberFormat(lng).format(value)
      }
      return value
    }
  }
})

Шаблон:

{
  "users": "Пользователей: {{count, number}}"
}

Результат для ru:

Пользователей: 1 234

Результат для en:

Users: 1,234

Использование Intl.NumberFormat обеспечивает корректную локализацию без ручной обработки.


Форматирование дат и времени

Для дат применяется Intl.DateTimeFormat или сторонние библиотеки (moment, dayjs).

Пример встроенного подхода:

i18next.init({
  interpolation: {
    format: (value, format, lng) => {
      if (format === 'date') {
        return new Intl.DateTimeFormat(lng).format(new Date(value))
      }
      return value
    }
  }
})

Шаблон:

{
  "created": "Создано: {{date, date}}"
}

Результат зависит от локали:

Создано: 29.05.2026

или

Created: 5/29/2026

Комбинированные форматы

Один и тот же механизм позволяет применять несколько форматов к одному значению.

{
  "report": "Отчёт: {{value, number}} шт., {{date, date}}"
}

Функция форматирования:

format: (value, format, lng) => {
  if (format === 'number') {
    return new Intl.NumberFormat(lng).format(value)
  }
  if (format === 'date') {
    return new Intl.DateTimeFormat(lng).format(new Date(value))
  }
  return value
}

Множественные правила и pluralization как часть форматирования

Множественные формы являются встроенным видом форматирования, зависящим от числового значения.

{
  "item": "1 элемент",
  "item_other": "{{count}} элементов"
}

Использование:

i18next.t('item', { count: 5 })

Результат:

5 элементов

Pluralization тесно связан с интерполяцией, так как значение count управляет выбором формы.


Пользовательские форматтеры и цепочки преобразований

Форматирование может строиться как цепочка логики внутри одной функции.

format: (value, format) => {
  switch (format) {
    case 'upper':
      return String(value).toUpperCase()
    case 'lower':
      return String(value).toLowerCase()
    case 'currency':
      return `$${Number(value).toFixed(2)}`
    default:
      return value
  }
}

Шаблон:

{
  "title": "{{name, upper}}"
}

Форматирование с параметрами локали

Функция форматирования получает текущую локаль, что позволяет адаптировать вывод без дополнительной логики.

format: (value, format, lng) => {
  if (format === 'currency') {
    return new Intl.NumberFormat(lng, {
      style: 'currency',
      currency: lng === 'ru' ? 'RUB' : 'USD'
    }).format(value)
  }
  return value
}

Использование ICU-стиля через плагины

i18next поддерживает ICU Message Format через дополнительные плагины, расширяя возможности интерполяции.

Пример ICU-строки:

{count, plural, one {# файл} few {# файла} many {# файлов} other {# файлов}}

Такие выражения позволяют описывать сложные языковые правила без ручного кодирования условий.


Встраивание форматирования в цепочку обработки перевода

Порядок обработки значений в i18next:

  1. Выбор ключа перевода
  2. Определение языка
  3. Обработка pluralization
  4. Интерполяция значений
  5. Применение format-функций
  6. Экранирование (если включено)

Форматирование выполняется на финальном этапе, что позволяет безопасно комбинировать несколько уровней трансформации.


Форматирование в связке с контекстом

Контекстные переводы позволяют менять форматы в зависимости от состояния данных.

{
  "message_male": "Он вошёл",
  "message_female": "Она вошла"
}

Использование:

i18next.t('message', { context: 'female' })

Форматирование может быть дополнено логикой:

format: (value, format) => {
  if (format === 'capitalize') {
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
  return value
}

Форматирование массивов и списков

Массивы требуют преобразования перед выводом.

{
  "list": "Элементы: {{items, list}}"
}
format: (value, format, lng) => {
  if (format === 'list') {
    return Array.isArray(value)
      ? value.join(', ')
      : value
  }
  return value
}

Производительность форматирования

Функция format вызывается при каждой интерполяции, поэтому её реализация влияет на производительность.

Оптимизация достигается через:

  • кэширование Intl-объектов
  • минимизацию условных ветвлений
  • предсоздание форматтеров

Пример кэширования:

const numberFormatter = {}

function getNumberFormatter(lng) {
  if (!numberFormatter[lng]) {
    numberFormatter[lng] = new Intl.NumberFormat(lng)
  }
  return numberFormatter[lng]
}

Ограничения встроенного форматирования

Интерполяционное форматирование имеет ряд особенностей:

  • отсутствует полноценный pipeline преобразований
  • сложные правила требуют внешних библиотек
  • форматтеры выполняются синхронно
  • невозможна асинхронная обработка значений

Эти ограничения компенсируются архитектурой плагинов и использованием стандартных API JavaScript.


Интеграция с внешними библиотеками форматирования

i18next часто используется вместе с:

  • dayjs
  • date-fns
  • numeral.js
  • Intl API

Пример с dayjs:

import dayjs from 'dayjs'

format: (value, format) => {
  if (format === 'dayjs') {
    return dayjs(value).format('DD.MM.YYYY')
  }
  return value
}

Роль форматирования в архитектуре локализации

Форматирование значений является связующим слоем между:

  • языковыми файлами
  • бизнес-логикой приложения
  • пользовательским интерфейсом

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