Repository navigation
fix(i18n,a11y): the enumerated literal aria-label names read each package's translation hook, and a census pins the family (objectui#12145) - #12149
Conversation
…lation hook (objectui#12145) The card's enumerated aria-label sites read their names from the locale packs instead of English literals. Eight keys are added to all ten packs; every other name reuses an existing key (one key per name). Claude-Session: https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK Co-authored-by: Claude <noreply@anthropic.com>
…e pins (objectui#12145) The census walks every packages/* and apps/* src tree and fails on any literal accessible name it does not declare; the card's stated exceptions are declared with reasons, and the sites its re-check pathspec never reached are frozen as a backlog. Each touched package gains a zh role-and-name pin read against the pack. Claude-Session: https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK Co-authored-by: Claude <noreply@anthropic.com>
…ion (objectui#12145) The source-count floors were guesses above the real shipped population; they are now floors under it, plus a guard that the files directly under a src/ root, which the card's pathspec never read, are in the population. Claude-Session: https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK Co-authored-by: Claude <noreply@anthropic.com>
✅ 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: ① Derived judgmentsReadings: card #12145 (body, triage 6109811077, claim 6110243674, dev report 6111181431); PR #12149 (body, the 45-file list, the net diff against Every public-surface and accept-set change the diff implies, judged:
Finding confirmed: the card's pathspec, without ② Semver level
Clause-②: yes The PR body's ③ Boundary flagsDev report
Also escalated to the seat, from the dev's acceptance notes (carrier none): 30 interpolating-template names need a ruling on how an interpolated name is keyed; Check-runs on the head, the reading as taken (42 runs): 35 success, among them Lint, Type Check, Build & E2E, Build Docs, Test (dist pins), Test shards 1/8, 3/8, 6/8 and 8/8, Governed Surface Queue Guard and the five changeset gates; 3 skipped (two matrix placeholders and dependabot); 4 in_progress: Test shards 2/8, 4/8, 5/8 and 7/8. Not a governed diff. The verdict below is the contract's; the landing still waits on the four shards' conclusions and on item 1 above. Implemented-by: VERDICT: PASS |
Fixes #12145
Clause-②: yes
The card's enumerated
aria-labelsites read their accessible names through their own package's translation hook, so a screen reader underzh(or any non-English pack) hears the viewer's language. Eight keys are added to all ten@object-ui/i18npacks with real translations; every other name reuses a key that already holds the same words. The family is pinned by a census test in the ordinary suite (not a CI gate), beside per-packagezhrole-and-name pins.Clause-②: yesis the claim's reading (comment 6110243674): the added keys widen theas constenpack, and so the publishedTranslationKeys. Confirmed on the built declarations at HEADebfc833:packages/i18n/dist/locales/en.d.tsdeclares all eight keys, anddist/index.d.tsre-exportsTranslationKeys(typeof en).Every enumerated site, and what happened to it
apps/consoleAppDocsIndex,BookPage,DocPage,DocsIndex,DocsSlug: "Loading documentation" (5)useObjectTranslationhelp.loadingDocumentation(new)app-shellRecordFormPage: "Breadcrumb"tcommon.breadcrumb(new)componentscustom/spinner.tsx: "Loading"createSafeTranslationhook; a caller'saria-labelstill winscommon.loading(reused; the English name is now "Loading…")componentsdebug/DebugPanel.tsx: "Developer Debug Panel", "Close debug panel"?__debug/ Ctrl+Shift+D), and its whole chrome is English developer copy, so translating two names would leave it half in one languagecomponentsrenderers/complex/data-table.tsx: "Row actions"useTableTranslationtable.rowActions(new)componentsui/pagination.tsx: "Go to previous page", "Go to next page"paginationrenderer (renderers/basic/pagination.tsx), passes the names, which the primitive spreads after its defaultstable.previousPage/table.nextPage(reused, PR objectui#12142)componentsui/sidebar.tsx: "Toggle Sidebar" (SidebarRail)I18nProvider. A host names it througharia-label/titlecommon.toggleSidebarfor a host)fieldsImageCropperDialog: "Image crop preview"useFieldTranslationfields.image.cropPreview(new)fieldsPercentField: "Percentage"useFieldTranslationfields.percent.slider(new)fieldsRecordPickerDialog: "Records"useFieldTranslationconsole.commandPalette.records(reused)plugin-chatbotelements/message.tsx: "Previous branch", "Next branch", "Remove attachment" x2MessageBranchPrevious,MessageBranchNextorMessageAttachment; they are only re-exported asAIElements. The branch buttons spreadpropslastplugin-chatbotelements/prompt-input.tsx: "Remove attachment" (PromptInputAttachment)ChatbotEnhanced, andpropsreach the chip, not the button. An optionalremoveLabelprop is added to the vendored element (the objectui#7254statusLabelsprecedent: additive, the upstream English stays when omitted);ChatbotEnhancedpasses the pack's namedetail.removeAttachment(reused)plugin-chatbotelements/prompt-input.tsx: "Submit" (PromptInputSubmit)ChatbotEnhanced, already overrode it withL.submit, whose fallback WAS the English literal. That producer now reads the pack, for the stop state tooconsole.ai.submit/console.ai.stopResponse(reused: the console already passes them)plugin-designerHistoryPanel: "Undo", "Redo"useDesignerTranslationdesigner.undo/designer.redo(reused)plugin-designerMinimap: "Canvas minimap"useDesignerTranslationdesigner.canvasMinimap(new)plugin-designerVersionHistory: "Version history"useDesignerTranslationdesigner.versionHistory(new)plugin-designerDashboardDesignPage: "Go back"useDesignerTranslationdetail.goBack(reused)plugin-detailrecord-alert.tsx: "Dismiss"thome.recoveryReminder.dismiss(reused)plugin-detailrecord-path.tsx: "Alternative terminal stages"plugin-gridBulkActionBar: "Bulk actions"tgrid.bulkActions(new)plugin-listTabBar(TabBarSelect): "Switch view"useObjectTranslationtopbar.switchView(reused: the app header's view switcher reads it)"Reused" follows triage's rule, one key per name: where the English name already had a key, the site borrows it rather than add a second (the "Dismiss" borrow picks the banner-dismiss key whose ten translations fit a dismissible alert). The card's re-check command, run on this branch, returns exactly the ten exempt literals above and nothing else.
The census:
packages/i18n/src/__tests__/ariaLabelLiteralCensus-12145.test.tsHome chosen by precedent:
machineLocaleCensus-9909.test.tsin the same directory is the repo's existing one-test census over every package's shipped sources, with comment masking throughscripts/js-comment-mask.mjsand declared exemptions cited by content. This census copies that shape.src/tree of apackages/*orapps/*workspace, minus tests, stories and tooling. Walked, not globbed, plus a guard that the files directly under asrc/root are in it (see the finding below).aria-label="…",aria-label={'…'}/{"…"}(the widening triage asked for), a braced template that interpolates nothing, and the'aria-label': '…'object key, when the value carries a letter (\p{L}, so a name in any script counts).title=/placeholder=/sr-only/ renamed props, and JSX text that the comment masker reads as a comment opener.Readings (the census as committed, run on each tree):
158c75dsite files, packs and tests at HEAD (Leg A below)ebfc833Finding: the card's re-check pathspec never read a file directly under
src/git grep … -- 'packages/*/src/**/*.tsx'has no:(glob)magic, so its pattern needs a/aftersrc/: no file directly under asrc/root was ever read (the control:aria-label="Undo"inplugin-designer/src/DataModelDesigner.tsxis not returned, while the same string insrc/components/HistoryPanel.tsxis). The same regex with:(glob)returned 114 sites on BASE, not 31. This PR translates the card's enumeration, per the claim's file surface; the 87 literal sites it did not enumerate (23 files, 11 packages,plugin-designerthe bulk of them) are frozen in the census's BACKLOG, so none can grow and each must leave the list in the commit that translates it. They are reported to the seat for slicing;auth,layoutandplugin-mapamong them do not depend on@object-ui/i18ntoday.Pins: one
zhrole-and-name query per package, each read against the packapps/console/src/pages/docsLoadingName-12145.test.tsx: the docs index spinner under en and zh. The spinner is a lucidesvg, which testing-library's role table gives no implicit role, so this one is found by its accessible name (getByLabelText).packages/components/src/__tests__/ariaLabelNames.zh-12145.test.tsx:Spinner(status), the data table's row menu trigger (button), thepaginationrenderer's links (link), with no provider (en) and under zh, and the primitive's English defaults absent under zh.packages/fields/src/__tests__/ariaLabelNames.zh-12145.test.tsx: the percent slider (slider).packages/plugin-chatbot/src/__tests__/ChatbotEnhanced.composerNames.zh-12145.test.tsx: the send button with no hostlabels, and a host label still winning.packages/plugin-designer/src/__tests__/ariaLabelNames.zh-12145.test.tsx: undo / redo (button), minimap (img), version history (region).packages/plugin-grid/src/__tests__/BulkActionBar.regionName.zh-12145.test.tsx: the bar (region).packages/plugin-list/src/components/__tests__/TabBarSelect.triggerName.zh-12145.test.tsx: the trigger (button).packages/plugin-detail/src/renderers/__tests__/record-alert.test.tsx: one added case, the dismiss button (button).packages/app-shell/src/views/RecordFormPage.listLinkPlural-11733.test.tsx: its breadcrumb lookup read the English literal; it now readscommon.breadcrumbfor the language under test, so its zh-CN case is the package's zh pin (navigation).Each zh case first asserts the zh and en values differ, or it would pin nothing.
Evidence (HEAD
ebfc833, one locked run, every leg restored)declared 0, found 1; every pin's zh case red (Unable to find role="region" and name "批量操作"and the like); the components en case red ("Loading…")BulkActionBar'st(…)back toaria-label={'Bulk actions'}(the braced shape) via objectstack'sscripts/ablation-replace.mjs: anchor 1 to 0, blobc9c2d24to05ef07eBulkActionBar.tsx · Bulk actions — declared 0, found 1), grid zh pin redListView's backlogaria-label="Bulk actions"removed (anchor 1 to 0, blobdb03daeto11c9b6a), its entry leftListView.tsx · Bulk actions — declared 1, found 0)After Leg A,
git diff HEADwas empty and the status clean; Legs B and C each restored to the HEAD blob withgit diff HEADempty; the run ended with the tree clean atebfc833.Gates (all at HEAD
ebfc833)turbo run build --filter=@object-ui/console^... --concurrency=2: 34 of 34 tasks; then the console itself: 35 of 35.type-check, each script name echoed):i18n,components,fields,plugin-grid,plugin-list,plugin-chatbot,plugin-designer,plugin-detail,app-shell,console: all exit 0. Each new or edited test file is in its package's type-checked program (tsconfig.test.json, or the console'stsconfig.json).packages/i18n/plusscripts/__tests__/check-i18n-call-site-keys.test.ts: 84 files passed; the 130 existing test files that import or query a changed module, in two runs: 69 and 61 files passed.check:i18n-keys,check:i18n-drift(8 keys added, 0envalues changed),check:i18n-dead-keys(report; none of the eight, nor any reused key, listed),check:i18n-designer-parity,check:eager-locale-catalogues(onlyeneager),check:eager-closure: all exit 0.check-changeset-presence.mjs(44 source files of 10 released packages, 1 changeset),changeset:check,check:changeset-claims,check:pending-changeset-literals,check:control-bytes,check:new-line-citations(0 new),check:phantom-deps,check:test-path-roots,check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shape; governed-surface guard: NOT GOVERNED.mainhas not moved since BASE158c75d, so no merge was needed. No docs page quotes these names, so none changed.Acceptance notes (outside the card, not edited here; handed to the seat)
aria-label={`Dismiss ${notification.title}`}in the three notification surfaces,Remove ${name}inTagsField/SelectionTray,Copy ${label ?? 'value'}in two console developer pages. 30 such sites on BASE.PaginationPrevious/PaginationNextrender visible "Previous" / "Next" spans, andSidebarTrigger(rendered bare by theheader-barrenderer) names itself through an Englishsr-onlyspan. Code read only.ChatbotEnhanced'suploadFilesfallback is still the English literal, the same shape as thesubmitfallback fixed here; the console passes its own label.Session:
https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sKGenerated by Claude Code