// ── Language registry ───────────────────────────────────────────────────────── // Only display names live here; full strings are lazy-loaded per language. export const TRANSLATIONS = { en: { 'lang.name': 'English' }, de: { 'lang.name': 'Deutsch' }, it: { 'lang.name': 'Italiano' }, es: { 'lang.name': 'Español (beta)' }, pt: { 'lang.name': 'Português (beta)' }, fr: { 'lang.name': 'Français' }, ja: { 'lang.name': '日本語 (beta)' }, }; // ── Module state ────────────────────────────────────────────────────────────── let _currentLang = 'en'; const _cache = {}; async function _loadLang(lang) { if (_cache[lang]) { return; } try { const { default: strings } = await import(`./i18n/${lang}.js`); _cache[lang] = strings; } catch (err) { console.error(`[i18n] Failed to load language "${lang}":`, err); // Mark as empty so we don't retry on every call; t() will fall back to English. _cache[lang] = {}; } } // ── Core API ────────────────────────────────────────────────────────────────── /** * Look up a translation key in the current language, falling back to English. * Replace {placeholder} tokens with values from `params`. */ export function t(key, params = {}) { const strings = _cache[_currentLang] ?? _cache.en ?? {}; const fallback = _cache.en ?? {}; let str = strings[key] ?? fallback[key] ?? key; for (const [k, v] of Object.entries(params)) { str = str.replaceAll(`{${k}}`, v); } return str; } export function getLang() { return _currentLang; } export async function setLang(lang) { if (!TRANSLATIONS[lang]) { return; } await Promise.all([_loadLang('en'), _loadLang(lang)]); _currentLang = lang; localStorage.setItem('stlt-lang', lang); document.documentElement.setAttribute('data-lang', lang); document.documentElement.setAttribute('lang', lang); applyTranslations(); } /** * Walk the DOM and apply translations to elements carrying data-i18n* attributes. */ export function applyTranslations() { // textContent document.querySelectorAll('[data-i18n]').forEach(el => { el.textContent = t(el.dataset.i18n); }); // innerHTML (safe: all values are hardcoded in translation files, not user input) document.querySelectorAll('[data-i18n-html]').forEach(el => { el.innerHTML = t(el.dataset.i18nHtml); }); // title attribute document.querySelectorAll('[data-i18n-title]').forEach(el => { el.title = t(el.dataset.i18nTitle); }); // aria-label attribute document.querySelectorAll('[data-i18n-aria-label]').forEach(el => { el.setAttribute('aria-label', t(el.dataset.i18nAriaLabel)); }); //