ThinkPHP多语言API需显式用lang()获取文案并注入lang字段,json()不自动翻译;语言包须UTF-8无BOM,通过app()->getLocale()获取当前语言码,Accept-Language需手动启用Lang::detect()支持。

ThinkPHP 多语言 API 接口返回 JSON,核心不是“切换语言再输出”,而是让 json() 响应自动携带当前语言标识(如 lang 字段)或根据请求头动态适配文案——但框架本身不自动翻译内容,你得自己控制文案来源。
多语言文案必须从语言包或数据库读取,不能硬编码在 json() 参数里
ThinkPHP 的 json() 方法只负责序列化和设头,它不会帮你查语言包、也不会调用 lang() 函数。如果你直接写 return json(['msg' => '操作成功']);,那无论用户请求的是 zh-cn 还是 en-us,返回的都是中文。
- 正确做法是:先用
lang('operate_success')获取当前语言的文案,再塞进数组 - 确保语言包文件存在且加载正常,例如
lang/zh-cn/common.php里有return ['operate_success' => '操作成功']; - 如果用数据库存多语言文案,需手动查表并按
Lang::getLang()或input('lang', config('app.default_lang'))取对应字段 - 别在控制器里用
Lang::setLocale('en')临时切换——它影响全局,可能干扰其他并发请求
json() 返回时怎么带语言标识字段
前端需要知道本次响应的语言环境(比如用于 fallback 或日志),最稳妥的方式是在 JSON 数据结构里显式加 lang 字段,而不是依赖响应头(Content-Language 不是必须的,且前端不一定读)。
- 推荐结构:
return json(['code' => 200, 'lang' => app()->getLocale(), 'msg' => lang('success'), 'data' => $data]); -
app()->getLocale()是 ThinkPHP 6/8 中获取当前语言码的标准方式(如zh-cn、en-us) - 避免用
Config::get('app.lang'),它返回的是配置默认值,不是运行时实际生效的语言 - 如果接口要兼容旧版,且已有统一响应封装(如
apiReturn()),就把lang字段统一注入到那个封装里,别每个接口都重复写
请求头 Accept-Language 怎么触发自动语言切换
ThinkPHP 默认不根据 Accept-Language 自动切语言,必须手动启用并配置中间件或初始化逻辑。
立即学习“PHP免费学习笔记(深入)”;
- 在
app/middleware.php中注册think\middleware\LoadLangPack(TP6)或确认AppInit中已调用Lang::detect() - 确保
config/app.php中'lang_switch_on' => true已开启,且'allow_lang_list'包含你支持的语言码(如['zh-cn', 'en-us']) -
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8这种格式会被Lang::detect()解析,但只在首次请求(无 cookie/session 时)生效;后续优先看lang参数或 session - 调试时用
curl -H "Accept-Language: en-us" http://api.test/user验证,别只靠浏览器地址栏直输——浏览器头可能被缓存或覆盖
JSON 中文乱码、字段缺失、返回空对象的常见原因
这些问题几乎从不来自多语言本身,而是底层 JSON 输出链路被破坏。
- 语言包文件用了 GBK 编码保存?PHP 文件必须是 UTF-8 无 BOM,否则
lang()返回的字符串是乱码,json_encode()会失败并返回false - 在
json()前不小心echo或var_dump()了?哪怕一个空格也会导致 header 发送失败,响应变成 HTML 文本,前端解析报Unexpected token < - 数据库字段含不可见字符(如零宽空格、BOM 片段)?这些会在
json_encode()后保留,但某些前端 JSON 解析器会静默失败 - 用了
json($data, 200)但$data是 null 或资源类型?json_encode(null)得到null字符串,不是{};资源类型直接返回false,最终输出空响应
真正难排查的,永远是“为什么我明明写了 lang(),返回的还是中文”——大概率是语言检测没生效,或者你根本没进多语言流程,而是 fallback 到了默认语言包。先看 app()->getLocale() 的值,再查语言包路径和内容,比反复改 json() 参数有用得多。



















