ThinkPHP6中lang()静默返回键名,主因是语言包路径错误(如非app/lang/zh-cn.php)、LoadLangPack中间件未启用、allow_lang_list配置不匹配或语言文件含BOM/非法输出。

语言包路径没对上,lang() 就会静默返回键名
ThinkPHP6 不报错、不提示、不抛异常,只默默把 lang('welcome') 返回成字符串 welcome。这不是函数坏了,是它根本没加载到任何语言包——因为路径压根没匹配上。
默认路径是 app/lang/zh-cn.php,不是 app/lang/zh_CN.php,也不是 app/lang/zh-cn/common.php(那是 TP5 的写法)。文件必须直接放在 app/lang/ 下,命名严格小写+短横线,扩展名是 .php,且内容只能是 return [...];,开头不能有 BOM、空格或 echo。
- 删掉所有类似
app/lang/zh_CN.php、app/lang/zh/目录、lang/zh-cn/validate.php这类非标准结构 - 新建
app/lang/zh-cn.php和app/lang/en-us.php,内容为return ['welcome' => '欢迎']; - 用
file_exists(app_path() . 'lang/zh-cn.php')手动验证路径是否存在
LoadLangPack 中间件没启用,语言包压根不会加载
即使路径全对、文件全在,LoadLangPack 中间件没注册,框架就当多语言功能不存在。它不像路由或日志那样默认开启,必须手动加进中间件栈。
打开 app/middleware.php,检查数组里有没有 'think\middleware\LoadLangPack'。如果注释了、拼错了、或者只加在某个路由组里而没放全局,都会导致整个请求周期内语言包零加载。
立即学习“PHP免费学习笔记(深入)”;
- 确认该中间件在
app/middleware.php的全局中间件数组中,且未被注释 - 多应用模式下,每个应用的
app/应用名/middleware.php都要单独配置 - 别和
Lang::class混用——LoadLangPack负责自动加载语言包,Lang中间件负责语言侦测与切换,二者分工不同
config/lang.php 里的 allow_lang_list 和实际请求不匹配
请求参数是 ?lang=zh,但配置里只写了 ['zh-cn', 'en-us'],那框架直接忽略这个参数, fallback 到 default_lang。更隐蔽的是,allow_lang_list 值必须是小写短横线格式,哪怕你服务器环境是 Windows,也不能写成 ZH-CN 或 zh_CN。
另外,detect_var 默认是 lang,但如果你改成了 l 却忘了同步前端 URL,参数就传不进来。
- 检查
config/lang.php中allow_lang_list是否包含你正在测试的语言标识,且格式完全一致 - 确认
detect_var和实际 GET 参数名一致,例如设为'l'就得用?l=zh-cn - 临时加一行
dump($this->request->param('lang'));在中间件里,看参数是否真被读到
语言包文件里有非法输出,include 失败但无提示
PHP include 一个带 BOM、多余空行、var_dump 或 UTF-8 编码错误的文件时,会中断执行并让后续 return 无效。结果就是语言包数组为空,lang() 找不到任何翻译项。
这类问题在跨编辑器协作时高频出现:VS Code 默认保存带 BOM 的 UTF-8,Notepad++ 可能混用编码,Git 提交时又自动转码……最终文件看着正常,实则已损坏。
- 用命令行
file -i app/lang/zh-cn.php查看真实编码,确保是utf-8且无bom - 用
xxd app/lang/zh-cn.php | head检查开头是否有ef bb bf(BOM 字节) - 在文件最开头加
if (headers_sent()) { die('lang file output before return'); }快速定位非法输出
路径、中间件、配置、文件内容——这四个点只要一个错位,lang() 就会“假装正常”,实则失效。最容易被忽略的是文件编码和中间件注册顺序,尤其在从 TP5 升级或复制旧项目时,习惯性沿用老路径结构,却忘了 TP6 的约定已变。



















