Встроенные постпроцессоры

В системе i18next постпроцессоры представляют собой дополнительный этап обработки уже интерполированной строки перевода. Они применяются после выполнения интерполяции и позволяют модифицировать итоговый текст: форматировать его, преобразовывать регистр, обрабатывать диапазоны значений, а также реализовывать специализированные сценарии отображения.

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


Постпроцессор получает на вход уже сформированную строку перевода и контекст вызова. Его задача — вернуть преобразованный результат или оставить строку без изменений.

Общая схема обработки выглядит следующим образом:

  1. Выбор ключа перевода
  2. Получение строки из ресурсов
  3. Интерполяция значений
  4. Выполнение postProcess (если указан)
  5. Возврат результата

Постпроцессоры активируются через параметр postProcess в вызове t.

i18next.t('key', {
  postProcess: 'processorName'
});

Также возможно передавать параметры, которые будут доступны внутри постпроцессора:

i18next.t('key', {
  postProcess: 'processorName',
  someOption: true
});

Встроенный постпроцессор interval

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

Этот механизм позволяет реализовывать конструкции вида «от X до Y» или различные текстовые формы для диапазонов.

Принцип работы interval

В ресурсе перевода задаётся строка с диапазонной логикой:

{
  "key": "Сообщений: {{count}}",
  "key_interval": "нет сообщений | одно сообщение | несколько сообщений | много сообщений"
}

При использовании:

i18next.t('key_interval', {
  postProcess: 'interval',
  count: 0
});

Поведение интервала

Постпроцессор анализирует значение count и выбирает соответствующий сегмент строки. Разделителем обычно выступает символ |.

Логика может включать диапазоны:

0
1
2-4
5+

Пример более явной формы:

{
  "messages_interval": "0 сообщений | 1 сообщение | 2-4 сообщения | 5+ сообщений"
}

Регистрация пользовательских постпроцессоров

Хотя встроенных постпроцессоров немного, архитектура i18next предполагает активное использование пользовательских.

Постпроцессор представляет собой объект с методом process:

const uppercasePostProcessor = {
  type: 'postProcessor',
  name: 'uppercase',

  process(value) {
    return value.toUpperCase();
  }
};

Регистрация:

i18next.use(uppercasePostProcessor).init({
  resources: {
    en: {
      translation: {
        key: 'hello world'
      }
    }
  }
});

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

i18next.t('key', {
  postProcess: 'uppercase'
});

Результат:

HELLO WORLD

Цепочка постпроцессоров

i18next поддерживает последовательное применение нескольких постпроцессоров. Они выполняются в порядке перечисления:

i18next.t('key', {
  postProcess: 'uppercase, customTrim'
});

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

Пример:

i18next.t('key', {
  postProcess: 'uppercase, reverse'
});

Если исходная строка:

hello

После обработки:

OLLEH

Доступ к параметрам внутри постпроцессора

Постпроцессор получает полный набор опций, переданных в t.

const debugPostProcessor = {
  type: 'postProcessor',
  name: 'debug',

  process(value, key, options) {
    if (options.debug) {
      return `[DEBUG] ${value}`;
    }
    return value;
  }
};

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

i18next.t('key', {
  postProcess: 'debug',
  debug: true
});

Контекст выполнения и порядок вызовов

Постпроцессоры вызываются после интерполяции, поэтому доступ к уже подставленным значениям сохраняется.

i18next.t('greeting', {
  name: 'Ivan',
  postProcess: 'uppercase'
});

Ресурс:

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

Этапы обработки:

  1. Интерполяция → Привет, Ivan
  2. Постпроцессор → ПРИВЕТ, IVAN

Особенности взаимодействия с интерполяцией

Постпроцессоры не влияют на механизм подстановки переменных. Интерполяция всегда выполняется раньше.

Это означает:

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

Ограничения встроенных постпроцессоров

Встроенный набор постпроцессоров минимален и рассчитан на базовые сценарии:

  • обработка диапазонов (interval)
  • совместимость с расширениями

Большинство реальных сценариев решается через:

  • пользовательские постпроцессоры
  • интерполяционные функции
  • форматтеры i18next

Контроль выполнения постпроцессоров

Постпроцессоры можно отключать, не указывая параметр postProcess:

i18next.t('key');

Также возможно динамическое управление через условия:

i18next.t('key', {
  postProcess: condition ? 'uppercase' : undefined
});

Взаимодействие с другими модулями i18next

Постпроцессоры находятся в конце цепочки обработки и взаимодействуют с другими механизмами следующим образом:

  • интерполяция передаёт уже готовую строку
  • плагины детекции языка не участвуют
  • backend-ресолверы не затрагиваются
  • pluralization выполняется до постпроцессинга

Это делает постпроцессоры финальным уровнем трансформации текста перед выводом.


Использование interval в сложных сценариях

При работе с числовыми диапазонами interval может использоваться совместно с динамическими значениями:

i18next.t('notifications_interval', {
  count: unreadMessages
});

Ресурс:

{
  "notifications_interval": "нет уведомлений | 1 уведомление | {{count}} уведомления | {{count}} уведомлений"
}

Здесь интерполяция и постобработка работают совместно: сначала подставляется count, затем выбирается корректная форма.


Порядок разрешения конфликтов

Если несколько постпроцессоров изменяют одну и ту же строку, итоговый результат зависит от порядка их объявления:

postProcess: 'trim, uppercase'

или

postProcess: 'uppercase, trim'

В первом случае сначала убираются пробелы, затем выполняется преобразование регистра. Во втором — наоборот, что может привести к различным результатам при наличии пробелов.