Концепция постобработки

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

Постобработчики (post processors) подключаются как расширения и формируют цепочку трансформаций, применяемых к итоговому тексту.


Место постобработки в пайплайне перевода

Процесс получения строки в i18next включает несколько этапов:

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

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


Концепция postProcessor

PostProcessor в i18next — это функция или модуль, который принимает готовую строку и возвращает её изменённую версию.

Базовая сигнатура постпроцессора:

const myPostProcessor = {
  type: 'postProcessor',
  name: 'customProcessor',

  process(value, key, options, translator) {
    return value;
  }
};

Параметры process:

  • value — итоговая строка перевода
  • key — ключ перевода
  • options — параметры перевода (interpolation, context и др.)
  • translator — доступ к API i18next внутри процесса

Подключение постпроцессора

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

import i18next from 'i18next';

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

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

i18next
  .use(uppercaseProcessor)
  .init({
    resources: {
      en: {
        translation: {
          hello: 'Hello {{name}}'
        }
      }
    },
    postProcess: ['uppercase']
  });

i18next.t('hello', { name: 'John' });

Результат:

HELLO JOHN

Цепочка постобработчиков

i18next поддерживает применение нескольких постпроцессоров последовательно.

postProcess: ['trim', 'uppercase', 'markdown']

Каждый следующий процесс получает результат предыдущего.


Типовые сценарии использования постобработки

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

Постобработка может использоваться для стилизации результата:

  • приведение к верхнему регистру
  • нормализация пробелов
  • добавление префиксов/суффиксов
const trimProcessor = {
  type: 'postProcessor',
  name: 'trim',

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

2. Безопасность и фильтрация

Постпроцессоры часто применяются для очистки текста:

  • удаление нежелательных символов
  • фильтрация запрещённых слов
  • защита от HTML-инъекций
const sanitizeProcessor = {
  type: 'postProcessor',
  name: 'sanitize',

  process(value) {
    return value.replace(/<script.*?>.*?<\/script>/gi, '');
  }
};

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


3. Поддержка markdown и rich-text

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

const markdownProcessor = {
  type: 'postProcessor',
  name: 'markdown',

  process(value) {
    return value
      .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
      .replace(/\*(.*?)\*/g, '<em>$1</em>');
  }
};

Пример перевода:

"welcome": "Hello **{{name}}**"

Результат:

Hello <strong>John</strong>

4. Постобработка чисел и единиц измерения

Хотя базовая интерполяция в i18next может форматировать числа, постпроцессор позволяет централизованно обрабатывать единицы измерения.

const unitProcessor = {
  type: 'postProcessor',
  name: 'units',

  process(value, key, options) {
    if (options.unit === 'km') {
      return `${value} km`;
    }
    if (options.unit === 'mi') {
      return `${value} miles`;
    }
    return value;
  }
};

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

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

const contextProcessor = {
  type: 'postProcessor',
  name: 'contextAware',

  process(value, key, options) {
    if (options.context === 'error') {
      return `⚠ ${value}`;
    }
    return value;
  }
};

Вызов:

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

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

В i18next интерполяция выполняется до постобработки. Это означает, что постпроцессор получает уже «развёрнутую» строку.

{
  "greeting": "Hello {{name}}"
}

После интерполяции:

Hello John

Постобработчик работает уже с финальным результатом.


Асинхронные ограничения

Постпроцессоры в i18next выполняются синхронно. Это накладывает ограничения:

  • нельзя выполнять async запросы
  • нельзя использовать await внутри process
  • нельзя обращаться к внешним API в реальном времени

Для подобных задач требуется предварительная подготовка данных до вызова t().


Порядок выполнения постпроцессоров

Если задано несколько постпроцессоров:

postProcess: ['trim', 'uppercase', 'suffix']

Порядок строго последовательный:

  1. trim → убирает пробелы
  2. uppercase → преобразует регистр
  3. suffix → добавляет окончание

Каждый этап получает модифицированный результат предыдущего.


Встроенный API translator

Параметр translator позволяет постпроцессору обращаться к внутренним методам i18next:

process(value, key, options, translator) {
  const fallback = translator.t(key, { lng: 'en' });
  return value || fallback;
}

Это позволяет реализовать сложные fallback-стратегии на уровне постобработки.


Кеширование и постобработка

Кэширование в i18next может влиять на постпроцессоры:

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

Это особенно важно при динамических трансформациях текста.


Ошибки и устойчивость цепочки

Постпроцессоры должны быть устойчивыми к ошибкам. Любое исключение может прервать цепочку обработки.

process(value) {
  try {
    return value.toUpperCase();
  } catch (e) {
    return value;
  }
}

В архитектуре i18next предпочтительно возвращать исходное значение при сбоях.


Комбинация с форматированием ICU и интерполяцией

При использовании ICU-подобных конструкций или сложной интерполяции постобработка применяется уже к финальному тексту:

  • plural rules уже вычислены
  • context уже выбран
  • переменные уже подставлены

Постпроцессор не участвует в логике выбора формы, а только модифицирует результат.


Реализация многоуровневых трансформаций

Постобработка позволяет строить конвейеры преобразований:

  • нормализация текста
  • локализация символов
  • стилизация интерфейса
  • добавление UI-маркеров
const pipeline = [
  { type: 'postProcessor', name: 'trim' },
  { type: 'postProcessor', name: 'sanitize' },
  { type: 'postProcessor', name: 'emojiReplace' }
];

Ограничения архитектуры постобработки

В i18next существуют ограничения:

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

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