refactor(i18n,format): translate ETA strings; consolidate time/duration formatters
- formatEta was hardcoded English (violated the trilingual rule) -> time.eta.* keys in EN/HU/DE; Scheduler's countdown 'now' likewise. - relativeFromMs added to format.ts; NotificationsPanel drops its duplicate relativeTime/relativeFromMs and the now-orphaned notifications.time.* keys. - Channels' fmtTotalDuration moved to format.ts as formatTotalHours.
This commit is contained in:
parent
5768c1a5cb
commit
9eaec27c7c
10 changed files with 61 additions and 64 deletions
|
|
@ -2,8 +2,14 @@ import i18n from "../i18n";
|
|||
|
||||
export function relativeTime(iso: string | null): string {
|
||||
if (!iso) return "";
|
||||
const then = new Date(iso).getTime();
|
||||
const secs = Math.max(0, (Date.now() - then) / 1000);
|
||||
return relativeFromMs(new Date(iso).getTime());
|
||||
}
|
||||
|
||||
/** Relative-time label from an epoch-millis timestamp (the ms-based half of relativeTime, for
|
||||
* client-side notifications whose timestamps are already numbers). One implementation, one
|
||||
* set of `time.*` strings — shared instead of re-implemented per component. */
|
||||
export function relativeFromMs(ms: number): string {
|
||||
const secs = Math.max(0, (Date.now() - ms) / 1000);
|
||||
const units: [number, string][] = [
|
||||
[60, "time.secondsAgo"],
|
||||
[3600, "time.minutesAgo"],
|
||||
|
|
@ -51,17 +57,21 @@ export function quotaActionLabel(action: string): string {
|
|||
return i18n.t(`quotaActions.${action}`, { defaultValue: action });
|
||||
}
|
||||
|
||||
/** Coarse, human ETA for a remaining duration in seconds ("~3 hours", "~2 days"). */
|
||||
/** Coarse, human ETA for a remaining duration in seconds ("~3 hours", "~2 days"). Translated
|
||||
* via the `time.eta.*` keys (was hardcoded English, violating the trilingual rule). */
|
||||
export function formatEta(seconds: number): string {
|
||||
if (seconds <= 0) return "done";
|
||||
if (seconds <= 0) return i18n.t("time.eta.done");
|
||||
const hours = seconds / 3600;
|
||||
if (hours < 1) return "< 1 hour";
|
||||
if (hours < 24) {
|
||||
const h = Math.round(hours);
|
||||
return `~${h} hour${h === 1 ? "" : "s"}`;
|
||||
}
|
||||
const d = Math.round(hours / 24);
|
||||
return `~${d} day${d === 1 ? "" : "s"}`;
|
||||
if (hours < 1) return i18n.t("time.eta.lessThanHour");
|
||||
if (hours < 24) return i18n.t("time.eta.hours", { count: Math.round(hours) });
|
||||
return i18n.t("time.eta.days", { count: Math.round(hours / 24) });
|
||||
}
|
||||
|
||||
/** Compact whole-channel total length ("12 h", "45 m"), hours-scale so H:MM:SS isn't huge. */
|
||||
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`;
|
||||
}
|
||||
|
||||
export function formatViews(n: number | null): string {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue