diff --git a/web/src/lib/format.ts b/web/src/lib/format.ts new file mode 100644 index 0000000..225a773 --- /dev/null +++ b/web/src/lib/format.ts @@ -0,0 +1,78 @@ +import { localeOf, type Lang } from "./i18n"; + +const DUR_UNITS: Record = { + en: { s: "s", m: "m", h: "h", d: "d" }, + fa: { s: "ث", m: "د", h: "س", d: "ر" }, +}; + +export const pctSign = (lang: Lang) => (lang === "fa" ? "٪" : "%"); + +export function fmtNumber(lang: Lang, value: number, digits = 0): string { + return new Intl.NumberFormat(localeOf(lang), { + minimumFractionDigits: digits, + maximumFractionDigits: digits, + }).format(value); +} + +/** Uptime percent: "99.98" — trims to the precision that matters. */ +export function fmtUptime(lang: Lang, pct: number): string { + const digits = pct >= 100 ? 0 : pct >= 99 ? 2 : 1; + return fmtNumber(lang, pct, digits); +} + +export function fmtLatency(lang: Lang, ms: number): string { + if (ms >= 1000) return `${fmtNumber(lang, ms / 1000, 2)}s`; + if (ms >= 100) return `${fmtNumber(lang, ms, 0)}ms`; + return `${fmtNumber(lang, ms, 1)}ms`; +} + +export function fmtClock(lang: Lang, date: Date): string { + return new Intl.DateTimeFormat(localeOf(lang), { + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + hour12: false, + }).format(date); +} + +export function fmtTime(lang: Lang, ts: number): string { + return new Intl.DateTimeFormat(localeOf(lang), { + hour: "2-digit", + minute: "2-digit", + hour12: false, + }).format(new Date(ts)); +} + +export function fmtDate(lang: Lang, ts: number): string { + return new Intl.DateTimeFormat(localeOf(lang), { + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + hour12: false, + }).format(new Date(ts)); +} + +export function fmtHour(lang: Lang, hour: number): string { + return fmtNumber(lang, hour); +} + +/** "3m 20s" style duration, localized digits and units. */ +export function fmtDuration(lang: Lang, ms: number): string { + const u = DUR_UNITS[lang]; + const s = Math.max(0, Math.round(ms / 1000)); + if (s < 60) return `${fmtNumber(lang, s)}${u.s}`; + const m = Math.floor(s / 60); + if (m < 60) return `${fmtNumber(lang, m)}${u.m} ${fmtNumber(lang, s % 60)}${u.s}`; + const h = Math.floor(m / 60); + if (h < 24) return `${fmtNumber(lang, h)}${u.h} ${fmtNumber(lang, m % 60)}${u.m}`; + const d = Math.floor(h / 24); + return `${fmtNumber(lang, d)}${u.d} ${fmtNumber(lang, h % 24)}${u.h}`; +} + +/** Seconds → "15s" / "5m" for check intervals. */ +export function fmtInterval(lang: Lang, sec: number): string { + if (sec < 60) return `${fmtNumber(lang, sec)}s`; + if (sec < 3600) return `${fmtNumber(lang, Math.round(sec / 60))}m`; + return `${fmtNumber(lang, Math.round(sec / 3600))}h`; +}