First commit, done on M6 from the PLAN.MD
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
// 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" }),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user