Tilgjengelegheit (Android + PWA): - Semantiske landemerke (header, main, aside, role=dialog) - aria-live-regionar for statusoppdateringar og lasteoverlegg - Fokusindikatorar (:focus-visible) og prefers-reduced-motion - Auka trykkmål til 48dp (infoknapp, oppdater, del, widget) - contentDescription på kart, kompass og framdriftsindikator - aria-current og role=listitem på tilfluktsromliste - Fokusfangst og fokusgjenoppretting i lasteoverlegg - Ikkje-farge-indikator (▶) for valt tilfluktsrom - Dynamisk lang-attributt basert på oppdaga språk - Lokaliserte aria-label (en/nb/nn) Nordindikator: - DirectionArrowView teiknar diskret «N»-markør på omkrinsen - Roterer uavhengig av hovudpila for kompasskalibrering - Berre på stor kompassvisning, ikkje minipila Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
50 lines
1.3 KiB
TypeScript
50 lines
1.3 KiB
TypeScript
/**
|
|
* Minimal i18n system: detects locale from navigator.languages,
|
|
* provides t(key, ...args) for string lookup with %d/%s substitution.
|
|
*/
|
|
|
|
import { en } from './en';
|
|
import { nb } from './nb';
|
|
import { nn } from './nn';
|
|
|
|
const locales: Record<string, Record<string, string>> = { en, nb, nn };
|
|
|
|
let currentLocale = 'en';
|
|
|
|
/** Detect and set locale from browser preferences, update document lang. */
|
|
export function initLocale(): void {
|
|
const langs = navigator.languages ?? [navigator.language];
|
|
for (const lang of langs) {
|
|
const code = lang.toLowerCase().split('-')[0];
|
|
if (code in locales) {
|
|
currentLocale = code;
|
|
break;
|
|
}
|
|
// nb and nn both start with "n" — also match "no" as Bokmål
|
|
if (code === 'no') {
|
|
currentLocale = 'nb';
|
|
break;
|
|
}
|
|
}
|
|
document.documentElement.lang = currentLocale;
|
|
}
|
|
|
|
/** Get current locale code. */
|
|
export function getLocale(): string {
|
|
return currentLocale;
|
|
}
|
|
|
|
/**
|
|
* Translate a string key, substituting %d and %s with provided arguments.
|
|
* Falls back to English, then to the raw key.
|
|
*/
|
|
export function t(key: string, ...args: (string | number)[]): string {
|
|
let str = locales[currentLocale]?.[key] ?? locales.en[key] ?? key;
|
|
|
|
// Replace %d and %s placeholders sequentially
|
|
for (const arg of args) {
|
|
str = str.replace(/%[ds]/, String(arg));
|
|
}
|
|
|
|
return str;
|
|
}
|