lang()返回原key是因语言包未加载,须在调用前完成三件事:Lang::setLang('zh-cn')执行、语言码严格为小写短横格式(如zh-cn)、语言包路径app/lang/zh-cn/common.php存在且返回纯数组。

lang() 调用返回原 key 而不是翻译内容
这不是接口“没切换”,而是 lang() 根本没加载对应语言包,框架静默 fallback 到 key 字符串。常见于中间件未提前设置语言、语言码格式错误或路径不对。
必须确保三件事在任何 lang() 调用前完成:
-
Lang::setLang('zh-cn')已执行(典型位置:语言切换中间件的handle()最开头) - 语言码严格小写带短横,如
zh-cn,不能是ZH_CN、zh_CN或zhcn(Linux 下大小写敏感) - 语言包路径为
app/lang/zh-cn/common.php,且该文件以return ['login_failed' => '登录失败'];形式返回数组,无 BOM、无输出、不放错目录(比如 config/lang.php 是无效的)
接口里调用 lang() 但切换后仍不变
ThinkPHP 6 的语言环境是「请求级」的,不是全局单例。如果你在控制器里手动调用 Lang::setLang('en-us'),只影响当前请求后续的 lang() 调用;但若语言切换逻辑写在中间件之外(比如某个 action 里),就可能被路由/前置中间件覆盖。
正确做法是把语言设置统一收口到中间件:
- 新建中间件
app/middleware/LangSwitchMiddleware.php - 在
handle()开头立即执行Lang::setLang($lang),其中$lang来自$request->param('lang')或$request->header('think-lang') - 确保该中间件在
app/middleware.php中注册且位置靠前(早于业务逻辑中间件)
别在控制器里重复 setLang —— 多次调用不会报错,但后一次会覆盖前一次,容易引发竞态。
lang() 在 API 接口里返回空或 null
这通常是因为语言包根本没加载成功,而框架又不报错。检查点比页面渲染更隐蔽:
- 确认
config/lang.php中'detect_var' => 'lang'和'use_cookie' => true已开启,否则?lang=en-us不生效 - API 请求一般不带 Cookie,所以依赖 Header 更可靠:前端需带
think-lang: en-us,后端才能识别 - 运行
php think route:list看目标接口是否在列表中;如果路由都未注册,lang()根本不会被执行 - 临时在接口方法开头加
dump(\think\facade\Lang::getLang());,看输出是不是你预期的语言码;如果不是,说明中间件没生效或被跳过
多语言包分组(如 home.php / api.php)没生效
ThinkPHP 6 默认只加载 common.php,其他文件需显式指定:
- 调用
lang('key', '', 'api')才会加载app/lang/zh-cn/api.php - 确保
config/lang.php中'allow_group' => ['common', 'api', 'home']已声明允许的分组名 - 不要指望
lang('key')自动跨文件查找 —— 它只查common.php,找不到就直接返回 key - 如果用注解路由或 RESTful 风格,建议把 API 相关翻译全放在
api.php,并在每个接口方法里显式传入分组名,避免混用导致漏翻译
最易忽略的是:语言包文件本身没问题,但分组名没进 allow_group 配置,框架会直接跳过加载,连 warning 都不抛。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











