When Nuxt i18n module is loaded in your app, it adds your locales
configuration to nuxtApp.$i18n
(or this.$i18n
), which makes it really easy to display a lang switcher anywhere in your app.
Here's an example of a lang switcher where a name
key has been added to each locale object in order to display friendlier titles for each link:
<script setup>
const { locale, locales } = useI18n()
const switchLocalePath = useSwitchLocalePath()
const availableLocales = computed(() => {
return locales.value.filter(i => i.code !== locale.value)
})
</script>
<template>
<NuxtLink v-for="locale in availableLocales" :key="locale.code" :to="switchLocalePath(locale.code)">
{{ locale.name }}
</NuxtLink>
</template>
export default defineNuxtConfig({
i18n: {
locales: [
{
code: 'en',
name: 'English'
},
{
code: 'es',
name: 'Español'
},
{
code: 'fr',
name: 'Français'
}
]
}
})
detectBrowserLanguage
, you must explicitly update the stored locale cookie. This is done with setLocaleCookie(locale)
or setLocale(locale)
, which sets the cookie and switches to the route of the specified locale. Not doing so can cause redirects based on the locale set on the locale cookie during navigation.The template code might look like this, for example:
<script setup>
const { locale, locales, setLocale } = useI18n()
const availableLocales = computed(() => {
return locales.value.filter(i => i.code !== locale.value)
})
</script>
<template>
...
<a href="#" v-for="locale in availableLocales" :key="locale.code" @click.prevent.stop="setLocale(locale.code)">
{{ locale.name }}
</a>
...
</template>
By default, the locale will be changed right away when navigating to a route with a different locale which means that if you have a page transition, it will fade out the page with the text already switched to the new language and fade back in with the same content.
To work around the issue, you can set the option skipSettingLocaleOnNavigate
to true
and handle setting the locale yourself from a onBeforeEnter
transition hook defined in a plugin.
If you would like to transition the entire Nuxt app, you can use the transition
of NuxtPage
to control it as follows:
export default defineNuxtConfig({
i18n: {
// ... your other options
skipSettingLocaleOnNavigate: true
}
}
<script setup lang="ts">
const { finalizePendingLocaleChange } = useI18n()
const onBeforeEnter = async () => {
await finalizePendingLocaleChange()
}
</script>
<template>
<NuxtLayout>
<NuxtPage
:transition="{
name: 'my',
mode: 'out-in',
onBeforeEnter
}"
/>
</NuxtLayout>
</template>
<style>
.my-enter-active,
.my-leave-active {
transition: opacity 0.3s;
}
.my-enter,
.my-leave-active {
opacity: 0;
}
</style>
Optional, wait for locale before scrolling for a smoother transition with Router Options:
import type { RouterConfig } from '@nuxt/schema'
export default <RouterConfig>{
async scrollBehavior(to, from, savedPosition) {
const nuxtApp = useNuxtApp()
// make sure the route has changed.
if (nuxtApp.$i18n && to.name !== from.name) {
// `$i18n` is injected in the `setup` of the nuxtjs/i18n module.
// `scrollBehavior` is guarded against being called even when it is not completed
await nuxtApp.$i18n.waitForPendingLocaleChange()
}
return savedPosition || { top: 0 }
}
}
If you have a specific transition defined in a page component with definePageMeta()
and need to add finalizePendingLocaleChange
at onBeforeEnter
hook for pageTransition
.
Example:
<script setup lang="ts">
const route = useRoute()
const { finalizePendingLocaleChange } = useI18n()
definePageMeta({
pageTransition: {
name: 'page',
mode: 'out-in'
}
})
route.meta.pageTransition.onBeforeEnter = async () => {
await finalizePendingLocaleChange()
}
</script>
<style scoped>
.page-enter-active,
.page-leave-active {
transition: opacity 1s;
}
.page-enter,
.page-leave-active {
opacity: 0;
}
</style>
In contrast to Vue i18n you should not directly set locale
, switch language by using setLocale()
or navigating to a route returned by switchLocalePath()
. This loads translations, triggers hooks and updates the locale cookie if used.