// UI strings live in en.json / fr.json. Content fields (cards, newspaper) are // { en, fr } objects read through tx(). const dict = {}; let lang = "en"; export async function initI18n(initial = "en") { for (const l of ["en", "fr"]) { dict[l] = await (await fetch(`js/i18n/${l}.json`)).json(); } setLang(initial); } export function setLang(l) { lang = dict[l] ? l : "en"; document.documentElement.lang = lang; } export const getLang = () => lang; export function t(key, vars) { let s = dict[lang]?.[key] ?? dict.en?.[key] ?? key; if (vars) for (const [k, v] of Object.entries(vars)) s = s.replaceAll(`{${k}}`, v); return s; } // Pick the current language from a { en, fr } content field. export const tx = (obj) => obj?.[lang] ?? obj?.en ?? ""; // Pronoun tokens for text that refers to the player: {sub} {Sub} {obj} {pos} {is} {has} {was} // in English, {sub} {Sub} {tonic} {e} (agreement ending) in French. Text that needs none of // them should avoid pronouns altogether. const PRONOUN_FORMS = { en: { he: { sub: "he", Sub: "He", obj: "him", pos: "his", is: "is", has: "has", was: "was" }, she: { sub: "she", Sub: "She", obj: "her", pos: "her", is: "is", has: "has", was: "was" }, they: { sub: "they", Sub: "They", obj: "them", pos: "their", is: "are", has: "have", was: "were" }, }, fr: { he: { sub: "il", Sub: "Il", tonic: "lui", e: "" }, she: { sub: "elle", Sub: "Elle", tonic: "elle", e: "e" }, they: { sub: "iel", Sub: "Iel", tonic: "ielle", e: "·e" }, }, }; export function tp(text, pronouns = "they") { const forms = PRONOUN_FORMS[lang]?.[pronouns] ?? PRONOUN_FORMS[lang]?.they ?? {}; return text.replace(/\{(\w+)\}/g, (match, key) => forms[key] ?? match); } // A historian's title: English is one string, French has a form per pronoun set. export function tt(title, pronouns = "they") { const v = title?.[lang] ?? title?.en ?? ""; return typeof v === "string" ? v : (v[pronouns] ?? v.they); } export function fmt(n, digits = 1) { return new Intl.NumberFormat(lang, { minimumFractionDigits: digits, maximumFractionDigits: digits }).format(n); } // ISO date (YYYY-MM-DD, treated as UTC) → long localized parts. export function dateParts(iso) { const d = new Date(`${iso}T00:00:00Z`); const f = (opts) => new Intl.DateTimeFormat(lang, { timeZone: "UTC", ...opts }).format(d); return { weekday: f({ weekday: "long" }), day: f({ day: "numeric" }), month: f({ month: "long" }), year: f({ year: "numeric" }), full: f({ dateStyle: "full" }), }; }