如何设置ThinkPHP语言中间件实现自动加载多语言?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1010个文字,预计阅读时间需要5分钟。
在Lang中,中间件不会自动生效,必须手动注册到全局中间件列表中。否则,语言包根目录不会加载,也不会返回原始键名。
Lang中间件必须显式注册到 app/middleware.php
ThinkPHP 不会默认启用多语言中间件,哪怕你把语言包放对了位置、配置也写全了,只要没注册,整个流程就卡在第一步。
常见错误现象:lang('hello') 始终返回 'hello',日志无报错,调试时 Lang::range() 返回空数组。
- 打开
app/middleware.php,确认数组中包含\think\middleware\Lang::class(不是注释状态) - 多应用模式下,需在对应应用目录下的
middleware.php单独注册,不能只改根目录 - 别和
\think\middleware\LoadLangPack混用——V6.0+ 已弃用该类,Lang中间件已内置自动加载逻辑
语言包路径和命名必须严格符合 lang/{lang}/common.php 格式
ThinkPHP 只按固定路径规则加载语言包:小写字母 + 连字符格式的 locale 目录名,内含返回数组的 PHP 文件。任何偏差都会静默失败。
立即学习“PHP免费学习笔记(深入)”;
常见错误现象:Language file not exists 报错,或切换语言后翻译不更新。
- 路径必须是
app/lang/zh-cn/common.php,不是app/lang/zh_CN.php、也不是config/lang.php -
zh-cn和ZH-CN在 Linux 服务器上完全不等价,大小写错误会导致文件找不到 -
common.php必须以return ['hello' => '你好'];结尾,不能是 JSON、YAML 或嵌套结构如return ['zh-cn' => [...]]
动态切换语言必须在中间件中调用 Lang::setLocale(),且早于任何 lang() 调用
URL 参数 ?lang=en-us 或 Cookie 并不会自动触发语言切换,Lang 中间件默认只读取 Accept-Language 头或配置项,不解析 GET 参数。
常见错误现象:用户点了“English”按钮,但页面文字没变;或者控制器里 Lang::setLocale('en-us') 没效果。
- 在自定义中间件(如
app/middleware/LangSwitch.php)中读取输入:$lang = input('lang', cookie('think_lang', 'zh-cn')) - 务必校验白名单:
in_array($lang, config('lang.allow_lang_list', ['zh-cn', 'en-us'])),防止非法值引发路径问题 - 调用
Lang::setLocale($lang)后,建议显式Lang::load()确保语言包重载(尤其手动设 locale 时) - 切勿在控制器构造函数中调用——中间件执行时机更早,此时 Lang 上下文尚未建立
Lang::get() 返回原键名?先查 Lang::range(),再看中间件执行顺序
返回键名不是配置错了,而是语言包压根没加载成功,或者 lang() 被调用时当前语言上下文还没就位。
最容易被忽略的是中间件顺序:如果 Lang 中间件排在 SessionInit 之后,它就读不到 cookie('think_lang');如果排在路由调度之后,控制器里第一行 lang() 就已执行完毕。
- 用
Lang::range()直接查看当前已加载的全部翻译项,比翻日志更快定位是否加载 - 确保
Lang中间件在SessionInit之后、但仍在路由匹配之前执行(即注册顺序应靠前) - 若用了模块化结构,检查模块级语言包路径:
app/module_name/lang/zh-cn/common.php优先级高于应用级
本文共计1010个文字,预计阅读时间需要5分钟。
在Lang中,中间件不会自动生效,必须手动注册到全局中间件列表中。否则,语言包根目录不会加载,也不会返回原始键名。
Lang中间件必须显式注册到 app/middleware.php
ThinkPHP 不会默认启用多语言中间件,哪怕你把语言包放对了位置、配置也写全了,只要没注册,整个流程就卡在第一步。
常见错误现象:lang('hello') 始终返回 'hello',日志无报错,调试时 Lang::range() 返回空数组。
- 打开
app/middleware.php,确认数组中包含\think\middleware\Lang::class(不是注释状态) - 多应用模式下,需在对应应用目录下的
middleware.php单独注册,不能只改根目录 - 别和
\think\middleware\LoadLangPack混用——V6.0+ 已弃用该类,Lang中间件已内置自动加载逻辑
语言包路径和命名必须严格符合 lang/{lang}/common.php 格式
ThinkPHP 只按固定路径规则加载语言包:小写字母 + 连字符格式的 locale 目录名,内含返回数组的 PHP 文件。任何偏差都会静默失败。
立即学习“PHP免费学习笔记(深入)”;
常见错误现象:Language file not exists 报错,或切换语言后翻译不更新。
- 路径必须是
app/lang/zh-cn/common.php,不是app/lang/zh_CN.php、也不是config/lang.php -
zh-cn和ZH-CN在 Linux 服务器上完全不等价,大小写错误会导致文件找不到 -
common.php必须以return ['hello' => '你好'];结尾,不能是 JSON、YAML 或嵌套结构如return ['zh-cn' => [...]]
动态切换语言必须在中间件中调用 Lang::setLocale(),且早于任何 lang() 调用
URL 参数 ?lang=en-us 或 Cookie 并不会自动触发语言切换,Lang 中间件默认只读取 Accept-Language 头或配置项,不解析 GET 参数。
常见错误现象:用户点了“English”按钮,但页面文字没变;或者控制器里 Lang::setLocale('en-us') 没效果。
- 在自定义中间件(如
app/middleware/LangSwitch.php)中读取输入:$lang = input('lang', cookie('think_lang', 'zh-cn')) - 务必校验白名单:
in_array($lang, config('lang.allow_lang_list', ['zh-cn', 'en-us'])),防止非法值引发路径问题 - 调用
Lang::setLocale($lang)后,建议显式Lang::load()确保语言包重载(尤其手动设 locale 时) - 切勿在控制器构造函数中调用——中间件执行时机更早,此时 Lang 上下文尚未建立
Lang::get() 返回原键名?先查 Lang::range(),再看中间件执行顺序
返回键名不是配置错了,而是语言包压根没加载成功,或者 lang() 被调用时当前语言上下文还没就位。
最容易被忽略的是中间件顺序:如果 Lang 中间件排在 SessionInit 之后,它就读不到 cookie('think_lang');如果排在路由调度之后,控制器里第一行 lang() 就已执行完毕。
- 用
Lang::range()直接查看当前已加载的全部翻译项,比翻日志更快定位是否加载 - 确保
Lang中间件在SessionInit之后、但仍在路由匹配之前执行(即注册顺序应靠前) - 若用了模块化结构,检查模块级语言包路径:
app/module_name/lang/zh-cn/common.php优先级高于应用级

