Оптимизация размера переводов

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

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

Разделение переводов по namespace

Одним из базовых механизмов сокращения объёма загружаемых данных выступает разделение переводов на namespaces.

Вместо монолитного файла translation.json используется структура:

  • common.json
  • auth.json
  • profile.json
  • checkout.json

Преимущества:

  • загружается только нужный домен переводов
  • уменьшается initial bundle size
  • повышается эффективность code splitting

Пример конфигурации:

i18next.init({
  ns: ['common', 'auth'],
  defaultNS: 'common',
  fallbackLng: 'en'
});

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

Ленивая загрузка переводов

Загрузка всех языков сразу приводит к линейному росту веса приложения при добавлении новых локалей. Решение — lazy loading ресурсов.

С использованием backend-плагина:

import HttpBackend from 'i18next-http-backend';

i18next.use(HttpBackend).init({
  backend: {
    loadPath: '/locales/{{lng}}/{{ns}}.json'
  }
});

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

  • загрузки только активного языка
  • подгрузки namespace по требованию
  • возможности кеширования на CDN уровне

Разделение языков по стратегиям загрузки

Разные языки имеют разную частоту использования. Это позволяет вводить уровни приоритетов:

  • primary languages (загружаются сразу): en, ru
  • secondary languages (загружаются по запросу): de, fr
  • long-tail languages (загружаются только при выборе пользователем)

Такой подход снижает начальный payload и улучшает LCP.

Минимизация структуры JSON переводов

Размер переводов часто увеличивается из-за избыточной структуры:

Избыточные ключи

Плохо:

{
  "button": {
    "submit_button_text_label_primary": "Отправить"
  }
}

Оптимально:

{
  "submit": "Отправить"
}

Сокращение глубины вложенности

Каждый уровень вложенности:

  • увеличивает размер ключей при сериализации
  • усложняет gzip/brotli сжатие
  • ухудшает читаемость и переиспользование

Рекомендуется ограничивать вложенность 2–3 уровнями.

Удаление неиспользуемых переводов

При масштабировании проекта появляются:

  • устаревшие ключи
  • неиспользуемые namespace
  • языки без аудитории

Практика оптимизации:

  • статический анализ вызовов t('key')
  • поиск orphan keys
  • автоматическое удаление через CI

Особое внимание уделяется строкам, используемым динамически — они часто не попадают в анализаторы.

Tree-shaking переводов на уровне сборщика

При использовании Webpack или Vite переводы могут быть частично извлечены в отдельные чанки.

Подход:

  • каждый namespace — отдельный async chunk
  • языки подключаются через dynamic import
const resources = await import(`./locales/${lng}/${ns}.json`);

Эффект:

  • сокращение initial bundle
  • параллельная загрузка ресурсов
  • улучшение caching granularity

Использование интерполяции вместо дублирования строк

Частая ошибка — создание множества похожих строк:

Плохо:

{
  "welcome_user": "Добро пожаловать, Иван",
  "welcome_admin": "Добро пожаловать, Админ"
}

Оптимально:

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

Это снижает:

  • количество ключей
  • общий размер файлов
  • нагрузку на парсинг JSON

Оптимизация множественного числа и контекстов

Множественные формы увеличивают объём переводов:

{
  "item_one": "1 элемент",
  "item_other": "{{count}} элементов"
}

При масштабировании языков с богатой морфологией (ru, pl, cs) объём растёт экспоненциально.

Оптимизация:

  • использование ICU MessageFormat
  • унификация правил pluralization
  • минимизация контекстных вариаций

Сжатие и доставка переводов

Переводы эффективно сжимаются стандартными алгоритмами:

  • gzip
  • brotli

Однако эффективность зависит от структуры:

  • повторяющиеся ключи улучшают compression ratio
  • глубокие ключи ухудшают эффективность
  • длинные ключи увеличивают overhead

Рекомендуется использовать CDN с включённым brotli для /locales/*.

Кэширование переводов

Кэширование снижает повторную загрузку ресурсов:

Стратегии:

  • HTTP caching (ETag, Cache-Control)
  • service worker caching
  • in-memory cache i18next

Пример:

i18next.init({
  cache: {
    enabled: true
  }
});

Важно учитывать версионирование переводов для предотвращения устаревших данных.

Оптимизация fallback-логики

Fallback-языки увеличивают количество потенциально загружаемых ресурсов.

Проблема:

  • цепочки fallback могут тянуть лишние языки

Решение:

  • минимизация fallback chain
  • ограничение до 1 уровня
  • отказ от каскадных fallback в клиенте

Разделение runtime и build-time переводов

Переводы можно разделить на:

  • build-time (статические интерфейсы)
  • runtime (динамические данные)

Статические переводы:

  • кнопки
  • UI элементы

Runtime переводы:

  • пользовательский контент
  • CMS строки

Разделение позволяет:

  • уменьшить initial payload
  • загружать динамику по API

Оптимизация через CDN-структуру

Структура хранения:

/locales/{lang}/{namespace}.json

Преимущества:

  • независимое кеширование языков
  • обновление отдельных namespace
  • параллельная загрузка

Дополнительно:

  • versioning через query string
  • immutable caching

Контроль размера через метрики

Размер переводов должен измеряться:

  • total JSON size per language
  • namespace size distribution
  • unused key ratio
  • duplication rate across languages

Эти метрики позволяют выявлять:

  • перегруженные языки
  • разрастающиеся namespaces
  • деградацию структуры переводов