切换语言时Pinia Store无法更新i18n翻译的问题求助
问题:Pinia Store 中 i18n 翻译在路由切换时不更新
模板中使用插值语法的翻译正常生效,但从 Pinia Store 获取的翻译内容仅在刷新带语言参数的URL时显示正确,通过router.push切换语言时无法自动更新。
相关代码片段
路由配置
const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', redirect: `/${i18n.global.locale.value}` }, { path: '/:lang', component: { render() { return h(resolveComponent('router-view')) } }, children: [ { path: '/:lang/', name: 'home', component: HomeView }, { path: '/:lang/about', name: 'about', component: AboutView }, { path: '/:lang/services', name: 'services', component: ServicesView }, { path: '/:lang/contacts', name: 'contacts', component: ContactsView }, { path: '/:lang/404', name: '404', component: NotFoundView }, ] }, ] }) router.beforeEach((to, from, next) => { let language = to.params.lang; if (!language) { language = 'en' } i18n.global.locale.value = language next() }) export default router
i18n 插件
import { createI18n } from 'vue-i18n' import en from '../locales/en.json' import fr from '../locales/fr.json' const instance = createI18n({ legacy: false, locale: import.meta.env.VITE_I18N_LOCALE || 'en', fallbackLocale: import.meta.env.VITE_I18N_FALLBACK_LOCALE || 'fr', messages: { en, fr }, fallbackWarn: false, missingWarn: false, globalInjection: true, }) export default instance; export const i18n = instance.global;
i18n Store
import { defineStore } from 'pinia'; import { useI18n } from "vue-i18n"; import { i18n } from '@/plugins/i18n'; export const useI18nStore = defineStore('i18nStore', () => { const t = useI18n({ inheritLocale: true, useScope: 'local', fallbackWarn: false }) const setNewLanguage = (language: string) => { i18n.locale.value = language; console.log(i18n.locale.value , "from store I18n") } return { t, setNewLanguage } })
业务 Store(问题核心)
import { ref} from 'vue' import { defineStore } from 'pinia' import { useI18nStore } from '../stores/i18nStore' interface ServiceOffered{ title: String, imgUrl: String, text: String, cta: String } export const useOfferedServicesStore = defineStore('offeredServices', () => { const translation = useI18nStore(); const { t } = translation.t; const offeredServices = ref<Array<ServiceOffered>>( [ { title: "", imgUrl: "", text: t('offeredServicesCard1'), cta: t('discoverMore') }, { title: "", imgUrl: "", text: t('offeredServicesCard2'), cta: t('discoverMore') }, { title: "", imgUrl: "", text: t('offeredServicesCard3'), cta: t('discoverMore') }, { title: "", imgUrl: "", text: t('offeredServicesCard4'), cta: t('discoverMore') } ] ); return { offeredServices } })
解决方案
1. 修正 i18n Store 的t方法导出
原代码中错误地返回了useI18n()的完整对象,需要直接返回t方法:
import { defineStore } from 'pinia'; import { useI18n } from "vue-i18n"; import { i18n } from '@/plugins/i18n'; export const useI18nStore = defineStore('i18nStore', () => { const { t } = useI18n({ inheritLocale: true, useScope: 'local', fallbackWarn: false }) const setNewLanguage = (language: string) => { i18n.locale.value = language; } return { t, setNewLanguage } // 直接返回t方法,而非包含t的对象 })
2. 让业务 Store 的翻译内容保持响应性
原代码中offeredServices的翻译仅在Store初始化时执行一次,需要用计算属性包裹,让其随语言变化自动重新计算:
import { computed } from 'vue' import { defineStore } from 'pinia' import { useI18nStore } from '../stores/i18nStore' interface ServiceOffered{ title: string, // TypeScript中推荐使用小写string而非String构造函数 imgUrl: string, text: string, cta: string } export const useOfferedServicesStore = defineStore('offeredServices', () => { const translation = useI18nStore(); const { t } = translation; // 现在可以直接解构t方法 // 用computed包裹,语言变化时自动重新生成翻译内容 const offeredServices = computed<Array<ServiceOffered>>(() => [ { title: "", imgUrl: "", text: t('offeredServicesCard1'), cta: t('discoverMore') }, { title: "", imgUrl: "", text: t('offeredServicesCard2'), cta: t('discoverMore') }, { title: "", imgUrl: "", text: t('offeredServicesCard3'), cta: t('discoverMore') }, { title: "", imgUrl: "", text: t('offeredServicesCard4'), cta: t('discoverMore') } ]); return { offeredServices } })
3. 简化路由配置(可选优化)
子路由无需重复父路由的/:lang前缀,使用相对路径即可:
const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', redirect: `/${i18n.global.locale.value}` }, { path: '/:lang', component: { render() { return h(resolveComponent('router-view')) } }, children: [ { path: '', // 对应/:lang/ name: 'home', component: HomeView }, { path: 'about', // 对应/:lang/about name: 'about', component: AboutView }, { path: 'services', // 对应/:lang/services name: 'services', component: ServicesView }, { path: 'contacts', // 对应/:lang/contacts name: 'contacts', component: ContactsView }, { path: '404', // 对应/:lang/404 name: '404', component: NotFoundView }, ] }, ] })
内容的提问来源于stack exchange,提问作者Pietro Ciccarello
相关产品推荐
相关产品推荐

