Nuxt & SSR
vue-i18n-kit is SSR-safe. Plugin state is stored per Vue app instance via provide/inject instead of a module-level singleton, so concurrent SSR requests cannot contaminate each other.
localStorage calls (used by persistLocale) are silently no-op on the server — try/catch handles the missing global.
Nuxt setup
ts
// plugins/i18n.ts
import { defineNuxtPlugin } from '#app'
import { createVueI18nPlugin } from 'vue-i18n-kit'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(
createVueI18nPlugin({
defaultLocale: 'en',
fallbackLocale: 'en',
locales: {
en: {
messages: () => import('~/locales/en.json'),
meta: { display: 'English', flag: '🇬🇧' },
},
ru: {
messages: () => import('~/locales/ru.json'),
meta: { display: 'Русский', flag: '🇷🇺' },
},
},
}),
)
})Server-side locale detection
To pick the locale based on the Accept-Language header:
ts
// plugins/i18n.ts
import { defineNuxtPlugin, useRequestHeaders } from '#app'
import { createVueI18nPlugin } from 'vue-i18n-kit'
const SUPPORTED = ['en', 'ru']
export default defineNuxtPlugin((nuxtApp) => {
const headers = useRequestHeaders(['accept-language'])
const accepted = headers['accept-language'] ?? ''
const detected = SUPPORTED.find((code) => accepted.toLowerCase().includes(code))
nuxtApp.vueApp.use(
createVueI18nPlugin({
defaultLocale: detected ?? 'en',
fallbackLocale: 'en',
locales: {
en: () => import('~/locales/en.json'),
ru: () => import('~/locales/ru.json'),
},
}),
)
})Notes
persistLocale— works on the client only; on the server it is silently ignored.- Hydration — the server and client render with the same
defaultLocale. If you usepersistLocale, the client will restore the user's saved locale after hydration. - Vite plugin and CLI — work the same way in Nuxt projects. Add
vueI18nMapPlugintonuxt.config.tsundervite.plugins. plugin.servicein Nuxt — create the plugin insidedefineNuxtPlugin(not at module level) so each SSR request gets its ownserviceinstance.