vue-i18n切换语言时表单校验提示未同步翻译问题
校验提示不跟随语言同步切换的核心原因:初始化rules时直接执行t()方法,将返回的静态字符串赋值给了message字段,该值仅会在组件setup初始化阶段计算一次,后续语言切换时不会自动重新执行t()拉取新文案,因此会一直停留在默认语言。
之前编写的watch逻辑报getters未定义,是因为setup中没有先实例化store就直接访问store.getters,属于变量未定义的基础错误;就算修复该问题,单纯修改i18n.locale也不会让已经写入rules的静态字符串自动更新,无法实现提示同步翻译的效果。
另外注意:vue-i18n 9.x版本默认是legacy(传统Options API)模式,如果要在setup中通过useI18n调用组合式API,需要在初始化时加上legacy: false配置,否则会出现实例调用异常,main.js的i18n配置需要调整为:
import { createI18n } from 'vue-i18n' const app = createApp(App) const i18n = createI18n({ legacy: false, // 开启组合式API支持 locale: 'ee', fallbackLocale: 'ee', messages }) app.use(i18n); app.mount('#app');
方案1:message传函数(推荐,代码量最少无额外监听)
Element Plus表单校验规则原生支持message字段传入函数,每次触发校验时都会重新执行该函数获取最新提示文案,不需要额外编写语言监听逻辑,只要全局i18n.locale切换正常,就能自动拿到对应语言的提示:
import { reactive } from 'vue' import { useI18n } from 'vue-i18n'; export default { setup() { const {t} = useI18n(); const rules = reactive<FormRules>({ name: [ // 不要直接调用t()传静态值,改为传入函数 { required: true, message: () => t('message.name_helper'), trigger: "blur" }, { min: 3, message: () => t('message.name_helper2'), trigger: "blur" }, ] }) return { rules } } }
用这个写法不需要写任何额外的监听逻辑,失焦、提交表单等触发校验的场景都会自动读取当前语言的翻译文案,已经弹出的旧提示会在下一次校验触发时自动更新,覆盖绝大多数业务场景。
方案2:监听语言变化手动更新rules(适合需要即时更新已弹出提示的场景)
如果需要切换语言的瞬间,页面上已经显示的校验提示立刻更新,不需要等下一次校验触发,可以使用该方案,同时修复之前watch的报错问题:
import { reactive, watch, nextTick, ref } from 'vue' import { useI18n } from 'vue-i18n'; // Vuex引入useStore,Pinia则引入对应store的初始化方法 import { useStore } from 'vuex' export default { setup() { const {t, locale} = useI18n(); const store = useStore() // 必须先实例化store,否则访问getters会报未定义 // 提前拿表单ref,用于后续刷新校验状态 const formRef = ref() const rules = reactive<FormRules>({ name: [ { required: true, message: t('message.name_helper'), trigger: "blur" }, { min: 3, message: t('message.name_helper2'), trigger: "blur" }, ] }) watch( () => store.getters.currentLang, async (newLang) => { // 同步全局语言状态 locale.value = newLang // 重新给所有校验规则赋值最新翻译 rules.name[0].message = t('message.name_helper') rules.name[1].message = t('message.name_helper2') // 可选:清空旧校验提示后重新触发校验,实现已弹出提示即时更新 if (formRef.value) { formRef.value.clearValidate() await nextTick() formRef.value.validate().catch(() => {}) } }, { immediate: true } ) return { rules, formRef } } }
优化建议:全局语言切换逻辑最好统一封装在store的action或者全局公共方法中,不需要在每个业务组件里重复写
i18n.locale.value = newLang的逻辑,避免多组件状态不同步。
内容的提问来源于stack exchange,提问作者EagerToSing

