lang
This commit is contained in:
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user