This commit is contained in:
2025-11-19 02:41:56 +01:00
parent 93b6bbff10
commit 87def54f3d
5 changed files with 491 additions and 482 deletions

View File

@@ -2,41 +2,31 @@
(function () {
const supportedLangs = ["de", "en", "it", "fr"];
let currentLang = "en";
let translations = {};
// Mapping für Flaggen + Label im Header
const langMeta = {
de: { flag: "🇩🇪", label: "DE" },
en: { flag: "🇬🇧", label: "EN" }, // oder 🇺🇸 wenn dir lieber
en: { flag: "🇬🇧", label: "EN" },
it: { flag: "🇮🇹", label: "IT" },
fr: { flag: "🇫🇷", label: "FR" }
};
function flattenTranslations(obj, prefix = "") {
const result = {};
Object.keys(obj).forEach((key) => {
const value = obj[key];
const newKey = prefix ? `${prefix}_${key}` : key;
if (value && typeof value === "object" && !Array.isArray(value)) {
Object.assign(result, flattenTranslations(value, newKey));
// 🔹 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": "..." }
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 {
result[newKey] = value;
target[key] = val;
}
});
return result;
}
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 data = await res.json();
translations = flattenTranslations(data);
} catch (err) {
console.error("i18n load error:", err);
translations = {};
}
return target;
}
function getInitialLang() {
@@ -47,23 +37,37 @@
const stored = localStorage.getItem("usbcheck_lang");
if (stored && supportedLangs.includes(stored)) return stored;
const navLang = (navigator.language || "en").slice(0, 2).toLowerCase();
const navLang = (navigator.language || navigator.userLanguage || "en")
.slice(0, 2)
.toLowerCase();
if (supportedLangs.includes(navLang)) return navLang;
return "en";
}
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); // 👈 hier wird strukturiert -> flach gemacht
} catch (err) {
console.error("i18n load error:", err);
translations = {};
}
}
function applyTranslations() {
document.documentElement.setAttribute("lang", getCurrentLang());
document.documentElement.setAttribute("lang", currentLang);
document.querySelectorAll("[data-i18n]").forEach((node) => {
const key = node.getAttribute("data-i18n");
if (!key || !translations[key]) return;
if (!key) return;
let value = translations[key];
if (typeof value !== "string") return;
// {year}-Placeholder ersetzen (für footer_copy etc.)
if (typeof value === "string" && value.includes("{year}")) {
// {year}-Platzhalter ersetzen (z. B. footer_copy)
if (value.includes("{year}")) {
const year = new Date().getFullYear();
value = value.replace("{year}", year);
}
@@ -72,20 +76,11 @@
});
}
function getCurrentLang() {
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;
return "en";
}
function updateLangCurrentLabel(lang) {
const meta = langMeta[lang] || { flag: "", label: lang.toUpperCase() };
const node = document.getElementById("langCurrentLabel") || document.getElementById("langCurrent");
const node =
document.getElementById("langCurrentLabel") ||
document.getElementById("langCurrent");
if (!node) return;
if (meta.flag) {
@@ -97,10 +92,9 @@
async function setLang(lang) {
if (!supportedLangs.includes(lang)) return;
currentLang = lang;
localStorage.setItem("usbcheck_lang", lang);
// URL-Parameter ohne Reload aktualisieren
const url = new URL(window.location.href);
url.searchParams.set("lang", lang);
window.history.replaceState({}, "", url.toString());
@@ -111,20 +105,15 @@
}
document.addEventListener("DOMContentLoaded", async function () {
const initialLang = getInitialLang();
currentLang = getInitialLang();
updateLangCurrentLabel(currentLang);
// Header-Label initial
updateLangCurrentLabel(initialLang);
// Übersetzungen laden und anwenden
await loadLangFile(initialLang);
await loadLangFile(currentLang);
applyTranslations();
// Dropdown-Elemente
const langCurrent = document.getElementById("langCurrent");
const langMenu = document.getElementById("langMenu");
// Dropdown öffnen/schließen
if (langCurrent && langMenu) {
langCurrent.addEventListener("click", function (e) {
e.stopPropagation();
@@ -147,7 +136,7 @@
});
}
// Sprachumschaltung / Klick auf .lang-pill
// Sprachumschaltung über .lang-pill
document.addEventListener("click", function (e) {
const btn = e.target.closest(".lang-pill");
if (btn) {
@@ -156,7 +145,7 @@
}
});
// Login / Avatar UI-Dummy wie vorher
// Login / Avatar Dummy
const loginButton = document.getElementById("loginButton");
const userAvatar = document.getElementById("userAvatar");
const avatarInitials = document.getElementById("avatarInitials");