Skip to content

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 use persistLocale, the client will restore the user's saved locale after hydration.
  • Vite plugin and CLI — work the same way in Nuxt projects. Add vueI18nMapPlugin to nuxt.config.ts under vite.plugins.
  • plugin.service in Nuxt — create the plugin inside defineNuxtPlugin (not at module level) so each SSR request gets its own service instance.