根本原因是uni.setlocale不触发vue响应式更新,且app端不支持该api;需用computed或全局状态管理监听语言变化并重算$t,动态加载语言包时注意路径、格式和时机。

uni-app 里用 $t 切语言但页面没更新?
根本原因不是 $t 写错了,而是 Vue 响应式系统没监听到语言变更——uni.setLocale 只改了底层 locale,没触发组件重新渲染。
实操上必须让组件“感知”语言变化,常见做法是把语言 key 挂在 data 或 computed 里,再用 watch 监听 uni.getLocale() 或自定义的全局语言状态:
- 别直接在模板里写
{{ $t('home.title') }}就完事,要包一层响应式 wrapper,比如{{ langText.home.title }} - 推荐用
computed返回翻译对象,每次语言切换后主动触发重算:computed: { langText() { return this.$t('') } } - 如果用了 Vuex/Pinia,确保语言 state 是响应式的,且组件依赖该 state(不能只靠
$t函数调用)
uni.setLocale 不生效或报错 not support
这个 API 在 H5 和微信小程序可用,但 App 端(iOS/Android)不支持,调用会静默失败或抛出错误;而且它只影响原生侧的系统级文案(如日期格式、数字分隔符),不影响你写的 $t 字符串。
真正控制多语言内容的,是你自己维护的语言包 + vue-i18n 或 @dcloudio/uni-i18n 的实例:
- App 端必须手动切换 i18n 实例的
locale属性,例如:i18n.locale = 'zh-CN' - 切换后记得调用
uni.reLaunch或uni.redirectTo是无效的——这会导致页面重启,违背“不刷新”要求 - 检查是否误把
uni.setLocale当成 i18n 切换入口,它和$t完全不在一个层级
用 @dcloudio/uni-i18n 动态加载语言包时白屏或报错
动态 import 语言文件(比如按需加载 zh.json)容易因路径、导出格式或 Promise 状态导致组件初始化失败,表现为页面空白或 Cannot read property 'message' of undefined。
关键点在于:语言包必须默认导出一个纯对象,且 key 结构要和 $t 调用路径严格匹配:
- 路径必须带扩展名,
import('./locales/zh.json')✅,import('./locales/zh')❌(H5 下可能报 404) - JSON 文件不能有 BOM,也不能含注释,否则某些平台解析失败
- 加载完成前,
$t会返回空字符串或 key 本身,建议加 loading 状态或 fallback 文案 - 不要在
beforeCreate里 await 动态 import,会阻塞实例创建;改用onLoad+nextTick触发更新
切换语言后 input placeholder、button text 还是旧的?
因为这些属性值不会自动响应 $t,Vue 模板里写 :placeholder="$t('input.hint')" 才会更新;直接写 placeholder="{{ $t('input.hint') }}" 是静态值,只在初始化时求值一次。
类似问题还出现在 uni.showToast、uni.showModal 等 API 的文案参数里:
- 所有运行时传入的文案,必须显式调用
$t,不能依赖模板编译时替换 - 组件 props 如果接收的是字符串而非响应式引用,切换语言后也不会变,需要
v-bind绑定 - 第三方 UI 库(如 uView、uCharts)的内置文案通常不走你的 i18n 实例,得查文档看是否支持 locale 配置项
最常被忽略的一点:语言切换逻辑如果放在某个页面的 methods 里,但其他页面没订阅变更,就会出现“部分页面更新、部分卡住”的情况。全局状态管理不是可选项,是必须项。










