在做 #3502(objectstack#5164 裁 A 的 objectui 段,viewSuffixes 去掉带前缀第二候选)时发现的相邻缺陷,不在该单范围内(不同包、不同事实),按 PD #10 单独立此单,未在 PR #3768 里修。
结论
objectstack#5164 收敛的是「_views 翻译键的拼写」,四面清单里 objectui 只列了 packages/i18n 的 viewSuffixes。但 objectui 还有第五个面没进清单:packages/app-shell 自己推导视图名,用的正是第 1 棒刚退休的 ?? 'list' 方言。于是一个只声明了默认 list(无 name)的对象,它的列表视图标签在 objectui 上永远回落英文。
证据
组装器身份(权威) —— 用仓内安装的 @objectstack/spec 实测:
node -e "import { expandViewContainer } from '@objectstack/spec'; ..."
expandViewContainer('showcase_contact', { list: { columns: ['name'] } })
→ [ { name: 'showcase_contact.default', viewKind: 'list' } ]
@objectstack/spec 自己的 d.ts 也写着:the default listimplicitly claims{object}.default``。第 1 棒(objectstack#6124,b3c1f3cd5)已把提取器改成向组装器查询这个键,所以转换后的译文包里该视图的键是 `objects.showcase_contact._views.default.label`。
objectui 侧的推导(三处,全是 'list'):
packages/app-shell/src/providers/MetadataProvider.tsx:207 — const k = view.list.name || 'list'; bucket.listViews[k] = view.list;
packages/app-shell/src/views/ObjectView.tsx:562 — const primaryId = primary.name || 'list';
packages/app-shell/src/views/ObjectView.tsx:640 — const primaryId = primary.name || 'list';(把 primary 提到 viewList 首位,id: primaryId)
汇合点:ObjectView.tsx:820 / 1881 用 viewLabel(objectDef.name, view.name || view.id, …)。无名 primary 的 view.name 是 undefined,view.id 就是上面推出来的 'list',于是 useObjectLabel 探测 objects.{obj}._views.list.label —— 而译文包里是 ..._views.default.label。命不中 → 回落英文。AppHeader.tsx:695-698 同链路。
全仓 grep:objectui 没有任何一处使用组装器身份 default(isAggregatedViewContainer 只在 spec-symbol-parity 测试里出现,expandViewContainer 在 src/ 内零调用)。
这是回归,而非旧疾
第 1 棒之前提取器写的是 _views.list.*,与 objectui 的 'list' 恰好对上,所以在 objectui 上是能命中的(不一致体现在 lint/注册表那一侧,即 #5164 的原始症状)。第 1 棒把键改名成 default 并同步迁移了 showcase / app-todo 的译文包之后,objectui 这一侧就落空了。objectui 仓内没有覆盖「默认列表视图标签解析」的测试,所以两仓 CI 都不会红。
影响
只声明默认 list(无 name)的对象 —— showcase 上有若干个 —— 在 objectui 里列表视图标签(以及 viewDescription / viewEmptyState)显示英文默认文案。与 #3502 的收窄无关:#3502 删掉的是「带对象前缀的全名」候选,这里落空的是裸键本身拼错了(list vs default),改不改 #3502 都一样。
建议方向(contract-first,勿在消费端加 ?? 兜底)
⛔ 不要在 viewSuffixes 里加 list → default 的双读 —— 那正是 #5164 裁 A 要消掉的第二方言。正确方向是让 objectui 别自己推:三处 name || 'list' 改为向 @objectstack/spec 的组装器要运行时身份(expandViewContainer / 与之等价的单视图身份函数),与第 1 棒对提取器的修法同构(该 PR 的验收意见明确说「向组装器查询比字面改 ?? 'default' 更忠实于裁决本义,且自动继承折叠规则」)。
注意这不只是译文键:primaryId 同时用作 viewList 的 id、viewOverrides 的查询键、以及 defaultViewId。改名可能牵动已保存的视图 override 记录键(listViewOverrides),需要判断是否要带迁移 —— 这一层请分诊时评估,可能需要维护者拍板,故本单未擅自动手。
相关
在做 #3502(objectstack#5164 裁 A 的 objectui 段,
viewSuffixes去掉带前缀第二候选)时发现的相邻缺陷,不在该单范围内(不同包、不同事实),按 PD #10 单独立此单,未在 PR #3768 里修。结论
objectstack#5164 收敛的是「
_views翻译键的拼写」,四面清单里 objectui 只列了packages/i18n的viewSuffixes。但 objectui 还有第五个面没进清单:packages/app-shell自己推导视图名,用的正是第 1 棒刚退休的?? 'list'方言。于是一个只声明了默认list(无name)的对象,它的列表视图标签在 objectui 上永远回落英文。证据
组装器身份(权威) —— 用仓内安装的
@objectstack/spec实测:@objectstack/spec自己的 d.ts 也写着:the defaultlistimplicitly claims{object}.default``。第 1 棒(objectstack#6124,b3c1f3cd5)已把提取器改成向组装器查询这个键,所以转换后的译文包里该视图的键是 `objects.showcase_contact._views.default.label`。objectui 侧的推导(三处,全是
'list'):packages/app-shell/src/providers/MetadataProvider.tsx:207—const k = view.list.name || 'list'; bucket.listViews[k] = view.list;packages/app-shell/src/views/ObjectView.tsx:562—const primaryId = primary.name || 'list';packages/app-shell/src/views/ObjectView.tsx:640—const primaryId = primary.name || 'list';(把 primary 提到viewList首位,id: primaryId)汇合点:
ObjectView.tsx:820/1881用viewLabel(objectDef.name, view.name || view.id, …)。无名 primary 的view.name是 undefined,view.id就是上面推出来的'list',于是useObjectLabel探测objects.{obj}._views.list.label—— 而译文包里是..._views.default.label。命不中 → 回落英文。AppHeader.tsx:695-698同链路。全仓 grep:objectui 没有任何一处使用组装器身份
default(isAggregatedViewContainer只在spec-symbol-parity测试里出现,expandViewContainer在src/内零调用)。这是回归,而非旧疾
第 1 棒之前提取器写的是
_views.list.*,与 objectui 的'list'恰好对上,所以在 objectui 上是能命中的(不一致体现在 lint/注册表那一侧,即 #5164 的原始症状)。第 1 棒把键改名成default并同步迁移了 showcase / app-todo 的译文包之后,objectui 这一侧就落空了。objectui 仓内没有覆盖「默认列表视图标签解析」的测试,所以两仓 CI 都不会红。影响
只声明默认
list(无name)的对象 —— showcase 上有若干个 —— 在 objectui 里列表视图标签(以及viewDescription/viewEmptyState)显示英文默认文案。与 #3502 的收窄无关:#3502 删掉的是「带对象前缀的全名」候选,这里落空的是裸键本身拼错了(listvsdefault),改不改 #3502 都一样。建议方向(contract-first,勿在消费端加
??兜底)⛔ 不要在
viewSuffixes里加list→default的双读 —— 那正是 #5164 裁 A 要消掉的第二方言。正确方向是让 objectui 别自己推:三处name || 'list'改为向@objectstack/spec的组装器要运行时身份(expandViewContainer/ 与之等价的单视图身份函数),与第 1 棒对提取器的修法同构(该 PR 的验收意见明确说「向组装器查询比字面改?? 'default'更忠实于裁决本义,且自动继承折叠规则」)。注意这不只是译文键:
primaryId同时用作viewList的id、viewOverrides的查询键、以及defaultViewId。改名可能牵动已保存的视图 override 记录键(listViewOverrides),需要判断是否要带迁移 —— 这一层请分诊时评估,可能需要维护者拍板,故本单未擅自动手。相关
viewSuffixes:去掉带前缀全名第二候选 —— objectstack#5164 裁 A 的 objectui 段 #3502 / PR fix(i18n): resolve_viewstranslation keys by the bare view name only (#3502) #3768(第 3 棒 objectui,只动packages/i18n)_views/viewLabel/primaryId/name || 'list'),无同题单。