thinkphp多语言必须在请求早期完成语言设置,否则lang()始终返回默认语言;lang/目录需严格小写+下划线命名,仅识别php数组文件;模块化路径优先级更高;lang::detect()不自动设语言,须手动调用lang::setlang()且必须在所有lang()调用前执行。

ThinkPHP 后台(如 ThinkPHPAdmin 类项目)要实现多语言,核心不是“加个插件就完事”,而是必须在请求生命周期早期、翻译调用前完成语言设置——否则 lang() 拿到的永远是默认语言,且不报错,排查极难。
lang/ 目录结构和文件命名必须严格小写 + 下划线
ThinkPHP 只识别 lang/zh-cn/common.php 这类路径,大小写错误或扩展名不对直接静默失效:
-
lang/zh_CN/common.php→ 不加载(Linux 服务器必挂) -
lang/zh-cn/common.json→ 不加载(只认 PHP 返回数组) -
lang/zh-cn.php→ 不加载(必须是子目录 +common.php或分组名如admin.php) - 模块化项目中,
app\admin\lang\en-us\common.php优先级高于app\lang\en-us\common.php
lang_switch_on 开启后,语言切换逻辑由 Lang::detect() 控制,但默认不读 Session
很多人以为设了 'lang_switch_on' => true 就能自动从 Session 读语言,其实不能。默认只检查三处(按顺序):$_GET['lang'] → cookie('think_language') → $_SERVER['HTTP_ACCEPT_LANGUAGE']:
- 想从 Session 读,必须自己写中间件,调用
Lang::setLang($request->session('lang')) -
Lang::detect()是只读探测,不会自动设置;真正生效的是Lang::setLang() - 中间件里调用
Lang::setLang()必须在$next($request)前,且不能在控制器构造函数里——那时中间件已执行完毕 - Cookie 名固定为
think_language,有效期 3600 秒,需手动改源码或重写行为才能调整
lang() 函数传参和 fallback 行为容易误判
lang() 在 key 缺失时不抛异常、不返回空,而是原样返回 key 字符串,线上几乎无法察觉:
-
lang('user_not_found')若语言包没定义该 key,结果就是字符串"user_not_found",看起来像“显示正常” - 占位符只支持
{name}格式,lang('hello', ['name' => 'Tom'])对应语言包中'hello' => 'Hi {name}!' - 复数语法仅支持竖线分隔:
'item|items',传入lang('item|items', 1)得'item',其他数字得'items' - 调试模式下缺失 key 会记日志,但生产环境默认静默——上线前务必用脚本比对所有语言包 key 是否齐全
最易被忽略的一点:语言包一旦加载,整个请求周期内不会再重新读取。哪怕你在中间件里先设了 zh-cn,又在控制器里调 Lang::setLang('en-us'),之前已触发的 lang() 调用仍用旧语言,新调用才生效。所以设置动作必须放在所有翻译调用之前,且只设一次。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











