Files
cup26/src/lib/format.ts
T
NilsBriggen 05010771a3 German language option + a full wording-clarity pass
A tiny typed i18n layer (no library): en.ts is the single source of UI
copy and the clarity rewrite lives there — shorter sentences, plain
words, the dense Methodology/Scoreboard copy untangled. de.ts mirrors
its shape exactly, enforced by the compiler, with placeholder parity
covered by tests. Every page now reads from the dictionary via useT();
dates flip locale through useFormat() (en-GB/de-DE); raw server values
(status, outcome, stage) map through total records.

The header gains an EN/DE toggle (persisted, defaults from the
browser language); <html lang> stays in sync.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 00:20:07 +02:00

51 lines
2.0 KiB
TypeScript

// Date/score formatting in the viewer's local timezone, in the app locale.
import type { Locale } from '@/stores/localeStore';
const TAG: Record<Locale, string> = { en: 'en-GB', de: 'de-DE' };
const cache = new Map<string, Intl.DateTimeFormat>();
function dtf(locale: Locale, kind: 'time' | 'day'): Intl.DateTimeFormat {
const key = `${locale}:${kind}`;
let f = cache.get(key);
if (!f) {
f = new Intl.DateTimeFormat(
TAG[locale],
kind === 'time' ? { hour: '2-digit', minute: '2-digit' } : { weekday: 'short', day: 'numeric', month: 'short' },
);
cache.set(key, f);
}
return f;
}
const dayKey = new Intl.DateTimeFormat('en-CA', { year: 'numeric', month: '2-digit', day: '2-digit' });
export function kickoffTime(iso: string, locale: Locale = 'en'): string {
return dtf(locale, 'time').format(new Date(iso));
}
export function kickoffDay(iso: string, locale: Locale = 'en'): string {
return dtf(locale, 'day').format(new Date(iso));
}
/** Stable local-day key (YYYY-MM-DD) for grouping fixtures by date — locale-independent. */
export function dayKeyOf(iso: string): string {
return dayKey.format(new Date(iso));
}
export function isToday(iso: string): boolean {
return dayKeyOf(iso) === dayKey.format(new Date());
}
/** "in 2m", "today 19:00", "Thu 11 Jun · 19:00" — a compact when-label.
* `rel` carries the localized templates (common.inMinutes / common.todayAt). */
export function relativeKickoff(
iso: string,
locale: Locale = 'en',
rel: { inMinutes: string; todayAt: string } = { inMinutes: 'in {n}m', todayAt: 'today {time}' },
): string {
const diffMin = Math.round((new Date(iso).getTime() - Date.now()) / 60000);
if (diffMin < 0) return kickoffTime(iso, locale);
if (diffMin < 60) return rel.inMinutes.replace('{n}', String(diffMin));
if (isToday(iso)) return rel.todayAt.replace('{time}', kickoffTime(iso, locale));
if (diffMin < 60 * 24 * 7) return `${kickoffDay(iso, locale)} · ${kickoffTime(iso, locale)}`;
return kickoffDay(iso, locale);
}