Lang中间件未注册导致自定义语言切换失效,需显式添加至middleware.php或路由绑定,确保在SessionInit后、控制器前执行;插件语言包须置于插件lang目录,命名小写短横线,含common.php数组;Cookie需插件前缀隔离;Lang::set()必须在首次lang()调用前完成。

Lang中间件没注册?自定义中间件根本不会触发
ThinkPHP 6 的 Lang 中间件默认不启用,更不会自动代理或接管语言逻辑。如果你写了自定义中间件但 Lang::set() 没生效,第一反应不是逻辑错,而是它压根没跑起来。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 确认
app/middleware.php全局中间件数组里已显式加入你的类,比如\app\middleware\CustomLangSwitch::class - 若只对某组路由生效,必须在路由定义中用
->middleware(CustomLangSwitch::class)绑定 - 中间件执行顺序很关键:它得在
SessionInit之后、任何控制器方法调用之前运行,否则读不到 session 或 cookie - 别依赖“框架会自动发现”,
handle()方法不被调用 = 语言切换逻辑完全失效
插件内语言包始终返回键名?lang目录结构和命名全错
插件独立多语言失败最常见原因:路径大小写、连字符、文件格式三重误配。系统静默跳过加载,lang('pay_failed') 就原样返回字符串。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 插件 lang 目录必须建在插件根目录下,如
app/plugin/WechatPay/lang/,不能塞进主应用app/lang/ - 子目录名严格小写+短横线:
zh-cn✔️,ZH-CN❌,zh_CN❌,Linux 服务器上大小写敏感,本地测试通过不等于线上可用 - 每个子目录下必须有
common.php,内容只能是 PHP 数组:return ['pay_failed' => '支付失败'];,JSON/YAML 被直接忽略 - 插件语言包不走主框架
Lang::load()自动链,必须靠中间件手动调\think\Lang::set($lang)并确保路径已注入
前端切换语言却影响全站?cookie 键名和作用域没隔离
插件页面点“English”结果整个后台也变英文,说明你用了全局 think_lang Cookie,没做插件级隔离。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 插件语言 Cookie 必须带前缀,如
plugin_wechat_lang,避免与主站或其他插件冲突 - 后端写 Cookie 时显式指定
path和domain,例如:cookie('plugin_wechat_lang', 'en-us', ['path' => '/', 'domain' => '.example.com']) - 前端 JS 写 Cookie 也必须匹配 path/domain,
document.cookie = 'plugin_wechat_lang=en-us; path=/; domain=.example.com;' - 中间件里读取时用
$request->cookie('plugin_wechat_lang', 'zh-cn'),别硬读$_COOKIE,防止被其他逻辑污染
Lang::set() 调用后 lang() 还是默认语言?时机晚于翻译调用
Lang::set('en-us') 执行成功不代表语言就切了——如果它出现在 lang('submit') 之后,那这次请求里所有翻译都已按旧语言固化。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 自定义中间件的
handle()方法开头就要完成语言设置,且必须在$next($request)前 - 绝对不要在控制器构造函数、
initialize()或模板中调Lang::set(),那时中间件早已执行完毕 - 插件控制器里首次调用
lang()前,必须确保\think\Lang::set()已执行,否则语言上下文就是空的 - 调试时可在中间件里加日志:
trace('lang set to: ' . $lang);,确认它真被执行且值正确
最易被忽略的一点:插件语言切换不是“设个变量就完事”,它要求路径、命名、Cookie 隔离、中间件注册、执行时机五者全部对齐。少一个,lang() 就退化成 return key。



















