В экосистеме i18next форматирование строк может выполняться не только
через встроенную интерполяцию, но и через механизм постобработчиков.
Одним из таких инструментов является sprintf postprocessor,
реализующий форматирование по принципу функций sprintf из
C-подобных языков.
Постпроцессор sprintf применяется на финальном этапе
формирования строки перевода — после того, как ключ перевода найден и
базовая интерполяция (если она используется) уже выполнена. Это
позволяет отделить получение перевода от его форматирования и применять
строгие, позиционные или типизированные шаблоны.
Механизм постобработки встроен в цепочку обработки переводов:
sprintf)PostProcessor — это функция, которая принимает строку и параметры и возвращает модифицированную строку.
Для использования требуется отдельный пакет:
npm install i18next-sprintf-postprocessor
Далее он подключается и регистрируется:
import i18next from 'i18next';
import sprintfPostProcessor from 'i18next-sprintf-postprocessor';
i18next
.use(sprintfPostProcessor)
.init({
lng: 'ru',
resources: {
ru: {
translation: {
welcome: 'Привет, %s!',
},
},
},
});
Форматирование строится на шаблонах:
%s — строка%d — целое число%f — число с плавающей точкой%0.2f — число с фиксированной точностью%1$s, %2$s — позиционные аргументыi18next.t('welcome', 'Иван');
Перевод:
Привет, Иван!
Шаблон:
{
"welcome": "Привет, %s!"
}
sprintf позволяет передавать массив аргументов:
i18next.t('userInfo', ['Иван', 30]);
Шаблон:
{
"userInfo": "Имя: %s, возраст: %d"
}
Результат:
Имя: Иван, возраст: 30
Позиционные спецификаторы позволяют менять порядок вставки без изменения аргументов:
{
"order": "Файл %2$s загружен пользователем %1$s"
}
i18next.t('order', ['Иван', 'report.pdf']);
Результат:
Файл report.pdf загружен пользователем Иван
Поддерживается контроль точности:
{
"price": "Цена: %0.2f ₽"
}
i18next.t('price', [199.956]);
Результат:
Цена: 199.96 ₽
PostProcessor можно комбинировать с другими механизмами:
i18next.t('key', {
postProcess: 'sprintf',
sprintf: ['Иван', 42],
});
Это позволяет явно управлять порядком обработки.
Встроенная интерполяция:
{
"welcome": "Привет, {{name}}"
}
i18next.t('welcome', { name: 'Иван' });
sprintf:
{
"welcome": "Привет, %s"
}
i18next.t('welcome', 'Иван');
Ключевые различия:
{
"log": "[%s] %s: %d ошибок"
}
i18next.t('log', ['INFO', 'Сервер', 5]);
[INFO] Сервер: 5 ошибок
{
"balance": "Баланс: %0.2f USD"
}
i18next.t('balance', [1024.5]);
Баланс: 1024.50 USD
{
"report": "Пользователь %s выполнил %d операций за %0.1f секунд"
}
i18next.t('report', ['Иван', 12, 3.456]);
Пользователь Иван выполнил 12 операций за 3.5 секунд
Если аргументы не переданы:
i18next.t('welcome');
Результат зависит от шаблона:
{
"welcome": "Привет, %s!"
}
Вывод:
Привет, %s!
То есть строка остаётся неформатированной, без ошибок выполнения.
sprintf может использоваться вместе с кастомными
постпроцессорами:
i18next
.use(sprintfPostProcessor)
.use(customPostProcessor);
Порядок применения влияет на итоговый результат, так как каждый postProcessor получает уже изменённую строку.
%s и параметров%d для строковых значенийПример ошибки:
i18next.t('user', { sprintf: { name: 'Иван' } });
Правильно:
i18next.t('user', ['Иван']);
Каждый вызов t() обрабатывает строку независимо,
postProcessor не сохраняет состояние между вызовами, что обеспечивает
детерминированность результата при одинаковых входных данных.