Lang::get()返回原key说明语言包未成功加载,应调用Lang::range()验证已加载键值对,检查lang_switch_on、default_lang配置、路径格式(如lang/zh-cn.php)、文件权限及加载时机。

Lang::get() 返回原 key 而不是翻译值?先查语言包是否真加载了
这不是配置没生效,而是运行时根本没读到对应语言文件。最直接的验证方式是调用 Lang::range() —— 它会返回当前已加载的所有语言键值对,不是猜,是看。
常见错误现象:
-
Lang::get('hello')始终返回'hello',不是'你好' - 日志里没报错,但翻译就是不出现
实操建议:
- 确认
app.lang_switch_on为true,且app.default_lang是合法值(如'zh-cn') - 语言包路径必须严格为
lang/zh-cn.php、lang/en-us.php,不能是zh_CN或zh--cn—— ThinkPHP 只认小写+短横线格式 - 检查文件权限:Linux 下若 web 用户无读取权限,
include失败但静默忽略,Lang::range()就为空 - 如果用了模块化结构,优先级是「模块 lang/ → 应用 lang/ → 框架 lang/」,别把包放错位置
lang() 函数占位符不替换?检查 key 是否存在且语法合规
lang('welcome_to_site', ['name' => 'Tom']) 不渲染出「欢迎来到 Tom 的站点」,大概率是语言包里压根没定义这个 key,或者占位符写法错了。
立即学习“PHP免费学习笔记(深入)”;
ThinkPHP 的占位符只认 {key} 格式,不支持 :key、%s 或其他变体。
实操建议:
- 语言包中必须写成
'welcome_to_site' => '欢迎来到 {name} 的站点',多一个空格或少一个花括号都会失效 - 复数语法
'item|items'仅在传入数字时触发,lang('item|items', 1)取左边,lang('item|items', 2)取右边 - key 缺失时默认返回原字符串(如
lang('missing')返回'missing'),线上环境不报错也不记录,容易误判;开启调试模式后缺失 key 会记入日志 - 建议上线前跑一次完整性检查:遍历所有模板和控制器中的
lang()调用,比对语言包 keys
切换语言后页面没变?Lang::setLocale() 调用时机和作用域不对
Lang::setLocale('en-us') 必须在任何 lang() 或 Lang::get() 调用之前执行,否则该次请求仍用旧 locale。中间件里设晚了、控制器构造函数里设、或者在路由分组之后才设,都会失效。
实操建议:
- 在全局中间件(如
app\common\middleware\Lang.php)里做设置,确保它在请求生命周期最早期执行 - 不要依赖 URL 参数做唯一判断 —— 比如用户从分享链接进来带
?lang=ja-jp,但 session 里存的是zh-cn,应以 session 为准 - 手动设完 locale 后,显式调用
Lang::load()更保险(尤其用了扩展语言包时) - 如果用了路由分组(如
lang/:lang),记得把:lang值透传给Lang::setLocale(),别只存不设
第三方扩展语言包不生效?ThinkPHP 默认不扫描 vendor 目录
vendor 里的插件语言包不会被自动加载,ThinkPHP 只扫描 lang/ 目录下的应用级语言包。
实操建议:
- 手动加载:在
app/common.php或启动中间件中调用Lang::load($path),路径需为绝对路径 - 例如:
Lang::load(EXTEND_PATH . 'somepkg/lang/zh-cn.php') - 注意:
EXTEND_PATH是常量,不是字符串拼接;若不确定路径,可用app()->getBasePath()拼接 - JSON 或 YAML 格式语言包不支持,必须是 PHP 文件并
return关联数组
最容易被忽略的点是:语言包加载失败时没有明显报错,只有 Lang::range() 为空、lang() 返回原 key 这两个安静的信号。调试时别跳过这一步,它比翻配置快十倍。



















