fix: numbers follow the UI language, not the browser's

`n.toLocaleString()` groups in the BROWSER's locale, so an English UI in a
Hungarian browser printed "1 234 567" while a Hungarian UI in an English
browser printed "1,234,567" — the number half of the date defect fixed in
618ef812. One `formatNumber` in lib/format.ts (a per-language cached
Intl.NumberFormat, like the relative-time formatters beside it) now serves
every grouped figure: Stats, Scheduler, the channel columns and the stats
popover, VideoCard's view tooltip, the ItemCount pill, and formatTotalHours.

ReleaseNotes' `toLocaleDateString(undefined, …)` was the one DATE site the
previous sweep missed; it moves onto formatDate.

The new cases assert both languages and that the two differ, instead of
comparing against the runtime's own default: that default is Hungarian on the
dev box and English on a CI image, so a one-language assertion would pass
under the old bug on half the machines. Verified in Chromium on :5173 with the
browser forced to hu-HU and the UI in English — Stats, Scheduler and the
channel table all keep comma grouping.
This commit is contained in:
2026-09-16 01:05:53 +02:00
parent 618ef812e6
commit a5bcd9fca2
11 changed files with 141 additions and 51 deletions
+22 -1
View File
@@ -132,7 +132,28 @@ export function formatEta(seconds: number): string {
export function formatTotalHours(sec: number): string {
if (!sec) return "—";
const h = Math.round(sec / 3600);
return h >= 1 ? `${h.toLocaleString()} h` : `${Math.max(1, Math.round(sec / 60))} m`;
return h >= 1 ? `${formatNumber(h)} h` : `${Math.max(1, Math.round(sec / 60))} m`;
}
// One grouped-number formatter per language, built lazily — the same reason as the relative-time
// formatters above: the stats tables and the feed format a number per row, and constructing an Intl
// formatter is the expensive part. Keyed by language because the user can switch it at runtime.
const numberFormatters = new Map<string, Intl.NumberFormat>();
/** A grouped number in the UI language ("1,234,567" in English, "1 234 567" in Hungarian). A bare
* `n.toLocaleString()` groups in the BROWSER's locale instead, so an English UI in a Hungarian
* browser showed space-grouped figures and vice versa — the number half of the same defect
* `formatDateTime` fixes for dates. Empty string for a missing/non-finite value, so a caller's
* `|| "—"` fallback covers it like a missing one. */
export function formatNumber(n: number | null | undefined): string {
if (n == null || !Number.isFinite(n)) return "";
const lang = i18n.language;
let formatter = numberFormatters.get(lang);
if (!formatter) {
formatter = new Intl.NumberFormat(lang);
numberFormatters.set(lang, formatter);
}
return formatter.format(n);
}
export function formatViews(n: number | null): string {