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:
@@ -4,7 +4,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { qk } from "../lib/queryKeys";
|
||||
import { History, Pause, Play, RefreshCw } from "lucide-react";
|
||||
import { api, type AdminQuotaRow, type Me } from "../lib/api";
|
||||
import { formatEta, quotaActionLabel } from "../lib/format";
|
||||
import { formatEta, formatNumber, quotaActionLabel } from "../lib/format";
|
||||
import { notify } from "../lib/notifications";
|
||||
import { notifyYouTubeActionError } from "../lib/youtubeErrors";
|
||||
import { useWizard } from "./WizardProvider";
|
||||
@@ -115,10 +115,10 @@ function Overview({ me }: { me: Me }) {
|
||||
</SettingRow>
|
||||
)}
|
||||
<SettingRow label={t("stats.sync.myVideos")} hint={t("stats.sync.myVideosHint")}>
|
||||
{s.my_videos.toLocaleString()}
|
||||
{formatNumber(s.my_videos)}
|
||||
</SettingRow>
|
||||
<SettingRow label={t("stats.sync.quotaLeft")} hint={t("stats.sync.quotaLeftHint")}>
|
||||
{s.quota_remaining_today.toLocaleString()}
|
||||
{formatNumber(s.quota_remaining_today)}
|
||||
</SettingRow>
|
||||
</div>
|
||||
) : status.isError ? (
|
||||
@@ -135,16 +135,16 @@ function Overview({ me }: { me: Me }) {
|
||||
<>
|
||||
<div className="space-y-1.5 text-sm">
|
||||
<SettingRow label={t("stats.sync.today")} hint={t("stats.sync.todayHint")}>
|
||||
{usage.data.today.toLocaleString()}
|
||||
{formatNumber(usage.data.today)}
|
||||
</SettingRow>
|
||||
<SettingRow label={t("stats.sync.last7d")}>
|
||||
{usage.data.last_7d.toLocaleString()}
|
||||
{formatNumber(usage.data.last_7d)}
|
||||
</SettingRow>
|
||||
<SettingRow label={t("stats.sync.last30d")}>
|
||||
{usage.data.last_30d.toLocaleString()}
|
||||
{formatNumber(usage.data.last_30d)}
|
||||
</SettingRow>
|
||||
<SettingRow label={t("stats.sync.allTime")}>
|
||||
{usage.data.all_time.toLocaleString()}
|
||||
{formatNumber(usage.data.all_time)}
|
||||
</SettingRow>
|
||||
</div>
|
||||
{Object.keys(usage.data.by_action).length > 0 && (
|
||||
@@ -155,7 +155,7 @@ function Overview({ me }: { me: Me }) {
|
||||
.map(([action, units]) => (
|
||||
<div key={action} className="flex justify-between gap-2">
|
||||
<span>{quotaActionLabel(action)}</span>
|
||||
<span className="tabular-nums">{units.toLocaleString()}</span>
|
||||
<span className="tabular-nums">{formatNumber(units)}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -274,7 +274,7 @@ function SystemStats() {
|
||||
<div className="text-xs text-muted mb-2">
|
||||
{t("stats.dailyTotal", {
|
||||
count: data.range_days,
|
||||
units: grandTotal.toLocaleString(),
|
||||
units: formatNumber(grandTotal),
|
||||
})}
|
||||
</div>
|
||||
{data.daily.length === 0 ? (
|
||||
@@ -285,7 +285,7 @@ function SystemStats() {
|
||||
<div
|
||||
key={d.day}
|
||||
className="flex-1 h-full flex items-end bg-card/50 rounded-t"
|
||||
title={t("stats.dailyTooltip", { day: d.day, units: d.total.toLocaleString() })}
|
||||
title={t("stats.dailyTooltip", { day: d.day, units: formatNumber(d.total) })}
|
||||
>
|
||||
<div
|
||||
className="w-full bg-accent hover:opacity-80 rounded-t transition"
|
||||
@@ -328,7 +328,7 @@ function UserRow({ row, max }: { row: AdminQuotaRow; max: number }) {
|
||||
{isSystem ? t("stats.system") : row.email}
|
||||
</span>
|
||||
<span className="text-sm font-semibold tabular-nums shrink-0">
|
||||
{row.total.toLocaleString()}
|
||||
{formatNumber(row.total)}
|
||||
</span>
|
||||
</button>
|
||||
{/* Proportion bar */}
|
||||
@@ -343,7 +343,7 @@ function UserRow({ row, max }: { row: AdminQuotaRow; max: number }) {
|
||||
{actions.map(([action, units]) => (
|
||||
<div key={action} className="flex items-center justify-between gap-2">
|
||||
<span>{quotaActionLabel(action)}</span>
|
||||
<span className="tabular-nums">{units.toLocaleString()}</span>
|
||||
<span className="tabular-nums">{formatNumber(units)}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user