(function () { var STORAGE_KEY = 'hyapp_h5_lang'; var DEFAULT_LANG = 'en'; var SUPPORTED = ['en', 'ar', 'tr', 'es', 'zh', 'id']; var scriptURL = document.currentScript && document.currentScript.src ? document.currentScript.src : '../common/i18n.js'; var localeBaseURL = new URL('locales/', scriptURL).toString(); var messages = {}; var currentLang = ''; function scopedSupported() { var scoped = window.HyAppI18nSupported || window.HyAppSupportedLanguages || null; if (!Array.isArray(scoped)) return SUPPORTED; var normalized = []; scoped.forEach(function (value) { var lang = String(value || '') .trim() .toLowerCase() .replace('_', '-'); if (lang.indexOf('ar') === 0) lang = 'ar'; else if (lang.indexOf('tr') === 0) lang = 'tr'; else if (lang.indexOf('es') === 0) lang = 'es'; else if (lang.indexOf('zh') === 0) lang = 'zh'; else if (lang.indexOf('id') === 0) lang = 'id'; if (SUPPORTED.indexOf(lang) >= 0 && normalized.indexOf(lang) < 0) { normalized.push(lang); } }); return normalized.length ? normalized : SUPPORTED; } function storageGet(key) { try { return window.localStorage ? window.localStorage.getItem(key) : ''; } catch (error) { return ''; } } function storageSet(key, value) { try { if (window.localStorage) { window.localStorage.setItem(key, value); } } catch (error) { // Some in-app browser contexts disable localStorage. Language still works for the current page session. } } function currentParams() { var parsed = window.HyAppParams && window.HyAppParams.current && window.HyAppParams.current.raw; if (parsed && parsed.get) return parsed; var params = new URLSearchParams(window.location.search); var hash = window.location.hash || ''; if (hash.indexOf('?') >= 0) { new URLSearchParams(hash.split('?').slice(1).join('?')).forEach( function (value, key) { if (!params.has(key)) params.set(key, value); } ); } return params; } function queryLang() { var params = currentParams(); return ( params.get('lang') || params.get('language') || params.get('locale') || params.get('app_lang') || params.get('appLanguage') || '' ); } function normalizeLang(value) { var lang = String(value || '') .trim() .toLowerCase() .replace('_', '-'); if (!lang) return ''; if (lang.indexOf('ar') === 0) lang = 'ar'; else if (lang.indexOf('tr') === 0) lang = 'tr'; else if (lang.indexOf('es') === 0) lang = 'es'; else if (lang.indexOf('zh') === 0) lang = 'zh'; else if (lang.indexOf('id') === 0) lang = 'id'; return scopedSupported().indexOf(lang) >= 0 ? lang : ''; } function resolveLang() { return ( normalizeLang(queryLang()) || normalizeLang(storageGet(STORAGE_KEY)) || normalizeLang(window.navigator.language) || DEFAULT_LANG ); } function load(lang) { var normalized = normalizeLang(lang) || DEFAULT_LANG; return window .fetch(localeBaseURL + normalized + '.json', { cache: 'no-store', }) .then(function (response) { if (!response.ok) throw new Error('locale_not_found'); return response.json(); }) .then(function (json) { messages = json || {}; currentLang = normalized; storageSet(STORAGE_KEY, currentLang); apply(); return messages; }) .catch(function () { if (normalized === DEFAULT_LANG) { messages = {}; currentLang = DEFAULT_LANG; apply(); return messages; } return load(DEFAULT_LANG); }); } function t(key, fallback) { return Object.prototype.hasOwnProperty.call(messages, key) ? messages[key] : fallback || key; } function apply(root) { var scope = root || document; document.documentElement.lang = currentLang || DEFAULT_LANG; document.documentElement.dir = currentLang === 'ar' ? 'rtl' : 'ltr'; scope.querySelectorAll('[data-i18n]').forEach(function (node) { node.textContent = t( node.getAttribute('data-i18n'), node.textContent ); }); scope .querySelectorAll('[data-i18n-placeholder]') .forEach(function (node) { node.setAttribute( 'placeholder', t( node.getAttribute('data-i18n-placeholder'), node.getAttribute('placeholder') || '' ) ); }); scope.querySelectorAll('[data-i18n-aria]').forEach(function (node) { node.setAttribute( 'aria-label', t( node.getAttribute('data-i18n-aria'), node.getAttribute('aria-label') || '' ) ); }); scope.querySelectorAll('[data-lang-option]').forEach(function (node) { node.classList.toggle( 'is-active', node.getAttribute('data-lang-option') === currentLang ); }); scope.querySelectorAll('[data-current-lang]').forEach(function (node) { node.textContent = (currentLang || DEFAULT_LANG).toUpperCase(); }); window.dispatchEvent( new CustomEvent('hyapp:i18n-ready', { detail: { lang: currentLang, messages: messages }, }) ); } function initLanguageMenu() { document.addEventListener('click', function (event) { var toggle = closest(event.target, '[data-language-toggle]'); var menu = document.querySelector('[data-language-menu]'); if (toggle && menu) { var expanded = toggle.getAttribute('aria-expanded') === 'true'; toggle.setAttribute( 'aria-expanded', expanded ? 'false' : 'true' ); menu.hidden = expanded; return; } var option = closest(event.target, '[data-lang-option]'); if (option) { if (menu) menu.hidden = true; var button = document.querySelector('[data-language-toggle]'); if (button) button.setAttribute('aria-expanded', 'false'); load(option.getAttribute('data-lang-option')); return; } if (menu && !closest(event.target, '.language-switcher')) { menu.hidden = true; var languageButton = document.querySelector( '[data-language-toggle]' ); if (languageButton) languageButton.setAttribute('aria-expanded', 'false'); } }); } function closest(node, selector) { while (node && node !== document) { if (node.matches && node.matches(selector)) return node; node = node.parentNode; } return null; } window.HyAppI18n = { load: load, apply: apply, t: t, lang: function () { return currentLang || DEFAULT_LANG; }, supported: scopedSupported(), }; function init() { initLanguageMenu(); load(resolveLang()); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();