В системе i18next ключ перевода представляет собой строковый идентификатор, по которому из словаря ресурсов извлекается локализованное значение. При статическом подходе ключи заранее фиксируются в коде и совпадают с путями в ресурсах:
t('errors.network.timeout')
Динамические ключи переводов возникают в ситуациях, когда идентификатор формируется во время выполнения программы. Такой подход используется при построении универсальных компонентов, обработке переменных типов сущностей, конфигурационных сценариев и мета-данных, где заранее неизвестно, какой именно ключ потребуется.
const key = `errors.${type}.${code}`;
t(key);
Ключ перестаёт быть фиксированным элементом структуры и превращается в вычисляемое значение, зависящее от состояния приложения.
Основной механизм динамических ключей заключается в конкатенации строк или шаблонных литералов. В i18next отсутствуют ограничения на источник ключа — это может быть результат API, состояние приложения или вычисляемая логика.
function getErrorMessage(type, code) {
return i18next.t(`errors.${type}.${code}`);
}
При таком подходе структура ресурсов должна поддерживать предсказуемую иерархию:
{
"errors": {
"network": {
"timeout": "Превышено время ожидания",
"offline": "Нет соединения"
},
"auth": {
"expired": "Сессия истекла"
}
}
}
Ключи становятся производными от доменной модели, что позволяет унифицировать обработку множества состояний через единый механизм.
В i18next предусмотрен механизм интерполяции, который часто заменяет необходимость динамических ключей. Вместо генерации нового ключа используется один шаблон с параметрами:
t('errors.message', { type: 'network', code: 'timeout' });
Ресурс:
{
"errors": {
"message": "{{type}} ошибка: {{code}}"
}
}
Однако интерполяция не всегда решает задачу, поскольку не подходит для выбора различных фраз с полностью разной семантикой. В таких случаях динамический ключ остаётся единственным корректным инструментом.
i18next поддерживает доступ к вложенным объектам через точечную нотацию:
t('validation.form.email.required');
При динамическом формировании таких путей важно учитывать, что структура ресурсов должна быть строго согласованной:
const field = 'email';
const rule = 'required';
t(`validation.form.${field}.${rule}`);
При масштабировании системы структура ключей становится контрактом между кодом и словарём переводов. Нарушение этого контракта приводит к деградации качества локализации.
i18next поддерживает разделение переводов на пространства имён (namespaces), что добавляет дополнительный уровень динамичности:
t(`${namespace}:${section}.${key}`);
Пример:
const namespace = 'auth';
const key = 'login.title';
t(`${namespace}:${key}`);
Ресурсы:
{
"auth": {
"login": {
"title": "Вход в систему"
}
}
}
Динамическое формирование namespace особенно полезно при модульной архитектуре, где каждый модуль владеет собственной зоной переводов.
При использовании динамических ключей возрастает вероятность обращения к несуществующим значениям. Для контроля используется проверка:
i18next.exists(`errors.${type}.${code}`);
Логика обработки:
const key = `errors.${type}.${code}`;
if (i18next.exists(key)) {
return i18next.t(key);
}
return i18next.t('errors.unknown');
Такой подход снижает риск появления необработанных fallback-значений в пользовательском интерфейсе.
Часто динамические ключи применяются при обработке списков однотипных элементов:
items.map(item => i18next.t(`products.${item.category}.${item.status}`));
Пример структуры:
{
"products": {
"book": {
"available": "В наличии",
"out_of_stock": "Нет в наличии"
}
}
}
Однако при увеличении количества категорий подобный подход усложняет поддержку словаря, так как создаётся зависимость между бизнес-логикой и структурой переводов.
Некоторые архитектуры используют шаблонные ключи как промежуточный слой:
const template = 'order.status.{status}';
const key = template.replace('{status}', order.status);
t(key);
Подобный подход позволяет централизовать структуру ключей, но увеличивает риск ошибок при ручной подстановке значений.
i18next использует разделители для навигации по вложенным объектам:
. — уровень вложенности: — namespaceПри динамическом формировании ключей важно учитывать конфигурацию:
i18next.init({
keySeparator: '.',
nsSeparator: ':'
});
При изменении этих параметров динамические ключи должны формироваться с учётом новой семантики, иначе происходит разрыв между кодом и ресурсами.
Распространённая проблема заключается в чрезмерной генерации ключей:
t(`label.${field}.${value}.${state}.${mode}`);
Такая конструкция приводит к экспоненциальному росту числа ключей и усложняет локализацию.
Другой проблемой является использование произвольных строк из внешних источников:
t(`messages.${apiResponse.messageCode}`);
Если входные данные не нормализованы, структура переводов становится неконтролируемой.
В ряде случаев динамические ключи заменяются более устойчивыми механизмами:
1. Карта соответствий
const map = {
timeout: 'errors.network.timeout',
offline: 'errors.network.offline'
};
t(map[code]);
2. Функциональный слой
function getTranslation(type, code) {
const dictionary = {
network: {
timeout: 'errors.network.timeout'
}
};
return i18next.t(dictionary[type][code]);
}
3. Интерполяция и условные шаблоны
t('errors.generic', { context: type });
Динамическое формирование строк не является значительной нагрузкой само по себе, однако влияние проявляется косвенно:
i18next кэширует результаты t(), но только при
идентичности ключа. Любая динамика снижает эффективность повторного
использования результата.
При использовании динамических ключей критическим становится единообразие структуры JSON:
{
"section": {
"subsection": {
"key": "value"
}
}
}
Любое отклонение от структуры приводит к необходимости дополнительной проверки ключей или усложнённой логике fallback.
В крупных приложениях динамические ключи становятся инструментом связывания доменной модели с локализацией. Их применение оправдано при:
При этом чрезмерная динамика приводит к снижению прозрачности системы переводов и усложняет поддержку словарей.