必须启用think\middleware\LoadLangPack中间件,且语言包路径、lang.php配置、Lang::get()调用三者对齐,否则语言切换永远不生效;最常见原因是路径错误(如zh_CN而非zh-cn)、文件未返回数组、存在BOM或输出,或多应用下未按app/{name}/lang/结构放置。

直接说结论:必须启用 think\middleware\LoadLangPack 中间件,且语言包路径、lang.php 配置、Lang::get() 调用三者对齐,否则语言切换永远不生效。
为什么加了中间件还是加载不到语言包?
最常见原因是语言包文件路径错误或命名不规范。ThinkPHP6 严格按约定路径查找:
- 单应用模式下,必须放在
app/lang/zh-cn.php或app/lang/en-us.php,不能是app/lang/zh_CN.php或app/lang/zh.php - 多应用模式下(如
app/api),路径应为app/api/lang/zh-cn.php,且该应用的config/lang.php必须存在并被正确加载 - 语言包文件必须返回数组,且不能有输出(如 BOM、echo、var_dump)——哪怕一个空格都会导致解析失败
- 如果用了
extend_list扩展语言包,路径必须是绝对路径,推荐用app()->getBasePath()拼接
detect_var 和 header_var 怎么选?
自动侦测语言时,系统按顺序检查:GET 参数 → Cookie → Header → HTTP_ACCEPT_LANGUAGE。关键点:
-
detect_var默认是lang,即 URL 中带?lang=en-us就能强制切换,适合调试和前端手动控制 -
header_var默认是think-lang,前端需在请求头里加think-lang: en-us,适合前后端分离项目统一控制 - 如果同时传了
lang=en-us和 Headerthink-lang: zh-cn,前者优先 —— 这个优先级不可更改 -
allow_lang_list是安全兜底项,不在列表里的值(比如lang=ja-jp)会被忽略,直接回落到default_lang
前后端分离项目怎么返回带翻译的错误码?
不能直接在控制器里写死中文,得把错误码和语言解耦。典型做法是:
立即学习“PHP免费学习笔记(深入)”;
- 在
config/error_code.php中定义键名而非文案,例如300001 => 'appid_not_correct' - 语言包中对应定义
'appid_not_correct' => 'APPID is invalid'(英文)和'appid_not_correct' => 'APPID 不合法'(中文) - 封装返回函数时调用
lang($error[$code]),而不是$error[$code] - 注意:如果
$code对应的语言变量不存在,lang()默认返回原字符串(即'appid_not_correct'),不会报错但会暴露键名 —— 这是调试期容易忽略的漏翻点
多应用下各应用语言包互相干扰吗?
不会干扰,但容易误配。核心机制是:每个应用启动时,会先加载自己目录下的 config/lang.php(如有),再加载全局 config/lang.php;语言包也按应用隔离:
-
app/api/lang/zh-cn.php只对api应用生效 -
app/admin/lang/en-us.php只对admin应用生效 - 如果某个应用没定义自己的
lang.php,它会继承全局配置,但语言包仍只读自己目录下的lang/ - 切记:
middleware.php中的中间件注册是全局的,所以LoadLangPack会为每个应用分别执行一次加载 —— 不用额外为每个应用单独注册
真正难搞的是语言包热更新:修改了 zh-cn.php 内容,但 Lang::get() 还返回旧值,大概率是 runtime 缓存没清,删掉 runtime/lang/ 目录即可。这个点上线后最容易卡住人。



















