多语言接口需手动接管语言切换逻辑,不能依赖URL参数自动生效;lang()函数在API请求中默认不识别?lang=xx,须在中间件或控制器initialize()中显式调用Lang::setLocale()并校验白名单。

多语言接口必须手动接管语言切换逻辑,不能依赖 URL 参数自动生效;lang() 函数在 API 请求中默认不识别 ?lang=xx,得在中间件或控制器开头显式调用 Lang::setLocale()。
API 请求里 ?lang=en-us 为什么没用
ThinkPHP 的 Lang 类默认只在 Web 页面请求中解析 $_GET['lang'],但 API 接口(尤其是前后端分离、JSON 格式请求)常被当作“非页面请求”跳过该逻辑。即使配置了 lang_switch_on => true,lang() 仍会沿用 default_lang。
- 现象:
lang('user_not_found')始终返回中文,哪怕请求是/api/user?lang=en-us - 原因:框架检测到请求头
Accept: application/json或无 HTML 相关上下文时,主动忽略 GET 参数中的lang - 解决:在全局中间件或 API 基类控制器的
initialize()中提前读取并设置:Lang::setLocale($this->request->param('lang', $this->request->cookie('lang', config('app.default_lang')))) - 注意:必须校验白名单,避免传入
../../../etc/passwd类路径遍历值 —— 用in_array($lang, config('app.lang_list'), true)过滤
lang() 在 JSON 接口返回里怎么安全输出翻译
直接在 return json([...]) 中调用 lang() 是可行的,但容易踩两个坑:键名缺失静默回退、复数语法未触发、嵌套结构错位。
- 缺失 key 时
lang('missing_key')默认返回字符串本身,前端看到 "missing_key" 会误以为后端出错 —— 开发期建议加日志:if (!Lang::has('missing_key')) Log::warning('Missing lang key: missing_key'); - 复数语法如
'item|items'必须传数字参数:lang('item|items', 1)才取左边,lang('item|items', 0)或2取右边;传字符串或 null 会直接返回原串 - 嵌套 key 如
lang('user.status.active')要求语言包里是['user' => ['status' => ['active' => '已激活']],平铺写成'user_status_active'不匹配 - 调试建议:在接口开头加
Log::info('Current lang:', ['locale' => Lang::getLangSet(), 'loaded' => Lang::range()]);
多语言错误提示怎么统一注入到验证器/异常响应
ThinkPHP 的验证器错误信息、系统异常提示(如 404、Token 失效)默认不走 lang(),需手动桥接。
立即学习“PHP免费学习笔记(深入)”;
- 验证器里别写死字符串:
['email' => ['require' => '邮箱必填']]→ 改成['email' => ['require' => lang('email_require')]],并在initialize()中确保语言已设好 - 全局异常处理(
app/exception_handle.php)中,对$e->getMessage()做一次lang()尝试:lang($e->getMessage()) ?: $e->getMessage(),但仅限已知错误码 key - 更稳妥做法:自定义异常类,构造时传入 lang key 和参数,
__toString()内部调用lang($this->key, $this->params) - 注意:不要在
__construct()里调lang()—— 此时Lang可能尚未初始化,尤其在命令行或队列任务中
接口多语言和 SEO 页面语言怎么共存不冲突
同一个域名下既有 JSON API,又有 SSR 页面(如管理后台),语言状态容易互相污染 —— 比如用户在页面点切换语言,API 却没同步;或 API 设置了 cookie,页面却读不到。
- 关键点:
Lang::setLocale()是单次请求内存态,不影响 session 或 cookie;而页面依赖 cookie(think_var)自动识别 - 方案一(推荐):API 响应头带
X-Content-Language: en-us,前端根据它控制 UI 语言,并主动把选中语言存入 localStorage + 同步写 cookie(同域下) - 方案二:所有 API 请求强制带
Cookie: think_var=en-us,后端中间件统一读取,避免重复判断 - 切勿混用:不要在 API 里调
$request->session()->set('lang', $lang)然后期望页面读 session —— 多数前后端分离项目禁用 session,且跨域时不可用 - 兼容性提醒:Linux 服务器上
zh-CN和zh-cn是不同目录,API 和页面必须用完全一致的 locale 字符串,否则语言包加载失败
最易被忽略的是语言包加载时机——Lang::setLocale() 必须在任何 lang() 调用前执行,且不能晚于中间件栈中其他可能触发翻译的组件(比如日志中间件、权限检查)。一旦漏掉,整条请求链路的语言就固定了,后续再设也无效。



















