Программная генерация переводов

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

Ключевой механизм — работа с ресурсами через API экземпляра i18next:

i18next.addResourceBundle(
  'ru',
  'common',
  {
    title: 'Заголовок',
    description: 'Описание',
  },
  true,
  true
);

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

  • deep (true/false) — рекурсивное объединение объектов;
  • overwrite (true/false) — перезапись существующих ключей.

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


Генерация ключей перевода на основе доменной модели

Одним из распространённых подходов является построение ключей динамически на основе структуры данных. Вместо статических строк применяется формирование путей:

const getKey = (entity, field) => `${entity}.${field}`;

i18next.t(getKey('user', 'name'));

Такая модель позволяет:

  • унифицировать структуру ключей;
  • автоматически масштабировать словари;
  • избегать дублирования текстов.

Однако при чрезмерной динамике возрастает риск появления «висячих ключей», когда перевод отсутствует в ресурсах. В таких случаях используется fallback-цепочка:

i18next.init({
  fallbackLng: 'en',
  saveMissing: true,
});

Использование saveMissing для автоматической генерации ключей

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

i18next.init({
  lng: 'ru',
  fallbackLng: 'en',
  saveMissing: true,
  missingKeyHandler: (lng, ns, key, fallbackValue) => {
    console.log('Отсутствует ключ:', key);
  }
});

При вызове:

i18next.t('dashboard.widgets.chart.title');

и отсутствии перевода система может:

  • отправить ключ на сервер;
  • сохранить в локальное хранилище;
  • записать в лог для последующей генерации словаря.

Программное формирование namespace

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);
      });
    });
  });

Такая схема используется при:

  • CMS-управляемых интерфейсах;
  • SaaS-платформах;
  • мультиарендных системах.

Динамическая генерация ключей для UI-компонентов

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: 'Выйти'
  });
}

Это позволяет:

  • не загружать весь словарь сразу;
  • уменьшить стартовый bundle;
  • формировать переводы по мере использования функциональности.

Генерация переводов через фабрики

Фабричный подход используется для стандартизации структуры переводов:

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
  );
});

Это позволяет связывать систему локализации с жизненным циклом приложения, включая:

  • загрузку плагинов;
  • активацию feature flags;
  • подключение удалённых модулей.

Генерация fallback-ключей

Fallback-ключи создаются программно для предотвращения пустых строк:

function safeT(key, options) {
  const result = i18next.t(key, options);
  return result === key ? `[${key}]` : result;
}

Такая обёртка позволяет отслеживать отсутствующие переводы и одновременно поддерживать читаемость интерфейса.


Автоматическое построение словаря из структуры UI

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);

Типичные подходы:

  • глубокое слияние объектов;
  • приоритет модульных переводов;
  • изоляция namespaces;
  • версионирование ресурсов.

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


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

При больших объёмах программной генерации важно учитывать:

  • стоимость операций merge;
  • размер глобального resource store;
  • частоту обновлений;
  • влияние на кеширование t-функции.

Оптимизация достигается через:

  • пакетную загрузку ресурсов;
  • разделение namespaces;
  • предварительную агрегацию словарей до вызова addResourceBundle;
  • минимизацию частых инкрементальных изменений.

Детерминированная генерация ключей

Стабильность системы переводов требует детерминированных ключей:

function stableKey(parts) {
  return parts.filter(Boolean).join('.');
}

Пример:

stableKey(['user', 'settings', 'theme']);

Результат:

user.settings.theme

Такой подход снижает риск появления дубликатов и облегчает миграцию переводов между версиями приложения.