diff --git a/public/assets/js/header.js b/public/assets/js/header.js index 60b9e69..0eda639 100644 --- a/public/assets/js/header.js +++ b/public/assets/js/header.js @@ -1,20 +1,57 @@ // public/assets/js/header.js document.addEventListener('DOMContentLoaded', function () { - const supportedLangs = ['de', 'en', 'it', 'fr']; + // -------------------------------------------------- + // Sprachauflösung: basiert NUR auf usbConfig / i18n + // -------------------------------------------------- + const cfg = window.usbConfig || {}; + const i18nCfg = cfg.i18n || {}; + const availLangs = i18nCfg.available || {}; + const availCodes = Object.keys(availLangs); - // Globale Config aus PHP-Partial (app_config.php) - const cfg = window.usbConfig || {}; - const cfgLang = (cfg.lang || '').toLowerCase(); + function normalizeLang(code) { + if (!code) return ''; + return String(code).slice(0, 2).toLowerCase(); + } function resolveCurrentLang() { - const url = new URL(window.location.href); - const urlLang = (url.searchParams.get('lang') || '').toLowerCase(); - const docLang = (document.documentElement.getAttribute('lang') || '').toLowerCase(); + const url = new URL(window.location.href); + const urlLang = normalizeLang(url.searchParams.get('lang')); - if (supportedLangs.includes(urlLang)) return urlLang; - if (supportedLangs.includes(cfgLang)) return cfgLang; - if (supportedLangs.includes(docLang)) return docLang; - return 'de'; + // 1) ?lang= aus der URL, wenn gültig + if (urlLang && availCodes.includes(urlLang)) { + return urlLang; + } + + // 2) localStorage (vom lang.js gesetzt) + const stored = normalizeLang(localStorage.getItem('usbcheck_lang')); + if (stored && availCodes.includes(stored)) { + return stored; + } + + // 3) PHP-Konfig (fileload/app_config) + const cfgLang = normalizeLang(i18nCfg.current || cfg.lang); + if (cfgLang && availCodes.includes(cfgLang)) { + return cfgLang; + } + + // 4) + const docLang = normalizeLang(document.documentElement.getAttribute('lang')); + if (docLang && availCodes.includes(docLang)) { + return docLang; + } + + // 5) Fallback: en, wenn vorhanden + if (availCodes.includes('en')) { + return 'en'; + } + + // 6) sonst erste verfügbare Sprache + if (availCodes.length > 0) { + return availCodes[0]; + } + + // 7) absolute Notlösung + return 'en'; } // -------------------------------------------------- diff --git a/public/assets/js/lang.js b/public/assets/js/lang.js index 66b8e7e..fde6806 100644 --- a/public/assets/js/lang.js +++ b/public/assets/js/lang.js @@ -1,22 +1,36 @@ // public/assets/js/lang.js (function () { - const supportedLangs = ["de", "en", "it", "fr"]; - let currentLang = "en"; + // --------------------------------------------- + // 1) Basis-Config aus PHP (app_config.php) + // --------------------------------------------- + const usbConfig = window.usbConfig || {}; + const i18nConfig = usbConfig.i18n || {}; + + // Map: { de: {code, label, flag}, en: {...}, dk: {...}, ... } + const availableLangs = i18nConfig.available || {}; + + // Liste der unterstützten Sprachen als Codes + const supportedLangs = Object.keys(availableLangs); + + // Sprache, die PHP in fileload.php ermittelt hat + let currentLang = i18nConfig.current || usbConfig.lang || "en"; + + // Wenn PHP eine Sprache setzt, die nicht in available ist, nimm erste verfügbare + if (!supportedLangs.includes(currentLang) && supportedLangs.length > 0) { + currentLang = supportedLangs[0]; + } + + // Fallback, wenn gar nichts da ist + if (!currentLang) { + currentLang = "en"; + } + let translations = {}; - const langMeta = { - de: { flag: "🇩🇪", label: "DE" }, - en: { flag: "🇬🇧", label: "EN" }, - it: { flag: "🇮🇹", label: "IT" }, - fr: { flag: "🇫🇷", label: "FR" } - }; - - // 🔹 WICHTIG: - // Diese Funktion nimmt eine verschachtelte JSON-Struktur - // und schreibt ALLE "Blatt-Keys" in ein flaches Objekt, - // OHNE den Pfad in den Keynamen einzubauen. - // D.h. { "hero": { "hero_kicker": "..." } } -> { "hero_kicker": "..." } + // --------------------------------------------- + // 2) Helper: Translations flatten + // --------------------------------------------- function flattenTranslations(obj, target = {}) { Object.keys(obj || {}).forEach((key) => { const val = obj[key]; @@ -29,15 +43,22 @@ return target; } + // --------------------------------------------- + // 3) Domain-Platzhalter ersetzen + // --------------------------------------------- function applyDomainPlaceholders(text) { if (typeof text !== "string") return text; const domains = window.appDomains || {}; const replacements = { "{{primary_domain}}": domains.primaryDomain || "usbcheck.it", - "{{primary_url}}": domains.primaryUrl || ("https://" + (domains.primaryDomain || "usbcheck.it")), + "{{primary_url}}": + domains.primaryUrl || + "https://" + (domains.primaryDomain || "usbcheck.it"), "{{fakecheck_domain}}": domains.fakecheckDomain || "ismyusbfake.com", - "{{fakecheck_url}}": domains.fakecheckUrl || ("https://" + (domains.fakecheckDomain || "ismyusbfake.com")), + "{{fakecheck_url}}": + domains.fakecheckUrl || + "https://" + (domains.fakecheckDomain || "ismyusbfake.com"), }; return Object.keys(replacements).reduce((acc, token) => { @@ -46,34 +67,58 @@ }, text); } + // --------------------------------------------- + // 4) Initiale Sprache bestimmen + // + // Priorität: + // a) PHP (usbConfig.i18n.current / usbConfig.lang) + // b) URL ?lang= (falls gültig und in available) + // c) localStorage (falls gültig) + // d) erste verfügbare Sprache + // --------------------------------------------- function getInitialLang() { const urlParams = new URLSearchParams(window.location.search); const paramLang = urlParams.get("lang"); - if (paramLang && supportedLangs.includes(paramLang)) return paramLang; + if (paramLang && supportedLangs.includes(paramLang)) { + return paramLang; + } const stored = localStorage.getItem("usbcheck_lang"); - if (stored && supportedLangs.includes(stored)) return stored; + if (stored && supportedLangs.includes(stored)) { + return stored; + } - const navLang = (navigator.language || navigator.userLanguage || "en") - .slice(0, 2) - .toLowerCase(); - if (supportedLangs.includes(navLang)) return navLang; + if (supportedLangs.includes(currentLang)) { + return currentLang; + } + + if (supportedLangs.length > 0) { + return supportedLangs[0]; + } return "en"; } + // --------------------------------------------- + // 5) i18n JSON per Fetch laden + // --------------------------------------------- async function loadLangFile(lang) { try { - const res = await fetch(`/assets/i18n/${lang}.json`, { cache: "no-store" }); + const res = await fetch(`/assets/i18n/${lang}.json`, { + cache: "no-store", + }); if (!res.ok) throw new Error(`Failed to load /assets/i18n/${lang}.json`); const raw = await res.json(); - translations = flattenTranslations(raw); // 👈 hier wird strukturiert -> flach gemacht + translations = flattenTranslations(raw); } catch (err) { console.error("i18n load error:", err); translations = {}; } } + // --------------------------------------------- + // 6) Data-i18n-Texte einsetzen + // --------------------------------------------- function applyTranslations() { document.documentElement.setAttribute("lang", currentLang); @@ -95,38 +140,68 @@ }); } + // --------------------------------------------- + // 7) Label + Flag im Button aktualisieren + // + // Nutzt ausschließlich availableLangs aus PHP: + // availableLangs[code] = { code, label, flag } + // --------------------------------------------- function updateLangCurrentLabel(lang) { - const meta = langMeta[lang] || { flag: "", label: lang.toUpperCase() }; + const info = availableLangs[lang] || { + code: lang, + label: lang.toUpperCase(), + flag: "", + }; + const node = document.getElementById("langCurrentLabel") || document.getElementById("langCurrent"); if (!node) return; - if (meta.flag) { - node.innerHTML = `${meta.flag}${meta.label}`; + const flag = info.flag || ""; + const label = info.label || info.code.toUpperCase(); + + if (flag) { + node.innerHTML = `${flag}${label}`; } else { - node.textContent = meta.label; + node.textContent = label; } } + // --------------------------------------------- + // 8) Sprache setzen + // + // Neu: + // - akzeptiert JEDE Sprache, die in availableLangs liegt + // - speichert in localStorage + // - schreibt ?lang= in die URL + // - lädt Seite neu, damit PHP + JS synchron sind + // --------------------------------------------- async function setLang(lang) { - if (!supportedLangs.includes(lang)) return; - currentLang = lang; - localStorage.setItem("usbcheck_lang", lang); + if (!supportedLangs.includes(lang)) { + console.warn("Unsupported language:", lang, supportedLangs); + return; + } + // URL-Parameter setzen const url = new URL(window.location.href); url.searchParams.set("lang", lang); - window.history.replaceState({}, "", url.toString()); + localStorage.setItem("usbcheck_lang", lang); - await loadLangFile(lang); - applyTranslations(); - updateLangCurrentLabel(lang); + // komplette Seite neu laden, + // damit PHP (fileload.php) + Meta-Tags + JS-Konfig konsistent sind + window.location.href = url.toString(); } + // --------------------------------------------- + // 9) DOM Ready + // --------------------------------------------- document.addEventListener("DOMContentLoaded", async function () { + // Initiale Sprache (kombiniert aus PHP, URL, localStorage) currentLang = getInitialLang(); updateLangCurrentLabel(currentLang); + // i18n JSON laden & Texte einsetzen await loadLangFile(currentLang); applyTranslations(); @@ -155,16 +230,18 @@ }); } - // Sprachumschaltung über .lang-pill + // Sprachumschaltung über .lang-pill (Buttons im Dropdown) document.addEventListener("click", function (e) { const btn = e.target.closest(".lang-pill"); if (btn) { const lang = btn.getAttribute("data-lang"); - setLang(lang); + if (lang) { + setLang(lang); + } } }); - // Login / Avatar – Dummy + // (Login / Avatar Dummy kann bleiben – unverändert) const loginButton = document.getElementById("loginButton"); const userAvatar = document.getElementById("userAvatar"); const avatarInitials = document.getElementById("avatarInitials"); @@ -179,9 +256,13 @@ } }); - userAvatar.addEventListener("click", function () { - alert("Account-Menü Platzhalter – hier später Profil/Logout etc. einbauen."); - }); + if (userAvatar) { + userAvatar.addEventListener("click", function () { + alert( + "Account-Menü Platzhalter – hier später Profil/Logout etc. einbauen." + ); + }); + } } }); })();