gsmol/web/js/i18n.js
2026-10-09 13:47:50 +03:00

31 lines
1.5 KiB
JavaScript

// Strings, loaded once from the flat dictionary scripts/build-locale.mjs
// generates from locales/en-US/main.ftl. No Fluent parser ships here — the
// build step already resolved the source file's syntax down to plain
// `{ $var }` placeholders, which is all this needs to substitute.
let messages = null;
export async function loadLocale() {
const response = await fetch("locales/en-US.json");
messages = await response.json();
}
// Falls back to the id itself on a miss, so a typo'd or forgotten call
// shows up as visibly wrong text in the UI rather than disappearing.
export function t(id, args = {}) {
const value = messages?.[id];
if (value === undefined) return id;
return value.replace(/\{\s*\$(\w+)\s*\}/g, (_, name) => args[name] ?? "");
}
// index.html's static markup keeps its literal English text and gains
// data-l10n-* attributes alongside it, so the page still reads correctly
// even if this runs late — this pass just overwrites it from the same
// English source, proving the wiring for whenever a second locale exists.
export function applyStaticLocale(root = document) {
for (const el of root.querySelectorAll("[data-l10n-id]")) el.textContent = t(el.dataset.l10nId);
for (const el of root.querySelectorAll("[data-l10n-placeholder]")) el.placeholder = t(el.dataset.l10nPlaceholder);
for (const el of root.querySelectorAll("[data-l10n-title]")) el.title = t(el.dataset.l10nTitle);
for (const el of root.querySelectorAll("[data-l10n-aria-label]"))
el.setAttribute("aria-label", t(el.dataset.l10nAriaLabel));
}