thinkphp语言包需同时满足路径、命名、注册、时机四条件才能加载成功;lang::get()返回原key或空值多因未加载;路径须小写连字符如lang/zh-cn/common.php;模块化优先加载app/admin/lang/zh-cn/common.php;lang中间件必须显式注册且置于sessioninit之后;lang::setlocale()须在任何lang()调用前执行;lang()缺失key时静默返回原字符串,不报错。

ThinkPHP 的语言包不会自动加载,必须满足路径、命名、注册、时机四个条件,缺一不可。Lang::get() 返回原 key 或空值,90% 是因为语言包根本没加载成功。
语言包路径和文件名必须严格小写连字符格式
ThinkPHP 只认 lang/zh-cn/common.php 这种结构,大小写或分隔符错一个就静默失败。
-
lang/zh_CN/common.php、lang/zh-cn.php、lang/zh-cn/index.php全部无效 - Linux 服务器上
lang/ZH-CN/和lang/zh-cn/是两个不同目录,前者永远加载不到 - 文件内必须用
return ['hello' => '你好'];,不能嵌套return ['zh-cn' => [...]] - 如果用模块化(如
app/admin),优先加载app/admin/lang/zh-cn/common.php,再 fallback 到应用级app/lang/zh-cn/common.php
Lang 中间件必须显式注册且顺序正确
不注册 think\middleware\Lang,整个多语言流程就卡在第一步——语言包压根不会被扫描。
- 确认
app/middleware.php中全局中间件数组包含think\middleware\Lang::class,不是注释状态 - 多应用模式下,每个应用的
middleware.php都要单独加 - 中间件执行顺序很重要:
SessionInit必须在Lang之前,否则读不到cookie('think_lang') - 别在控制器构造函数里调用
Lang::setLocale()—— 此时中间件已执行完毕,改了也白改
动态切换语言必须在请求最开始设置
Lang::setLocale() 或 Lang::setLang() 必须在任何 lang() 调用前执行,否则本次请求仍用默认语言。
- 从 URL 参数取值:检查
config/app.php中是否设置了'lang_switch_on' => true,并确保'VAR_LANGUAGE' => 'lang'(默认)与实际参数名一致 - 从 Cookie 读取:
Lang中间件默认只读think_lang键,写的时候必须用cookie('think_lang', 'en-us'),不是setcookie()手动设 - 从 Session 读取:需自行在中间件中写逻辑,
Lang::detect()默认不读 Session,得手动$request->session('lang', 'zh-cn') - 设置后不会重载已加载的语言包,所以必须在中间件 handle 方法开头就调用
Lang::setLang($lang)
lang() 函数行为和常见静默陷阱
lang() 不报错、不抛异常,key 缺失时直接返回字符串本身,这是最容易误判“生效了”的地方。
-
lang('missing_key')返回'missing_key',不是null或空字符串 - 开启调试模式(
app_debug => true)时,缺失 key 会记入日志,但线上环境默认静默 - 占位符只支持
{name}格式,lang('hello {name}', ['name' => 'Tom'])才生效,:name或%s无效 - 复数语法用竖线:
'item|items',传入数字 1 时取左边,其他值取右边;传字符串或数组会直接当单数处理
最常被忽略的是模块级语言包未启用,或者 Lang 中间件注册了但执行顺序靠后,导致控制器里第一次调用 lang() 时上下文还没建立。路径、命名、注册、时机——四者齐备,语言包才真正“活”起来。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











