ThinkPHP 6+语言包必须置于根目录小写lang/下,子目录如zh-cn需全小写短横线格式,文件仅能return关联数组且无BOM或输出;模块级加载须同时满足路径、中间件注册及extend_list配置;lang()不降级匹配,键名须完全一致。

lang/ 目录必须小写且严格分层
ThinkPHP 6+ 只认 lang/(全小写)这个路径,放在项目根目录下;任何变体如 Lang/、LANGUAGE/、config/lang/ 或 app/lang/ 都不会被自动加载。子目录名是语言代码,必须用短横线分隔、全小写,比如 zh-cn、en-us、ja-jp —— zh_CN、ZH-CN、chinese 全部失效。
每个语言子目录下至少要有一个 PHP 文件,常见命名是 common.php,也可以按模块拆分,比如 user.php、admin.php。文件内容只能是一行 return [] 关联数组,不能有 echo、var_dump、?> 后多余空格或 BOM 头,否则整个文件静默不加载。
语言包文件必须返回纯数组,不能带输出
这是最常踩的坑:文件开头是 <?php ,结尾不能有 ?>,更不能在 return 后多一行空白或不可见字符。编辑器默认保存带 BOM 的 UTF-8 文件,会导致 lang() 返回空字符串或原 key 名,且无报错、无日志提示。
正确写法只有这一种形式:
立即学习“PHP免费学习笔记(深入)”;
return [
'welcome' => '欢迎',
'submit' => '提交',
];
错误示例包括:
-
<?php return [...]; ?>—— 多了?>容易引入尾部空白 -
echo 'test'; return [...];—— 任何输出都会中断解析 -
<?php return [...]; ?>\n—— 换行符也算输出 - 用 VS Code 或 Sublime 默认保存为 UTF-8 with BOM
模块级语言包需三条件同时满足
如果你的项目有 index、admin 等模块,并希望各模块独立维护语言包(比如 app/index/lang/zh-cn/common.php),必须同时做到:
- 模块目录下存在
lang/{lang_code}/子目录结构 - 该模块的
middleware.php中注册了\think\middleware\LoadLangPack::class -
config/lang.php中的'extend_list'未清空(留空或显式包含模块路径)
缺一不可。否则框架只加载根目录 lang/ 下的内容,模块级语言包完全被忽略。
lang() 查不到 key 时默认返回原字符串
lang('user.login_title') 调用时,框架不做任何键名解析或降级匹配 —— 它只查你定义的完整字符串。如果 lang/zh-cn/common.php 里没写 'user.login_title' 这个 key,就直接返回 'user.login_title' 本身,而不是尝试找 'login_title' 或 'user.login'。
这意味着:
- 键名必须和调用处**逐字一致**,大小写、点号、空格都不能差
- 测试时不能只看“页面没报错”,得确认渲染出的文本确实是翻译后的内容
- 建议在开发期开启调试模式,配合日志记录未命中的 key,避免漏翻
路径和命名规范、零输出、模块加载条件、键名完全匹配——这四点里任意一个松动,多语言就会“看起来配好了,实际没生效”。



















