В i18next переводческие ресурсы традиционно загружаются из статических JSON-файлов, однако архитектура библиотеки допускает полную программную генерацию и модификацию словарей во время выполнения приложения. Такой подход используется в сценариях, где тексты формируются на основе пользовательских данных, приходят с сервера после авторизации или создаются модульно при ленивой загрузке функциональных блоков.
Ключевой механизм — работа с ресурсами через API экземпляра i18next:
i18next.addResourceBundle(
'ru',
'common',
{
title: 'Заголовок',
description: 'Описание',
},
true,
true
);
Параметры определяют поведение слияния:
Программная генерация переводов часто используется при модульной архитектуре, где каждый модуль сам регистрирует свои строки.
Одним из распространённых подходов является построение ключей динамически на основе структуры данных. Вместо статических строк применяется формирование путей:
const getKey = (entity, field) => `${entity}.${field}`;
i18next.t(getKey('user', 'name'));
Такая модель позволяет:
Однако при чрезмерной динамике возрастает риск появления «висячих ключей», когда перевод отсутствует в ресурсах. В таких случаях используется fallback-цепочка:
i18next.init({
fallbackLng: 'en',
saveMissing: true,
});
Функция автоматического сохранения отсутствующих переводов позволяет строить систему, где ключи создаются на основе фактического использования приложения.
i18next.init({
lng: 'ru',
fallbackLng: 'en',
saveMissing: true,
missingKeyHandler: (lng, ns, key, fallbackValue) => {
console.log('Отсутствует ключ:', key);
}
});
При вызове:
i18next.t('dashboard.widgets.chart.title');
и отсутствии перевода система может:
Namespaces позволяют разделять переводческие контексты. Генерация namespaces в рантайме часто применяется в плагинной архитектуре:
i18next.addResourceBundle('ru', 'plugin_calendar', {
nextEvent: 'Следующее событие',
noEvents: 'Нет событий',
});
При подключении модуля:
i18next.loadNamespaces('plugin_calendar');
Это даёт возможность:
Часто тексты приходят с backend в виде структур, которые необходимо преобразовать в словарь:
fetch('/api/translations')
.then(res => res.json())
.then(data => {
Object.entries(data).forEach(([lng, resources]) => {
Object.entries(resources).forEach(([ns, bundle]) => {
i18next.addResourceBundle(lng, ns, bundle, true, true);
});
});
});
Такая схема используется при:
UI-компоненты часто требуют предсказуемых, но автоматически формируемых ключей:
function buildComponentKey(componentName, state) {
return `components.${componentName}.${state}`;
}
i18next.t(buildComponentKey('button', 'disabled'));
Пример структуры ресурсов:
{
"components": {
"button": {
"disabled": "Недоступно",
"loading": "Загрузка"
}
}
}
Такой подход обеспечивает строгую иерархию и упрощает поддержку больших интерфейсов.
i18next поддерживает интерполяцию, которая активно используется при программной генерации сообщений:
i18next.t('greeting', {
name: user.name,
age: user.age
});
Ресурс:
{
"greeting": "Пользователь {{name}}, возраст {{age}}"
}
Интерполяция позволяет избегать генерации множества однотипных строк и переносить вариативность в параметры.
Контекст (context) используется для создания вариаций одного ключа без дублирования:
i18next.t('cart.item', { context: 'empty' });
i18next.t('cart.item', { context: 'full' });
Ресурс:
{
"cart": {
"item_empty": "Корзина пуста",
"item_full": "Товары в корзине"
}
}
Контекст может формироваться программно:
const context = items.length === 0 ? 'empty' : 'full';
i18next.t('cart.item', { context });
Плюрализация в i18next позволяет автоматически формировать ключи вида
one, few, many, что особенно
важно при динамическом создании ресурсов:
i18next.t('messages', { count: 5 });
Ресурс:
{
"messages_one": "1 сообщение",
"messages_few": "{{count}} сообщения",
"messages_many": "{{count}} сообщений"
}
Генерация таких структур часто автоматизируется:
function buildPluralKey(base) {
return {
one: `${base}_one`,
few: `${base}_few`,
many: `${base}_many`
};
}
При модульной системе перевод может создаваться в момент инициализации:
export function registerProfileTranslations(i18n) {
i18n.addResourceBundle('ru', 'profile', {
title: 'Профиль',
edit: 'Редактировать',
logout: 'Выйти'
});
}
Это позволяет:
Фабричный подход используется для стандартизации структуры переводов:
function createFormTranslations(entityName) {
return {
title: `${entityName}.title`,
submit: `${entityName}.submit`,
cancel: `${entityName}.cancel`
};
}
Использование:
const userForm = createFormTranslations('userForm');
i18next.t(userForm.title);
Такая стратегия удобна при большом количестве однотипных форм.
В архитектурах с событийной моделью переводы могут добавляться реактивно:
eventBus.on('module:loaded', (module) => {
i18next.addResourceBundle(
module.lng,
module.ns,
module.translations,
true,
true
);
});
Это позволяет связывать систему локализации с жизненным циклом приложения, включая:
Fallback-ключи создаются программно для предотвращения пустых строк:
function safeT(key, options) {
const result = i18next.t(key, options);
return result === key ? `[${key}]` : result;
}
Такая обёртка позволяет отслеживать отсутствующие переводы и одновременно поддерживать читаемость интерфейса.
UI-структуры могут служить источником генерации переводов:
const uiSchema = {
header: {
title: true,
subtitle: true
},
footer: {
copyright: true
}
};
function buildResources(schema, prefix = '') {
const result = {};
Object.keys(schema).forEach(key => {
const path = prefix ? `${prefix}.${key}` : key;
if (schema[key] === true) {
result[path] = path;
} else {
Object.assign(result, buildResources(schema[key], path));
}
});
return result;
}
При динамическом добавлении переводов важна стратегия разрешения конфликтов:
i18next.addResourceBundle('ru', 'common', newBundle, true, true);
Типичные подходы:
Без контроля конфликтов динамическая генерация приводит к нестабильности отображаемых строк.
При больших объёмах программной генерации важно учитывать:
Оптимизация достигается через:
addResourceBundle;Стабильность системы переводов требует детерминированных ключей:
function stableKey(parts) {
return parts.filter(Boolean).join('.');
}
Пример:
stableKey(['user', 'settings', 'theme']);
Результат:
user.settings.theme
Такой подход снижает риск появления дубликатов и облегчает миграцию переводов между версиями приложения.