Опции плагина и сервис
Опции плагина
interface I18nPluginOptions {
defaultLocale: string
fallbackLocale?: string
locales: Record<string, LocaleEntry>
persistLocale?: boolean
storageKey?: string
vueI18nOptions?: Record<string, unknown>
}| Опция | Тип | По умолчанию | Описание |
|---|---|---|---|
defaultLocale | string | — | Обязательна. Локаль, загружаемая при старте. |
fallbackLocale | string | — | Локаль, используемая, когда ключ отсутствует в активной локали. Также предзагружается синхронно, чтобы быть доступной сразу. |
locales | Record<string, LocaleEntry> | — | Обязательна. Соответствие кодов локалей объектам сообщений, функциям-загрузчикам или объектам LocaleDefinition. Форматы ниже. |
persistLocale | boolean | false | Сохранять выбранную локаль в localStorage и восстанавливать её при следующем визите. |
storageKey | string | 'vue3-i18n-locale' | Ключ, используемый для localStorage, когда persistLocale равен true. |
vueI18nOptions | object | — | Дополнительные опции, передаваемые напрямую в createI18n из vue-i18n. |
Форматы записи локали
Каждая локаль в карте locales принимает одну из трёх форм. Их можно свободно смешивать в одном конфиге.
1. Простой объект сообщений (синхронный)
locales: {
en: { buttons: { submit: 'Submit' }, greeting: 'Hello, {name}!' },
}Сообщения встраиваются в приложение на этапе сборки и доступны сразу.
2. Асинхронная функция-загрузчик (ленивая)
locales: {
ru: () => import('./locales/ru.json'),
}JSON-файл загружается только при вызове setLocale('ru'). До этого он никак не влияет на размер начального бандла.
3. LocaleDefinition — сообщения + пользовательские метаданные
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.
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: 'Русский' } },
},
})// 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
| Свойство | Тип | Описание |
|---|---|---|
locale | Ref<string> | Текущая активная локаль — тот же экземпляр ref, что и useLocale().locale. |
isLoading | Ref<boolean> | true, пока идёт загрузка файла локали. |
setLocale | (lang: string) => Promise<void> | Переключить локаль. Ленивая загрузка при необходимости. Бросает исключение, если lang не зарегистрирован. |
availableLocales | ComputedRef<LocaleInfo[]> | Все зарегистрированные локали с их метаданными. Один и тот же computed-экземпляр при каждом обращении. |
onLocaleChange | (cb: (lang: string) => void) => () => void | Подписаться на переключения локали. Возвращает функцию отписки. |
onLocaleChange
Подписывайтесь на переключения локали из любого места — полезно для синхронизации внешнего состояния, которое не может управляться реактивностью Vue.
// Обновить <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() компонента Vue | useLocale(), useT(), useAvailableLocales() — реактивные, удобные для шаблонов |
| Route guards, хранилища Pinia, служебные модули | plugin.service — не нужен getCurrentInstance() |
| Точки входа SSR, серверный middleware | plugin.service — внедрите инстанс плагина из вашего файла плагина |
Замечание об SSR
service хранит состояние в замыкании, создаваемом при вызове createVueI18nPlugin. В SSR плагин должен создаваться на каждый запрос, а не на уровне модуля:
// ✅ Правильно — один инстанс плагина на каждый запрос Nuxt
export default defineNuxtPlugin((nuxtApp) => {
const plugin = createVueI18nPlugin({ ... })
nuxtApp.vueApp.use(plugin)
})// ❌ Неправильно — общий для всех SSR-запросов
const plugin = createVueI18nPlugin({ ... }) // уровень модуля
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(plugin) // plugin.service.locale общий — запросы заражают друг друга
})TypeScript
Все публичные типы реэкспортируются для использования в проектах-потребителях:
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:
// types/i18n.ts
export interface AppLocaleMeta {
display: string // человекочитаемое имя локали
flag?: string // эмодзи-флаг, опционально
author?: string // указание переводчика, опционально
}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 бросает описательную ошибку, если запрошенная локаль не зарегистрирована:
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 — доверить это плагину (рекомендуется для большинства проектов):
app.use(createVueI18nPlugin({
defaultLocale: 'en',
locales: { ... },
persistLocale: true,
}))Вариант B — управлять хранилищем самостоятельно:
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.