如何在Nuxt 3中配置异步i18n?客户端翻译丢失问题
Nuxt 3 异步i18n客户端翻译丢失问题解决
问题背景
需要实现Nuxt 3异步i18n配置:从API获取可用语言→通过路由前缀/Cookie检测当前语言并加载对应翻译→监听onBeforeLanguageSwitch事件按需加载新语言翻译。当前遇到的问题是:服务端渲染正常,HTML中可见翻译内容,但客户端侧i18n会重新初始化,导致翻译数据丢失。
现有代码
nuxt.config.ts
i18n: { locales: ['en', 'ru', 'es', 'de', 'fi', 'sv', 'fr', 'it', 'br'], defaultLocale: 'en', strategy: 'prefix', detectBrowserLanguage: { useCookie: true, cookieKey: 'i18n_redirected', redirectOn: 'root', }, },
plugins/i18n.ts
export default defineNuxtPlugin(nuxtApp => { useAsyncData('directory_translations', async () => { const data = await DirectoryApi.getAllDirectories() const directory = DirectoryService.createDirectoryObject(data) const translationsData = await DirectoryApi.getTranslations(directory.languages[nuxtApp.$i18n.locale.value].ID) const translations = DirectoryService.createTranslationsObject(translationsData, directory) nuxtApp.$i18n.mergeLocaleMessage(nuxtApp.$i18n.locale.value, translations) useState('directory', () => directory) useState('translations', () => translations) }) nuxtApp.$i18n.onBeforeLanguageSwitch = async (oldLocale, newLocale, isInitialSetup, nuxtApp) => { const directory = useState('directory') as Ref<Directory> const translationsData = await DirectoryApi.getTranslations(directory.value.languages[newLocale].ID) const translations = DirectoryService.createTranslationsObject(translationsData, directory.value) nuxtApp.$i18n.mergeLocaleMessage(newLocale, translations) } })
测试组件
<script lang="ts" setup> const {messages} = useI18n() </script> <template> <div> {{ JSON.stringify(messages) }} </div> </template>
解决方案
问题根源
服务端通过mergeLocaleMessage添加的翻译数据,没有被序列化传递到客户端;客户端hydration时i18n重新初始化,messages恢复为空,且未从服务端传递的状态中恢复翻译数据。同时原配置硬编码了locales,不符合“从API获取可用语言”的需求。
修正步骤
1. 调整nuxt.config.ts配置
移除硬编码的locales,改为后续在插件中动态设置:
// nuxt.config.ts i18n: { defaultLocale: 'en', strategy: 'prefix', detectBrowserLanguage: { useCookie: true, cookieKey: 'i18n_redirected', redirectOn: 'root', }, locales: [] // 留空,后续动态配置 },
2. 重写plugins/i18n.ts逻辑
确保服务端获取的翻译数据能在客户端复用,同时动态设置可用语言:
// plugins/i18n.ts export default defineNuxtPlugin(async (nuxtApp) => { // 1. 获取可用语言列表并动态配置i18n locales const { data: directory } = await useAsyncData('directory', async () => { const data = await DirectoryApi.getAllDirectories() return DirectoryService.createDirectoryObject(data) }) if (directory.value) { nuxtApp.$i18n.locales = Object.keys(directory.value.languages).map(lang => ({ code: lang, name: lang // 可根据API返回替换为语言名称 })) } // 2. 获取当前语言翻译,客户端复用服务端数据 const currentLocale = nuxtApp.$i18n.locale.value const { data: translations } = await useAsyncData(`translations_${currentLocale}`, async () => { if (!directory.value) return {} const translationsData = await DirectoryApi.getTranslations(directory.value.languages[currentLocale].ID) return DirectoryService.createTranslationsObject(translationsData, directory.value) }) // 服务端/客户端都执行merge,保证翻译数据不丢失 if (translations.value) { nuxtApp.$i18n.mergeLocaleMessage(currentLocale, translations.value) } // 3. 语言切换时按需加载翻译,避免重复请求 nuxtApp.$i18n.onBeforeLanguageSwitch = async (oldLocale, newLocale) => { if (!directory.value) return // 检查目标语言翻译是否已加载 if (!nuxtApp.$i18n.messages[newLocale]) { const translationsData = await DirectoryApi.getTranslations(directory.value.languages[newLocale].ID) const newTranslations = DirectoryService.createTranslationsObject(translationsData, directory.value) nuxtApp.$i18n.mergeLocaleMessage(newLocale, newTranslations) } } })
3. 组件使用说明
组件无需修改,直接使用useI18n提供的t函数或messages即可:
<script lang="ts" setup> const { t, messages } = useI18n() </script> <template> <div> {{ t('your.translation.key') }} <!-- 调试用:{{ JSON.stringify(messages) }} --> </div> </template>
核心优化点
- 用
useAsyncData存储目录和翻译数据,Nuxt自动序列化并传递到客户端,避免重复API请求 - 动态设置
nuxtApp.$i18n.locales,满足从API获取可用语言的需求 - 语言切换前检查翻译是否已存在,避免重复请求
- 服务端和客户端都执行
mergeLocaleMessage,确保客户端hydration后翻译数据正常
内容的提问来源于stack exchange,提问作者frezzzen
相关产品推荐
相关产品推荐

