React 多页面 i18n 语言切换失效问题排查
现象
后台管理系统切到英文后,大部分页面正常刷新,但镜像仓库、系统设置、开放 API 管理、版本管理这几个页面的界面文字没有任何变化,刷新页面也没用。
排查过程
先确认语言状态本身没问题:localStorage 里的值确实被改掉了,其他页面也能读到新值。问题范围锁定在这几个页面之后,差异点找到了——这几个页面是后来按菜单拆分的独立入口,各自 import 了 i18n 配置并单独初始化。也就是说,项目里同时存在多个 i18n 实例,语言切换只改到了其中一个,其他页面的实例浑然不觉。
修复方案
- i18n 单例化:整个项目只初始化一次,各页面只消费实例。
- 语言变化时通过统一的状态通知各页面重渲染,而不是让每个页面自己监听。
- 切换语言同步写入 localStorage,刷新后保持选择。
// src/i18n.ts 单例模块
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import resources from './locales';
if (!i18n.isInitialized) {
i18n.use(initReactI18next).init({
resources,
lng: localStorage.getItem('lang') || 'zh-CN',
fallbackLng: 'zh-CN',
interpolation: { escapeValue: false },
});
}
export default i18n;
各页面入口统一改为 import './i18n',不再各自 init。改造完这四个页面全部恢复正常。
延伸
这类问题的本质是「实例分裂」。页面按模块拆分之后,任何全局单例——i18n、请求实例、主题上下文——都要确认全项目只有一份。后续我们加了 lint 规则,禁止在页面级代码里调用 i18n.init()。
多页面应用里,全局状态的生命周期应该跟应用一致,而不是跟某个页面一致。