Repository navigation
feat(spec): a joined report's block headings and a master-detail field's inline grid heading are translatable - #26757
Conversation
…inlineTitle
A joined report's block label/description and a master-detail field's
inlineTitle are authored, user-visible labels with no translation slot.
Add `reports.<r>.blocks.<b>.{label,description}` and
`objects.<o>.fields.<f>.inlineTitle`, overlay them in translateReport and
translateObject's field pass (packaged-base rule, ADR-0029 D9.2a), walk
them in i18n extract so `os i18n check` counts them, and translate the
example rows that ship them.
Claude-Session: https://claude.ai/code/session_01WGufziF7p6fS8zz6Gtt1gq
Co-authored-by: Claude <noreply@anthropic.com>
…lation slots Claude-Session: https://claude.ai/code/session_01WGufziF7p6fS8zz6Gtt1gq Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): 6 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 154 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin c761fd0abc317684fe1af8353272fe79b868772b && git checkout c761fd0abc317684fe1af8353272fe79b868772b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 88fb255cbac335cc97e9d148daadf164cfec2343 bcbc83749b5adc7aff859f5d2351a0b75cc1e3e1 && git checkout -B drift-repro 88fb255cbac335cc97e9d148daadf164cfec2343 && git merge --no-ff bcbc83749b5adc7aff859f5d2351a0b75cc1e3e1
node scripts/docs-audit/affected-docs.mjs --json 88fb255cbac335cc97e9d148daadf164cfec2343
|
Contract reviewServed-tier: Inputs read: cards #26112 and #26142 with every comment (claim 6442845658, fold pointer 6442877409, os-dev-report 6444984537), PR #26757 body, file list (19 files, 645/27, equal to ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Rendered 2026-10-27T15:04Z · read-only review of head |
维护者速读 (席位终稿)
席位意见:接受。契约复核 PASS(6445499937)。两个 ui 文件不改是实测结论:渲染器读的就是服务端已翻译的文档。 席位核对 · ACCEPT ·
|
Requested by Yibo Wang · project thread
Fixes #26112
Fixes #26142
Clause-②: yes
Metadata-protocol: added
Skills-docs: follow-up owed #26759 —
skills/objectstack-i18n/SKILL.md(thefields.{field_name}row and thereportssentence) missesinlineTitleandreports.{report}.blocks.{block};skills/**is Tier H, so the two-line edit rides that card after this PR lands维护者速读
reports.REPORT.blocks.BLOCK.label/.description),以及主从字段的内嵌表格标题(objects.CHILD.fields.FIELD.inlineTitle);服务端翻译器按请求语言覆盖,os i18n extract/check也开始统计这两个键。packages/spec/src/system/i18n-resolver.ts(translateReportBlocks与translateObject字段处理中的inlineTitle)、packages/spec/src/system/translation.zod.ts(两个新槽位)、packages/cli/src/utils/i18n-extract.ts(walkReports与字段遍历)。pnpm --filter @objectstack/example-showcase exec vitest run test/zh-cn-report-blocks-inline-titles.test.ts,预期 3 个用例通过:示例应用的联合报表区块显示「未完成任务 / 已完成任务」,发票与费用报销的内嵌表格标题显示「发票明细 / 费用明细」。What changes
translation.zod.ts):FieldTranslationSchemagainsinlineTitle; thereportsgroup gainsblocks, a record keyed by the joined block's requiredname, closed atlabel/description(aliasesname/title/headingontolabel).i18n-resolver.ts):translateReportoverlays each block through a newtranslateReportBlocks;translateObject's field pass overlaysinlineTitle. Both follow the packaged-base rule (ADR-0029 D9.2a), judged per block (matched byname) and per field. A document whose blocks and fields the bundle does not address comes back as the same reference.ui/packages/plugin-report/src/DatasetReportRenderer.tsx) drawsblock.labeloffGET /meta/report, andattachInlineSubforms(ui/packages/app-shell/src/providers/MetadataProvider.tsx) copies the child field'sinlineTitleoffGET /meta/object, both localized at the REST boundary. So the fix lands in the two translators, and neither ui file changes.inlineTitlehas no translation slot — the inline child grids on a zh-CN create form read "Versions / Deviations / Payment Plan" #26142 fallback decision: no fallback to the child object's translated plural label. An authoredinlineTitlewith no entry keeps its authored text, because a bundle translates an attribute and never swaps another attribute in over authored text (the rulepages.PAGE.titlefollows). An absentinlineTitlealready renders the child's translated label.i18n-extract.ts):walkReportswalksblocks[], the field walk emitsinlineTitle, both viapushOptional(a block without alabel, or a field without aninlineTitle, is recorded and never demanded).os i18n checkcounts them through the same entries: blocks in the report bucket,inlineTitlein the field bucket.showcase_task_overviewand the invoice / expense-report inline headings; the CRM zh-CN bundle translates the opportunity's product grid heading. Each key is translated at birth, socheck:i18n-coveragestays at its baseline (527, none new).reports.blocksliveness row withlabel/descriptionchildren (translation 36 → 38 live), plusgen:api-surface,gen:export-origins,gen:docs,gen:strictness-ledger,gen:liveness-countsoutput.Tests
packages/spec/src/system/i18n-report-blocks.test.ts(10): the slot at all three doors, the closed face, thetitlealias, the overlay, the BCP-47 ladder, reference identity, and the packaged-base rule per block.packages/spec/src/system/i18n-field-inline-title.test.ts(7): the slot, a non-string refusal, the overlay through the type dispatch with nounrecognized_keys, no plural-label fallback, and the packaged-base rule.packages/cli/test/i18n-block-inline-title-walk.test.ts(5): the extracted keys, unwritten strings recorded without being demanded, the bundle round trip, and coverage reporting both gaps and then clearing them.examples/app-showcase/test/zh-cn-report-blocks-inline-titles.test.ts(3): the acceptance pin for both cards, on the app's own metadata and bundle.Acceptance notes
validate-translation-references(lint) checks thatreports.REPORTnames a real report, but it does not check thatblocks.BLOCKnames a real block of that report, so a mistyped block key resolves nothing without an orphan finding. This is noted, not filed.resolveTextreads an inline locale map'sdefaultonly. That predates this change and is unrelated to the bundle path.Verification
All readings were taken at
bcbc83749(after mergingorigin/main5cc31c788throughos-regen-merge.sh) unless marked as taken at595f62162(the pre-merge head).Tests and typecheck
pnpm --filter @objectstack/spec test(595f621): Test Files 733 passed, Tests 21938 passed / 1 todo.pnpm --filter @objectstack/spec test:repo(595f621): Test Files 80 passed, Tests 1295 passed.pnpm --filter @objectstack/cli exec vitest run --project unit(595f621): Test Files 340 passed, Tests 4928 passed. The integration tier is left to CI: no spawn entry or integration file is touched.pnpm --filter @objectstack/runtime test(595f621): Test Files 459 passed, Tests 7443 passed / 19 skipped.src/system/+src/ui/report*spec tests 64 files / 2150 tests, the two cli i18n walk files 9 tests, and the showcase pin 3 tests, all passing.Ablations (one per behaviour; src-resolved suites, each restored byte-identical by blob hash)
translateReportwith the block pass removed:i18n-report-blocks.test.ts6 failed / 4 passed.translateObjectwith theinlineTitleassignment removed:i18n-field-inline-title.test.ts3 failed / 4 passed.inlineTitlepush deleted: the cli walk test 3 failed / 2 passed.labelpush deleted: the cli walk test 4 failed / 1 passed.Gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 109 families (595f621; the derivation at bcbc837 is the same list). 107 exit 0. Two exit 3 (prerequisite: a whole-repo build),spec check:skill-examplesandcheck:dual-build-cjs-loads, are NOT MEASURED locally and left to CI.--ranreconciliation: 109 derived, 107 run, 2 NOT-MEASURED, 0 UNRUN.check:i18n,check:i18n-coverage,check:i18n-walk-parity, speccheck:liveness,check:empty-state,check:strictness-ledger,check:api-surface,check:authorable-surface,check:generated,check:nul-bytes, all exit 0.!in the title and no(narrowing)arm.Generated by Claude Code