Интеграция с webpack и vite

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


Архитектура работы i18next в модульных сборщиках

i18next в браузерных приложениях обычно опирается на:

  • основную библиотеку i18next
  • плагин загрузки переводов (i18next-http-backend или кастомный backend)
  • detector языка (i18next-browser-languagedetector)
  • интеграции с фреймворками (React, Vue, Svelte — опционально)

В условиях webpack и Vite критически важно разделять:

  • core runtime i18next
  • переводы (JSON ресурсы)
  • механизм загрузки ресурсов

Это позволяет избежать увеличения initial bundle и обеспечить code splitting по языкам.


Структура переводов для сборщиков

Рекомендуемая структура файлов:

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

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

  • загружать только нужные части переводов
  • уменьшать размер initial chunk
  • ускорять гидратацию UI

Интеграция с webpack

Базовая установка

npm install i18next i18next-http-backend i18next-browser-languagedetector

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

import i18n from 'i18next';
import HttpBackend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';

i18n
  .use(HttpBackend)
  .use(LanguageDetector)
  .init({
    fallbackLng: 'en',
    debug: false,

    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json'
    },

    ns: ['common', 'auth'],
    defaultNS: 'common',

    interpolation: {
      escapeValue: false
    }
  });

export default i18n;

Загрузка переводов через webpack dev server

Webpack по умолчанию не обслуживает JSON как i18n-ресурсы без правильной конфигурации.

webpack.config.js

const path = require('path');

module.exports = {
  devServer: {
    static: {
      directory: path.join(__dirname, 'public')
    },
    compress: true,
    port: 3000
  }
};

Переводы должны находиться в public/locales, чтобы быть доступными через HTTP.


Альтернативный подход: импорт переводов через webpack

Вместо HTTP можно использовать статический импорт:

import enCommon from './locales/en/common.json';
import ruCommon from './locales/ru/common.json';

i18n.init({
  resources: {
    en: {
      common: enCommon
    },
    ru: {
      common: ruCommon
    }
  },
  lng: 'en',
  fallbackLng: 'en'
});

Особенности подхода

  • увеличивает bundle size
  • исключает сетевые запросы
  • подходит для небольших приложений

Динамическая загрузка через webpack chunking

Webpack позволяет разделить переводы на чанки:

const loadLocale = (lng) => {
  return import(
    /* webpackChunkName: "locale-[request]" */
    `./locales/${lng}/common.json`
  );
};

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

i18n.init({
  lng: 'en',
  fallbackLng: 'en',
  resources: {}
});

export const setLanguage = async (lng) => {
  const resources = await loadLocale(lng);

  i18n.addResourceBundle(
    lng,
    'common',
    resources.default || resources
  );

  i18n.changeLanguage(lng);
};

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

  • lazy-loading языков
  • уменьшение initial bundle
  • контроль над кешированием

Интеграция с Vite

Vite использует ES modules и нативную поддержку динамических импортов, что упрощает работу с i18n-ресурсами.

Установка

npm install i18next i18next-http-backend i18next-browser-languagedetector

Базовая конфигурация

import i18n from 'i18next';
import HttpBackend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';

i18n
  .use(HttpBackend)
  .use(LanguageDetector)
  .init({
    fallbackLng: 'en',
    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json'
    },
    ns: ['common'],
    defaultNS: 'common',
    interpolation: {
      escapeValue: false
    }
  });

export default i18n;

Работа с Vite public directory

Vite автоматически обслуживает папку public.

Структура:

/public
  /locales
    /en/common.json
    /ru/common.json

URL загрузки:

/locales/en/common.json

Использование import.meta.glob

Vite предоставляет мощный механизм сборки переводов без HTTP backend.

const modules = import.meta.glob('./locales/*/*.json', {
  eager: true
});

const resources = {};

for (const path in modules) {
  const match = path.match(/\.\/locales\/(.+)\/(.+)\.json/);

  if (match) {
    const lng = match[1];
    const ns = match[2];

    resources[lng] = resources[lng] || {};
    resources[lng][ns] = modules[path];
  }
}

i18n.init({
  resources,
  lng: 'en',
  fallbackLng: 'en'
});

Особенности import.meta.glob

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

Lazy-loading языков в Vite

export const loadLanguage = async (lng) => {
  const modules = import.meta.glob('./locales/*/*.json');

  const entries = Object.entries(modules);

  for (const [path, loader] of entries) {
    if (path.includes(`/${lng}/`)) {
      const mod = await loader();

      const nsMatch = path.match(/\.\/locales\/.+\/(.+)\.json/);
      const ns = nsMatch ? nsMatch[1] : 'common';

      i18n.addResourceBundle(lng, ns, mod.default || mod);
    }
  }

  i18n.changeLanguage(lng);
};

Сравнение подходов webpack и Vite

HTTP backend

  • одинаково работает в webpack и Vite
  • требует размещения файлов в public
  • поддерживает CDN
  • подходит для больших приложений

Static import

  • простота
  • отсутствие асинхронной загрузки
  • увеличенный bundle

Dynamic import (webpack chunks)

  • гибкий code splitting
  • контроль загрузки
  • сложнее конфигурация

import.meta.glob (Vite)

  • оптимальный баланс
  • статический анализ
  • автоматическая агрегация ресурсов
  • минимальная ручная конфигурация

Кеширование и производительность

При использовании HTTP backend важно учитывать:

  • заголовки Cache-Control для JSON
  • версионирование переводов
  • использование CDN

Пример:

/locales/en/common.json?v=1.2.0

Организация namespace при сборке

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

  • common — базовый UI
  • auth — авторизация
  • dashboard — интерфейс панели
  • errors — сообщения ошибок

При сборке это позволяет:

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

Поддержка SSR в сборщиках

При SSR важно:

  • избегать browser-only detection
  • использовать синхронную инициализацию
  • передавать ресурсы на сервер
i18n.init({
  lng: 'en',
  resources,
  initImmediate: false
});

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

  • размещение переводов вне public при HTTP backend
  • отсутствие fallbackLng
  • смешивание статических и динамических ресурсов
  • неправильная конфигурация base path в Vite
  • отсутствие namespace separation