Files

73 lines
2.5 KiB
JavaScript

// 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" }),
};
}