fix(plugin-report): report and preview measures follow the display locale (#4575) - #4582
Merged
yinlianghui merged 1 commit intoAug 13, 2026
Merged
Conversation
…cale (#4575) objectui#4566 gave `formatMeasure` / `formatDimensionValue` an optional trailing `locale` and threaded `useDisplayLocale()` from the dashboard's `DatasetWidget`. The parameter is optional by design, so the consumers that card could not reach kept formatting in the MACHINE's locale — a German session read a report measure as `1,234.5` beside a dashboard measure rendering `1.234,5`. The remaining thirteen sites thread the display locale: DatasetReportRenderer (ten — grouped table cells and total, the single-value chart metric, and the cross-tab's header, down-axis cell, cell and three totals), DatasetPreview (two) and DatasetDefaultInspector's format-hint sample (one). English output does not move: these sites already grouped through `Intl`, so the only change is whose locale is used. Every new case pins de AND en, so at least one half must fail on any runner. The cross-tab builds its header labels inside a `useMemo`, so the locale joins that dependency array — measured: removing only that entry turns exactly the dep-isolation case red and leaves the other nine green. The metadata designer's `locale` prop is deliberately not used — it is the designer's chrome language (`useMetadataLocale()`: exactly en-US or zh-CN), not a number-formatting locale. Both packages are patch: their built `.d.ts` are byte-identical (dist cleared between builds; verified falsifiable with a probe export). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
yinlianghui
marked this pull request as ready for review
August 13, 2026 13:42
yinlianghui
deleted the
claude/issue-4575-report-preview-measure-locale
branch
August 13, 2026 13:42
This was referenced Aug 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4575
objectui#4566 (PR #4577) gave
formatMeasure/formatDimensionValuein@object-ui/corean optional trailinglocaleand threadeduseDisplayLocale()through the dashboard'sDatasetWidget. The parameter is OPTIONAL by design, so the producer could land without dragging every consumer with it — which left the consumers it could not reach still formatting in the MACHINE's locale. A German session read a report measure as1,234.5directly beside a dashboard measure that, after #4566, rendered1.234,5.What changed
All thirteen censused call sites thread
useDisplayLocale(). Line numbers were re-located by content and matched the issue's census exactly:packages/plugin-report/src/DatasetReportRenderer.tsxbucketLabel(792), cross-tab down-axis cell (980), measure cell (994), row total (1005), column total (1019), grand total (1029)packages/app-shell/src/views/metadata-admin/previews/DatasetPreview.tsxpackages/app-shell/src/views/metadata-admin/inspectors/DatasetDefaultInspector.tsxTwo findings shaped the implementation:
The cross-tab formats inside a
useMemo.bucketLabelis called from within thepivotmemo, so it takes the locale as a parameter and the locale joins that memo's dependency array. Threading the call alone would leave the across-axis headers frozen in whatever locale they were first built with.The metadata designer's
localeprop is deliberately NOT the channel. That prop comes fromuseMetadataLocale(), which resolves to exactlyen-USorzh-CN— it is the designer's chrome language, so a German session getsen-USfrom it. The preview's numbers must match what the report and dashboard render for the same dataset, which isuseDisplayLocale(). A dedicated case pins the discriminator: chrome locale held aten-USwhile the session is German still renders1.234,5.Red-first, with the directions predicted in writing
Runner machine locale measured as
en-US. Every case pins the same value in de AND en, so at least one half must fail on ANY runner — before the change both render in the machine's locale, which is what makes the machine locale stop being a test input.Predicted, then measured — 11 red / 12 green, exactly as written:
The 12 green-on-both-sides cases are the en byte-identity pins plus the labelled guards. English output does not move — these sites already grouped through
Intl, so the only change is whose locale is used. (Contrast objectui#4553, whereformatPercenthad never grouped and moving en WAS the fix.)Reverse verification of the dependency array
Removing only the dep-array entry, leaving the locale threaded into the call, turns exactly one case red and leaves the other nine green:
That isolation is only possible because the harness re-uses one report element across the rerender, so React bails out on the unchanged child: the parent does not re-render, the
readNames(...)array props keep their identity, anduseDatasetRowsdoes not refetch (its effect is keyed on a signature the locale is not part of). Restored and verified byte-identical by sha256. Not reasoning-guarded — genuinely isolated.Malformed-tag safety is not re-implemented; it belongs to the producer's
formatNumberInLocaleretry. One guard per package pins only that a bad tag does not take the surface down, asserted against the producer's own no-locale output so it stays machine-locale-independent.Verification
packages/plugin-report, metadata-adminpreviews+inspectors, plus fix(core): dashboard measures follow the display locale (#4566) #4577's producer pins (dataset-format.locale,DatasetWidget.measureLocale) — 99 files, 1145 passed, 1 skipped, 0 failed. Existing suites green and untouched.tscpasses (tsc --noEmit && tsc -p tsconfig.test.json) — clean.origin/mainbaseline — NET ZERO: plugin-report 72 → 72, app-shell 2373 → 2373 (0 errors both sides)..d.tsboth ways: withdist/andtsconfig.tsbuildinfocleared between builds, plugin-report (10 files) and app-shell (416 files) declarations are byte-identical. Falsified with a positive control — a temporary probe export made the comparison differ, and reverting returned it to identical — so the check is not blind. Hencepatch+patch, never minor: the only signature that gained a parameter is the file-local, non-exportedbucketLabel.check:control-bytesOK; NBSP/NNBSP written asescapes throughout, with trim-only normalizers where Testing Library's default would collapse them.check:phantom-deps: OK — both packages already declared@object-ui/i18n.Note
These surfaces are now deterministic where they previously followed whatever locale the machine ran in:
useDisplayLocaleends at a concrete'en'rather than theundefinedthat handsIntlthe machine's locale. The inspector case that mounts with no providers at all documents that, and is why the sibling suite stays green untouched.Surface respected:
ReportViewer.tsx(#4548),packages/react, SettingsView (#4570),apps/consoleentry (#4563), types + ObjectGrid exportOptions (#4535) andcontent/docs/releases/were not touched.Generated by Claude Code