fix(plugin-timeline): dates follow the active locale instead of hardcoded en-US (#4513) - #4523
Merged
Merged
Conversation
…oded en-US (#4513) `renderer.tsx` passed a literal 'en-US' to four Intl calls (the hour, day and month gantt headers, and the `long` item date) and passed nothing at all to a fifth (the `short` item date), so a fully Chinese timeline rendered an English axis and English item dates. The bare call is the same defect spelled as an omission: no tag means the MACHINE's locale, which agreed with the other four only by the accident of an en-US runner. All five now resolve through `useDisplayLocale()` (tenant regional default → active UI language → 'en'), the one channel objectui#4468 / PR #4512 converged `@object-ui/fields` onto. The two date helpers are module-level functions, so the locale is read once in `TimelineRenderer` and threaded down: `generateTimeScaleHeaders` takes an optional trailing `locale` defaulting to 'en' (it is exported and driven directly by the spec-parity test), and the module-private `formatDate` takes it as a required parameter so no future branch can silently reintroduce either wrong channel. English output is byte-identical at every site. The locale-free header vocabularies (`Week n`, `Qn YYYY`, `YYYY`) are untouched — they need the package's translate channel rather than a locale tag, filed as objectui#4520. 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
|
`generateTimeScaleHeaders` is reachable from the package entry (`index.tsx` does `export * from './renderer'`) and its published declaration grew an optional trailing `locale?: string`. Entry-reachable additive API growth is minor, not patch — patch is for changes with no API-surface movement at all. `dist/index.d.ts` being byte-identical does not argue for patch: the entry re-exports by reference, so the resolved public surface moved even though the entry file's bytes did not. The contrapositive of #4496, which was graded patch precisely because its .d.ts additions were NOT re-exported from the entry; #4403 / #4177 / #4485 / #4495-regrade are the line this follows. Additive and back-compatible is what minor means — no consumer breaks, existing three-argument callers keep compiling and keep producing byte-identical output. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
yinlianghui
marked this pull request as ready for review
August 13, 2026 04:38
Collaborator
Author
|
PM step-7 复核 — ACCEPT (session_017Qqyix2QcnpUC9XeYVDzx3)
Auto-merge armed (squash). Generated by Claude Code Generated by Claude Code |
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.
Closes #4513
A
zhconsole rendered a fully Chinese timeline widget whose axis readAug 11/Sep 2026. Nothing a user or a tenant configured could reach those dates.The five sites (all verified on current
main, no drift since the #4468 census)renderer.tsx:71toLocaleString('en-US', { month, day, hour })— hour gantt headerAug 11, 9 AM8月11日 9时renderer.tsx:77toLocaleDateString('en-US', { month, day })— day gantt headerAug 118月11日renderer.tsx:108toLocaleDateString('en-US', { month, year })— month gantt headerAug 20262026年8月renderer.tsx:157toLocaleDateString()—shortitem date8/11/20262026/8/11renderer.tsx:160toLocaleDateString('en-US', { year, month, day })—longitem dateAugust 11, 20262026年8月11日:157is the same defect spelled as an omission rather than a literal: a bare call means the machine's locale, so it agreed with the other four only by the accident of an en-US runner (this container resolvesen-US, confirmed) and would render a third locale on anyone else's machine.The fix — the established one-resolver
All five resolve through
useDisplayLocale()from@object-ui/i18n(tenant regional default → active UI language →'en'), the channel PR #4512 confirmed for all six@object-ui/fieldssites.Intlaccepts'zh'verbatim, so there is no mapping table here or anywhere else.Both date helpers are module-level functions and cannot host a hook, so the locale is read once in
TimelineRenderer— above every variant's early return, so the hook count can never depend onvariant— and threaded down to all seven call sites:generateTimeScaleHeaderstakes an optional trailinglocaledefaulting to'en'. It is exported (index.tsxdoesexport * from './renderer') and driven directly by the spec-parity test, so growing the signature was measured necessary — the alternative, a locale-less exported wrapper, would have left a second hardcoded channel inside the very function the card is about. Additive and back-compatible: existing three-argument callers keep compiling and keep producing byte-identical output, since'en'and the retired'en-US'agree at all three header sites.formatDatetakes it as a required parameter, so no future branch can silently reintroduce either wrong channel.No other signature changed;
TimelineRenderer's props are untouched.Red-first, per site
Both test files were written against the unfixed renderer and re-run against
origin/mainafter the fix as reverse verification. Predicted direction — zh red, en green — held exactly: 8 failed | 13 passed, and the 8 are precisely the zh sites plus the explicit-locale helper case. Verbatim pre-fix output:After the fix: 45 passed (45) across all 6 files in the package.
Must-not-change (green on both sides)
en sessionblock, and green before and after by construction.Week n,Qn YYYY,YYYY).dateFormat: 'iso'stays a machine format and does not become a locale one.Two traps this card named
toLocale*output, so there is no respelling to do (the spec-parity test asserts only locale-free forms:Q1 2026,2025, and non-empty length). The new fallback file spells its expectations'en'explicitly rather than computing them from a bare call, so they cannot silently follow the runner the way the code under test used to.timeline-date-locale-fallback.test.tsx, which mounts noI18nProviderat all — a provider-less render placed after azhcase in the same file would resolve'zh'from react-i18next's global instance and assert test ordering rather than behavior. That file also states honestly that its rendered cases are green on both sides on an en-US runner and are therefore a must-not-change pin, not red-first evidence.Grading
patchfor@object-ui/plugin-timelineonly —@object-ui/i18nis consumed, not changed..d.tsmeasured both ways (build before, build after, diff), and the whole delta is one optional parameter:Verification
Dependency closure built first; heavy runs serialized under the shared lock.
pnpm --filter '@object-ui/plugin-timeline^...' build— greenpnpm exec vitest run packages/plugin-timeline/(repo root) — 45 passed (45), 6 filesnpx tsc --noEmit— green;npx tsc -p tsconfig.test.json— green (both, per the package'stype-check)npx eslint .— 0 errors (68 pre-existing warnings, unchanged)node scripts/check-control-bytes.mjs— OK, 4237 files; plus a targeted self-scan of the four changed filesOut of scope, filed
#4520 — the same renderer's
Week n/Qn YYYYgantt headers and the'Items'row-label default are hardcoded English strings. Same session, same surface, but they need the package's translate channel (useTimelineTranslation) rather than a locale tag, and they are vocabulary growth rather than a mechanical extension of this fix. NoIntlcall is involved, so the two edits are disjoint.Generated by Claude Code