Repository navigation
fix(cli): os i18n extract seeds a field help entry from its description when inlineHelpText is empty - #29280
Conversation
The extractor scaffolded objects.O.fields.F.help from `help ?? inlineHelpText ?? description`, which stops at an empty string. The console draws `inlineHelpText || description`, so for a field with `inlineHelpText: ''` the drawn description was never offered for translation. Each link now counts only when it carries authored text (asAuthoredLabel), the rule the rest of the file already uses. Claude-Session: https://claude.ai/code/session_01ADHkmT5Q35nWM5fCTsoR5H Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADHkmT5Q35nWM5fCTsoR5H Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADHkmT5Q35nWM5fCTsoR5H Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 35 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 3f2e2a0238d5400720f210e0a5b5c01b671ae8ed && git checkout 3f2e2a0238d5400720f210e0a5b5c01b671ae8ed
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8a8a03d3533c76de53a43ce745064877cbded7a8 3298a9c9dfc478feb88bfb9e3fb5158782501bd4 && git checkout -B drift-repro 8a8a03d3533c76de53a43ce745064877cbded7a8 && git merge --no-ff 3298a9c9dfc478feb88bfb9e3fb5158782501bd4
node scripts/docs-audit/affected-docs.mjs --json 8a8a03d3533c76de53a43ce745064877cbded7a8 |
|
domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1 维护者速读
席位意见:与 diff 相符,只改抽取器(卡的 Edge 1)。Edge 2(解析器把 席位核对ACCEPT ·
|
Requested by Steve · project thread
Fixes #29221
Clause-②: no
Metadata-protocol: none
维护者速读
os i18n extract为字段help条目取默认语言原文时,改为取help、inlineHelpText、description中第一个真正写了内容的值;空字符串视为没写,与 console 帮助行inlineHelpText || description的读法一致。??链停在inlineHelpText: ''上,这类字段的help条目没有原文,console 实际显示的 description 从未进入翻译包。help条目选原文;非空inlineHelpText仍优先于 description,help仍最优先,全空字段照旧。仓库内没有任何非测试源码写inlineHelpText: ''或help: '',已提交的翻译包不变。回滚即撤掉本 PR。packages/cli/src/utils/i18n-extract.ts中collectExpectedEntries的字段help那一段;packages/cli/test/i18n-extract-inline-help-text.test.ts新增的 describe。pnpm --filter @objectstack/cli exec vitest run --project unit test/i18n-extract-inline-help-text.test.ts,应看到 15 条全过。What changes
collectExpectedEntries(packages/cli/src/utils/i18n-extract.ts) seeds a field'sobjects.OBJECT.fields.FIELD.helpentry from the first authored link ofhelp,inlineHelpText,description, read throughasAuthoredLabel, the one "authored" test the file already uses (a non-empty string, or a non-empty inline locale map). Before, it readfield.help ?? field.inlineHelpText ?? field.description, which stops at an empty string.inlineHelpText: ''orhelp: ''beside adescriptionnow scaffolds the description, which is the line the console draws (fieldHelpTextin@object-ui/fields:inlineHelpText || description).helpwins over both; a non-emptyinlineHelpTextwins overdescription; a field whose links are all empty gets the same seed-less entry as before.||(a single space is truthy, so it is the line drawn) and the resolver's non-empty check in PR fix(spec): serve a field's translated help on its authored inlineHelpText #29217. Skipping it here would make the extractor disagree with both..changeset/29221-i18n-extract-field-help-empty-link.md, apatchfor@objectstack/cli.The
os i18n checkcoverage gate reads the same entries, so a field withinlineHelpText: ''and adescriptionno longer reports its default locale as missinghelp.Tests
New
describeinpackages/cli/test/i18n-extract-inline-help-text.test.ts(9 tests, beside the existing order pins):inlineHelpText: ''withdescription: 'B'seedshelp='B';help: ''likewise;help: ''with aninlineHelpTextseeds theinlineHelpText;inlineHelpTextstill wins overdescription;helpstill wins over both (with and without an emptyinlineHelpText);inlineHelpTextstays the source, and the restated console reader draws it too;help, the seed equals the line the console draws (inlineHelpText || description, restated);computeI18nCoveragecounts the default locale as covered when the seed is the description behind an emptyinlineHelpText.No forced edits to existing tests.
Acceptance notes
helpentry is the only place in the extractor that derives help text through a fallback chain. The other help keys each read one key with no fallback: flow screen fields'inlineHelpText(the screen field schema has nodescription), form section entries'helpText, action params'helpText, bulk params'help, metadata-form fields'helpText. Each already goes throughasAuthoredLabelorpushOptional, so an empty string authors no entry there.i18n-coverage.tshas no derivation of its own.inlineHelpText: ''orhelp: ''(git grephits only CHANGELOG prose and the@object-ui/fieldsREADME/docblock).check:i18n(the nine generated bundle packages) andcheck:i18n-coverageare in the gate run below; nothing was regenerated.inlineHelpTextand a differentdescriptiongets onehelpentry, seeded from theinlineHelpText, and the resolver serves its translation ondescriptiontoo. Readers of a field'sdescriptionbesides the console's help line, read on this head:ObjectFieldInspector), the form canvas preview (ObjectFormCanvas), the data-model designer's row tooltip (DataModelDesigner.fieldTooltip), the property editor (plugin-designerPropertyEditor), andMetadataService.toFieldPayload, which writesdescriptionback on save.RecordDetailPanelcopiesdescriptiononto each detail field; no renderer inplugin-detaildraws a field'sdescription(grep on this head).summarizeActionParams) uses a backing field'sdescriptionas a param's help when the param has nohelpText. It reads the registry's object, not a localized serve (traced to the MCP domain's declarations loop; not traced end to end).descriptionentry from the extractor would need a bundle key thatFieldTranslationSchemadoes not declare, which is apackages/specchange. The fix that needs no new key is in the resolver (translateObject): serve thehelpentry ondescriptiononly when the field authors no non-emptyinlineHelpText. That is spec seat 1's surface and reverses what the i18n: a field's translated help never shows when the field authors inlineHelpText — the server serves fields.FIELD.help on description and the console draws inlineHelpText first #29153 ruling kept, so it is reported to the seat, not done here.Verification
Head
3298a9c9, the merge oforigin/mainat01252a45. Heavy runs went throughos-verify-lock.sh.cli package: unit tests, typecheck, lint
pnpm --workspace-concurrency=2 --filter '@objectstack/cli^...' build: VERDICT command-exit 0.pnpm --filter @objectstack/cli build && pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 && pnpm --filter @objectstack/cli typecheckona6ea00b0(the commit before the merge): Test Files 372 passed (372), Tests 5259 passed (5259); typecheck andcheck:test-typecheckOK. VERDICT command-exit 0. Theintegrationtier is CI's (no integration-tier file or spawn entry touched).origin/main(it touched no cli file; it touchedpackages/specandservice-analytics, both rebuilt): the two extractor files, Test Files 2 passed (2), Tests 39 passed (39). VERDICT command-exit 0.eslint --no-inline-configon the two touched cli files (the rootpnpm lintcommand, scoped): exit 0, no output.Ablation: the old chain turns the new pins red
scripts/ablation-replace.mjsputfield.help ?? field.inlineHelpText ?? field.descriptionback over the new chain (anchor 1 to 0, blob21178839abf6to1ccf82f67d58), ran the test file through the lock and restored (git diff HEADempty after). The test imports the extractor fromsrc, so no build was involved.inlineHelpText: ''beside a description,help: ''beside a description,help: ''beside aninlineHelpText(eachexpected undefined to be 'B'or'I'), the console-agreement matrix (expected undefined to be 'B'), and the coverage case (expected [ { severity: 'error', … } ] to deeply equal []).helpwins, non-emptyinlineHelpTextwins, whitespace stays, all-empty is seed-less): they hold before and after, as intended.dispatch-gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon3298a9c9: 61 commands (the same list as ona6ea00b0, before the merge). Each ran with stdin closed; 58 exited 0 on the first pass.check-plugin-teardown-shape.mjs --self-testafter fetching its pinned fixture commit;check:dual-build-cjs-loadsandcheck:i18n-coverageafterturbo run build --filter='./packages/**' --filter='./examples/**'(VERDICT command-exit 0).check:i18n-coverage: "OK (14 config(s), 426 baselined untranslated string(s), none new)";check:i18nexit 0. The working tree stayed clean: nothing was regenerated.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran FILE(each line carrying its exit code): "61 derived famil(ies) accounted for — 61 run, 0 NOT-MEASURED (a DERIVED zero — all 61 recorded an exit code and none of them is 3)". Exit 0.--commandsdoes not list. Those are CI's readings.Generated by Claude Code