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

Ленивая загрузка переводов (lazy loading translations) — важная техника при работе с многоязычными приложениями на Vue.js, позволяющая существенно уменьшить первоначальный размер бандла и ускорить старт приложения. Основная идея заключается в том, чтобы загружать языковые файлы только тогда, когда они действительно нужны, а не включать все переводы сразу.


Основы организации переводов

Переводы обычно хранятся в виде отдельных файлов JSON. Для каждого языка создается свой файл, например:

// locales/en.json
{
  "greeting": "Hello",
  "farewell": "Goodbye"
}

// locales/ru.json
{
  "greeting": "Привет",
  "farewell": "До свидания"
}

При традиционном подходе эти файлы импортируются в главный файл i18n при старте приложения:

import { createI18n } from 'vue-i18n';
import en from './locales/en.json';
import ru from './locales/ru.json';

const i18n = createI18n({
  locale: 'en',
  messages: { en, ru },
});

Проблема такого подхода — все языки сразу включаются в бандл, что увеличивает размер загрузки. Для крупных проектов это становится критичным.


Настройка ленивой загрузки

Vue I18n (v9 и выше) поддерживает динамический импорт сообщений. Основной механизм выглядит так:

import { createI18n } from 'vue-i18n';

const i18n = createI18n({
  legacy: false,
  locale: 'en',
  messages: {} // изначально пустой объект
});

async function loadLocaleMessages(locale) {
  if (!i18n.global.availableLocales.includes(locale)) {
    const messages = await import(`./locales/${locale}.json`);
    i18n.global.setLocaleMessage(locale, messages.default);
  }
  i18n.global.locale.value = locale;
}
  • import() — динамический импорт, который Webpack или Vite преобразует в отдельный чанк.
  • i18n.global.setLocaleMessage() — добавляет загруженные сообщения в i18n.
  • i18n.global.locale.value — переключает текущий язык.

Интеграция с роутером

Часто перевод загружается при смене маршрута, если разные маршруты требуют разные локали:

import router from './router';
import i18n from './i18n';

router.beforeEach(async (to, from, next) => {
  const locale = to.params.lang || 'en';
  await loadLocaleMessages(locale);
  next();
});
  • to.params.lang — параметр языка из URL, например /ru/home.
  • Такой подход позволяет не загружать язык, пока пользователь не перейдет на соответствующую страницу.

Кэширование загруженных сообщений

Чтобы избежать повторной загрузки одного и того же языка, стоит проверять наличие локали в availableLocales:

if (!i18n.global.availableLocales.includes(locale)) {
  const messages = await import(`./locales/${locale}.json`);
  i18n.global.setLocaleMessage(locale, messages.default);
}

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


Оптимизация под большие проекты

  1. Разделение файлов по модулям: Вместо одного большого JSON-файла на язык можно создать несколько файлов для разных разделов приложения:
locales/
 ├─ en/
 │   ├─ common.json
 │   ├─ dashboard.json
 │   └─ profile.json
 └─ ru/
     ├─ common.json
     ├─ dashboard.json
     └─ profile.json

Загрузка модуля при необходимости:

async function loadModuleLocale(locale, module) {
  const messages = await import(`./locales/${locale}/${module}.json`);
  i18n.global.mergeLocaleMessage(locale, messages.default);
}
  • mergeLocaleMessage() объединяет новые сообщения с уже существующими.
  1. Предзагрузка при определенных событиях: Иногда полезно загружать язык заранее, например, при наведении на кнопку смены языка, чтобы ускорить реакцию интерфейса.

  2. Совмещение с кешированием в localStorage: Можно сохранять уже загруженные переводы в localStorage, чтобы при повторном визите не делать дополнительный запрос.


Практические нюансы

  • Динамический импорт зависит от сборщика. В Webpack нужно убедиться, что путь к файлу статический или соответствует шаблону, иначе сборка может не создать отдельный чанк.
  • В некоторых случаях важно учитывать fallback-язык: если перевод не найден, отобразить значение по умолчанию или английскую версию.
  • Для TypeScript рекомендуется создавать типы для сообщений, чтобы избежать ошибок при обращении к ключам перевода.

Преимущества ленивой загрузки переводов

  • Снижение первоначального размера бандла: язык загружается только при необходимости.
  • Ускорение старта приложения: меньше данных передается при первой загрузке.
  • Гибкая организация переводов: возможность делить языки на модули.
  • Поддержка динамического переключения языков: переключение происходит без перезагрузки страницы.

Ленивая загрузка переводов является стандартной практикой для крупных Vue.js приложений и существенно повышает производительность и удобство поддержки многоязычности.