thinkphp多语言需同时满足配置开启、目录结构正确、命名规范、加载时机合适四条件,常见错误是路径或大小写不匹配导致lang()返回key;config/app.php须设lang_switch_on、default_lang、lang_list三项,语言包须置于lang/zh-cn/common.php等规范路径。

ThinkPHP 多语言功能不是“开个开关就自动生效”,必须同时满足配置开启、目录结构正确、语言包命名规范、加载时机合适这四个条件,缺一不可。最常踩的坑是语言包放错位置或文件名大小写不匹配,导致 lang('xxx') 始终返回空字符串或原始 key。
app.php 里怎么配多语言开关和默认语言
在 config/app.php 中必须显式设置以下三项,少一个都会失效:
-
'lang_switch_on' => true:这是硬性开关,不设为true,整个多语言机制不会启动 -
'default_lang' => 'zh-cn':指定初始语言,注意必须是小写短横线格式,zh_CN或ZH-CN都无效 -
'lang_list' => ['zh-cn', 'en-us']:明确列出允许切换的语言代码,用数组而非逗号分隔字符串(ThinkPHP 6+ 要求)
旧版 ThinkPHP 5.x 支持 'LANG_LIST' => 'zh-cn,en-us' 字符串写法,但 6.x 已废弃,写成字符串会导致 Lang::detect() 拿不到合法列表,自动检测失败。
语言包文件必须放在 lang/zh-cn/common.php 这种路径下
语言包不是随便建个 lang.php 就行,ThinkPHP 严格按路径约定加载:
- 根目录下建
lang/文件夹(不是config/lang.php,也不是application/lang/) - 每个语言建子目录,如
lang/zh-cn/、lang/en-us/,目录名必须全小写 + 短横线,zh_CN在 Linux 服务器上直接被忽略 - 每个子目录里放
common.php(默认分组),返回纯数组:return ['hello' => '你好']; - 如果要用分组(比如只给后台用),可建
lang/zh-cn/admin.php,调用时写lang('hello', 'admin')
常见错误:lang/zh-cn.php 这种单文件结构不被识别;lang/zh-cn/zh-cn.php 重复命名也不行;JSON/YAML 文件完全不支持。
lang() 函数为什么总是输出 key 而不是翻译内容
这通常不是函数写错了,而是语言包根本没加载成功。排查顺序如下:
- 检查当前请求是否触发了语言检测逻辑——ThinkPHP 6 默认在
app_init阶段调用Lang::detect(),但如果中间件中提前调用了Lang::setLang('en-us'),会覆盖自动检测结果 - 确认
Lang::getLangSet()返回值是否为你期望的语言码,不是则说明检测失败或被覆盖 -
lang('hello')在模板中写作{:lang('hello')},不能写成{lang('hello')}(后者是 Smarty 语法) - 若使用
__()助手函数,它只是lang()的别名,行为完全一致,不解决加载问题
特别注意:控制器中手动调用 Lang::setLang('en-us') 后,该请求生命周期内语言即锁定,后续 lang() 全部按此语言查表,但不会持久化到 cookie —— 持久化需自己写 cookie('think_language', 'en-us', 3600)。
URL 切换 ?lang=en-us 不生效?检查 VAR_LANGUAGE 和检测顺序
ThinkPHP 默认用 lang 参数名,但这个可配置。如果你改成 'lang_detect_var' => 'l',那 URL 就得是 ?l=en-us,否则检测不到。
检测优先级固定为:GET 参数 → Cookie(key 为 think_language) → HTTP_ACCEPT_LANGUAGE → default_lang。只要前一步拿到合法值,后面就跳过。所以如果 cookie 里存着过期的 zh-CN,即使 URL 带了 ?lang=en-us 也无效——因为 cookie 先命中且格式错误被忽略,最终 fallback 到 default_lang。
建议开发期清空 cookie 再测,或临时在中间件里加一行 cookie('think_language', null); 强制重置。
真正麻烦的是模块级语言包叠加和缓存干扰:比如 app\home\lang\zh-cn\common.php 和根 lang/zh-cn/common.php 同时存在时,ThinkPHP 会合并数组,但键冲突以模块为准;而 OPcache 可能缓存了旧的 common.php,改完语言内容没变化,先 opcache_reset() 再试。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











