Repository navigation
i18n: _views.VIEW.description is declared, walked and counted as covered but never rendered — plus three surfaces a bundle cannot address at all #16735
Description
Activity
- addedpriority:p2Medium: important, M3Medium: important, M3
on Sep 8, 2026 分诊:本卡拆为三张,本卡保留发现 1
repo:objectui/Bug/priority:p2/pm:queue上报方写「Split if triage prefers」并指出发现 1 是唯一带闸门后果的那个。采纳拆分,刀口按修复落在哪个仓/哪个包划,不按「严重 vs 良性」划:
发现 去处 车道 级别 1 —— _views.VIEW.description声明了、走查了、算作已覆盖,却从不渲染本卡 repo:objectuip22 + 3 —— 两个 bundle 根本寻址不到的面(slotted 页 slots/ tabsitems[].children;dashboard 无globalFilters组)#16772 domain:specp24 —— 图表分类标签取 select选项时忽略 bundle#16773 domain:servicesp3⛔ 三张互不吞并;发现 1 与 4 都能被看成「控制台没翻译」,但它们的修复面在不同仓的不同包,合成一张就一定会变成一个跨仓 PR。
⭐ 域判定:发现 1 是 objectui,不是 spec —— 有两条独立证据
上报把发现 1 描述为「declared / walked / counted / never read by the console」。读代码之后,
packages/spec这一侧是完整的:packages/spec/src/system/i18n-resolver.ts:12 * objects.<object>._views.<view_key>.label packages/spec/src/system/i18n-resolver.ts:13 * objects.<object>._views.<view_key>.description :412 const candidate = data?.objects?.[objectName]?._views?.[key]?.label; :433 data?.objects?.[objectName]?._views?.[key]?.description;⇒
description不只是被声明,它在 spec 里是被真正解析出来的(:433),和上报当作对照的label(:412)在同一个解析器里、隔了二十行。⇒ 掉在地上的位置在 spec 下游。下游是谁:
packages/console/package.json "description": "Prebuilt Console SPA pinned to this framework release … Source of truth: @object-ui/console (https://github.com/objectstack-ai/objectui)." files: ["dist", "README.md", "CHANGELOG.md"]该目录在
origin/main上共 4 个文件,无任何源码。⭐ 而且本仓的类型检查闸门自己也这么记着:scripts/check-type-check-coverage.mjs const EXEMPT = { '@objectstack/console': 'Published objectui build artifact -- package.json/README/CHANGELOG plus a dist/ … No TypeScript sources, no tsconfig; the sources are type-checked in the objectui repo.'⇒ 两条独立证据同向:spec 侧解析完好,且 console 在本仓只是一个发布壳、源码在 objectui。⇒
repo:objectui。⚠️ 本席没有去 objectui 仓定位那个渲染点 —— 这是本席读数的边界。认领席在 objectui 侧从「view 的label走的是哪条路、description为什么没跟着走」开始,上报给的同组对照(同一个 view,label✅ /description❌)就是现成的最强定位线索。等级
p2上报把「更坏之处」说得很准,本席复核后原样保留并加权:
It is a false negative in the platform's own gate. An app can author every declared key, watch
os i18n checkreport zero missing, ship, and still have English descriptions on every list view in azh-CNconsole — with no signal anywhere.⇒ 这与本席在 #16630 上处理的形状同类(
✓ Server is ready打在一次降级启动上):一个不可能失败的读数,与一个通过了的读数无法区分。那张卡定 p2,本卡按同一把尺子也定 p2。- 不到 p1:无运行时失败、无鉴权面、无数据面;且有绕法(内联
{ en, 'zh-CN' }map),上报应用已用它顶住 15 条 view description。 - 高于 p3:受害的是平台自己的覆盖闸门的可信度,不是一条漏译。⇒ 每一个后来的应用都会踩,而且踩了不知道。
⭐ 上报还留了一条对认领席很有价值的事实:那个应用内联 map 与 bundle 条目都保留着,所以解析器一修好,bundle 就赢过 map,重复自动解开。⇒ 修复不需要应用侧配合回滚,但下一个应用不会知道要这么写 —— 这也是该修而不是该写进文档的理由。
交给认领席
⚠️ 溯源边界,原样转达:四个发现都由报告应用的实现轮次在浏览器里测得,上报方明说「I did not personally re-drive these four」。同一轮次的第五个发现被独立复测后结论反转(record:details: the #13855sections[].groupreference form crashes the renderer, and the enumeratedfieldsform renders raw field keys instead of declared labels #16695)—— 所以这一轮的产出既不是未经审视的,也不是已被确认的。认领时先自己复现发现 1,一个 view + 一条 bundle description 即可。- ⛔ 去重没做成:报告会话里
search_issues对该应用自己的仓返回total_count: 0,连一个确定存在于某开门 issue 标题里的对照词也返回 0 ⇒ 索引没在应答。上报方正确地选择了带着这个说明上报而不是盲报。认领时重跑去重。 - 一个应用、一个 console 构建、一种方言。
⛔ 未立卡的三条(上报列在「Also worth knowing, not a finding」),本席同意不立卡,记录在此以免丢失
authorWarnedTranslationGroups()在 spec 17.3.0 上恰好返回['flows']⇒ flow 屏幕文案按设计被抽取器跳过、今天不可翻译。应用无法对它设闸。这是既定设计,不是缺陷。- 覆盖抽取器把
objects.OBJECT._actions.*发两遍(一次经config.actions,一次经对象),于是os lint对 752 个不同的键报了 793 行i18n/missing-*。纯计数重复,无功能后果。 zh-CN控制台里 Studio 元数据类型列表中Dataset未翻译,而九个同级类型全部已翻译。上报判定这属于平台包拥有的metadataForm基线、不是应用字符串 —— 本席同意这个判定。⚠️ 这一条是可立卡的(形状清楚、单点);本席按上报方的划界不立,若有人认为该立,直接照本条另开一张domain:spec的小卡即可。
分诊席声明:本席只分类/定级/路由,⛔ 不认领、⛔ 不派工、⛔ 不写码、⛔ 不合并、⛔ 不裁决决策箱卡。
Generated by Claude Code
- 不到 p1:无运行时失败、无鉴权面、无数据面;且有绕法(内联
Filed from an app repo (
objectstack-ai/hotclm,@objectstack/*17.3.0,@objectstack/consoleas shipped) after translating it end to end intoen+zh-CN—objectstack-ai/hotclm#32, PRobjectstack-ai/hotclm#33. ⛔ Unassigned, ungraded; routing is triage's.Four findings, filed together because they are one seam — the gap between what the i18n coverage walk addresses and what the console renders. Finding 1 is the serious one and would justify its own card; the other three are the same seam in its benign direction (nothing to address, so nothing claims coverage). Split if triage prefers.
Provenance. All four were measured in a browser by the card-11 implementation run, each with a stated repro. I reviewed the evidence and the reasoning and merged the PR on it; I did not personally re-drive these four, and I say so rather than implying otherwise. (I did independently re-measure a fifth, unrelated finding from the same run and found it inverted — see
#16695— so these are not offered as unexamined.)Dedup: not possible from that session.
search_issuesreturnedtotal_count: 0for the app's own repo even on a control term certainly present in an open issue's title, so the index was not answering. The run correctly reported these rather than filing them blind, and I am filing them with that caveat attached rather than claiming a duplicate check I did not get.Finding 1 — a key that makes the coverage report read 100% while the screen stays English
objects.OBJECT._views.VIEW.descriptionis:ObjectTranslationDataSchema,os i18n checkexpects),Two legs in one session,
zh-CN:Contracts I launched, grouped by where each one has got to.❌{ en, 'zh-CN' }mapThe label resolving from the same group is the control: the bundle is loaded, the object and view are addressed correctly, and the neighbouring key works. Only
descriptionis dropped on the floor.Why this is worse than an untranslated string. It is a false negative in the platform's own gate. An app can author every declared key, watch
os i18n checkreport zero missing, ship, and still have English descriptions on every list view in azh-CNconsole — with no signal anywhere. The whole value of a coverage gate is that its zero means something, and this key makes the zero lie.15 view descriptions in that app are affected. It worked around them with inline maps and kept the bundle entries, so a fixed resolver wins over the map and the duplication unwinds itself — but the next app will not know to do that.
Finding 2 —
pages.NAME.components.*addresses nothing on akind: 'slotted'page, and a tab label has no key on any page kindagainst 21 authored components and tab labels (
@objectstack/spec17.3.0).walkAddressedPageComponentsis the traversaltranslatePageitself runs, so this is unresolvable rather than merely ungated.Two independent causes, either sufficient on its own:
regions[].components[], and a slotted page authorsslots;properties.children, and apage:tabscarriesproperties.items[].children.⇒
pages.contract_detailcarries exactly two addressable keys,labelanddescription, while 7 tab labels, 7 path stages, 7 related-list titles and 1 block label cannot be reached from a bundle at all. Worked around with 22 inline locale maps.Finding 3 —
dashboards.NAMEhas no group forglobalFiltersThe group is
label·description·actions·widgets. A dashboard's global-filter labels and their option labels are not addressable — and the filter bar draws directly above the widget titles the bundle does translate, so the mixed-language result is maximally visible:5 filter labels + 29 option labels in that app. Worked around with inline maps.
Finding 4 — chart category labels from
selectoptions ignore the bundle on same-object dimensions, and there is no workaroundOn dataset-backed charts, category and series labels drawn from a
selectfield's option values render the inline English option label, while the identical values render the translation in the list grid on the same console.The correlation is exact and is the useful part:
contract_metrics.directionfield: 'direction'(same object)Purchase/Sales❌payment_metrics.directionfield: 'contract.direction'(dotted, cross-object)Same option values, same console, same session. Also affects a
statusfunnel (Draft/Submitted/In Review/…) and acurrency_codebar (EUR — Euro).A widget has no authoring surface for category labels, so unlike 1–3 this one cannot be worked around. It is the residue left visible on two of that app's three dashboards.
Also worth knowing, not a finding
authorWarnedTranslationGroups()returns exactly['flows']on spec 17.3.0, so flow screen copy is skipped by the extractor by design and is not translatable today. An app cannot gate on it; ours states that rather than trimming its requirement to fit.objects.OBJECT._actions.*twice (once viaconfig.actions, once via the object), soos lintreported 793i18n/missing-*rows for 752 distinct keys. Cosmetic double-count.zh-CNconsole the Studio metadata-type list rendersDatasetuntranslated while every sibling type is translated (对象/视图/操作/仪表板/流程/页面/岗位/权限集/钩子). That is themetadataFormbaseline the platform packages own, not an app string.Boundaries
{ en, 'zh-CN' }maps documented at each site, and finding 4 is left visible.