Yii多语言切换必须在应用初始化早期设置language,否则组件已按默认语言初始化;需在web/index.php中new Application后、run()前赋值,或在bootstrap阶段处理URL前缀;Url::to()不自动补语言段,须显式传lang参数并清缓存。

Yii 多语言切换不是改个 language 配置就能生效的事——它必须在应用初始化早期就定下来,否则视图、验证器、日期格式器等组件已经按默认语言初始化完毕,再改也白搭。
Yii::$app->language 必须在 Application::init() 前设置
常见错误是把语言赋值写在 Controller::beforeAction() 或 actionLanguage() 里。这时 Yii::t() 已经查过缓存、Formatter 已经按旧语言加载 ICU 数据,界面不会变,数字/日期格式也不对。
- 最稳妥的位置是入口文件
web/index.php,在new yii\web\Application($config)实例化后、->run()前立即赋值 - 或者在
bootstrap阶段(如自定义 Bootstrap 类)中,从Yii::$app->request->getPathInfo()提取首段语言码(如/zh-CN/site/index中的zh-CN),验证后再设 - 别依赖
$_GET['lang']:开启美化 URL 后该参数为空;也别在UrlRule子类里改language,规则匹配发生在语言初始化之后
URL 路由带语言前缀时,Url::to() 不会自动补 lang 段
默认 Url::to(['site/about']) 只按路由规则拼接,完全不感知当前语言上下文。结果就是点击链接后跳回默认语言页,用户刚切的 ja-JP 瞬间变 en-US。
- 所有内部跳转必须显式传参:
Url::to(['site/about', 'lang' => Yii::$app->language]) - 如果项目大量使用
Url::to(),建议封装一个LangUrl::to()工具方法,默认合并当前Yii::$app->language - 切换语言链接要防嵌套:比如从
/zh-CN/site/index切到英文,目标地址应是/en-US/site/index,不是/en-US/zh-CN/site/index;需先用explode('/', $path)剥离首段语言前缀再拼新前缀
翻译文件路径和命名必须严格匹配 PhpMessageSource 规则
Yii::t('app', 'Home') 能否找到翻译,取决于 sourceLanguage、basePath、目录结构、文件名、数组键三者是否完全对齐。错一个就静默失败,不报错也不显示翻译。
-
basePath必须指向真实存在的可读目录,例如@app/messages→ 对应./messages/ - 语言子目录名必须是标准语言代码,如
zh-CN、en-US,不能写成zh_cn或zh - 分类名(
app)对应文件名(app.php),且文件内必须是return ['Home' => '首页'];形式;键名大小写敏感,'home'≠'Home' - 若用通配符规则
'*',确保fileMap显式声明了每个 category 的映射,否则PhpMessageSource找不到文件就返回原文
动态切换语言后,必须同步持久化并清 runtime 缓存
只改 Yii::$app->language 是临时的,刷新页面就回退。而且 PhpMessageSource 默认缓存翻译结果,改了语言但没清缓存,还是显示旧语言内容。
- 语言值建议存入 session:
Yii::$app->session['language'] = $lang;,并在入口处读取 - 切换完成后调用
Yii::$app->i18n->translator->flush();清空翻译缓存(或直接删runtime/messages/下对应语言目录) - 注意
sourceLanguage应固定为en-US(或其他你代码里写的原始语言),不要随用户语言动态改,否则Yii::t()匹配逻辑会混乱
真正卡住人的从来不是“怎么写翻译文件”,而是语言设置时机、URL 生成逻辑、缓存清理这三处细节——它们不报错,但让整个多语言链路半途失效。



















