多语言不生效主因是语言包未加载:路径命名错误(如zh_cn)、大小写敏感、加载时机过晚(须在lang()前于中间件中调用)、缓存未生成或目录不可写。

多语言不生效,90% 不是框架坏了,而是语言包根本没被加载进来——路径错、命名错、时机错、缓存没刷,四者占其三。
lang/ 目录结构和文件名写错
ThinkPHP 只认 lang/zh-cn/common.php 这种格式:小写字母 + 短横线 + common.php(或你指定的分组名),其他全无效。
-
lang/zh_CN/common.php、lang/zh-cn.php、lang/zh-cn/index.php都不会被加载,也不报错,静默跳过 - Linux 服务器上
zh-CN≠zh-cn,大小写敏感,本地 Windows 开发时可能侥幸通过,一上生产就失效 - 语言包文件必须以
return ['key' => 'value'];结尾,不能是echo、print或带 BOM 头的 UTF-8 - 模块级语言包优先级高于应用级,但前提是模块目录下真有
lang/zh-cn/common.php,否则退回到应用lang/
Lang::setLang() 调用太晚或位置不对
语言切换必须在任何 lang() 或 Lang::get() 调用之前完成,否则该次请求全程用默认语言。
- 别在控制器
__construct()里调Lang::setLang()——中间件还没执行,Lang 类甚至没初始化好 - 必须在中间件中设,例如
app\common\middleware\Lang.php的handle()方法开头就执行:Lang::setLang($request->session('lang', 'zh-cn')) - 如果用 URL 参数切换(如
?lang=en-us),要确认lang_switch_on为true,且detect_var配置匹配(默认是lang) - 手动设完后,建议补一句
Lang::load()强制重载,尤其在Lang::setLocale()后,避免缓存残留旧包
语言包已加载但 key 找不到翻译
lang('missing_key') 返回原字符串 'missing_key',不是空也不是异常,极易误判为“生效了”。
- 开启调试模式后,缺失 key 会记进日志;线上默认静默,上线前务必跑一次完整性检查脚本
- 嵌套键如
Lang::get('user.name')要求语言包里是return ['user' => ['name' => '用户名']],写成'user_name' => '用户名'就取不到 - 用
Lang::range()直接打印当前已加载的所有键值对,比翻文件更准 - 第三方扩展的语言包(比如 vendor 中的插件)不会自动加载,得手动调
Lang::load(EXTEND_PATH . 'pkg/lang/zh-cn.php')
缓存未生成或 runtime 目录不可写
每次请求都重新 require 语言文件,PHP 解析开销远大于 lang() 查数组本身——TTFB 高 50ms+ 往往卡在这儿。
-
lang_cache配置项设为true只是开关,不等于缓存已存在;必须手动触发编译(如命令行运行php think lang:build) - 确保
runtime/lang/目录可写,生成的缓存文件如zh-cn.php是序列化后的 PHP 数组,直接 include - 用了路由语言前缀(如
/zh-hans/)时,官方明确说明 Cookie 保存语言功能无效,别依赖它 - 模板里每写一个
{:lang('xxx')}就查一次语言包存在性,高频页面建议把翻译结果提前塞进变量传入,减少重复调用
最常被忽略的是:Lang 中间件没注册、语言包路径拼错、Lang::setLang() 放在了 lang() 之后——这三处一错,其余全白搭。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











