Interval постпроцессор

Interval postprocessor в i18next используется для интервальной обработки числовых значений при формировании текста, когда стандартной плюрализации оказывается недостаточно. Основная задача механизма — выбор варианта строки не по языковым правилам множественного числа, а по заданным числовым диапазонам, что особенно важно для бизнес-логики, статистики, таймеров, прогрессов и любых случаев, где требуется явное управление интервалами.

Постпроцессоры в i18next представляют собой этап обработки результата t() после подстановки интерполяций и выбора ключа перевода. Они позволяют модифицировать итоговую строку без изменения исходных ресурсов.

Регистрация постпроцессора выполняется через механизм расширения:

i18next.use(postProcessor);

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

Сущность interval postprocessor

Interval postprocessor предназначен для интерпретации числовых диапазонов и выбора соответствующего варианта строки на основе значения count или другого числового параметра.

Ключевая особенность — замена стандартной plural-логики на декларативные диапазоны:

  • точные значения
  • диапазоны (a-b)
  • открытые интервалы (n-inf)
  • объединённые правила

Это позволяет описывать сложные языковые и бизнес-формы без привязки к CLDR plural rules.

Синтаксис интервалов

Интервалы задаются внутри строки перевода в виде набора правил:

(0){...}
(1){...}
(2-4){...}
(5-20){...}
(21-inf){...}

Каждое правило состоит из двух частей:

  • диапазон в круглых скобках
  • значение в фигурных скобках

Поддерживаемые формы диапазонов:

  • (n) — точное совпадение
  • (a-b) — включительный диапазон
  • (a-inf) — всё от a и выше
  • (-inf-b) — всё до b включительно

Принцип выбора интервала

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

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

Подключение interval postprocessor

В экосистеме i18next интервал обычно подключается как отдельный модуль:

import i18next from 'i18next';
import IntervalPostProcessor from 'i18next-interval-postprocessor';

i18next.use(IntervalPostProcessor).init({
  lng: 'ru',
  resources: {
    ru: {
      translation: {
        apples: '(0){нет яблок} (1){{{count}} яблоко} (2-4){{{count}} яблока} (5-inf){{{count}} яблок}'
      }
    }
  }
});

После регистрации становится доступным использование постпроцессора через параметр postProcess.

Использование в t()

Вызов перевода с интервалами требует передачи числового значения и активации постпроцессора:

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

Изменение значения count приводит к выбору другого интервала:

i18next.t('apples', {
  count: 3,
  postProcess: 'interval'
});

Значение 3 попадает в диапазон (2-4).

Интерполяция внутри интервалов

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

"messages": "(0){пусто} (1){{{count}} элемент} (2-inf){{{count}} элементов}"

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

i18next.t('messages', {
  count: 12,
  postProcess: 'interval'
});

Отличие от встроенной плюрализации

Стандартная система plural в i18next опирается на языковые правила CLDR, которые определяют формы множественного числа в зависимости от локали.

Interval postprocessor полностью игнорирует эти правила и заменяет их числовыми диапазонами.

Ключевые отличия:

  • plural: зависит от языка
  • interval: зависит от явно заданных диапазонов
  • plural: фиксированное количество форм
  • interval: произвольное количество правил

Практическое применение

Счётчики с произвольной логикой

"onlineUsers": "(0){нет пользователей} (1){1 пользователь} (2-4){{{count}} пользователя} (5-inf){{{count}} пользователей}"

Прогресс и состояния

"progress": "(0){не начато} (1-30){начальный этап} (31-70){в процессе} (71-99){почти готово} (100){завершено}"

Временные интервалы

"time": "(0){сейчас} (1-59){{{count}} минут назад} (60-119){час назад} (120-inf){{{count}} минут назад}"

Обработка крайних случаев

Отрицательные значения

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

(-inf- -1){ошибка} (0){ноль} (1-inf){{{count}}}

Поведение зависит от реализации постпроцессора и требует явного контроля.

Дробные значения

При передаче float значения обычно приводятся к числовому сравнению без округления логики интервалов. Это может приводить к неожиданным результатам, поэтому чаще применяется предварительное округление:

i18next.t('key', {
  count: Math.floor(value),
  postProcess: 'interval'
});

Взаимодействие с несколькими постпроцессорами

i18next поддерживает цепочки постпроцессоров:

i18next.t('key', {
  count: 3,
  postProcess: ['interval', 'uppercase']
});

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

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

Неймспейсы и организация ресурсов

Interval-строки обычно располагаются в стандартных переводах, без выделения отдельного namespace. Однако при сложных системах локализации часто выделяются отдельные группы:

resources: {
  ru: {
    stats: {
      users: '(0){нет} (1){1} (2-inf){{{count}}}'
    }
  }
}

Вызов:

i18next.t('stats:users', {
  count: 7,
  postProcess: 'interval'
});

Производительность и особенности обработки

Interval postprocessor выполняет парсинг строки на каждом вызове t(). При большом количестве переводов это создаёт нагрузку, особенно при динамических интерфейсах.

Оптимизационные подходы включают:

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

Конфликты с plural и context

Если ключ одновременно содержит plural-формы и interval-выражения, поведение определяется порядком постобработки. Interval полностью переопределяет выбор формы, игнорируя plural rules.

Пример конфликтной структуры:

"key_one": "one",
"key_other": "other",
"key": "(0){none} (1){one} (2-inf){many}"

В режиме interval plural-формы не используются.

Типовые ошибки конфигурации

  • отсутствие postProcess: 'interval'
  • пересечение диапазонов
  • некорректный порядок правил
  • отсутствие fallback для значений вне диапазонов

Пример проблемной конфигурации:

(1-5){A} (3-10){B}

Значение 3 попадёт в первое совпадение (1-5), что может быть неочевидным.

Расширенные сценарии

Interval postprocessor часто используется как слой над доменной логикой:

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

В таких сценариях интервал выступает декларативной моделью состояний, заменяя условные конструкции в коде.