Skip to content

fix(i18n): define home.recentApps.itemType.report and .metadata in all ten packs - #6163

Merged
yinlianghui-tw merged 1 commit into
mainfrom
claude/issue-6023-recent-item-type-keys
Aug 24, 2026
Merged

fix(i18n): define home.recentApps.itemType.report and .metadata in all ten packs#6163
yinlianghui-tw merged 1 commit into
mainfrom
claude/issue-6023-recent-item-type-keys

Conversation

@yinlianghui-tw

Copy link
Copy Markdown
Collaborator

Fixes#6023

All ten locale packs now define home.recentApps.itemType.report and
home.recentApps.itemType.metadata, and the two matching missingMembers entries in
scripts/i18n-call-site-key-baseline.json are cleared.

Verified at cd8d6594d.

Premise re-verified, not inherited

The card rules out narrowing RecentItem['type'], and that ruling-out holds. Both members
are written at runtime, in packages/app-shell/src/hooks/useTrackRouteAsRecent.ts:

:105 type: 'metadata', // inside `if (seg2 === 'metadata')`, for /metadata/:metaType/:metaName
:148 type: 'report', // inside `case 'report':`, for /report/:seg3

The union at packages/app-shell/src/context/RecentItemsProvider.tsx:47 is unchanged.
Narrowing it would have shrunk the check rather than paid off the debt — the exact
resolution the gate's own hint text warns against.

The nine translations were found, not composed

Every pack already renders both words, so nothing was invented for any locale. Sources:

  • report — the singular Report carried by appDesigner.navReport,
    appDesigner.navTypeReport and search.badgeReport (that last one is the closest
    analogue: a type badge on a search result).
  • metadata — the Metadata carried by layout.metadata.label, the nav entry for the
    same /metadata/... surface these recent items point at.
localereportsourcemetadatasource
arتقريرfound (3 keys agree)البيانات الوصفيةfound (7 uses)
deBerichtfound (3 keys agree)Metadatenfound (7 uses)
esInformefound (3 keys agree)Metadatosfound (7 uses)
frRapportfound (3 keys agree)Métadonnéesfound (7 uses)
jaレポートfound (3 keys agree)メタデータfound (7 uses)
ko보고서found (3 keys agree)메타데이터found (7 uses)
ptRelatóriofound (3 keys agree)Metadadosfound (7 uses)
ruОтчётfound (3 keys agree)Метаданныеfound (7 uses)
zh报表found — see note元数据found (7 uses)

One judgement call, zh report. The pack is not unanimous: 12 uses of 报表 against 1
of 报告 (console.breadcrumb.reports). Five of the six report-valued keys, including all
three singular ones, read 报表, so 报表 is what the pack says. The lone 报告 outlier is
noted here rather than touched — out of scope for this card.

Register and capitalisation follow each pack's own four existing itemType members rather
than English title case; the found values already matched (capitalised in de/es/fr/pt/ru,
caseless in ar/ja/ko/zh), so no case was adjusted.

Verification

The ratchet does work — the ablation pair. Keys added and baseline cleared, the gate is
green. With the two en lines deleted and the baseline still cleared, it reddens and names
both members. The mutation was confirmed on disk before the result was read (grep count on
each anchor line went 1 to 0, and the itemType block was printed back), and the restore
leg ran under a trap, verified clean by git status.

  • pnpm check:i18n-keys (fixed state) — exit 0, its own verdict line:
    Every in-scope call-site key resolves against the en pack (2822 keys), … and every dynamic key family either checks its members against a declared vocabulary or says in writing why it has none. — with 18 with a static vocabulary (112 member key(s) checked exactly).
  • pnpm check:i18n-keys (ablated state) — exit 1:
    2 dynamic-family findings — the head resolves, so the prefix rule is satisfied; these are about the MEMBERS behind it: followed by
    HomeRail.tsx:251:21 [missing-member] home.recentApps.itemType.metadata and
    HomeRail.tsx:251:21 [missing-member] home.recentApps.itemType.report.
  • pnpm vitest run packages/i18n/src/__tests__ (root vitest, never package-scoped) —
    exit 0, Test Files 54 passed (54) / Tests 898 passed (898). All ten packs pass
    all-locales-key-parity.test.ts individually: zh|ja|ko|de|fr|es|pt|ru|ar defines every en key plus … defines no key that en lacks, and placeholders match en in every pack.
  • pnpm check:i18n-drift — exit 0:
    Compared the ten locale packs at 7797e3b74 (merge-base with origin/main) with the working tree: 0 en value(s) changed (2 key(s) added, 0 removed …).
  • node scripts/check-changeset-presence.mjs — exit 0:
    ✅ 10 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s).
  • pnpm changeset:check — exit 0, ✅ No changeset declares a major bump.
  • node scripts/check-control-bytes.mjs — exit 0,
    ✅ check-control-bytes: OK (scanned 5098 tracked text file(s); skipped 85 binary).
  • pnpm turbo run type-check --filter=@object-ui/i18n — exit 0,
    Tasks: 4 successful, 4 total.
  • pnpm check:i18n-dead-keys — a report, not a gate; neither new key appears in it (both
    are dynamic-template-reachable).

Every exit code above was captured before any pipe (redirect to a file, then read the
file), and each line quoted is the gate's own, not a bare $?.

Lint was narrowed, and here is why the narrowing is a measurement. eslint ran over the
ten changed .ts files rather than the repo. (1) The universe comes from eslint's own
config, not a guess: run against the other two changed paths, eslint reports File ignored because no matching configuration was supplied. for both scripts/i18n-call-site-key-baseline.json
and the changeset .md, so the diff's lintable set is exactly those ten files. (2) The
count comes from --format json: files eslint actually linted: 10, errors: 0 warnings: 0, exit 0. (3) eslint.config.js enables no type-aware linting — its
languageOptions carries only ecmaVersion and globals, with no project or
projectService — so no untouched file's verdict can move because of this diff. CI runs
the full farm regardless.

Two things reported, not fixed

HomeRail.tsx:251 falls back to the bare lowercase it.type while RecentApps.tsx:55
and StarredApps.tsx:61 both pass capitalizeFirst(item.type). Once these keys exist the
fallback stops firing for report and metadata, so it is moot for them — but it stays
wrong for any future member, and it is the reason the English rail read report where the
cards read Report. Out of scope here; flagged for the PM to decide whether it wants a
card.

The baseline note was left exactly as it is, per the standing instruction. Reporting
one consequence rather than acting on it: the note's sentence
missingMembers is a THIRD list (objectui#4964), NOT part of that pair and NOT empty now
has a stale clause, because this change takes missingMembers to zero. The load-bearing
half is untouched and still true — the BOTH LISTS ARE NOW EMPTY sentinel is scoped to the
missingKeys + missingPrefixes pair, and residue-namespaces-3546.test.tsx's
the ratchet is empty — this is the terminal state, not a partial one passes. Not edited;
the PM decides.


Generated by Claude Code

…l ten packs
RecentItem['type'] is a six-member union and useTrackRouteAsRecent writes both
`metadata` (:105) and `report` (:148) at runtime, but the packs defined only
four of the six. Ten packs missing the same member identically is full parity,
so no pack-vs-pack gate saw it, and the three consumers' inline defaultValue
rendered a plausible English word rather than a raw key -- objectui#3517's
mechanism for hiding a missing key for months.
The nine translations reuse each pack's own existing rendering of the same word
(appDesigner.navReport / search.badgeReport for `Report`, layout.metadata.label
for `Metadata`) rather than newly composed copy.
Clears the two matching `missingMembers` entries in the call-site key baseline;
that list is a ratchet, so a baselined entry whose defect is gone fails too. The
baseline `note` is untouched: its `BOTH LISTS ARE NOW EMPTY` sentinel is scoped
to the missingKeys/missingPrefixes pair and is asserted elsewhere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3221.2 KB3990.2 KB
Main entry chunk (gzip)153.7 KB350 KB
Entry fileindex-CMfHbhSB.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)10.38KB3.90KB
app-shell (runtime-config.js)18.10KB6.51KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)505.15KB114.53KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)168.48KB46.47KB
fields (index.js)238.40KB59.89KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)23.13KB7.63KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)7.77KB3.13KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.53KB3.38KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.64KB1.50KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)1.93KB0.88KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.66KB18.32KB
plugin-chatbot (index.js)188.21KB44.67KB
plugin-dashboard (index.js)133.35KB34.45KB
plugin-designer (index.js)212.30KB42.80KB
plugin-detail (index.js)244.14KB61.94KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)125.63KB30.64KB
plugin-gantt (index.js)164.15KB39.88KB
plugin-grid (index.js)201.05KB54.38KB
plugin-kanban (index.js)52.89KB14.59KB
plugin-list (index.js)111.86KB27.22KB
plugin-map (index.js)20.11KB6.64KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.49KB11.93KB
plugin-timeline (index.js)26.49KB7.59KB
plugin-tree (index.js)9.26KB3.13KB
plugin-view (index.js)84.57KB20.74KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)54.84KB18.43KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.35KB0.70KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)12.13KB3.65KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)7.54KB2.63KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.49KB2.14KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(i18n): home.recentApps.itemType.report and .metadata are missing from all ten packs — the first members the #4964 exact check measured

2 participants

@yinlianghui-tw@claude