fix(desktop): timestamps follow the OS locale instead of en-US - #6190
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Approved 0fd360a This is a focused bug fix that makes desktop timestamps respect the OS locale instead of being hardcoded to en-US. The implementation is self-contained, well-tested, and properly handles edge cases like POSIX locale format normalization. You can customize Macroscope's approvability policy. Learn more. |
f2dc81b to
0fd360a
Compare
Dismissing prior approval to re-evaluate 0fd360a
|
Pushed a follow-up commit for the review. Rebased onto latest Fixed — mixed-language tooltips. Correct, and it was a regression this PR introduced. Fixed — adapter boundary. POSIX normalization ( Fixed — desktop coverage. Two tests added to Not doing — user documentation. Not doing — shared Verification after the change: |
The packaged desktop app ships only the en-US Chromium locale pak, and Chromium resolves its default Intl locale from the application locale rather than from the OS. Passing `undefined` to Intl.DateTimeFormat in the renderer therefore always meant "en-US", so the default "Locale" timestamp setting rendered 3:44 PM on a machine whose region asks for 15:44. Expose the OS locale over the desktop bridge via app.getSystemLocale(), which the pak trim does not affect, and format timestamps with it. Web keeps passing `undefined` and resolves from the browser as before.
Review follow-up. The tooltip month name is back on the runtime locale. Localizing it from the OS locale while the surrounding ordinal suffix and day-before-month order stay English produced mixed-language labels such as "15:44, 4th Juni 2026". Localizing that whole label is a separate change. POSIX identifier normalization (en_GB -> en-GB) moves to the Electron service, where the macOS NSLocale behavior that causes it belongs, so the renderer no longer carries platform knowledge. The renderer keeps a fallback for a tag it cannot use, since this formatter backs every timestamp in the UI. Adds focused ElectronApp coverage for both the passthrough and the normalization.
0fd360a to
244ca16
Compare
There was a problem hiding this comment.
One consistency issue found in apps/web/src/timestampFormat.ts: the day-aware timestamp now mixes the host locale (time) with the runtime-default locale (numeric date). Details inline.
Posted via Macroscope — UI Consistency
| // Deliberately not the host locale: the tooltip's ordinal suffix and | ||
| // day-before-month order below are English, so a localized month alone would | ||
| // read "4th Juni 2026". Localizing the whole label is a separate change. |
There was a problem hiding this comment.
The English-tooltip exception is well justified, but the two numeric date formatters below (numericDateFormatter, numericDateWithYearFormatter) are still built with undefined while the time formatter now uses timestampLocale. formatDayAwareTimestamp concatenates the two, so on packaged desktop — where the runtime default is pinned to en-US — an en-GB machine renders 8/13 15:44 instead of 13/08 15:44, i.e. UK hour cycle with US month/day order in the same label. That also contradicts the formatDayAwareTimestamp docstring, which promises "locale digit order".
These formatters emit no English words, so the reason given here for monthNameFormatter doesn't apply to them; suggest passing timestampLocale to both (they are declared after the timestampLocale binding, so no reordering is needed), or adding a short note if leaving them on the runtime default is deliberate.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 244ca16. Configure here.
|
|
||
| // Deliberately not the host locale: the tooltip's ordinal suffix and | ||
| // day-before-month order below are English, so a localized month alone would | ||
| // read "4th Juni 2026". Localizing the whole label is a separate change. |
There was a problem hiding this comment.
Chat dates stay US-ordered
Medium Severity
formatDayAwareTimestamp now formats the time with timestampLocale but still builds the date prefix via numericDateFormatter and numericDateWithYearFormatter on the runtime default. On packaged desktop that default stays en-US, so older chat timestamps pair an OS-locale time with US M/D order. Unlike monthNameFormatter, these numeric formatters have no English-only scaffolding that would make the host locale unsafe.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 244ca16. Configure here.
|
The current head still has the date-prefix locale bug identified by Macroscope and Bugbot. I prepared and verified the focused fix, but Please update both Verified locally against head |
## What's Changed * fix(desktop): route mouse thumb buttons to the in-app browser by @akosbalogh in pingdotgg/t3code#4459 * fix(web): keep the final segment of directory paths with a trailing separator by @jorvarea in pingdotgg/t3code#5460 * Keep block code plain when copying from rendered markdown by @yashranaway in pingdotgg/t3code#4468 * fix(web): add web app manifest so installed app keeps its scope by @Albro3459 in pingdotgg/t3code#4306 * Skip user hooks during Claude capability probes by @yashranaway in pingdotgg/t3code#4466 * fix(mobile): use Android monospace font family by @tastelessjolt in pingdotgg/t3code#4609 * fix(desktop): timestamps follow the OS locale instead of en-US by @brzzdev in pingdotgg/t3code#6190 * fix(web): keep multi-select questions open after the first click by @RaitP1 in pingdotgg/t3code#6646 * fix(web): stop clipping the changed-files expand hover on Windows by @mrmg in pingdotgg/t3code#6545 * fix(server): allow long-running git pushes by @devchaudhary24k in pingdotgg/t3code#6499 * fix(desktop): keep probing backend readiness while the process is alive by @lgwacker in pingdotgg/t3code#5526 * fix(server): allow install scripts in npm-global provider updates by @hey-jj in pingdotgg/t3code#5646 * fix: detect SSH remotes with non-git user prefixes (e.g. gitlab@) by @JackatDJL in pingdotgg/t3code#3649 * fix(web): describe what Ultracode does in the Reasoning picker by @delltrak in pingdotgg/t3code#6092 * fix(server): settle pending user-input requests when a Claude session stops by @AaronAbuUsama in pingdotgg/t3code#5127 * fix(server): stop replaying a command receipt for a different aggregate by @ostapondo in pingdotgg/t3code#5246 * fix(server): settle snoozed threads immediately by @0bkevin in pingdotgg/t3code#5379 * fix(mobile): prevent crash on sign out in settings by @shubhu121 in pingdotgg/t3code#4899 * fix(mobile): local-checkout threads record their branch so PR badges show by @Zeus-Deus in pingdotgg/t3code#4986 * fix(web): contain long approval commands by @Serendeep in pingdotgg/t3code#6503 * feat(web): make right panel maximize bindable by @husseinraoouf in pingdotgg/t3code#5091 * fix(server): respect inherited OPENCODE_CONFIG_CONTENT by @jonocodes in pingdotgg/t3code#4242 * fix(marketing): detect Mac chip on homepage download button by @mahdibm-dev in pingdotgg/t3code#4197 * Keep the server alive when a response write hits a dead socket by @yashranaway in pingdotgg/t3code#4470 * Limit physical key fallback to non-Latin layout output by @yashranaway in pingdotgg/t3code#4469 * fix: restore CLAUDE.md symlink target by @NgoQuocViet2001 in pingdotgg/t3code#3929 * fix(clients): default clone destination to folder plus repo name by @inayayousfi in pingdotgg/t3code#5989 * fix(web): keep timestamp date and time in the same locale by @juliusmarminge in pingdotgg/t3code#7081 * feat(desktop): add signal macOS DMG installer background by @Brechard in pingdotgg/t3code#6201 ## New Contributors * @akosbalogh made their first contribution in pingdotgg/t3code#4459 * @jorvarea made their first contribution in pingdotgg/t3code#5460 * @yashranaway made their first contribution in pingdotgg/t3code#4468 * @Albro3459 made their first contribution in pingdotgg/t3code#4306 * @tastelessjolt made their first contribution in pingdotgg/t3code#4609 * @brzzdev made their first contribution in pingdotgg/t3code#6190 * @RaitP1 made their first contribution in pingdotgg/t3code#6646 * @devchaudhary24k made their first contribution in pingdotgg/t3code#6499 * @lgwacker made their first contribution in pingdotgg/t3code#5526 * @JackatDJL made their first contribution in pingdotgg/t3code#3649 * @delltrak made their first contribution in pingdotgg/t3code#6092 * @AaronAbuUsama made their first contribution in pingdotgg/t3code#5127 * @0bkevin made their first contribution in pingdotgg/t3code#5379 * @shubhu121 made their first contribution in pingdotgg/t3code#4899 * @Zeus-Deus made their first contribution in pingdotgg/t3code#4986 * @husseinraoouf made their first contribution in pingdotgg/t3code#5091 * @jonocodes made their first contribution in pingdotgg/t3code#4242 * @mahdibm-dev made their first contribution in pingdotgg/t3code#4197 * @NgoQuocViet2001 made their first contribution in pingdotgg/t3code#3929 * @inayayousfi made their first contribution in pingdotgg/t3code#5989 **Full Changelog**: pingdotgg/t3code@v0.0.34-nightly.20260815.1101...v0.0.34-nightly.20260815.1102 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.34-nightly.20260815.1102


Fixes #6178.
Problem
On the packaged desktop app, the default Timestamp format: Locale setting always renders US 12-hour times —
3:44 PMon a machine whose region asks for15:44.The app ships only the
en-USChromium locale pak (DESKTOP_ELECTRON_LANGUAGES,scripts/build-desktop-artifact.ts:629), and Chromium resolves its defaultIntllocale from the application locale rather than from the OS. PassingundefinedtoIntl.DateTimeFormatin the renderer therefore meansen-UShowever the machine is configured, so the"locale"branch ofgetTimestampFormatOptions— which deliberately omitshour12and defers to the runtime — silently means "US 12-hour" on desktop.DEFAULT_TIMESTAMP_FORMATis"locale", so this is the out-of-the-box experience for every desktop user outside the US.Measured inside the packaged renderer (0.0.33, macOS set to
en_GB):The time zone resolving correctly while the locale does not is the tell: the OS is reachable from the process, and it is specifically the application locale that the pak trim pins.
Fix
Read the OS locale in the main process with
app.getSystemLocale()— which the pak trim does not affect, unlikeapp.getLocale()— expose it over the existing desktop bridge, and format timestamps with it. The bridge member followsgetAppBranding: a syncsendSyncgetter, so the cached, synchronous formatter needs no async plumbing.Web is unchanged: with no bridge present the resolver returns
undefinedand the browser keeps resolving its own locale, which is already correct there.resolveTimestampLocalenormalizes POSIX-style tags (en_GB→en-GB) and falls back to the runtime default rather than throwing if the host ever reports something ICU rejects, since the formatter backs every timestamp in the UI.Before / after
Chat timestamps, rendered by the real client under each locale. Same fixture, same crop; only the locale the formatter receives differs.
en-US— what desktop shows today)en-GB)A note on how these were produced, so the evidence is not overstated: the bug does not reproduce in a dev run, because
electronLanguagesis an electron-builder packaging option andpnpm starthas every locale pak. These are the web client driven under a locale-pinned Chromium context —en-USfor before, the OS localeen-GBfor after — which is exactly the pair of locales the formatter receives on either side of this change. The IPC half is covered by types and by thegetAppBrandingprecedent it mirrors, not by these images.Surfaces
undefinedwithout a bridge.DesktopBridgegains one optional member.Out of scope
Three other call sites format with an implicit locale and are wrong on desktop for the same reason. Left alone to keep this to one concern; happy to follow up:
apps/web/src/components/settings/ConnectionsSettings.tsx:144apps/web/src/components/clerk/MobileClientsUserProfilePage.logic.ts:3packages/client-runtime/src/state/threadSettled.ts:300(snooze preset labels)Testing
resolveTimestampLocaleis unit tested for the tag it picks and for the hour cycle that results, including theen-GB→15:44/en-US→3:44 PMpair.ElectronApp.test.tscovers the OS-locale passthrough and the POSIX normalization. Targetedvp test runon both files (25 and 8 passing), plus typecheck and lint on the three touched packages.Four other
ElectronApptest stubs gained the newsystemLocalemember. Those four are among 22 desktop test files that fail to import in my environment onmain— an unrelatedvi.mock/electronissue, identical before and after this change — so they are type-correct but I could not execute them locally.ElectronApp.test.tsitself is not affected and runs green.Written by Claude Opus 5 in T3 Code.
Note
Low Risk
Localized display-only timestamp formatting on desktop; web unchanged. Fallbacks avoid throws on bad locale tags.
Overview
Fixes packaged desktop timestamps always rendering as US 12-hour when Timestamp format: Locale is selected, because Chromium’s default
Intllocale is pinned toen-US(only that locale pak ships).The main process now reads
Electron.app.getSystemLocale(), normalizes POSIX tags (en_GB→en-GB), and exposes the result via a new syncgetSystemLocaleIPC path ondesktopBridge(mirroringgetAppBranding).In
timestampFormat.ts,resolveTimestampLocalevalidates the host tag and feeds it into cachedIntl.DateTimeFormatinstances so wall-clock times follow the OS (e.g.15:44foren-GB). Without a bridge (web), behavior is unchanged (undefined→ browser default). Invalid tags fall back instead of breaking the UI.DesktopBridgegains optionalgetSystemLocale. Desktop test stubs pick upsystemLocaleonElectronApp; new unit tests cover locale resolution and Electron passthrough/normalization.Reviewed by Cursor Bugbot for commit 244ca16. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix timestamp formatting to use OS locale instead of en-US
systemLocaleto theElectronAppservice, readingElectron.app.getSystemLocale()and normalizing POSIX-style tags (e.g.en_GB→en-GB).getSystemLocale) andwindow.desktopBridge.getSystemLocale().resolveTimestampLocalein timestampFormat.ts to validate the host-provided locale usingIntl.DateTimeFormat.supportedLocalesOf, falling back to the runtime default on invalid or missing values.Intl.DateTimeFormattimestamp formatters now use the resolved OS locale instead of an impliciten-USdefault.en-GB), which may differ visually from previous output.Macroscope summarized 244ca16.