Repository navigation
fix(plugin-form,fields,i18n): the record page's line-items panel and the grid field speak the user's language (objectui#11131) - #11143
Conversation
…utton and the grid's Add / empty text read the catalogue (objectui#11131) The record page's `record:line_items` panel rendered its default title "Line Items" and its "Save" / "Saving…" button as English literals, and the line-items grid (`GridField`) did the same for "Add line", the list-mode empty text and the read-only "No items". They now resolve through the panel's `createSafeTranslation` table and the fields package's `useFieldTranslation`, reusing `common.save`, `detail.saving` and `detail.add`. Four new keys land in all ten packs: `form.lineItems.title`, `fields.grid.addLine`, `fields.grid.noItems` and `fields.grid.noItemsAddHint`. An authored `title` / `add_label` still wins, and English output is byte-identical to the literals it replaces. Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec Co-authored-by: Claude <noreply@anthropic.com>
…e in zh and without a provider (objectui#11131) A zh render of the panel's default title, both Save button states, the grid's Add label and both empty texts, with authored `title` and `add_label` controls; and provider-less companions that hold the English to the literals it replaced. Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec Co-authored-by: Claude <noreply@anthropic.com>
…„{{label}}“ span (objectui#11131)
`fields.grid.noItemsAddHint` quotes the Add button's label with a
matched German pair, so the census moves from 68 to 69 spans and the
open / close identity from 68 / 68 / 0 to 69 / 69 / 0.
Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec
Co-authored-by: Claude <noreply@anthropic.com>
…fields and i18n (objectui#11131) Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec Co-authored-by: Claude <noreply@anthropic.com>
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract reviewServed-tier: Inputs: card objectui#11131 (body, triage Gates on the head. Runs were still in progress when this review began; the poll waited until every run had completed (the last at about 2026-09-29T20:49Z) before judging. All 43 check-runs on ① Derived judgmentsAccept-set: nothing moves. No schema, prop, type, zod arm or accepted value changes; the diff touches two components' default strings, ten locale packs, one census pin, four new pin files and one changeset. Public surface: four new pack keys appear in
② Semver level
③ Boundary flags
Out-of-scope notes, each answered at the head:
(1) and (2) belong in one family remainder card. Same defect class, same two-file pattern, and (2) reuses this PR's Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #11131
Clause-②: no
What
Under a zh session the record page's
record:line_itemspanel (LineItemsPanel) rendered its default titleLine Itemsand itsSave/Saving…button in English. The line-items grid (GridField) did the same for its Add button (Add line), the list-mode empty text (No items yet — click “Add” to begin.) and the read-only empty state (No items). They now read the locale packs.Only the defaults move. An authored
titleoradd_labelstill wins, and an authoredadd_labelis also the label the empty text names. English output is byte-identical to the literals it replaces, with and without an i18n provider.Where each string goes
LineItemsPaneltitleLine Itemsform.lineItems.titleform.masterDetail.lineItemis the singular row noun (Line item), a different stringLineItemsPanelbuttonSavecommon.saveLineItemsPanelbutton, in flightSaving…detail.savingMasterDetailForm's Save already readsGridFieldAdd buttonAdd linefields.grid.addLinedetail.addisAdd)GridFieldlist-mode empty textNo items yet — click “{{label}}” to begin.fields.grid.noItemsAddHint{{label}}holeadd_labelis authoredAdddetail.addGridFieldread-only empty stateNo itemsfields.grid.noItemsappDesigner.navNoPreviewItemshas the same English but belongs to the app designer's nav preview, andlist.noItemsisNo items foundThe four new keys are in all ten packs.
Which translation path, and why
Panel: its own
useLineItemsTranslationtable, notuseFormChromeTranslation. The dispatch asked for one of the two, not both. The panel already owned acreateSafeTranslationhook (for the malformed-filter sentence), andformChrome.tsstates the precedent for exactly that case:WizardForm,DrawerFormandModalFormhave hooks of their own and carry the rows they read. The panel's table now carriesform.lineItems.title,common.saveanddetail.savingnext toview.malformedFilter. UsinguseFormChromeTranslationinstead would have meant editingformChrome.ts, which is outside the claim's declared file surface, to add the title row and move the malformed-filter row. The triage direction namesuseFormChromeTranslation, and this choice departs from that name. It is flagged in the report, not settled silently here.Grid:
useFieldTranslationwith an inlinedefaultValueat each call site. This is the fields package's own path, which the grid already reads for its date cells. An inline default is whatcreateSafeTranslation's provider-less fallback renders for a key its table lacks.pnpm check:i18n-keysholds each one to itsenvalue, and its interpolation-parity rule holds the call site's arguments to the{{label}}hole. Rows inFIELD_DEFAULTS(useFieldTranslation.ts) would also have worked, but that file is outside the declared surface.Tests
Pins, new:
packages/plugin-form/src/LineItemsPanel.i18nChrome-11131.test.tsx: under zh, the default title reads 明细行, the idle button 保存, the in-flight button 保存中… and the grid's Add button 添加行. A read-only panel over no rows shows 暂无条目. CONTROL: an authoredtitlerenders as written.packages/fields/src/widgets/GridField.i18nChrome-11131.test.tsx: under zh, the Add button reads 添加行, the list-mode empty text reads 暂无条目,点击“添加”开始添加。 and the read-only empty state reads 暂无条目. CONTROL: an authoredadd_labelis the button label and fills the empty text's hole..no-providercompanions, one per package. With no provider mounted they pin the English byte for byte:Line Items,Save,Add line,No items,No items yet — click “Add” to begin., and an authored label in the hole. Each is its own file because anI18nProvidermount registers react-i18next's module-global instance for the rest of its file.An existing pin was updated:
packages/i18n/src/__tests__/de-quote-pairing-3876.test.tsis a census of the de pack's „…“ spans. The new denoItemsAddHintquotes the label with a matched pair, so the count goes from 68 to 69 spans and the open / close identity from 68 / 68 / 0 to 69 / 69 / 0. Its comment names the key, following the file's own convention. This file is outside the claim's list. It moved because the de value adds a quoted span, not by choice.Reverse verification, run with the fix committed: both source files were checked out from the base
db11afd49, keeping the new keys and pins. An on-disk grep confirmed it (title key 1 → 0,'Line Items'literal present,fields.grid.addLine1 → 0). Run over the four pin files, the result was 7 failed | 5 passed (12), which was the predicted direction. All seven zh cases went red, the two CONTROLs included, since each also asserts pack chrome. All five provider-less cases stayed green because the English is unchanged. After restoring withgit checkout HEAD --, the blob hashes matched HEAD andgit diff HEADwas empty.Gate ablation: I changed the grid's
noItemsAddHintinline default by one word throughablation-replace.mjs(anchor 1 → 0).check:i18n-keysthen went to exit 1 with[default-value-drift] fields.grid.noItemsAddHint. The file was restored and matched the HEAD blob.At
370aaf443(the final commit):pnpm exec vitest run --maxWorkers=2 packages/i18n/ packages/plugin-form/src/LineItemsPanel packages/fields/src/widgets/GridField packages/app-shell/src/__tests__/defaults-maps-mirror-en-pack.test.tsxgave 96 files passed, 1410 tests passed, 13 skipped. This is a declared narrowing.8cf648cfeI ran the whole ofpackages/plugin-form/,packages/fields/andpackages/i18n/plus the mirror test: 444 files, 6466 tests passed and 2 failed. Both failures were the de census above, fixed in5081cc63f. The only later commit adds the changeset, which no test reads.pnpm --filter @object-ui/i18n type-check, then@object-ui/fields, then@object-ui/plugin-form, all exit 0. These ran after building plugin-form's dependency closure withturbo run build --filter='@object-ui/plugin-form^...'(11/11 tasks). Each package'stsconfig.test.jsonlists the new test files (--listFilesOnly).pnpm exec eslinton the 17 changed.ts/.tsxfiles gave exit 0: 0 errors and 43 warnings, all on lines this diff does not touch. The file count comes from--format json, which reports all 17 as linted and none ignored.eslint.config.jsconfigures no type-aware linting (noprojectServiceorparserOptions.project), so this diff cannot move the verdict on an untouched file. The repo-widepnpm lintbelongs to CI.check:i18n-keys,check:i18n-drift(4 keys added, 0envalues changed),check:i18n-dead-keys(no new key among the candidates),check-changeset-presence,check:control-bytes,check:new-line-citations(0 new) andcheck:changeset-claims.Acceptance notes
LineItemsPanelstill hasLoading…,Save the record first to add line items.,This record’s line items have not been loaded., theFailed to load / save line itemsfallbacks and the no-child-object hint.GridFieldstill hasTotal,Columns,Optional columns,Computedand the row actions'aria-label/titlepairs. Under zh the probe sawSave the record first to add line items.and theTotalfooter in English. The row-action pairs disagree with each other (Duplicate rowvsDuplicate line), so choosing their keys is not purely mechanical.MasterDetailForm's collection heading (d.titlefalling back to aLine Itemsliteral) is the same string. The probe measured it in English under zh too. That file is held by the claim on objectui#11132 (a different defect, the totals' currency sign), so it is not touched here. After this PR the fix can reuseform.lineItems.title.detail.add(Add), while the button defaults toAdd line. That mismatch predates this PR and is kept byte-identical. Its only list-mode producer,MasterDetailForm's in-form collection, always passesadd_label, so no rendered screen shows the two disagreeing.Session:
https://claude.ai/code/session_011p7ikEivgXefNDaE5S5UecGenerated by Claude Code