Repository navigation
Description
objectstack lint's i18n coverage is driven by a shared walker whose kind union
simply has no entry for an app object's _sections:
packages/cli/src/utils/i18n-extract.ts:93-108—ExpectedEntry['source']is
object | field | option | view | action | globalAction | app | navigation | dashboard | widget | page | metadataType | metadataFormSection | metadataFormField. The twometadataForm*kinds cover Studio metadata
forms (metadataForms.<type>.sections.*, hidden behind
--include-platform), not app objects.- The walker never emits an
objects.<o>._sections.*path: the string
'_sections'does not occur ini18n-extract.ts, and nothing walks
fieldGroupsor a field'sgroup. packages/cli/src/utils/i18n-coverage.ts:190-204(COVERAGE_SOURCE) mirrors
the same union, socomputeI18nCoveragestructurally cannot report a missing
section heading.
Yet the surface is real and supported end-to-end everywhere else:
ObjectTranslationDataSchema declares _sections
(packages/spec/src/system/translation.zod.ts), the resolver applies them
(record detail pages render translated headings), and os i18n extract will
never scaffold them either — same walker.
Code references pinned to main @ 98369a8.
Measured impact (HotCRM, four locales)
HotCRM's metadata declares 85 sections across 15 objects (union of field
groups and page/view sections[].name). Before objectstack-ai/hotcrm#697,
ja-JP and es-ES each carried 2 of 85 — English headings on essentially
every record page and form — while objectstack lint reported 0 i18n
warnings for both. The gap also kept growing invisibly: objects added later
(crm_event, crm_event_attendee) shipped with headings untranslated in every
locale, and nothing flagged it. Downstream had to build its own guard
(hotcrm#697) deriving the expected set from metadata.
Suggested fix shape
Add a section kind to the walker: emit
objects.<o>._sections.<key>.label for (a) every distinct group across an
object's fields — the fields are the authority for which sections exist;
fieldGroups[].label supplies the default-locale text — and (b) every
sections[].name under the object's pages/form views. Both sources are needed;
detail pages nest sections inside page:tabs → components → properties.sections, which a shallow walk misses. COVERAGE_SOURCE then maps
it, giving lint an i18n/missing-section category and the extractor the
scaffold for free (they share the walker — that co-derivation is the point of
collectExpectedEntries).
Related: #5164 (the _views key-spelling disagreement between composer,
extractor and lint — adjacent producer-drift problem on the neighbouring group).
Downstream: objectstack-ai/hotcrm#683 (part 2).
Activity
baozhoutao commentedon Aug 5, 2026
分诊(cli 车道 PM,
session_016FNvXhtSdnEGEfLEsMmvxh,2026-08-05):入队pm:queue并即时派发。判级:auto-queue 类 —— 具名位置(walker kind union 缺section)+ 实测影响(HotCRM 85 section 仅 2 有译文而 lint 零告警)+ 修法草图齐备,属「声明即强制」恢复不变量类(spec 声明_sections、resolver 消费,唯独覆盖面结构性缺位)。查重仅相邻 #5377(spec 车道,tab label)与 #5164(_views拼写,已留串行备忘),无重复。walker 两文件自674ac99后无 churn,前提引用(98369a8)仍有效。维护者可否决。认领:PM 循环第 2 轮(cli 车道)
会话:
session_016FNvXhtSdnEGEfLEsMmvxh分支:
claude/issue-5405-i18n-walker-sectionsWorktree:
objectstack-issue-5405域:
domain:cli文件面:
packages/cli/src/utils/i18n-extract.ts、packages/cli/src/utils/i18n-coverage.ts+packages/cli对应测试(与在飞 #5412commands/doctor.ts不相交)执行口径:按 issue 修法草图 —— walker 增
sectionkind,双源取齐(字段group的去重集为准 + pages/form views 的sections[].name,注意 detail page 的深嵌套page:tabs → components → properties.sections);COVERAGE_SOURCE映射之,lint 得i18n/missing-section类别,extractor 骨架随共享 walker 免费获得。⛔ 不动_views族(#5164 领地,截断待修复)。Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
验收(cli 车道 PM,
session_016FNvXhtSdnEGEfLEsMmvxh):ACCEPT → PR #5416。origin/main逐验成立(零命中带_views=9 反查对照);声明面(ObjectTranslationDataSchema._sections)与消费面(sectionLabel三处渲染端)双向核实,「只有走查器不知道这个面」定性准确。deriveFieldGroupLayout)与共享页面走查(lintwalkPageComponents)取齐 —— 「声明的 = 被门禁的」是同一个集合而非两张会漂移的清单;重绑定组件按自身绑定记 key 这条正确性,正是复用而非重抄的收益。packages/lint/src/index.ts一行导出,理由充分(lint: no reference-integrity or option-key validation for app metadata #3583 先例:重复实现该走查已产出过死规则),changeset 如实计 lint minor,lint 全量 1198 例绿。该偏移经复核为正确工程判断,记录在案。??别名读法 (#5017) #5046 纪律逐条补正向配对;22 例新增,真实 showcase 取数 6 key 精确断言,60s 超时齐备。objects.*._sections—— 段落标题不再是「声明了、渲染了、却零告警」的面 (#5405) #5416 落地后与 linttranslation-target-unknown的矛盾已由 dev 预先立案(lint:translation-target-unknownmisses a view container's DEFAULTform.sections— correctly translating a rendered heading is reported as a stale key #5415)并复现——该单本 PM 即刻分诊处理,缩短两规则打架的窗口。下一步:CI 全绿后转 ready 入合并队列,跟到 MERGED。
Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
REWORK 第 1 轮(cli 车道 PM,
session_016FNvXhtSdnEGEfLEsMmvxh,2026-08-05 10:5xZ):PR #5416 CI 一处红 ——check:i18n-coverage棘轮(showcase 未翻译声明串 451 → 461)。非缺陷,是本功能的正确后果:walker 新采出的 showcase_sectionskey 在其声明支持的 locale 语言包里没有译文,repo 级门当场逮住(dev 本地只跑了包级 typecheck,覆盖不到该门)。已按同一认领返工原 dev:脚手架 + 按 showcase 既有体例翻译新 key,⛔ 不动棘轮基线、不缩 supportedLocales;pnpm check:i18n-coverage回到 ≤451 后追加 commit(auto-merge 已挂,绿即自动入队)。文件面追加examples/app-showcase/**翻译 bundle,PM 批准记录在案。Generated by Claude Code
i18n(showcase): 翻译 walker 新采出的 10 个段落标题 (#5405)
baozhoutao commentedon Aug 5, 2026
REWORK 第 1 轮闭环(cli 车道 PM,
session_016FNvXhtSdnEGEfLEsMmvxh):修复 commite3d1e855c已推同分支,验收通过。examples/app-showcase/src/system/translations/index.ts,基线文件与supportedLocales均未触;10 个 zh-CN key(showcase_task 8 + showcase_semantic_zoo 2)按 bundle 既有词汇表取词。刻意落在恰好 451 —— 棘轮双向,多译反而要动基线,dev 的判断正确。check-i18n-coverage: OK … none new;原有验证无回归(cli 750 例、showcase 124 例、三包 typecheck 绿)。examples/),此类改动 push 前必须跑 repo 级check:i18n-coverage(需先turbo run build)。后续 cli/lint 面派发词携带此条。ContactViews未注册(showcase:ContactViewsis exported but never registered inobjectstack.config.ts— the docs' canonical "create form ≠ edit form" example does not run #5420),其 4 个 section 对真实 config 的门不可见 —— 该证据已由 dev 补到 showcase:ContactViewsis exported but never registered inobjectstack.config.ts— the docs' canonical "create form ≠ edit form" example does not run #5420,与本 PM 的串行注记互证。CI 绿后 auto-merge 自动入队,跟到 MERGED。
Generated by Claude Code
fix(cli): i18n 覆盖走查收集 `objects.*._sections` —— 段落标题不再是「声明了、渲染了、却零告警」的面 (
fix(showcase): register `ContactViews` in the stack config (objectsta…
feat(lint): warn when a form section has a `label` but no `name` — th…