N
Nuxt5d ago
Piskr

Nuxt-i18n language switcher

So I'm trying to setup localization for my app. Now I've used the provided setup from the docs and managed to get it working for one language. When I try to switch the language, I get a lot of warnings for missing keys in my locale messages. Which is very strange as both of the language JSONs are exactly the same. So for a test I changed the config to use the other language as default and it works, but when switching the result is the same. So this is how I setup in my nuxt.config:
i18n: {
lazy: false,
defaultLocale: 'en',
locales: [
{ code: 'en', name: 'English', file: 'en.json' },
{ code: 'sl', name: 'Slovenian', file: 'sl.json' }
]
},
i18n: {
lazy: false,
defaultLocale: 'en',
locales: [
{ code: 'en', name: 'English', file: 'en.json' },
{ code: 'sl', name: 'Slovenian', file: 'sl.json' }
]
},
In my root folder I've created a new folder(s) i18n/locales/ with 2 json files, en.json and sl.json. When I try to switch with:
async function changeLanguage(langCode: 'en' | 'sl') {
const to = switchLocalePath(langCode)

sidebarStore.setLanguage(langCode)

locale.value = langCode

await refreshData()

//const path = switchLocalePath(langCode)
if (to) {
await router.push(to)
}

// 4. close the menu
showLanguageDropdown.value = false

}
async function changeLanguage(langCode: 'en' | 'sl') {
const to = switchLocalePath(langCode)

sidebarStore.setLanguage(langCode)

locale.value = langCode

await refreshData()

//const path = switchLocalePath(langCode)
if (to) {
await router.push(to)
}

// 4. close the menu
showLanguageDropdown.value = false

}
It loads, but it doesn't find any keys. Then I do a direct URL with the updated language path it does load the correct translations. When using:
<NuxtLink :to="switchLocalePath('en')">EN</NuxtLink>
<NuxtLink :to="switchLocalePath('sl')">SLO</NuxtLink>
<NuxtLink :to="switchLocalePath('en')">EN</NuxtLink>
<NuxtLink :to="switchLocalePath('sl')">SLO</NuxtLink>
It does switch, but because there is no call for refreshData(), so the data is not translated. So my question is how to correctly switch between translations?
3 Replies
kapa.ai
kapa.ai5d ago
Hi @Piskr. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- It looks like your Nuxt i18n configuration and language files are set up correctly, but you’re experiencing issues where switching languages via your custom function results in missing translation keys, while direct URL navigation works as expected. Based on the knowledge sources, here are some key points and suggestions: 1. File-based Lazy Loading:
If you specify a file property for each locale, you must also set lazy: true and provide the langDir option pointing to your locales directory. Otherwise, Nuxt i18n will not know where to load the language files from. Your current config has lazy: false, which means it expects all translations to be inlined, not loaded from files.
Example:
i18n: {
lazy: true,
langDir: 'i18n/locales/',
defaultLocale: 'en',
locales: [
{ code: 'en', name: 'English', file: 'en.json' },
{ code: 'sl', name: 'Slovenian', file: 'sl.json' }
]
}

i18n: {
lazy: true,
langDir: 'i18n/locales/',
defaultLocale: 'en',
locales: [
{ code: 'en', name: 'English', file: 'en.json' },
{ code: 'sl', name: 'Slovenian', file: 'sl.json' }
]
}

See related discussion 2. Switching Locale and Data Refresh:
When you use switchLocalePath and navigate, Nuxt i18n will handle the locale change and load the correct translations. However, if you manually set locale.value = langCode and call refreshData(), you might be changing the locale before the route actually updates, leading to a mismatch in loaded translations.
The recommended way is to use NuxtLink or programmatic navigation with the path from switchLocalePath, and let Nuxt i18n handle the rest. If you need to refresh data after the locale changes, you should do so in a watcher or after navigation is complete. 3. Direct Navigation Works:
This suggests your translation files and routing are correct, but the manual locale switch is not triggering the correct reactivity or file loading. 4. Summary of Correct Approach:
- Use lazy: true and langDir if you use external JSON files. - Use NuxtLink or router.push(switchLocalePath(langCode)) to switch languages. - If you need to refresh data, do it after navigation is complete, possibly by watching the locale or route. Example config:
export default defineNuxtConfig({
i18n: {
lazy: true,
langDir: 'i18n/locales/',
defaultLocale: 'en',
locales: [
{ code: 'en', name: 'English', file: 'en.json' },
{ code: 'sl', name: 'Slovenian', file: 'sl.json' }
]
}
})
export default defineNuxtConfig({
i18n: {
lazy: true,
langDir: 'i18n/locales/',
defaultLocale: 'en',
locales: [
{ code: 'en', name: 'English', file: 'en.json' },
{ code: 'sl', name: 'Slovenian', file: 'sl.json' }
]
}
})
Example switcher:
<NuxtLink :to="switchLocalePath('en')">EN</NuxtLink>
<NuxtLink :to="switchLocalePath('sl')">SLO</NuxtLink>
<NuxtLink :to="switchLocalePath('en')">EN</NuxtLink>
<NuxtLink :to="switchLocalePath('sl')">SLO</NuxtLink>
If you need to refresh data, watch the locale:
watch(locale, async () => {
await refreshData()
})
watch(locale, async () => {
await refreshData()
})
This approach ensures translations are loaded and data is refreshed after the language actually changes. If you follow these steps and still encounter issues, double-check your file paths and ensure your JSON files are valid and accessible. If you need more advanced control, refer to the official Nuxt i18n documentation.
The knowledge sources do not provide a direct example of your exact use case, but the above advice is based on similar issues and recommended practices found in the sources, especially regarding lazy loading and file-based locales Stack Overflow Post.
---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai5d ago
<@214445863982858240> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
WiFi Plug
WiFi Plug5d ago
I'm kinda new to this too, but I get it working a few days ago so I can share my files and you can test it out. Firstly I assume you want to persist language changes in which case you need to enable cookies in your i18n setup so it persists through a refresh
i18n: {
// Module Options
strategy: 'no_prefix', // URL prefix will not be used
locales: [
{
code: 'en',
iso: 'en-US',
name: 'English',
file: 'en.json',
},
{
code: 'fr',
iso: 'fr-FR',
name: 'Français',
file: 'fr.json',
},
{
code: 'es',
iso: 'es-ES',
name: 'Español',
file: 'es.json',
},
{
code: 'pl',
name: 'Polski',
file: 'pl.json',
},
// Add other languages Nuxt UI Pro supports or you need
],
defaultLocale: 'en', // Default locale if no preference or cookie
lazy: true, // Load translations on demand
langDir: 'locales', // Directory for translation files

// Browser language detection
detectBrowserLanguage: {
useCookie: true, // Crucial: This tells i18n to use a cookie
cookieKey: 'i18n_redirected', // Default cookie name, you can change it
alwaysRedirect: false, // Don't redirect if a cookie is already set (important for no_prefix)
redirectOn: 'root', // Detect on first visit to the root path
fallbackLocale: 'en', // Fallback if detected browser lang isn't available
},
},
i18n: {
// Module Options
strategy: 'no_prefix', // URL prefix will not be used
locales: [
{
code: 'en',
iso: 'en-US',
name: 'English',
file: 'en.json',
},
{
code: 'fr',
iso: 'fr-FR',
name: 'Français',
file: 'fr.json',
},
{
code: 'es',
iso: 'es-ES',
name: 'Español',
file: 'es.json',
},
{
code: 'pl',
name: 'Polski',
file: 'pl.json',
},
// Add other languages Nuxt UI Pro supports or you need
],
defaultLocale: 'en', // Default locale if no preference or cookie
lazy: true, // Load translations on demand
langDir: 'locales', // Directory for translation files

// Browser language detection
detectBrowserLanguage: {
useCookie: true, // Crucial: This tells i18n to use a cookie
cookieKey: 'i18n_redirected', // Default cookie name, you can change it
alwaysRedirect: false, // Don't redirect if a cookie is already set (important for no_prefix)
redirectOn: 'root', // Detect on first visit to the root path
fallbackLocale: 'en', // Fallback if detected browser lang isn't available
},
},
this is my nuxt.config.ts, in my case I didn't want the locale in the url but if you do you just switch the strategy then in my app.vue i have this
// i18n language stuff
import * as locales from '@nuxt/ui-pro/locale'

const { locale } = useI18n()

const lang = computed(() => locales[locale.value].code)
const dir = computed(() => locales[locale.value].dir)

useHead({
htmlAttrs: {
lang,
dir,
},
})
// i18n language stuff
import * as locales from '@nuxt/ui-pro/locale'

const { locale } = useI18n()

const lang = computed(() => locales[locale.value].code)
const dir = computed(() => locales[locale.value].dir)

useHead({
htmlAttrs: {
lang,
dir,
},
})
in my script tag which sets my html header with the language as you change languages, aswell as setting the locale in uapp
<UApp
:toaster="{ position: 'bottom-left', expand: true, duration: 5000 }"
:locale="locales[locale]"
>
<UApp
:toaster="{ position: 'bottom-left', expand: true, duration: 5000 }"
:locale="locales[locale]"
>
<script setup lang="ts">
// Use useI18n to get current locale, available locales, and the setLocale function
const { locale, setLocale: i18nSetLocale, locales: i18nConfiguredLocales } = useI18n()

// This computed property will be bound to ULocaleSelect's v-model
// When ULocaleSelect changes the value, the `set` part of this computed will run.
const selectedLocale = computed({
get: () => locale.value, // Current locale
set: async (newLocaleCode: string) => {
if (newLocaleCode !== locale.value) {
await i18nSetLocale(newLocaleCode)
// @nuxtjs/i18n's setLocale function, when useCookie is true,
// will handle updating the cookie.
}
},
})

// The locales to display in the ULocaleSelect dropdown.
// These come directly from your @nuxtjs/i18n configuration in nuxt.config.ts.
const displayLocales = computed(() => {
return i18nConfiguredLocales.value as Array<{ code: string; name: string; [key: string]: any }>
})
</script>

<template>
<ULocaleSelect v-model="selectedLocale" :locales="displayLocales" />
</template>
<script setup lang="ts">
// Use useI18n to get current locale, available locales, and the setLocale function
const { locale, setLocale: i18nSetLocale, locales: i18nConfiguredLocales } = useI18n()

// This computed property will be bound to ULocaleSelect's v-model
// When ULocaleSelect changes the value, the `set` part of this computed will run.
const selectedLocale = computed({
get: () => locale.value, // Current locale
set: async (newLocaleCode: string) => {
if (newLocaleCode !== locale.value) {
await i18nSetLocale(newLocaleCode)
// @nuxtjs/i18n's setLocale function, when useCookie is true,
// will handle updating the cookie.
}
},
})

// The locales to display in the ULocaleSelect dropdown.
// These come directly from your @nuxtjs/i18n configuration in nuxt.config.ts.
const displayLocales = computed(() => {
return i18nConfiguredLocales.value as Array<{ code: string; name: string; [key: string]: any }>
})
</script>

<template>
<ULocaleSelect v-model="selectedLocale" :locales="displayLocales" />
</template>
granted im also using nuxt-ui-pro language switcher in my setup but it should be similar. that's my language switcher component so on page load it grabs the users browsers default locale, unless they're manually switches languages in which case it will update my pages text to that language and update the cookie to persist the new language on page reloads then in my
i18n\locales\en.json
i18n\locales\en.json
etc i have
{
"auth": {
"signIn": "Sign in",
"signUp": "Sign up"
},
"navigation": {
"home": "Home",
"profile": "Profile"
}
}
{
"auth": {
"signIn": "Sign in",
"signUp": "Sign up"
},
"navigation": {
"home": "Home",
"profile": "Profile"
}
}
and then for example in my sign up button to display the translated text i have this
<UButton
:label="$t('auth.signUp')"
trailing-icon="i-heroicons-arrow-right-20-solid"
/>
<UButton
:label="$t('auth.signUp')"
trailing-icon="i-heroicons-arrow-right-20-solid"
/>
so i can change language and the text updates immediately throughout But yeah i think i remember something potentially about missing keys or at least the text didn't update immediately until i refreshed my page but with this setup it works great. probably just missing the cookie which i believe when updated will refresh your text translations so you don't get missing keys warning I'm not using a pinia store for this either btw, didn't see a reason since the cookie persists their language nicely you might not need the UApp locale part maybe that's only a nuxt ui pro thing and you can replace the localeselector with your diy one there's an example in their docs also if their browser default language is set to one you don't have configured in your nuxt config it won't set the cookie to it it defaults to your fallback

Did you find this page helpful?