必须配置 detect_var 且启用 LoadLangPack 中间件,URL 参数 ?lang=zh-cn 才生效;参数值须在 allow_lang_list 中、路径文件名需严格匹配、注意大小写与 Cookie 冲突。

URL参数触发多语言切换必须配 detect_var
不配置 detect_var,?lang=zh-cn 这类参数完全无效——系统压根不会去读取它。这个配置是开启 URL 语言切换的开关,不是可选项。
它默认值是 'lang',但如果你希望用 ?l=zh-cn 或 ?language=en-us,就得在 config/lang.php 里显式改掉:
return [
'detect_var' => 'l', // 改成你想要的 GET 参数名
'allow_lang_list' => ['zh-cn', 'en-us'],
'default_lang' => 'zh-cn',
];
-
detect_var只影响 GET 参数读取,不影响 Cookie 或 Header 检测逻辑 - 参数值必须在
allow_lang_list里,否则会被忽略,回退到default_lang - 大小写敏感:传
?lang=ZH-CN不会命中zh-cn,建议前端统一小写处理
LoadLangPack 中间件没启用,detect_var 配了也白配
detect_var 是中间件行为的一部分,不是配置即生效。如果 app/middleware.php 里没注册 \think\middleware\LoadLangPack,整个多语言检测流程(包括读 detect_var)根本不会执行。
常见错误是只改了配置,忘了加中间件,结果怎么调参都切不了语言。
立即学习“PHP免费学习笔记(深入)”;
- 全局生效:把
\think\middleware\LoadLangPack::class加进app/middleware.php的数组里 - 仅对某组路由生效:用
->middleware(\think\middleware\LoadLangPack::class)显式绑定 - 别在控制器构造函数里手动调
Lang::detect()——中间件已做这事,重复调可能覆盖检测结果
语言包文件名和路径不匹配 detect_var 就会失效
即使 ?lang=en-us 被正确读到,系统仍要按约定路径加载对应语言包。路径不对,就会报 Language file not exists,然后静默 fallback 到默认语言。
ThinkPHP 默认查找路径是 app/lang/{lang}/xx.php 或 app/lang/{lang}.php,其中 {lang} 必须严格等于 detect_var 解析出的值(小写、连字符格式)。
- ✅ 正确:URL 传
?lang=zh-cn→ 系统找app/lang/zh-cn.php - ❌ 错误:URL 传
?lang=zh_CN→ 系统找app/lang/zh_cn.php(不存在) - ❌ 错误:文件叫
app/lang/zh.php,但detect_var值是zh-cn→ 找不到 - 语言包内直接返回数组,不要嵌套:写
return ['hello' => '你好'];,别写return ['zh-cn' => ['hello' => '你好']]
想让 ?lang=xxx 立即生效,得关掉缓存或清空 Cookie
如果之前访问过站点且设置了语言 Cookie(use_cookie => true),那么即使现在传 ?lang=en-us,系统也会优先取 Cookie 值,导致 URL 参数被跳过。
这不是 bug,是设计逻辑:Cookie > GET 参数 > Accept-Language > default_lang(V6.0.3+ 后支持 Header 优先级可调)。
- 开发调试时建议临时关掉
use_cookie,或手动删掉浏览器里的think_langCookie - 生产环境若需“URL 强制覆盖”,可在中间件前自定义一个前置逻辑,先清除或忽略 Cookie
- Header 方式(如
think-lang: en-us)在 V6.0.3+ 可通过header_var配置,优先级高于 Cookie,适合 API 场景
detect_var → 校验 allow_lang_list → 匹配语言包路径 → 加载内容 → 覆盖 Cookie 逻辑。任一环断裂,都会表现为“参数没反应”。



















