lang中间件必须显式注册到app/middleware.php中,否则ja-jp语言包不会加载;路径必须为全小写短横线格式(如lang/ja-jp/),且需调用lang::load()手动重载。

Lang中间件必须显式注册,否则ja-jp语言包根本不会加载
ThinkPHP 的 Lang 中间件默认不启用,哪怕你已创建 lang/ja-jp/common.php 并配置了 allow_lang_list,只要没在 app/middleware.php 里把它加进全局中间件数组,整个请求生命周期中语言包都不会被扫描和加载——Lang::get('hello') 就会原样返回 'hello',不报错也不提示。
实操要点:
- 打开
app/middleware.php,确认think\middleware\Lang::class在返回的数组中(不是注释状态) - 若用多应用模式(如
app/index/),需检查对应应用目录下的middleware.php - 中间件顺序很重要:它必须排在
SessionInit之后、路由执行之前,否则读不到$_COOKIE['think_lang']或input('lang')
ja-jp 目录名和文件名必须全小写、短横线分隔,不能是 ja_JP 或 ja
ThinkPHP 只识别严格符合 lang/{lang}/xx.php 格式的路径,其中 {lang} 必须是小写字母 + 短横线(如 ja-jp),不接受下划线、大写或省略地区码。写成 lang/ja_JP/、lang/ja/ 或 lang/JA-JP/ 都会导致 Language file not exists 警告,且静默回退到默认语言。
常见错误场景:
- 从 macOS 或 Windows 复制文件时保留了大小写(如
JA-JP),但 Linux 服务器区分大小写 → 找不到目录 - 语言包放在
app/index/lang/ja-jp.php(平级单文件)→ ThinkPHP 6+ 默认只扫描lang/{lang}/子目录结构 -
config/lang.php里配了'ja' => '日本語',但这只是前端展示名,不影响加载路径
Lang::setLocale('ja-jp') 后必须手动触发 Lang::load(),否则仍用旧语言
当你通过 URL 参数(如 ?lang=ja-jp)或用户点击切换语言时,调用 Lang::setLocale('ja-jp') 只是改了当前请求的语言上下文,不会自动重载语言包——因为 Lang 中间件已在初始化阶段完成了一次加载。此时不显式补一次 Lang::load(),后续所有 Lang::get() 仍走的是上一个语言的缓存。
安全做法(推荐放在中间件或控制器基类中):
- 先校验
$lang是否在Lang::getAllowLangList()白名单内 - 再执行
Lang::setLocale($lang) - 立刻跟一句
Lang::load()(无参数,表示按当前 locale 重新加载全部语言包) - 如需持久化,额外写 cookie:
cookie('think_lang', $lang, 3600)(注意键名必须是think_lang)
ja-jp 语言包内容必须是扁平数组或精确嵌套,不能混用结构
lang/ja-jp/common.php 必须返回纯关联数组,且键名层级要和调用方式完全一致。比如你在模板里写 {:lang('user.login')},那语言包就必须是:
return [
'user' => [
'login' => 'ログイン'
]
];
如果写成平铺形式 'user.login' => 'ログイン',或者嵌套错一层(如 'ja-jp' => ['user' => [...]]),Lang::get('user.login') 就会返回空字符串或原键名。
调试建议:
- 用
Lang::range()打印当前已加载的所有键值,确认user.login是否真实存在 - 检查 PHP 文件是否含 BOM 头(尤其 Windows 编辑器保存时易带入),会导致解析失败且无提示
- 避免在语言包里写任何 echo/print/log 语句——PHP 文件被 include 时会直接输出,破坏 JSON 响应或页面结构
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











