// public/assets/js/lang.js
(function () {
// ---------------------------------------------
// 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 = {};
// ---------------------------------------------
// 2) Helper: Translations flatten
// ---------------------------------------------
function flattenTranslations(obj, target = {}) {
Object.keys(obj || {}).forEach((key) => {
const val = obj[key];
if (val && typeof val === "object" && !Array.isArray(val)) {
flattenTranslations(val, target);
} else {
target[key] = val;
}
});
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"),
"{{fakecheck_domain}}": domains.fakecheckDomain || "ismyusbfake.com",
"{{fakecheck_url}}":
domains.fakecheckUrl ||
"https://" + (domains.fakecheckDomain || "ismyusbfake.com"),
};
return Object.keys(replacements).reduce((acc, token) => {
const value = replacements[token];
return acc.split(token).join(value);
}, 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;
}
const stored = localStorage.getItem("usbcheck_lang");
if (stored && supportedLangs.includes(stored)) {
return stored;
}
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",
});
if (!res.ok) throw new Error(`Failed to load /assets/i18n/${lang}.json`);
const raw = await res.json();
translations = flattenTranslations(raw);
} catch (err) {
console.error("i18n load error:", err);
translations = {};
}
}
// ---------------------------------------------
// 6) Data-i18n-Texte einsetzen
// ---------------------------------------------
function applyTranslations() {
document.documentElement.setAttribute("lang", currentLang);
document.querySelectorAll("[data-i18n]").forEach((node) => {
const key = node.getAttribute("data-i18n");
if (!key) return;
let value = translations[key];
if (typeof value !== "string") return;
// {year}-Platzhalter ersetzen (z. B. footer_copy)
if (value.includes("{year}")) {
const year = new Date().getFullYear();
value = value.replace("{year}", year);
}
value = applyDomainPlaceholders(value);
node.innerHTML = value;
});
}
// ---------------------------------------------
// 7) Label + Flag im Button aktualisieren
//
// Nutzt ausschließlich availableLangs aus PHP:
// availableLangs[code] = { code, label, flag }
// ---------------------------------------------
function updateLangCurrentLabel(lang) {
const info = availableLangs[lang] || {
code: lang,
label: lang.toUpperCase(),
flag: "",
};
const node =
document.getElementById("langCurrentLabel") ||
document.getElementById("langCurrent");
if (!node) return;
const flag = info.flag || "";
const label = info.label || info.code.toUpperCase();
if (flag) {
node.innerHTML = `${flag}${label}`;
} else {
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)) {
console.warn("Unsupported language:", lang, supportedLangs);
return;
}
// URL-Parameter setzen
const url = new URL(window.location.href);
url.searchParams.set("lang", lang);
localStorage.setItem("usbcheck_lang", 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();
const langCurrent = document.getElementById("langCurrent");
const langMenu = document.getElementById("langMenu");
if (langCurrent && langMenu) {
langCurrent.addEventListener("click", function (e) {
e.stopPropagation();
langMenu.classList.toggle("hidden");
});
document.addEventListener("click", function (e) {
if (!langMenu.classList.contains("hidden")) {
if (!langMenu.contains(e.target) && !langCurrent.contains(e.target)) {
langMenu.classList.add("hidden");
}
}
});
langMenu.addEventListener("click", function (e) {
const pill = e.target.closest(".lang-pill");
if (pill) {
langMenu.classList.add("hidden");
}
});
}
// 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");
if (lang) {
setLang(lang);
}
}
});
// (Login / Avatar Dummy kann bleiben – unverändert)
const loginButton = document.getElementById("loginButton");
const userAvatar = document.getElementById("userAvatar");
const avatarInitials = document.getElementById("avatarInitials");
if (loginButton && userAvatar) {
loginButton.addEventListener("click", function () {
loginButton.classList.add("hidden");
userAvatar.classList.remove("hidden");
if (avatarInitials && !avatarInitials.textContent.trim()) {
avatarInitials.textContent = "UC";
}
});
if (userAvatar) {
userAvatar.addEventListener("click", function () {
alert(
"Account-Menü Platzhalter – hier später Profil/Logout etc. einbauen."
);
});
}
}
});
})();