fix(plugin-gantt): tooltip numbers and currency follow the display locale (#4553) - #4557
Merged
Merged
Conversation
…cale (#4553) The tooltip value formatter in ObjectGantt's `tasks` memo had its four temporal call sites threaded with `useDisplayLocale()` by objectui#4272. The numeric cases beside them passed no locale, so they reached `new Intl.NumberFormat(undefined, ...)` — the machine's locale, which is neither of the repo's two locale channels. One tooltip rendered two conventions: a German session read `5. Jan. 2024` on the date row and `1,234.50` on the amount row below it, where German groups with `.` and marks the decimal with `,`. Inverted separators read as a different number, not an unstyled one. `number`/`integer`/`float`/`decimal` and `currency` now pass the `displayLocale` already read at component level, via each formatter's existing locale parameter. No formatter signature and no memo dependency changed; the package's .d.ts files are byte-identical. `percent` is deliberately NOT threaded: `formatPercent(value, precision)` takes no locale parameter at all, so closing that half needs a `@object-ui/fields` signature change, which is outside this card's ruled surface. It is pinned by a test and escalated on #4553. 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
|
Collaborator
Author
|
PM step-7 复核 — ACCEPT(本 PR 为 #4553 的两站点半,卡保持开放候 percent 裁决执行)(session_017Qqyix2QcnpUC9XeYVDzx3)
Percent ruling: option A — posted on #4553; the same dev continues. Auto-merge armed (squash) — landing verified per the merge-queue discipline. Generated by Claude Code Generated by Claude Code |
yinlianghui
marked this pull request as ready for review
August 13, 2026 09:05
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.
Part of #4553 — two of the card's three call sites. The third is a premise
inversion that needs a ruling before it can be touched; details below, and this
PR deliberately does not close the card.
What changed
formatFieldValue(the tooltip value formatter inside ObjectGantt'stasksmemo) had its four TEMPORAL call sites threaded with
useDisplayLocale()by#4272 / PR #4544. The numeric cases beside them passed no locale, so they
reached
new Intl.NumberFormat(undefined, ...)— the MACHINE's locale, whichis neither of the repo's two locale channels.
One tooltip, two conventions: a German session read
5. Jan. 2024on the daterow and
1,234.50on the amount row directly below it, where German groups with.and marks the decimal with,. Inverted separators do not read as anunstyled number — they read as a different number.
number/integer/float/decimalandcurrencynow pass thedisplayLocalealready read at component level (L435, added by PR #4544), usingeach formatter's existing locale parameter. No formatter signature changed and
no memo dependency changed —
displayLocalehas been in that array since #4272.The card's premise held for two of three formatters
The ruling required measuring each formatter's signature in
packages/fieldsfirst, and treating a missing locale parameter as a premise inversion. Measured:
formatNumber(value, decimals = 2, locale?)formatCurrency(value, currency?, locale?)formatPercent(value, precision = 0)The issue states all three end up at
formatDisplayNumberwith an undefinedlocale.
formatPercentdoes not: its whole body is`${percentDisplayValue(value).toFixed(precision)}%`. It builds noIntl.NumberFormatand never reachesformatDisplayNumber, so its output isnot the machine's locale but no locale — an ASCII decimal mark, never
grouped, byte-identical on every machine (
1235%where German wants1.235 %).So the percent row is a different defect class from the other two, and threading
is not available to it: closing it means adding a parameter to a
@object-ui/fieldsexport, which this card's ruled surface excludes(
packages/fieldsis read-only here). Per the ruling I stopped rather thanedited fields. The percent row is pinned as-is by a test in this PR, labelled
as evidence of the inversion rather than an endorsement, so the gap cannot drift
unnoticed and will go red the day
formatPercentgrows a locale.Verification
Red-first, directions predicted in writing before the run and recorded in the
test file header. Runner: node v22.22.2 / ICU 78.2 / machine locale en-US.
Before the fix — both call sites independently red (assertion order is
deliberate: a failing
expectaborts its test, so with the number row assertedfirst everywhere the currency site would never report its own red):
After:
Tests 5 passed (5). Full package suite:Test Files 44 passed (44),Tests 383 passed (383)— PR #4544's date threading and PR #4554's currency-depand locale-dep cases green untouched, field-explicit currency precedence
unchanged.
Reverse verification via
git diff > fix.patch+git checkout --(nevergit stash): removing the fix restored exactly those 3 failures with the 2 pinsstill green; restore confirmed byte-identical by sha256.
enis pinned byte-identical at every touched site. Thoseencases are PINS,green on both sides —
enand the runner'sen-UScoincide here, so theyassert unchanged English output and are not evidence the fix works; the
decases carry that.
Other gates: both tsc passes green (
tsc --noEmit && tsc -p tsconfig.test.json);eslint 0 errors, and the new test file produces the same 5 warnings as its two
sibling locale test files already on main (identical stub idiom, no drift);
check:control-bytes,check:phantom-deps,changeset:checkall green.Why
patchConsumer-side threading only, module-local: the package's 9
dist/*.d.tsfilesare byte-identical before and after (verified by sha256 in both directions).
Surface
packages/plugin-gantt/src/ObjectGantt.tsx, one new test file, one changeset —nothing else.
packages/fields, plugin-grid, app-shell/studio, plugin-kanban andthe CelPredicateField family are untouched.
Generated by Claude Code