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."
+ );
+ });
+ }
}
});
})();