lang
This commit is contained in:
@@ -1,19 +1,9 @@
|
||||
// public/assets/js/header.js
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// --------------------------------------------------
|
||||
// Sprachauflösung: basiert auf derselben Logik wie lang.js
|
||||
//
|
||||
// Priorität:
|
||||
// a) ?lang= in der URL
|
||||
// b) localStorage (usbcheck_lang)
|
||||
// c) Browsersprache
|
||||
// d) 'en' wenn vorhanden
|
||||
// e) erste verfügbare Sprache
|
||||
// --------------------------------------------------
|
||||
const cfg = window.usbConfig || {};
|
||||
const i18nCfg = cfg.i18n || {};
|
||||
const availLangs = i18nCfg.available || {};
|
||||
const availCodes = Object.keys(availLangs);
|
||||
const cfg = window.usbConfig || {};
|
||||
const i18nCfg = cfg.i18n || {};
|
||||
const availLangs = i18nCfg.available || {};
|
||||
const availCodes = Object.keys(availLangs);
|
||||
|
||||
function normalizeLang(code) {
|
||||
if (!code) return "";
|
||||
@@ -47,43 +37,30 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
const url = new URL(window.location.href);
|
||||
const urlLang = normalizeLang(url.searchParams.get("lang"));
|
||||
|
||||
// a) ?lang= aus der URL, wenn gültig
|
||||
// 1) ?lang
|
||||
if (urlLang && availCodes.includes(urlLang)) {
|
||||
return urlLang;
|
||||
}
|
||||
|
||||
// b) localStorage (vom lang.js gesetzt)
|
||||
const stored = normalizeLang(localStorage.getItem("usbcheck_lang"));
|
||||
if (stored && availCodes.includes(stored)) {
|
||||
return stored;
|
||||
}
|
||||
if (stored && !availCodes.includes(stored)) {
|
||||
localStorage.removeItem("usbcheck_lang");
|
||||
}
|
||||
|
||||
// c) Browsersprache
|
||||
// 2) Browsersprache
|
||||
const browserLang = detectBrowserLang();
|
||||
if (browserLang) {
|
||||
return browserLang;
|
||||
}
|
||||
|
||||
// d) Fallback: en, wenn vorhanden
|
||||
// 3) EN
|
||||
if (availCodes.includes("en")) {
|
||||
return "en";
|
||||
}
|
||||
|
||||
// e) Sonst erste verfügbare Sprache
|
||||
if (availCodes.length > 0) {
|
||||
return availCodes[0];
|
||||
}
|
||||
|
||||
// f) absolute Notlösung
|
||||
return "en";
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// LOGIN-BUTTON → /login mit redirect + lang
|
||||
// --------------------------------------------------
|
||||
// LOGIN-BUTTON
|
||||
const loginBtn = document.getElementById("loginButton");
|
||||
|
||||
if (loginBtn) {
|
||||
@@ -96,7 +73,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
const lang = resolveCurrentLang();
|
||||
|
||||
// Wenn wir bereits auf /login sind → nur zum #auth scrollen
|
||||
if (currentPath === "/login" || currentPath === "/login/") {
|
||||
const authEl = document.getElementById("auth");
|
||||
if (authEl) {
|
||||
@@ -105,7 +81,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sonst: auf Login-Seite mit lang + redirect-Parameter
|
||||
const url = "/login/?lang=" + encodeURIComponent(lang) +
|
||||
"&redirect=" + encodeURIComponent(redirect) +
|
||||
"#auth";
|
||||
@@ -114,9 +89,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
});
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// AVATAR-MENÜ (userAvatar / userMenu)
|
||||
// --------------------------------------------------
|
||||
// AVATAR-MENÜ & LOGOUT wie gehabt (deine bestehende Logik)
|
||||
const avatarBtn = document.getElementById("userAvatar");
|
||||
const userMenu = document.getElementById("userMenu");
|
||||
|
||||
@@ -129,7 +102,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
avatarBtn.setAttribute("aria-expanded", expanded ? "false" : "true");
|
||||
});
|
||||
|
||||
// Klick außerhalb schließt Menü
|
||||
document.addEventListener("click", function (event) {
|
||||
if (userMenu.classList.contains("hidden")) {
|
||||
return;
|
||||
@@ -145,9 +117,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
});
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// LOGOUT-MODAL
|
||||
// --------------------------------------------------
|
||||
const logoutButtons = document.querySelectorAll('[data-logout-link="true"]');
|
||||
const backdrop = document.getElementById("logoutModalBackdrop");
|
||||
const btnConfirm = document.getElementById("logoutConfirm");
|
||||
@@ -182,7 +151,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
showLogoutModal(href);
|
||||
|
||||
// Avatar-Menü beim Öffnen des Modals schließen
|
||||
if (userMenu && !userMenu.classList.contains("hidden")) {
|
||||
userMenu.classList.add("hidden");
|
||||
if (avatarBtn) {
|
||||
@@ -192,7 +160,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
});
|
||||
});
|
||||
|
||||
// Bestätigen → weiter zur Logout-URL
|
||||
btnConfirm.addEventListener("click", function () {
|
||||
if (logoutTarget) {
|
||||
window.location.href = logoutTarget;
|
||||
@@ -201,12 +168,10 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
}
|
||||
});
|
||||
|
||||
// Abbrechen → Modal schließen
|
||||
btnCancel.addEventListener("click", function () {
|
||||
hideLogoutModal();
|
||||
});
|
||||
|
||||
// Klick auf Hintergrund schließt Modal (außer man klickt auf die Card)
|
||||
backdrop.addEventListener("click", function (event) {
|
||||
const card = backdrop.querySelector(".max-w-sm");
|
||||
if (card && !card.contains(event.target)) {
|
||||
@@ -214,7 +179,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
}
|
||||
});
|
||||
|
||||
// ESC-Taste schließt Modal
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Escape" && !backdrop.classList.contains("hidden")) {
|
||||
hideLogoutModal();
|
||||
|
||||
@@ -1,26 +1,14 @@
|
||||
// public/assets/js/lang.js
|
||||
(function () {
|
||||
// ---------------------------------------------
|
||||
// 1) Basis-Config aus PHP (app_config.php)
|
||||
// ---------------------------------------------
|
||||
const usbConfig = window.usbConfig || {};
|
||||
const usbConfig = window.usbConfig || {};
|
||||
const i18nConfig = usbConfig.i18n || {};
|
||||
|
||||
// Map: { de: {code, label, flag}, en: {...}, ... }
|
||||
const availableLangs = i18nConfig.available || {};
|
||||
|
||||
// Liste der unterstützten Sprachen als Codes
|
||||
const supportedLangs = Object.keys(availableLangs);
|
||||
|
||||
// Aktuelle Sprache (wird unten per getInitialLang() gesetzt)
|
||||
let currentLang = "en";
|
||||
|
||||
// Translations-Map (geflacht)
|
||||
let translations = {};
|
||||
|
||||
// ---------------------------------------------
|
||||
// 2) Helper: Translations flatten
|
||||
// ---------------------------------------------
|
||||
function flattenTranslations(obj, target = {}) {
|
||||
Object.keys(obj || {}).forEach((key) => {
|
||||
const val = obj[key];
|
||||
@@ -33,13 +21,9 @@
|
||||
return target;
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// 3) Domain-Platzhalter ersetzen
|
||||
// ---------------------------------------------
|
||||
function applyDomainPlaceholders(text) {
|
||||
if (typeof text !== "string") return text;
|
||||
|
||||
// Primär aus usbConfig.domains, Fallback auf window.appDomains
|
||||
const domains = usbConfig.domains || window.appDomains || {};
|
||||
const replacements = {
|
||||
"{{primary_domain}}": domains.primaryDomain || "usbcheck.it",
|
||||
@@ -58,9 +42,6 @@
|
||||
}, text);
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
// 4) Browsersprache erkennen (2-Buchstaben-Code)
|
||||
// ------------------------------------------------
|
||||
function detectBrowserLang() {
|
||||
const nav = window.navigator || {};
|
||||
const candidates = [];
|
||||
@@ -84,58 +65,38 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// 5) Initiale Sprache bestimmen
|
||||
//
|
||||
// Priorität:
|
||||
// a) URL ?lang= (falls gültig)
|
||||
// b) localStorage (explizit gewählte Sprache)
|
||||
// c) Browsersprache
|
||||
// d) 'en', wenn vorhanden
|
||||
// e) erste verfügbare Sprache
|
||||
// ---------------------------------------------
|
||||
// *** Deine Priorität:
|
||||
// 1) ?lang
|
||||
// 2) Browser
|
||||
// 3) en
|
||||
function getInitialLang() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const paramLang = (urlParams.get("lang") || "").toLowerCase();
|
||||
|
||||
// a) URL-Parameter, wenn gültig
|
||||
// 1) URL-Parameter
|
||||
if (paramLang && supportedLangs.includes(paramLang)) {
|
||||
return paramLang;
|
||||
}
|
||||
|
||||
// b) localStorage (vom User über Switcher gewählt)
|
||||
const stored = (localStorage.getItem("usbcheck_lang") || "").toLowerCase();
|
||||
if (stored) {
|
||||
if (supportedLangs.includes(stored)) {
|
||||
return stored;
|
||||
}
|
||||
// Ungültigen alten Wert aufräumen
|
||||
localStorage.removeItem("usbcheck_lang");
|
||||
// 2) Browsersprache
|
||||
const browser = detectBrowserLang();
|
||||
if (browser) {
|
||||
return browser;
|
||||
}
|
||||
|
||||
// c) Browsersprache
|
||||
const browserLang = detectBrowserLang();
|
||||
if (browserLang) {
|
||||
return browserLang;
|
||||
}
|
||||
|
||||
// d) Wenn 'en' existiert → nimm 'en'
|
||||
// 3) EN (immer vorhanden laut deiner Vorgabe)
|
||||
if (supportedLangs.includes("en")) {
|
||||
return "en";
|
||||
}
|
||||
|
||||
// e) Sonst erste verfügbare Sprache
|
||||
// Sicherheitsfallback
|
||||
if (supportedLangs.length > 0) {
|
||||
return supportedLangs[0];
|
||||
}
|
||||
|
||||
// Worst-Case (sollte nie eintreten)
|
||||
return "en";
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// 6) i18n JSON per Fetch laden
|
||||
// ---------------------------------------------
|
||||
async function loadLangFile(lang) {
|
||||
const code = (lang || "").toLowerCase();
|
||||
if (!supportedLangs.includes(code)) {
|
||||
@@ -145,9 +106,7 @@
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`/assets/i18n/${code}.json`, {
|
||||
cache: "no-store",
|
||||
});
|
||||
const res = await fetch(`/assets/i18n/${code}.json`, { cache: "no-store" });
|
||||
if (!res.ok) throw new Error(`Failed to load /assets/i18n/${code}.json`);
|
||||
const raw = await res.json();
|
||||
translations = flattenTranslations(raw);
|
||||
@@ -157,9 +116,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// 7) Data-i18n-Texte einsetzen
|
||||
// ---------------------------------------------
|
||||
function applyTranslations() {
|
||||
document.documentElement.setAttribute("lang", currentLang);
|
||||
|
||||
@@ -169,21 +125,16 @@
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// 8) Label + Flag im Button aktualisieren
|
||||
// ---------------------------------------------
|
||||
function updateLangCurrentLabel(lang) {
|
||||
const code = (lang || "").toLowerCase();
|
||||
|
||||
@@ -208,14 +159,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// 9) Sprache setzen (via Switcher)
|
||||
//
|
||||
// - akzeptiert nur Sprachen aus availableLangs
|
||||
// - speichert in localStorage
|
||||
// - schreibt ?lang= in die URL
|
||||
// - lädt Seite neu, damit PHP + JS synchron sind
|
||||
// ---------------------------------------------
|
||||
// Wenn du später mal explizit via JS Sprache setzen willst
|
||||
// (z.B. beim Klick auf ein eigenes UI-Element), kannst du:
|
||||
function setLang(lang) {
|
||||
const code = (lang || "").toLowerCase();
|
||||
if (!supportedLangs.includes(code)) {
|
||||
@@ -225,20 +170,13 @@
|
||||
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set("lang", code);
|
||||
localStorage.setItem("usbcheck_lang", code);
|
||||
|
||||
window.location.href = url.toString();
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// 10) DOM Ready
|
||||
// ---------------------------------------------
|
||||
document.addEventListener("DOMContentLoaded", async function () {
|
||||
// Initiale Sprache (kombiniert aus URL, localStorage, Browser)
|
||||
currentLang = getInitialLang();
|
||||
updateLangCurrentLabel(currentLang);
|
||||
|
||||
// i18n JSON laden & Texte einsetzen
|
||||
await loadLangFile(currentLang);
|
||||
applyTranslations();
|
||||
|
||||
@@ -258,26 +196,19 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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)
|
||||
// Nur falls du später data-lang in .lang-pill nutzt,
|
||||
// im aktuellen header.php kommen die Links ja direkt mit ?lang=... aus PHP.
|
||||
document.addEventListener("click", function (e) {
|
||||
const btn = e.target.closest(".lang-pill");
|
||||
if (btn) {
|
||||
const lang = btn.getAttribute("data-lang");
|
||||
if (lang) {
|
||||
// Nur wenn data-lang gesetzt ist → JS-gesteuerter Wechsel
|
||||
setLang(lang);
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
if (!btn) return;
|
||||
|
||||
const targetLang = btn.getAttribute("data-lang");
|
||||
if (!targetLang) return;
|
||||
|
||||
e.preventDefault();
|
||||
setLang(targetLang);
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user