发现于 #6241 的实施(旁证,与该单改动无关 —— 改前改后同样成立)。基线 origin/main @ 026101660。
事实
packages/rest/src/rest-server.ts 的三个元数据读取 handler 都把原始 的 :type 路径段透传给翻译 helper:
:4033 列表:this.translateMetaItems(req, req.params.type, …)
:4445 / :4579 单条(缓存分支 / 非缓存分支):this.translateMetaEnvelope(req, req.params.type, …)
:4878 复合名:同上
两个 helper 都以 isTranslatableMetaType(type) 作为是否本地化的判据(rest-server.ts:2722 / :2768),而它查的是 TRANSLATABLE_METADATA_TYPES(packages/spec/src/system/i18n-resolver.ts:462)—— 由 METADATA_DOCUMENT_TRANSLATORS 的键派生 ,而那张表只有单数键 :
view / action / object / app / dashboard / page
translateMetadataDocument 的 JSDoc 也写明参数是 "Canonical metadata type string"。于是复数拼写落不进集合,isTranslatableMetaType('apps') === false,整个本地化被跳过。
而 Prime Directive #3 规定 REST 的规范拼写是复数 (/api/v1/meta/apps),元数据路由两种拼写都受理。
实测
真 RestServer.translateMetaItem,zh-CN bundle 提供 apps.setup.label,同一份文档,只改 type 参数的拼写:
singular "app" label = "XLABELX" ← 已翻译
plural "apps" label = "Setup" ← 未翻译(原样英文)
(探针一次性,未提交。)
影响
同属 #3984 记下的「按类型的判断只在单数拼写下生效」家族,但落点不在闸门而在 i18n 判据上:#3984 与 #6241 修的是 handler 内的闸门 读归一值,这条是 handler 把原始值透传给下游 helper ,而该 helper 的判据集合恰好只认单数。
可能的处置(未定,交分诊)
三处落点,择一即可,但必须一次改齐三个 handler ,否则会出现「列表翻译、单条不翻译」这种更难查的不一致:
在 handler 侧传归一值 —— 三个 handler 把 req.params.type 换成已归一的局部量(GET /meta/books/:name(复数拼写)绕过 ADR-0046 §6.7 audience 门禁 —— 缓存分支的 doc/book 排除写的是字面量比较 #6241 之后单条 handler 顶部已有 metaType)。改动最小,但把「谁负责归一」留在了调用方,第四个 handler 仍会忘。
在 helper 侧归一 —— translateMetaItem / translateMetaItems 入口处折叠一次。一处生效、覆盖全部调用方,是「下一个 handler 也不会忘」的形状。
在 spec 侧让 isTranslatableMetaType / translateMetadataDocument 认复数 —— 影响面最大(spec 是契约),且与「单数是 canonical metadata type name」(PD Implement ObjectStack protocol specification with Zod schemas and TypeScript interfaces #3 前半句)相冲,倾向不选。
倾向 2:与 #6241 「归一发生在拥有该职责的那一层」的判据一致 —— REST 的翻译 helper 自己拥有「这个类型翻不翻」的判断,就该由它归一;protocol 对自己的 type 参数正是这么做的(PLURAL_TO_SINGULAR[type] ?? type)。
关联:#6241 (在其实施中测得,互不阻塞)、#3984 (同族前身)、#3786 (该集合改为派生的那次)。
发现于 #6241 的实施(旁证,与该单改动无关 —— 改前改后同样成立)。基线
origin/main @ 026101660。事实
packages/rest/src/rest-server.ts的三个元数据读取 handler 都把原始的:type路径段透传给翻译 helper::4033列表:this.translateMetaItems(req, req.params.type, …):4445/:4579单条(缓存分支 / 非缓存分支):this.translateMetaEnvelope(req, req.params.type, …):4878复合名:同上两个 helper 都以
isTranslatableMetaType(type)作为是否本地化的判据(rest-server.ts:2722/:2768),而它查的是TRANSLATABLE_METADATA_TYPES(packages/spec/src/system/i18n-resolver.ts:462)—— 由METADATA_DOCUMENT_TRANSLATORS的键派生,而那张表只有单数键:translateMetadataDocument的 JSDoc 也写明参数是 "Canonical metadata type string"。于是复数拼写落不进集合,isTranslatableMetaType('apps') === false,整个本地化被跳过。而 Prime Directive #3 规定 REST 的规范拼写是复数(
/api/v1/meta/apps),元数据路由两种拼写都受理。实测
真
RestServer.translateMetaItem,zh-CN bundle 提供apps.setup.label,同一份文档,只改 type 参数的拼写:(探针一次性,未提交。)
影响
packages/client的 SDK 对拼写不做加工,this.url('/meta/' + type + '/' + name)原样转发调用方给的拼写,所以照着 PD Implement ObjectStack protocol specification with Zod schemas and TypeScript interfaces #3 写的调用方正好踩中。未断言具体哪个仓内调用点用了复数拼写读可翻译类型 —— 这条按可达性写,不按已观测的线上故障写。与 #3984 / #6241 的关系
同属 #3984 记下的「按类型的判断只在单数拼写下生效」家族,但落点不在闸门而在 i18n 判据上:#3984 与 #6241 修的是 handler 内的闸门读归一值,这条是 handler 把原始值透传给下游 helper,而该 helper 的判据集合恰好只认单数。
可能的处置(未定,交分诊)
三处落点,择一即可,但必须一次改齐三个 handler,否则会出现「列表翻译、单条不翻译」这种更难查的不一致:
req.params.type换成已归一的局部量(GET /meta/books/:name(复数拼写)绕过 ADR-0046 §6.7 audience 门禁 —— 缓存分支的 doc/book 排除写的是字面量比较 #6241 之后单条 handler 顶部已有metaType)。改动最小,但把「谁负责归一」留在了调用方,第四个 handler 仍会忘。translateMetaItem/translateMetaItems入口处折叠一次。一处生效、覆盖全部调用方,是「下一个 handler 也不会忘」的形状。isTranslatableMetaType/translateMetadataDocument认复数 —— 影响面最大(spec 是契约),且与「单数是 canonical metadata type name」(PD Implement ObjectStack protocol specification with Zod schemas and TypeScript interfaces #3 前半句)相冲,倾向不选。倾向 2:与 #6241 「归一发生在拥有该职责的那一层」的判据一致 —— REST 的翻译 helper 自己拥有「这个类型翻不翻」的判断,就该由它归一;protocol 对自己的
type参数正是这么做的(PLURAL_TO_SINGULAR[type] ?? type)。关联:#6241(在其实施中测得,互不阻塞)、#3984(同族前身)、#3786(该集合改为派生的那次)。