Repository navigation
fix(plugin-form,console): the form family's feedback chrome resolves through the i18n catalogue (objectui#11039) - #11066
Conversation
…8n catalogue (objectui#11039) The success toast, the refused-navigation note, the thank-you heading, the loading line, the load-failure heading and the default submit and cancel labels of the form family now read the locale packs instead of English literals. Authored values still win. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
…h fixtures (objectui#11039) A zh-CN render of each default, container by container, with authored-override controls (an I18nLabel map and a plain string) and an en control. The fixtures that asserted the old English literals, or the old English defaults under a zh provider, move with the change. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
Patch for plugin-form, i18n and the console. The pending objectui#10935 changeset no longer says the master-detail defaults stay English. The pin headers state the measured red leg. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
|
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
|
Fixes #11039
Clause-②: no
What
The form family's own feedback chrome now resolves through the i18n catalogue instead of English literals: the default success toast, the note it carries when a declared
navigateOnSuccesswas refused, the thank-you heading, the loading line, the load-failure heading, and the default submit and cancel labels. plugin-form goes throughcreateSafeTranslation: a new shared hook informChrome.ts(read byObjectForm's default arm,TabbedForm,SplitFormandMasterDetailForm) and the tablesWizardForm,DrawerFormandModalFormalready had.pnpm check:i18n-keysholds every table to theenpack, so a provider-less host still renders English. The console'sFormPageuses the console's own hook,useObjectTranslation, with the same pack keys;main.tsxmounts theI18nProviderabove every console route.An authored value still wins, and it is untouched: each default sits behind the same
||/??as before, after objectui#11050's resolution of the sevenI18nLabelmembers (a locale map, or a plain string). No schema key is added, renamed or retyped.The enumeration (on
origin/mainat6466a09df, after PR 11050)Created/Savedsuccess toastredirect),WizardForm(the same four)successMessage; athank-youbehaviour'smessageform.created/form.saved(new)Created,Saved, and "TITLE saved"MasterDetailForm's built-in save toast (shown only without a hostonSuccess)titlenames the record; no message keyform.created,form.saved,form.savedNamed(new,{{title}})WizardFormform.navigateRefused(new)Thanks!WizardFormthank-youbehaviour'stitlepublicForm.thankYouTitle(existing)Loading form...TabbedForm,SplitForm,WizardForm,DrawerFormpublicForm.loading(existing)Error loading formModalFormform.errorLoading(new)Create/Updatesubmit labelTabbedForm,SplitForm,DrawerForm,ModalFormsubmitTextform.create/form.update(existing)CancelDrawerForm,ModalFormcancelTextcommon.cancel(existing)Save/Create/CancelMasterDetailFormsubmitText/cancelTextcommon.save/form.create/common.cancel(existing)Loading…FormPagecommon.loading(existing)SubmittedtoastFormPageform.submitted(new)Thanks!(two panels)FormPagethank-youtitlepublicForm.thankYouTitleYour submission has been received.(two panels)FormPagethank-youmessagepublicForm.thankYouMessage(existing)The card named the toast,
Thanks!, the loading line, the load-failure heading and the note. The submit and cancel defaults are the same class in the same files (the brief's example);FormPage's loading line, itsSubmittedtoast and the message under itsThanks!are the card's classes in the card's file. Beyond this line, see Acceptance notes.Keys: reused where one already meant the same thing
publicForm.loading(Loading form…),publicForm.thankYouTitleandpublicForm.thankYouMessagewere in all ten packs with nothing reading them:pnpm check:i18n-dead-keyslisted all three as confirmed dead at the merge base. They say exactly this, so they are reused, and they are off that list now (105 confirmed dead before, 102 after).form.saveSuccess(Saved successfully, also confirmed dead) is not reused for the toast: it has no no-argument create twin (form.createSuccesstakes{{object}}), so reusing it would either pairCreatedwithSaved successfullyor rewrite both toasts' English on every form.form.created/form.savedkeep the toast byte-identical in English.MasterDetailForm's edit Save iscommon.save, notform.saveRecord: seven packs wordform.saveRecordas "save record" (deDatensatz speichern), while this button's English is the plain verb, whichcommon.saveis in every pack.form.errorLoadingfollowsgrid.errorLoading.NAVIGATE_ON_SUCCESS_REFUSED_NOTE: an end user sees it, so it joinsIt is passed as the
descriptionoftoast.success(...)(sonner, through@object-ui/components), which renders under the toast's title, so the submitter reads it. Its own doc block says so ("What the submitter is told"), quoting the maintainer ruling of 2026-08-17: "the success toast carries a note that the declared navigation was not performed". The zh pin reads it on the toast (red on the base). The constant still exists: it is now read from theformChrome.tstable, so it has one spelling, andWizardFormre-exports it, because the tests import it from there.navigateOnSuccessstays as written in every pack, since it is the key's name.Wording
zh: 已创建, 已保存, "TITLE已保存", 已提交, 表单加载失败, and 此表单声明的
navigateOnSuccess跳转目标被拒绝,因此未执行跳转。 The reused keys read 正在加载表单…, 感谢您的提交! and 我们已成功收到您的信息。 The zhpublicForm.thankYouTitlechanges its ASCII!to the full-width!, the zh pack's punctuation, now that a form shows it. The other eight packs follow each pack's own neighbours (form.createSuccess,grid.errorLoading,publicForm.loading). No new value carries an ellipsis; the reusedpublicForm.loadinghas U+2026 in all ten packs.Three English strings change their rendered text, each because it is now a key whose English differs from the old literal. The changeset says so:
Loading form...becomesLoading form…(U+2026);Thanks!becomesThank you!(default arm,WizardForm,FormPage);FormPage'sYour submission has been received.becomesYour submission has been received successfully.Every other English default renders the same text as before.
Pins
packages/plugin-form/src/formChrome.i18n-11039.test.tsx: 29 cases throughObjectFormunder a realI18nProvider. Each zh case first waits for a probe outside the form to read the zh pack. The zh loading line in the simple, tabbed, split, wizard and drawer forms; the zh load-failure heading in all six; 创建 / 更新 in simple, tabbed, split, drawer and modal; 取消 in drawer and modal; 已创建 (simple, wizard) and 已保存 (simple edit) toasts; the zh thank-you heading (simple, wizard); and the zh note on a refusednavigateOnSuccess(simple, wizard). ThreeCONTROLcases: anI18nLabelmapsuccessMessagewith a plainsubmitText; a mapsubmitTextwith a plainsuccessMessageon a wizard, whose toast keeps the authored message and carries the zh note; and an authored thank-youtitlewith a mapcancelText. Plus anencase:Loading form…,Error loading form,Create,Createdwith the English note, andThank you!.apps/console/src/components/FormPage.chromeI18n-11039.test.tsx: 5 cases on the real/f/:slugroute, with nothing wrapped around it: the zh loading line 加载中…, the zh toast 已提交, the zh thank-you heading and message, aCONTROLwith a declared thank-youtitleandmessage, anden.Red leg, at
80db9c47a. The eight edited containers (ObjectForm,WizardForm,TabbedForm,SplitForm,DrawerForm,ModalForm,MasterDetailForm,FormPage) were replaced by their merge-base blobs, each hash-checked on disk (t('form.errorLoading')inObjectForm.tsxwent from 1 to 0, and theLoading form...literal came back). Everything else stayed at HEAD. Over the two pins and the eight moved fixture files: 43 failed, 52 passed. The formChrome pin: 27 of 29 fail. TwoCONTROLcases pass, because authored values always won, so they are the must-not-change guards. The wizardCONTROLfails only on the note, which is chrome. The FormPage pin: 4 of 5 fail, and itsCONTROLpasses. The script restored withgit checkout HEAD --under atrap, verified every file against its HEAD blob hash, and read an emptygit diff HEAD. Green at the same head: 29 and 5 passed.Fixtures that moved with the change (pin updates, not regressions)
ObjectForm.i18nLabels.test.tsx(zh): the create button is 创建, and the nothing-authored control's toast is 已创建.MasterDetailForm.i18nLabels.test.tsx(zh): the toasts read 采购单已保存 and PO已保存, and the nothing-authored control reads 创建, 取消, 保存 and 已保存.ObjectForm.submitRedirect.test.tsx,WizardForm.submitRedirect.test.tsx:Thank you!.FormPage.submit,.outcomeToast,.recordId,.redirect: each now installs the en catalogue the way the app does (createI18n, whose global the harness resets after every test), and asserts the new message. The negative assertions moved to the new string too; left alone they would have passed vacuously.examples/schema-catalog/test/catalog-gallery-render.test.tsx:FORM_LOADINGisLoading form…. Its wait is negative (not.toContain), so the old literal would not have turned red: it would have silently stopped waiting. The comment's stale cross-file line citation is now a content citation.Also: the pending objectui#10935 changeset said the master-detail defaults "are still English". Its prose now says this change moves them; its frontmatter is untouched (
check-changeset-overwritereports it under its case 2, a deliberate correction; report-only). Theobject-master-detail-formregistry descriptions ofsubmitText/cancelTextnow say the default is in the active UI language.Verification (all at
80db9c47a)pnpm exec vitest run packages/i18n/ packages/plugin-form/: Test Files 216 passed (216), Tests 2910 passed, 14 skipped. This includesall-locales-key-parity,en-zh-key-parity,ellipsis-glyph-3878,untranslated-identity-4376,de-quote-pairing-3876andraw-key-call-sites-3546.pnpm exec vitest run apps/console/: Test Files 131 passed (131), Tests 1475 passed.packages/plugin-view/, plus app-shell'sObjectFormDesigner.test.tsxandRecordFormPage.i18n.test.tsx, plus the gallery test: 63 files, 1207 passed.scripts/__tests__, derived withgit grep -l -Eover the touched names and paths (the form files,FormPage,formChrome,i18n/src/locales,plugin-form/src,.changeset,schema-catalog,apps/console/src/components): 46 files, Tests 2171 passed.@object-ui/i18nand@object-ui/plugin-formDone, and@object-ui/consoleexit 0, each after building its dependency closure.tsc -p tsconfig.test.json --listFilesOnlylists the plugin-form pin, and the console's--listFilesOnlylists its pin.pnpm check:i18n-keysexit 0 (37 factory tables, 912 rows, 912 matching).pnpm check:i18n-driftexit 0 (0 en values changed, 6 keys added).pnpm check:control-bytesOK.pnpm check:new-line-citations: 0 new.node scripts/check-changeset-presence.mjs,pnpm changeset:checkandpnpm check:pending-changeset-literalspass.pnpm check:changeset-claims(report-only) names seven pending changesets that mention a touched file (6237-wizard-step-config-split,6661-app-launcher-nav-menu-renderers,8738-object-form-fields-description, and fourconsole-form…ones). All re-read, all still true: each is about another aspect of those files.--format jsonreports 31): with inline config honoured, as each package'slintruns, 0 errors and 210 warnings; with--no-inline-config, 1 error and 217 warnings, and those per-file counts equal the merge-base blobs linted the same way through--stdin --stdin-filename. The one error is an existing, inline-suppressedreact-hooks/static-componentsinFormPage's widget row. The narrowing excludes nothing: the population is the changed files from the diff against the merge base,eslint.config.jssets noparserOptions.projectorprojectService(no type-aware linting), and no rule undereslint-rules/reads a file, so this diff cannot move a verdict on an untouched file.Bundle
Console built at the merge-base sources and at HEAD: the sources were swapped, rebuilt, restored and rebuilt, and a marker was checked in dist both ways. The eager closure is 330 of 2446 chunks both times, so no chunk entered it, and 3,181,419 became 3,181,741 bytes gzipped (+322; raw +1,788). By chunk:
i18n-locale-en+241 raw / +82 gzipped (the en pack),plugin-form+1,471 / +252,index(FormPage) +76 / −7. No new external module entered either chunk:FormPagealready imported@object-ui/i18n, and the newformChrome.tsimports onlycreateSafeTranslation, which plugin-form already did.check-eager-closure-budget: 3107.2 KB of 3149.4 KB (headroom 42.2 KB, 42.6 KB at the base).check-eager-locale-catalogues: exactly one eager catalogue,en.Acceptance notes
Left English on purpose. Each is chrome, not a default behind an author key the card named, and each is noted rather than widened into here:
FormPage: the submit button'sSubmit/Submitting…/Uploading…,Redirecting…, and theRequired: …refusal. The zh pin submits through that EnglishSubmitunder a zh catalogue.MasterDetailForm's line-item chrome:Loading columns…,Subtotal,Tax (…%),Total,Line item — row N,Apply,Add, andSaving…on its Save button.ModalForm's master-detail dialog: itssr-onlydescription,Enter the record and its line items, then save.ObjectForm's field-security hint,You do not have edit access to this field.EmbeddableFormtakes its chrome from host-suppliedtexts(thepublicForm.*vocabulary inpublic-forms.md), which is a different mechanism.No README or
content/docspage describes these defaults (grepped for the literals; the oneThanks!inpublic-forms.mdis an authoredtitlein an example), so no docs change is due.Dispatched dev run for the
domain:uiseat #1, sessionsession_01DuWo5bdP9SdVebamn99GGk, claim comment 5885696581.Generated by Claude Code