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

В основе работы i18next лежит внутреннее хранилище ресурсов — ResourceStore, представляющее собой структуру в памяти, где организованы все загруженные переводы. Данные хранятся в виде:

  • язык → пространство имён (namespace) → ключи переводов

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

Ключевая особенность этого слоя заключается в том, что он является первичным кэшем. Любая загруженная локализация остаётся в памяти до перезагрузки страницы или перезапуска процесса Node.js.

При стандартной инициализации:

  • при первом запросе t('key') выполняется поиск в ResourceStore
  • если данных нет — запускается загрузка через backend
  • после загрузки результат сохраняется в память

Таким образом, повторное использование переводов внутри одного сеанса происходит мгновенно.


Кэширование на уровне backend-слоя

i18next не ограничивается только памятью. Основной механизм масштабируемого кэширования реализуется через backend-плагины.

HTTP backend и браузерный кэш

При использовании HTTP-загрузчика переводов (i18next-http-backend) запросы к JSON-файлам проходят через стандартный механизм fetch/XHR, а значит могут использовать:

  • HTTP cache headers (Cache-Control, ETag)
  • встроенный кэш браузера
  • прокси-кэш (CDN)

Типичная схема:

  1. Запрос /locales/en/translation.json
  2. Браузер проверяет наличие валидного кэша
  3. При наличии — используется локальная копия
  4. При отсутствии — выполняется сетевой запрос
  5. Ответ сохраняется в HTTP-кэше

Дополнительно можно управлять поведением через:

  • requestOptions.cache (для fetch)
  • заголовки сервера
  • версионирование URL

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

i18next
  .use(Backend)
  .init({
    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json',
      requestOptions: {
        cache: 'default'
      }
    }
  });

Кэширование в localStorage

Для браузерных приложений часто применяется долговременное хранение переводов в localStorage. Это снижает количество сетевых запросов при повторных посещениях.

Существует специализированный backend:

  • i18next-localstorage-backend

Его принцип работы:

  1. При загрузке сначала проверяется наличие данных в localStorage
  2. Если данные найдены и не устарели — они используются
  3. Если отсутствуют или устарели — выполняется запрос к серверу
  4. Новый результат записывается обратно в localStorage

Структура хранения обычно включает:

  • язык
  • namespace
  • timestamp
  • payload переводов

Это позволяет реализовать простую TTL-логику.


TTL и стратегия устаревания данных

Кэш переводов требует контроля актуальности, поскольку обновления интерфейса могут ломать согласованность текстов.

Часто используется подход:

  • фиксированный TTL (например, 24 часа)
  • версионирование переводов
  • контроль хэша файла

Пример логики:

  • если storedVersion !== currentVersion → кэш инвалидируется
  • если now - storedTimestamp > TTL → повторная загрузка

Это особенно важно в SPA и PWA, где приложение может работать неделями без перезагрузки.


Chained backend как многоуровневый кэш

Для сложных приложений применяется комбинация источников через:

  • i18next-chained-backend

Он позволяет выстроить цепочку:

  1. localStorage (быстрый доступ)
  2. memory store (i18next ResourceStore)
  3. HTTP backend (источник истины)

Схема работы:

  • сначала проверяется локальный кэш
  • затем память процесса
  • затем сеть

Такой подход минимизирует задержки и снижает нагрузку на сервер.


Кэширование на уровне файловой системы (Node.js)

В серверных приложениях на Node.js используется файловый backend:

  • i18next-fs-backend

Хотя файловая система сама по себе не является кэшем, на практике реализуются дополнительные оптимизации:

  • чтение файлов происходит один раз
  • далее данные остаются в памяти ResourceStore
  • возможен внешний LRU-кэш при кастомной реализации

Типичная оптимизация:

  • preload всех языков при старте сервера
  • исключение повторных чтений JSON

Динамическая загрузка и ленивый кэш

i18next поддерживает стратегию lazy-loading переводов, при которой:

  • языки и namespaces загружаются по мере необходимости
  • отсутствующие ключи не блокируют рендер
  • данные догружаются асинхронно

Это приводит к естественному кэшированию:

  • первый запрос → загрузка
  • последующие → мгновенный доступ из памяти

Особенно эффективно в приложениях с множеством языков, где полный набор переводов слишком велик для предварительной загрузки.


Инвалидация кэша

Ключевая проблема любых систем локализации — обновление переводов без конфликтов с уже закэшированными версиями.

Используются несколько подходов:

1. Версионирование ресурсов

URL включает версию:

/locales/en/translation.v2.json

Изменение версии автоматически обходится без очистки клиентских кэшей.


2. Cache busting

Добавление параметров запроса:

/locales/en/translation.json?v=12345

Часто используется hash сборки.


3. Принудительная перезагрузка ресурсов

i18next позволяет вручную сбрасывать ресурсы:

  • удаление языка из ResourceStore
  • повторный reloadResources

Это используется при runtime-обновлениях интерфейса.


Совместное использование с service worker

В PWA-приложениях кэширование переводов может быть вынесено на уровень service worker:

  • перехват запросов /locales/*
  • хранение JSON в Cache Storage
  • обновление по стратегии stale-while-revalidate

Поток обработки:

  1. Service Worker отдаёт закэшированную версию
  2. Фоново запрашивает обновление
  3. Обновляет кэш при изменении

Это снижает задержки до нуля при повторных открытиях приложения.


Интерполяция и влияние на кэш

Хотя интерполяция ({{value}}) не влияет напрямую на хранение переводов, она важна для понимания стабильности кэша:

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

Это позволяет хранить минимальный объём ресурсов без дублирования строк.


Оптимизация объёма кэша

При масштабных проектах критично контролировать размер локализаций:

  • разделение на namespaces (common, auth, dashboard)
  • загрузка только нужных модулей
  • использование partialBundledLanguages
  • удаление неиспользуемых ключей

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


Поведение при повторной инициализации

При повторном вызове i18next.init:

  • ResourceStore может быть переиспользован
  • либо перезаписан, если включена новая конфигурация
  • backend-кэш сохраняется независимо от инстанса

В SPA это позволяет сохранять переводы между переходами по роутам без повторной загрузки.


Согласованность между слоями кэширования

Эффективная работа системы зависит от согласованности трёх уровней:

  • HTTP cache
  • memory store (ResourceStore)
  • persistent storage (localStorage/IndexedDB)

Нарушение синхронизации приводит к типичным проблемам:

  • устаревшие переводы при обновлении интерфейса
  • дублирование загрузок
  • расхождение версий между вкладками браузера

Для устранения таких ситуаций используется:

  • единый versioning key
  • централизованная стратегия обновления ресурсов
  • очистка кэша при смене сборки приложения