5.2 KiB
5.2 KiB
todos:
- id: "middleware" content: "新建 app/middleware/Language.php:读 X-Lang、归一化、每请求 locale()、设 $request->language" status: pending
- id: "register" content: "config/middleware.php 全局组在 TraceId 前注册 Language 中间件" status: pending
- id: "config" content: "config/translation.php 增加 supported=['zh_CN','en'],保留默认 zh_CN" status: pending
- id: "trans-files" content: "新建 resource/translations/{zh_CN,en}/messages.php,含 errors(按 OtaErrorCode)+ validation + common.ok" status: pending
- id: "exception" content: "BusinessException message 改可选;Handler 渲染时 trans('errors.'+code);Logic 7 处抛出去掉中文只传 code" status: pending
- id: "result-auth" content: "Result::fail 支持空 message 回退 trans;AdminAuth/InternalTokenAuth 去掉中文消息" status: pending
- id: "validate" content: "3 个 validator 的 $message 改翻译 key;AdminController::validate 返回前 trans();补全 validation.* 译文" status: pending
- id: "verify" content: "internal/admin 带 X-Lang 验证消息随 locale 变化 + 连续请求无串台,跑收尾检测脚本" status: pending isProject: false
OTA 接口国际化(i18n)
结论先行
「中间件解析 header」思路正确,但在 Webman(常驻进程)里核心动作是 locale($lang),不是把语言塞进 $request->language。$request->language 只作附带标记(给 Logic/日志用,非必须)。已具备:config/translation.php、symfony/translation。缺:语言中间件、翻译文件、把硬编码消息接到 trans()。
约定:自定义头 X-Lang(值 zh_CN / en),默认 zh_CN,覆盖 internal + admin。
数据流
flowchart LR
req["HTTP 请求 X-Lang: en"] --> lang["Language 中间件 locale(en) + request->language"]
lang --> auth["Auth 中间件 Result::fail(code)"]
auth --> ctrl["Controller / Validate"]
ctrl --> logic["Logic throw BusinessException(code)"]
logic --> handler["Handler trans(code) 渲染"]
handler --> resp["{code, message(已按 locale 翻译), data}"]
改动点
1. 语言中间件(新增)
新建 app/middleware/Language.php(MiddlewareInterface):
- 读
X-Lang(可兼容X-Language),归一化(zh/zh-CN/zh_cn→zh_CN;en/en-US→en),不在支持列表则用默认。 - 每个请求都调
locale($lang)(进程级全局状态,必须每请求重置,否则串语言)。 - 设
$request->language = $lang(附带)。 - 支持列表 + 默认值读
config('translation')(见第 5 步)。
2. 注册为全局中间件
config/middleware.php 的 '' 组在 TraceId 前加入 app\middleware\Language::class,确保 admin/internal 鉴权失败消息也按 locale 翻译。
3. 翻译文件(新增)
新建 resource/translations/zh_CN/messages.php 与 resource/translations/en/messages.php,返回两段:
errors=> 以OtaErrorCode各常量字符串为 key 的消息(对应现 Logic / Auth 里的中文)。validation=> 校验消息 key(见第 6 步)。
调用形如 trans('errors.' . $code)、trans($validationKey)。
4. 消息改为 trans() 取值
- app/exception/Handler.php:渲染
BusinessException时message = trans('errors.' . $code)(为空回退 code)。 - app/exception/BusinessException.php:
message改为可选;Logic 抛出时只传 code,去掉硬编码中文(FirmwareLogic5 处、OtaReportLogic/OtaCheckLogic/UpgradeRecordQueryLogic各 1 处)。需要动态文案的保留可选 message 入参。 - app/support/Result.php:
fail(string $code, ?string $message = null, ...),$message为空时取trans('errors.' . $code);成功message用trans('common.ok')。 - 两个 Auth 中间件(
AdminAuth、InternalTokenAuth)Result::fail去掉中文,只传 code。
5. 配置补充
config/translation.php 增加 supported => ['zh_CN','en'],locale 维持 zh_CN 作默认。中间件据此校验/回退。
6. 校验消息国际化(think\Validate)
为统一到单一 i18n(trans),不引入 think\Lang 第二套:
- 3 个 validator(
FirmwareCreateValidate、FirmwareListValidate、UpgradeRecordListValidate)的$message值改为翻译 key(如validation.firmware.product_key_required)。 - app/admin/controller/AdminController.php
validate()返回前对错误信息做trans()(key 命中则翻译,未命中原样返回)。 - 两个 locale 的
messages.php补全这些validation.*key。
验证
- internal:
POST /internal/ota/check带/不带X-Lang: en,断言鉴权失败、业务异常、参数错误的 message 随 locale 变化。 - admin:固件创建非法参数,
X-Lang: en返回英文校验消息。 - 连续两请求(en 后 zh_CN)验证无 locale 串台(常驻进程回归)。
- 收尾跑
~/.cursor/skills/slot-backend-completion-report/scripts/report.sh并附检测结果。
不做 / 待确认
- 不替换为 Accept-Language(已选自定义头)。
- 英文译文先给准确直译,文案润色后续可调。