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
+3 -2
View File
@@ -1,5 +1,6 @@
import { useTranslation } from "react-i18next";
import { Layers } from "lucide-react";
import { formatNumber } from "../../lib/format";
// At a million and above we stop printing the exact figure — six digits is the readable ceiling, so
// the pill shows "1M+" and the tooltip carries the precise number.
@@ -20,12 +21,12 @@ export default function ItemCount({ count }: { count?: number }) {
? ""
: t("common.itemCount", {
count,
formattedCount: count >= OVERFLOW_AT ? "1M+" : count.toLocaleString(),
formattedCount: count >= OVERFLOW_AT ? "1M+" : formatNumber(count),
});
return (
<span
data-testid="item-count"
title={count?.toLocaleString()}
title={count == null ? undefined : formatNumber(count)}
className="glass-card inline-flex shrink-0 items-center justify-center gap-1.5 rounded-full border border-border px-3 py-1 text-sm text-muted min-w-[9rem] whitespace-nowrap"
>
<Layers className="h-3.5 w-3.5 shrink-0 text-muted" aria-hidden="true" />