"use strict"; (function (root) { // Translations are data files (ui/i18n/.json); adding a language means adding a file. // The Core injects the catalogs into the window before the page runs; Node tests read the files. const catalogs = (function loadCatalogs() { const injected = globalThis.__CHJ_I18N__ && globalThis.__CHJ_I18N__.catalogs && globalThis.__CHJ_I18N__.catalogs.module; if (injected) return injected; if (typeof require === "function" && typeof __dirname === "string") { const fs = require("fs"), path = require("path"), dir = path.join(__dirname, "i18n"), result = {}; for (const file of fs.readdirSync(dir)) if (/^[a-z]{2,3}(-[A-Za-z0-9]+)?\.json$/.test(file)) result[file.slice(0, -5)] = JSON.parse(fs.readFileSync(path.join(dir, file), "utf8")); return result; } return {}; })(); // Language list (native names, locales, text direction) injected by the Core. const languageEntry = (code) => (globalThis.__CHJ_I18N__?.manifest?.languages || []).find((entry) => entry.code === code); function createI18n(initialLanguage = "en") { let language; const setLanguage = (value) => { // Exact code first (zh-tw), then the base language (de-at → de). const full = String(value || "").toLowerCase().replace(/_/g, "-"); const requested = Object.hasOwn(catalogs, full) ? full : full.split("-")[0]; language = Object.hasOwn(catalogs, requested) ? requested : "en"; return language; }; setLanguage(initialLanguage); const t = (key, values = {}) => (catalogs[language][key] || catalogs.en[key] || key) .replace(/\{(\w+)\}/g, (match, name) => Object.hasOwn(values, name) ? String(values[name]) : match); const staticText = new WeakMap(); let applied = false; const apply = (document) => { document.documentElement.lang = language; document.documentElement.dir = languageEntry(language)?.dir === "rtl" ? "rtl" : "ltr"; // Text a module has set itself (a version, a count, server data) is not the static translation. document.querySelectorAll("[data-i18n]").forEach((element) => { if (staticText.has(element) && element.textContent !== staticText.get(element)) return; const text = t(element.dataset.i18n); element.textContent = text; staticText.set(element, text); }); // A status message from before the switch is in the old language. const status = applied ? document.getElementById("status") : null; if (status) { status.textContent = ""; status.classList.remove("error"); } applied = true; document.querySelectorAll("[data-i18n-aria-label]").forEach((element) => { element.setAttribute("aria-label", t(element.dataset.i18nAriaLabel)); }); }; const errorMessage = (error) => { const message = error?.message || String(error || t("Unknown error")); const code = error?.code || message.match(/\b(HASH_[A-Z_]+|ENOENT|EACCES|EPERM)\b/)?.[1]; return language !== "en" && catalogs[language][code] ? t(code) : message; }; return { t, apply, setLanguage, getLanguage: () => language, errorMessage }; } const exported = { catalogs, createI18n }; if (typeof module === "object" && module.exports) module.exports = exported; else root.chjHashI18n = exported; })(typeof window === "object" ? window : globalThis);