import { normalizeLocale, type SupportedLocale } from "./message-contract.js"; const FORMAT_FALLBACK = "—"; export type DateFormatStyle = "short" | "medium" | "long"; export function formatDate( locale: SupportedLocale, value: Date | number, options: Readonly<{ dateStyle?: DateFormatStyle; timeZone?: string; }> = {}, ): string { try { const date = value instanceof Date ? value : new Date(value); if (Number.isNaN(date.getTime())) return FORMAT_FALLBACK; return new Intl.DateTimeFormat(normalizeLocale(locale), { dateStyle: options.dateStyle ?? "medium", timeZone: options.timeZone ?? "UTC", }).format(date); } catch { return FORMAT_FALLBACK; } } export function formatNumber( locale: SupportedLocale, value: number, options: Readonly<{ style?: "decimal" | "percent"; maximumFractionDigits?: number; }> = {}, ): string { try { if (!Number.isFinite(value)) return FORMAT_FALLBACK; return new Intl.NumberFormat(normalizeLocale(locale), options).format(value); } catch { return FORMAT_FALLBACK; } } export function formatRelativeTime( locale: SupportedLocale, value: number, unit: Intl.RelativeTimeFormatUnit, ): string { try { if (!Number.isFinite(value)) return FORMAT_FALLBACK; return new Intl.RelativeTimeFormat(normalizeLocale(locale), { numeric: "auto", }).format(value, unit); } catch { return FORMAT_FALLBACK; } } export function formatList( locale: SupportedLocale, values: readonly string[], ): string { try { return new Intl.ListFormat(normalizeLocale(locale), { style: "long", type: "conjunction", }).format(values); } catch { return values.join(", "); } } export function selectPlural( locale: SupportedLocale, value: number, choices: Readonly< Partial> & { other: string } >, ): string { try { if (!Number.isFinite(value)) return choices.other; return choices[ new Intl.PluralRules(normalizeLocale(locale)).select(value) ] ?? choices.other; } catch { return choices.other; } } export function selectMessage( value: string, choices: Readonly & { other: string }>, ): string { return choices[value] ?? choices.other; } export { FORMAT_FALLBACK };