ThinkPHP6多应用模式下语言包需为每个子应用独立配置路径、启用LoadLangPack中间件、设置独立lang.php配置,三者缺一不可。

多应用下语言包路径必须独立配置
ThinkPHP6多应用模式中,app/lang/zh-cn.php这类全局语言包不会自动被子应用加载——每个应用默认只扫描自己目录下的语言包。比如访问/admin时,框架优先查找app/admin/lang/zh-cn.php,而不是app/lang/zh-cn.php。
常见错误现象:后台页面全是英文(或键名),但前台正常;或者lang('welcome')在index应用返回“欢迎”,在admin应用却原样返回welcome。
- 确认
app/admin/lang/目录存在,且内含zh-cn.php和en-us.php(命名必须小写+短横线,不能是zh_CN或zh.php) - 每个子应用的语言包文件必须以
return [];形式返回数组,开头不能有BOM、空格、echo或var_dump - 若想复用公共语言项,可在
app/admin/lang/zh-cn.php中require主语言包:return array_merge(require APP_PATH . 'lang/zh-cn.php', ['admin_title' => '后台管理']);
LoadLangPack中间件需在各应用中单独启用
ThinkPHP6的think\middleware\LoadLangPack中间件不是全局注册就一劳永逸的——多应用模式下,每个子应用的middleware.php都必须显式声明它,否则该应用的语言包根本不会被扫描。
容易踩的坑:只在根目录app/middleware.php里加了中间件,但app/admin/middleware.php是空的或未创建,导致admin应用完全不加载语言包。
立即学习“PHP免费学习笔记(深入)”;
- 检查
app/admin/middleware.php是否存在;若不存在,手动创建并填入:return [think\middleware\LoadLangPack::class]; - 确保该文件中没有其他中间件覆盖或干扰,例如
SessionInit必须在LoadLangPack之前执行(否则读不到think_langCookie) - 不要在子应用中间件中重复注册
Lang中间件(think\middleware\Lang),它只负责侦测,加载由LoadLangPack完成
lang.php配置项作用域仅限当前应用
config/lang.php在多应用模式下不是共享配置——每个子应用需有自己的config/lang.php,否则default_lang、allow_lang_list等设置对子应用无效。
典型表现:URL带?lang=en-us在前台生效,进后台却仍是中文,且切换无响应。
- 在
app/admin/config/下新建lang.php,内容至少包含:'default_lang' => 'zh-cn', 'allow_lang_list' => ['zh-cn', 'en-us'] - 子应用的
lang.php中lang_path可自定义,如'lang_path' => APP_PATH . 'admin/lang/',但通常保持默认即可 - 别把
app/config/lang.php当作“总配置”——TP6不支持跨应用继承配置,每个config/目录下的文件只对该应用生效
动态切换语言时Locale必须在中间件早期设置
在子应用控制器里调用Lang::setLocale('en-us')基本无效,因为LoadLangPack中间件已在请求初期完成加载;此时再改Locale,已加载的语言包不会重载,后续lang()仍用旧语言。
最常被忽略的点:以为只要前端传了think-lang: en-us头,后台就会自动切语言——其实得靠中间件在handle()开头就读取并设置。
- 确保子应用的
middleware.php中LoadLangPack位于首位(或至少在任何业务中间件之前) - 验证
config/lang.php中'header_var' => 'think-lang'与前端请求头一致,且'detect_var' => 'lang'匹配GET参数名 - 调试时可用
Lang::getLangSet()打印当前语言标识,确认是否真的被中间件识别成功,而不是fallback到default_lang



















