Skip to content

Опции плагина и сервис

Опции плагина

ts
interface I18nPluginOptions {
  defaultLocale: string
  fallbackLocale?: string
  locales: Record<string, LocaleEntry>
  persistLocale?: boolean
  storageKey?: string
  vueI18nOptions?: Record<string, unknown>
}
ОпцияТипПо умолчаниюОписание
defaultLocalestringОбязательна. Локаль, загружаемая при старте.
fallbackLocalestringЛокаль, используемая, когда ключ отсутствует в активной локали. Также предзагружается синхронно, чтобы быть доступной сразу.
localesRecord<string, LocaleEntry>Обязательна. Соответствие кодов локалей объектам сообщений, функциям-загрузчикам или объектам LocaleDefinition. Форматы ниже.
persistLocalebooleanfalseСохранять выбранную локаль в localStorage и восстанавливать её при следующем визите.
storageKeystring'vue3-i18n-locale'Ключ, используемый для localStorage, когда persistLocale равен true.
vueI18nOptionsobjectДополнительные опции, передаваемые напрямую в createI18n из vue-i18n.

Форматы записи локали

Каждая локаль в карте locales принимает одну из трёх форм. Их можно свободно смешивать в одном конфиге.

1. Простой объект сообщений (синхронный)

ts
locales: {
  en: { buttons: { submit: 'Submit' }, greeting: 'Hello, {name}!' },
}

Сообщения встраиваются в приложение на этапе сборки и доступны сразу.

2. Асинхронная функция-загрузчик (ленивая)

ts
locales: {
  ru: () => import('./locales/ru.json'),
}

JSON-файл загружается только при вызове setLocale('ru'). До этого он никак не влияет на размер начального бандла.

3. LocaleDefinition — сообщения + пользовательские метаданные

ts
locales: {
  en: {
    messages: () => import('./locales/en.json'),
    meta: { display: 'English', flag: '🇬🇧' },
  },
  ru: {
    messages: () => import('./locales/ru.json'),
    meta: { display: 'Русский', flag: '🇷🇺', author: 'Danil Lisin' },
  },
}

meta — произвольный объект, форма которого полностью на усмотрение проекта. Доступен через useLocale().localeMeta и useAvailableLocales().availableLocales[n].meta. Все три формы можно свободно смешивать в одной карте locales.

Сервис плагина

createVueI18nPlugin возвращает объект I18nPlugin — он удовлетворяет интерфейсу Plugin из Vue (поэтому app.use(plugin) работает без изменений) и предоставляет свойство .service, доступное в любом месте приложения, включая места вне setup() компонента Vue.

ts
import { createVueI18nPlugin } from 'vue-i18n-kit'

export const i18nPlugin = createVueI18nPlugin({
  defaultLocale: 'en',
  locales: {
    en: { messages: () => import('./locales/en.json'), meta: { display: 'English' } },
    ru: { messages: () => import('./locales/ru.json'), meta: { display: 'Русский' } },
  },
})
ts
// router/index.ts — вне setup()
import { i18nPlugin } from '@/i18n'

router.beforeEach(async (to) => {
  const lang = to.params.lang as string
  if (lang) await i18nPlugin.service.setLocale(lang)
})

API service

СвойствоТипОписание
localeRef<string>Текущая активная локаль — тот же экземпляр ref, что и useLocale().locale.
isLoadingRef<boolean>true, пока идёт загрузка файла локали.
setLocale(lang: string) => Promise<void>Переключить локаль. Ленивая загрузка при необходимости. Бросает исключение, если lang не зарегистрирован.
availableLocalesComputedRef<LocaleInfo[]>Все зарегистрированные локали с их метаданными. Один и тот же computed-экземпляр при каждом обращении.
onLocaleChange(cb: (lang: string) => void) => () => voidПодписаться на переключения локали. Возвращает функцию отписки.

onLocaleChange

Подписывайтесь на переключения локали из любого места — полезно для синхронизации внешнего состояния, которое не может управляться реактивностью Vue.

ts
// Обновить <html lang> при каждом переключении
i18nPlugin.service.onLocaleChange((lang) => {
  document.documentElement.lang = lang
})

// Отписаться, когда больше не нужно
const unsubscribe = i18nPlugin.service.onLocaleChange((lang) => {
  analytics.track('locale_changed', { lang })
})
unsubscribe()

service против composables — что когда использовать

КонтекстРекомендуемый API
setup() компонента VueuseLocale(), useT(), useAvailableLocales() — реактивные, удобные для шаблонов
Route guards, хранилища Pinia, служебные модулиplugin.service — не нужен getCurrentInstance()
Точки входа SSR, серверный middlewareplugin.service — внедрите инстанс плагина из вашего файла плагина

Замечание об SSR

service хранит состояние в замыкании, создаваемом при вызове createVueI18nPlugin. В SSR плагин должен создаваться на каждый запрос, а не на уровне модуля:

ts
// ✅ Правильно — один инстанс плагина на каждый запрос Nuxt
export default defineNuxtPlugin((nuxtApp) => {
  const plugin = createVueI18nPlugin({ ... })
  nuxtApp.vueApp.use(plugin)
})
ts
// ❌ Неправильно — общий для всех SSR-запросов
const plugin = createVueI18nPlugin({ ... })   // уровень модуля
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(plugin)   // plugin.service.locale общий — запросы заражают друг друга
})

TypeScript

Все публичные типы реэкспортируются для использования в проектах-потребителях:

ts
import type {
  // Плагин
  I18nPluginOptions,
  I18nPlugin, // тип возврата createVueI18nPlugin — Plugin & { service }
  I18nService, // { locale, isLoading, setLocale, availableLocales, onLocaleChange }

  // Типы записи локали
  LocaleMessages, // Record<string, unknown>
  LocaleEntry, // LocaleMessages | LocaleLoader | LocaleDefinition
  LocaleDefinition, // { messages, meta? }
  LocaleInfo, // { code, meta } — возвращается useAvailableLocales

  // Формы возврата composables
  UseLocaleReturn,
  UseTReturn,
  UseAvailableLocalesReturn,
  UseFormatReturn,
  UsePluralizeReturn,

  // Плюрализация
  PluralVars, // Record<string, string | number>
} from 'vue-i18n-kit'

Типизация метаданных локали

Определите общепроектный интерфейс для формы вашего meta и передайте его как generic в оба composables:

ts
// types/i18n.ts
export interface AppLocaleMeta {
  display: string // человекочитаемое имя локали
  flag?: string // эмодзи-флаг, опционально
  author?: string // указание переводчика, опционально
}
ts
import type { AppLocaleMeta } from '@/types/i18n'
import { useLocale, useAvailableLocales } from 'vue-i18n-kit'

const { localeMeta } = useLocale<AppLocaleMeta>()
localeMeta.value?.display // string | undefined  ✓

const { availableLocales } = useAvailableLocales<AppLocaleMeta>()
availableLocales.value[0].meta?.flag // string | undefined  ✓

Обработка ошибок

Неизвестная локаль

setLocale бросает описательную ошибку, если запрошенная локаль не зарегистрирована:

ts
try {
  await setLocale('de')
} catch (err) {
  // [vue-i18n-kit] Locale "de" is not registered. Available locales: en, ru
  console.error(err.message)
}

Неудачный сетевой запрос

Если функция-загрузчик отклоняется, setLocale сбрасывает isLoading в false и повторно бросает исходную ошибку. isLoading.value гарантированно равен false после блока catch.

Плагин не установлен

Вызов любого composable до app.use(createVueI18nPlugin(...)) немедленно бросает исключение:

[vue-i18n-kit] Plugin not installed. Call app.use(createVueI18nPlugin(...)) before using composables.

Сохранение локали

Когда установлено persistLocale: true, выбранная локаль сохраняется в localStorage под настроенным storageKey. При следующей загрузке страницы плагин читает это значение и использует его как начальную локаль, откатываясь на defaultLocale, если сохранённое значение не является зарегистрированным кодом локали.

Вызовы localStorage обёрнуты в try/catch, поэтому плагин работает без проблем в окружениях с ограниченным доступом к хранилищу (приватный режим браузера, некоторые контексты iframe).

persistLocale против ручного localStorage

persistLocale: trueРучной localStorage
НастройкаОдна опция в createVueI18nPluginЧитаете при старте, пишете в onLocaleChange
Восстановление при загрузкеАвтоматическоеВы читаете ключ и передаёте значение как defaultLocale
Хорошо подходит, когдаНужно лишь пережить перезагрузку страницыВы храните дополнительные данные рядом с локалью, используете sessionStorage или делите ключ с другими частями приложения

Вариант A — доверить это плагину (рекомендуется для большинства проектов):

ts
app.use(createVueI18nPlugin({
  defaultLocale: 'en',
  locales: { ... },
  persistLocale: true,
}))

Вариант B — управлять хранилищем самостоятельно:

ts
const saved = localStorage.getItem('my-locale')
const initial = ['en', 'ru'].includes(saved ?? '') ? saved! : 'en'

app.use(i18nPlugin) // persistLocale НЕ установлен

i18nPlugin.service.onLocaleChange((lang) => {
  localStorage.setItem('my-locale', lang)
})

Не комбинируйте оба варианта для одного и того же ключа хранилища. Если установлен persistLocale: true, а вы также вручную вызываете localStorage.setItem, плагин перезапишет ваше значение при следующем setLocale.