gsmol/web/js/i18n.js
randogoth 70087fa470 feat: base UI strings on carrier's shared Fluent source
Vendors carrier's locales/en-US/main.ftl (extended to cover gsmol's
remaining strings) as the single source both clients draw wording
from, adds a dependency-free .ftl-to-JSON build step (devbox run
locale) since the file only ever uses Fluent's flat subset, and
replaces every hardcoded string in index.html/app.js with a lookup
into the generated dictionary.

Along the way: removes connect()'s requirePin check, which turned out
to be unreachable under the app's own invariants (every call site
already guarantees its target host is pinned before calling it), and
fixes a leftover call to store.setMasterSaved — removed in the earlier
settings redesign — that was silently breaking onboarding's "I saved
it" button.
2026-10-08 23:43:59 +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));
}