Миграция с других библиотек на i18next

Переход с других систем интернационализации на i18next требует предварительного анализа существующей модели локализации, структуры ключей и способа интеграции переводов в UI. Основная сложность миграции заключается не в синтаксических различиях API, а в различиях философии: многие библиотеки используют форматированные сообщения или компонентный подход, тогда как i18next опирается на ключ-значение, контексты, интерполяцию и плагины.

Ключевая особенность миграции — сохранение стабильности текстов при постепенном переключении слоёв интернационализации без полной переписки приложения.


Анализ исходной системы интернационализации

Перед переносом переводов необходимо выделить модель, используемую в текущей системе:

  • строковые ключи (key-based)
  • форматированные сообщения (ICU, MessageFormat)
  • компонентная локализация (React/Vue компоненты)
  • директивы (Angular/Vue directives)
  • runtime interpolation (ручная замена переменных)
  • pluralization (ручная или библиотечная)

Каждая из этих моделей влияет на то, как данные будут преобразованы в формат i18next.


Базовая модель i18next

i18next использует следующую структуру:

{
  "common": {
    "welcome": "Добро пожаловать",
    "cart": {
      "items": "В корзине {{count}} товаров"
    }
  }
}

Основные концепции:

  • ключи с вложенной структурой
  • интерполяция через {{ }}
  • поддержка множественного числа
  • контексты (context)
  • namespaces (разделение переводов)
  • fallback языки

Стратегия миграции: поэтапный переход

1. Инвентаризация переводов

Переводы из исходной системы группируются по категориям:

  • UI тексты
  • системные сообщения
  • ошибки API
  • динамические сообщения
  • форматированные строки

На этом этапе формируется единый словарь, который станет источником для i18next resources.


2. Нормализация ключей

Разные библиотеки используют разные схемы:

  • t('WELCOME_MESSAGE')
  • formatMessage({ id: 'welcome.message' })
  • <Trans i18nKey="welcome.message" />

В i18next рекомендуется привести всё к единому виду:

  • auth.login.title
  • cart.item.count
  • errors.network.timeout

Важно сохранить иерархию, а не плоскую структуру.


3. Перенос строковых ресурсов

Из JSON или JS-объектов исходной системы данные преобразуются в формат i18next:

Было (например, react-intl):

{
  "welcome.message": "Добро пожаловать, {name}"
}

Стало:

{
  "welcome": {
    "message": "Добро пожаловать, {{name}}"
  }
}

Основные изменения:

  • {name}{{name}}
  • плоские ключи → вложенные структуры

4. Замена API вызовов

Старый подход (generic i18n)

intl.formatMessage({ id: 'welcome.message' }, { name: 'Alex' });

Новый подход i18next

i18next.t('welcome.message', { name: 'Alex' });

или при иерархии:

i18next.t('welcome.message', { name: 'Alex' });

5. Работа с React/Vue компонентами

React Intl → i18next

<FormattedMessage id="cart.items" values={{ count }} />

заменяется на:

import { useTranslation } from 'react-i18next';

const { t } = useTranslation();

t('cart.items', { count });

или:

<Trans i18nKey="cart.items" values={{ count }} />

6. Переход с vue-i18n

Исходный вариант

this.$t('message.welcome', { name })

i18next вариант

i18next.t('message.welcome', { name })

или через обёртку:

import { useTranslation } from 'react-i18next';
const { t } = useTranslation();

Особенность миграции с Vue — замена реактивных watch-систем на подписку i18next.


7. Обработка множественного числа

Старый формат

{
  "items": "1 item | {count} items"
}

i18next формат

{
  "items_one": "{{count}} товар",
  "items_few": "{{count}} товара",
  "items_many": "{{count}} товаров"
}

или через встроенную pluralization:

{
  "items": "{{count}} товар",
  "items_plural": "{{count}} товаров"
}

Использование:

i18next.t('items', { count: 5 });

8. Интерполяция и форматирование

Многие библиотеки используют кастомные форматтеры:

ICU формат:

{count, plural, one {# item} other {# items}}

i18next:

{
  "items": "{{count}} item"
}

или с форматами:

i18next.t('price', {
  price: 1200,
  formatParams: {
    price: {
      currency: 'USD'
    }
  }
});

Дополнительно подключаются плагины форматирования.


Миграция архитектуры хранения переводов

Flat JSON → Namespaces

Многие системы используют плоский JSON:

{
  "login.title": "Вход",
  "login.button": "Войти"
}

В i18next предпочтительнее:

{
  "login": {
    "title": "Вход",
    "button": "Войти"
  }
}

Разделение на namespaces:

  • auth.json
  • cart.json
  • common.json
  • errors.json

Интеграция в приложение

Инициализация

import i18next from 'i18next';

i18next.init({
  lng: 'ru',
  fallbackLng: 'en',
  resources: {
    ru: {
      common: require('./locales/ru/common.json')
    }
  }
});

React интеграция

import { initReactI18next } from 'react-i18next';

i18next.use(initReactI18next).init({
  resources,
  lng: 'ru'
});

Миграция динамических ключей

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

t(`error.${code}`);

В i18next сохраняется аналогичная модель:

i18next.t(`error.${code}`);

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

{
  "error": {
    "404": "Не найдено",
    "500": "Ошибка сервера"
  }
}

Обработка fallback и частичной миграции

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

  • legacy i18n
  • i18next

Стратегия:

  1. i18next становится primary
  2. legacy используется как fallback
  3. постепенное удаление legacy API

Пример обёртки:

function t(key, options) {
  if (i18next.exists(key)) {
    return i18next.t(key, options);
  }
  return legacyT(key, options);
}

Частые ошибки при миграции

Несовпадение интерполяции

  • {name} → ломается
  • {{name}} → требуется строгое соответствие

Потеря структуры ключей

Плоские ключи без namespace приводят к конфликтам:

  • title
  • button
  • title в разных модулях

Неправильная pluralization

Многие библиотеки используют ICU, но i18next требует отдельной настройки plural rules.


Игнорирование fallbackLng

Без fallback языка возможны “дыры” в UI при неполной миграции.


Постепенная стратегия внедрения i18next

  • параллельная работа двух систем
  • миграция namespace за namespace
  • замена UI-компонентов частями
  • унификация ключей
  • удаление legacy слоёв после стабилизации

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

При использовании TypeScript:

interface Resources {
  common: {
    welcome: string;
  };
}

Дополнительно применяются:

  • проверки отсутствующих ключей
  • CI-валидация JSON
  • автоматическая синхронизация языков

Организация больших проектов

Рекомендуемая структура:

locales/
  ru/
    common.json
    auth.json
    cart.json
  en/
    common.json
    auth.json
    cart.json

Namespaces подключаются лениво:

i18next.loadNamespaces('cart');

Работа с legacy форматами сообщений

Если исходная система использует ICU:

{count, plural, one {# item} other {# items}}

возможны два подхода:

  • конвертация в i18next plural rules
  • использование i18next ICU plugin

Миграция API ошибок и backend сообщений

Backend часто возвращает:

{
  "error": "USER_NOT_FOUND"
}

В i18next:

i18next.t(`errors.${errorCode}`);

или через mapping layer:

const message = i18next.t(errorMap[code]);

Постмиграционная стабилизация

После завершения переноса:

  • удаляются legacy ключи
  • фиксируются namespaces
  • оптимизируется загрузка переводов
  • вводится строгая схема ключей
  • включается контроль отсутствующих переводов