Repository navigation
feat(spec,cli,lint): translate a form section entry's label, placeholder and helpText from _sections.SECTION.fields.FIELD - #25620
Conversation
…elpText from _sections.<section>.fields.<field> Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkEdTSFyHwijHNXRdNTARE
… entry copy keys Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkEdTSFyHwijHNXRdNTARE
… copy Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkEdTSFyHwijHNXRdNTARE
…ounts Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkEdTSFyHwijHNXRdNTARE
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkEdTSFyHwijHNXRdNTARE
📓 Docs Drift CheckThis PR changes 3 package(s): 10 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 4 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 151 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 f34af0988cebc62ddf388bb9fe459e09d813ee79 && git checkout f34af0988cebc62ddf388bb9fe459e09d813ee79
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 7265b33e779e1d63afe50fb86e411beda7582838 37a9e0fee342606e7c11b2c5877e27c009a22d28 && git checkout -B drift-repro 7265b33e779e1d63afe50fb86e411beda7582838 && git merge --no-ff 37a9e0fee342606e7c11b2c5877e27c009a22d28
node scripts/docs-audit/affected-docs.mjs --json 7265b33e779e1d63afe50fb86e411beda7582838
|
席位核对ACCEPT · #25459 ·
Generated by Claude Code |
Contract reviewServed-tier: Inputs: card #25459 (body and every comment; the triage grade is the row in round record 6369194370 on #6015: p2, spec, i18n; no maintainer ruling on the card), PR #25620 body and file list, the net diff of ① Derived judgments
② Semver level
Clause-②: yes (widening) ③ Boundary flagsDev report
Check-runs on Implemented-by: VERDICT: PASS |
Fixes #25459
Clause-②: yes (widening)
Metadata-protocol: added
What
A form section entry (
{ field, label, placeholder, helpText }in a form view'ssections[].fields) overrides the object field's copy for that form. A translation pack had no key for those three strings, andtranslateViewnever readconfig.sections[].fields[], so a public form's entry overrides stayed in the authoring language beside translated headings and field labels.The address, kept to the one
_sectionsconvention:SECTIONis the section'snameandFIELDthe entry's ownfield.Landing (as the PM measured, confirmed)
packages/spec/src/system/translation.zod.ts:_sections.SECTIONgains a strictfieldsrecord of{ label, placeholder, helpText }(help/hint/tooltipare refused with the rename tohelpText;entriesis refused with the rename tofields).packages/spec/src/system/i18n-resolver.ts:translateFormSectionsnow calls a newtranslateFormSectionEntriesfor each named section. The rules are the section rules, one level down: only copy the entry authors is translated, a missing key keeps the authored string, and an entry string that diverged from the packaged section's entry with the samefieldkeeps its value (ADR-0029 D9.2a, through the existingpackagedPart+valueOverridesPackagedBase, no second comparison). No address: a section without aname, a bare field-name entry, and a composite entry's sub-fields.packages/cli/src/utils/i18n-extract.ts(domain:serverrider, scaffold only):walkObjectSectionsemits the key for every entry string a form view's named section authors, from the same three form-view anchors the heading walk reads (view.sections,form.sections,formViews.*.sections), in thesectionbucket.i18n-coverage.tsneeds no hunk: coverage is computed from that same walker, soos i18n check/os lintsee the keys with no other change (pinned).packages/lint/src/validate-translation-references.ts: the_sectionsfacts gain each form-view section's entryfields, andtranslation-target-unknownreports a_sections.SECTION.fields.FIELDkey no form-view section of that name declares as an entry object.validate-translatable-sections.tsis unchanged (see Acceptance notes).packages/rest/src/public-form-section-i18n.test.ts(domain:serverrider, one door pin):GET /forms/:slugwithAccept-Language: zh-CNserves the translated entry label, placeholder and helpText when the pack has them, and the authored copy when it has none or underen.Tests (real readings, head 37a9e0f)
packages/spec: full--project localsuite in three chunks:src/system56 files / 1948 tests;src/uiand the root files 187 / 6603; every other directory 429 / 12167 (+1 todo). All passed. That includesi18n-resolver.form-sections.test.ts(new block: one pin per key,label,placeholderandhelpText, beside the existing section pins; also missing key, authored-only, nameless section, explicit override vs packaged base, entry added after the fact, no input mutation) andtranslation.test.ts(accepts the node; strict;helpgoes tohelpText).packages/lint: full suite 158 files / 7238 tests passed (new case: an entry key that resolves is accepted; a key under afieldGroupssection and one for a bare field-name entry are reported aserror).packages/cli(unit tier, narrowed): every unit test file that imports the extractor or coverage module, 33 files / 384 tests passed, including the newtest/i18n-form-section-entry-coverage.test.tsand the namedi18n-form-title-coverageandi18n-bulk-action-coverage. The full unit tier needs more than the container's foreground cap; the integration tier is CI's.packages/rest: the fivetranslateView-reaching suites, 5 files / 128 tests passed (public-form-section-i18n17, 3 of them new).packages/metadata-protocol: it callstranslateViewinsrc/protocol.tsbut has no translation test of its own. Its read path is exercised by the rest suites above over the realObjectStackProtocolImplementation.spec,lint,cliandrestexit 0.scripts/ablation-replace.mjs: the entry overlay's guardif (!Array.isArray(entries)) return entries;was replaced withif (entries !== undefined) return entries;(anchor 1 to 0, blob 5942acf6 to 1b8de47c). Result: 5 of 23 ini18n-resolver.form-sections.test.tsfailed (the label, placeholder and helpText pins, authored-only, and override). Restored, blob back to HEAD,git diff HEADempty. The suite readssrc/, so the ablation needed no rebuild.Gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 117 commands on this diff. Exit codes were captured before any pipe and reconciled with--ran: 117 accounted for, 116 run with exit 0, 1 NOT MEASURED, 0 unrun.pnpm check:dual-build-cjs-loads(exit 3). It needs the whole workspace built, which is CI's job.check-plugin-teardown-shape --self-test: its pinned fixture commit was absent from this shallow clone.check:skill-examples: needed@objectstack/client-reactrebuilt.check:i18n,check:i18n-coverage,check:i18n-walk-parity: needed@objectstack/clibuilt.check:query-options-erasure: a repo-wide eslint ratchet. It ran detached until it finished.pnpm --filter @objectstack/spec check:generatedflagged two stale artifacts.--fixregenerated exactly those two, and they are committed:content/docs/references/system/translation.mdxand thesystem/strictness-ledger count (377 to 378 sites, from the one new strict shape).Acceptance notes
{ en, 'zh-CN' }is authored copy and takes the catalog when the pack has a key. Not measured: whether the console renders such a map on an entry today. The crash that blocked it in objectui is closed, but this session did not run the console.validate-translatable-sectionsstill warns only about a nameless section that has a heading. A nameless section with no heading, whose entries author override copy, has no address and gets no warning. Left as is, because extending that rule is outside this card's ask.fieldsof a composite or repeater entry are not addressed. Their names are relative to the parent entry, so keying them under the section would collide.🤖 Generated with Claude Code
https://claude.ai/code/session_01PkEdTSFyHwijHNXRdNTARE
Generated by Claude Code