/* ===================================================================== DOGFATHER UNIVERSE — main.js Gemeinsame Navigation, mobiles Menü, Footer, Nebel-Effekt. Läuft rein clientseitig (kein Build-Tool, kein Fetch von Partials), damit jede Seite auch direkt per Doppelklick (file://) funktioniert. ===================================================================== */ (function () { "use strict"; /* =================================================================== Mehrsprachigkeit (i18n) Fünf Sprachen: Deutsch (Standard, IMMER die Sprache beim ersten Besuch), Englisch, echtes Schweizerdeutsch (Dialekt, nicht nur Hochdeutsch mit ß→ss — Wunsch von Dogi; da Dialekt keine einheitliche Schriftform hat, wurde eine gängige, Zürich-nahe Schreibweise gewählt), Französisch, Portugiesisch. Rein clientseitig, kein Build-Tool: - I18N_CORE deckt die sitewide gemeinsamen Textstücke ab (Navigation, Fußzeile, Musik-Widget) — läuft auf JEDER Seite, weil main.js überall eingebunden ist. - Seiteneigene Inhalte (z.B. die Startseite) bekommen zusätzlich ein eigenes Wörterbuch über window.I18N_PAGE (siehe assets/js/i18n-*.js), das per data-i18n="schluessel" auf Elemente gemappt wird. Markennamen (DogFather, HasiDog, Casper, VanVan, Team Dogi, Modi-Team, Scout-Team, Streamer, Creator, Manager, Community) bleiben bewusst in JEDER Sprache unübersetzt — das ist die Marke. Gewählte Sprache landet in localStorage und bleibt beim Klicken durch die Seite erhalten. Ein komplett neuer Besuch (keine Speicherung) startet immer auf Deutsch — nie automatische Browsersprache-Erkennung. =================================================================== */ /* Bewusst KEINE Flaggen-Emojis: Windows rendert Flaggen-Emojis grundsätzlich nicht als Bild, sondern als nackten Buchstaben-Code (z.B. "DE") — zusammen mit dem eigenen Kürzel wäre das "DE DE", "GB EN" (Flagge≠Sprachcode bei Englisch) usw. Ein einzelnes Globus-Symbol im Knopf plus volle Sprachnamen im Dropdown ist eindeutig und funktioniert auf jedem Betriebssystem gleich. */ /* Pro Sprache eine kräftige, gut leuchtende Akzentfarbe (glut) — für Schrift-Leuchten, Knopf-Aurora und die glänzende Kugel (deren Farbverlauf wird rein in CSS aus dieser einen Farbe gebaut, siehe .sprach-kugel in main.css). Angelehnt an die jeweilige Landesfarbe, aber bewusst gesättigter/heller (nicht die originalen, oft eher stumpfen Flaggenfarben), damit der Polarlicht-Effekt gut trägt. */ const SPRACHEN = [ { code: "de", kurz: "DE", name: "Deutsch", glut: "#ffb300" }, { code: "de-CH", kurz: "CH", name: "Schwiizerdütsch", glut: "#ff3b3b" }, { code: "en", kurz: "EN", name: "English", glut: "#2f6bff" }, { code: "fr", kurz: "FR", name: "Français", glut: "#00c2ff" }, { code: "pt", kurz: "PT", name: "Português", glut: "#20d97a" }, ]; const SPRACHE_SCHLUESSEL = "dogi-sprache"; function getSprache() { const gespeichert = localStorage.getItem(SPRACHE_SCHLUESSEL); return SPRACHEN.some((s) => s.code === gespeichert) ? gespeichert : "de"; } function setSprache(code) { if (!SPRACHEN.some((s) => s.code === code)) return; localStorage.setItem(SPRACHE_SCHLUESSEL, code); document.documentElement.setAttribute("lang", code); renderHeader(); renderFooter(); applyTranslations(); applyMusicWidgetSprache(); // Seiteneigene Skripte (z.B. der Live-Status auf index.html) können // darauf reagieren, um dynamisch gesetzten Text (nicht über // data-i18n) ebenfalls neu zu übersetzen. document.dispatchEvent(new CustomEvent("dogi-sprache-geaendert", { detail: { sprache: code } })); } const I18N_CORE = { nav_start: { de: "Start", "de-CH": "Start", en: "Home", fr: "Accueil", pt: "Início" }, nav_dogfather: { de: "DogFather", "de-CH": "DogFather", en: "DogFather", fr: "DogFather", pt: "DogFather" }, nav_dogfather_person: { de: "Die Person", "de-CH": "D Person", en: "The Person", fr: "La personne", pt: "A pessoa" }, nav_dogfather_streamer: { de: "Streamer", "de-CH": "Streamer", en: "Streamer", fr: "Streamer", pt: "Streamer" }, nav_dogfather_casper: { de: "Casper", "de-CH": "Casper", en: "Casper", fr: "Casper", pt: "Casper" }, nav_dogfather_vanvan: { de: "VanVan", "de-CH": "VanVan", en: "VanVan", fr: "VanVan", pt: "VanVan" }, nav_dogfather_zeitreise: { de: "Zeitreise", "de-CH": "Zytreis", en: "Timeline", fr: "Chronologie", pt: "Linha do tempo" }, nav_hasidog: { de: "HasiDog", "de-CH": "HasiDog", en: "HasiDog", fr: "HasiDog", pt: "HasiDog" }, nav_hasidog_welt: { de: "HasiDog-Welt", "de-CH": "HasiDog-Wält", en: "HasiDog World", fr: "Monde HasiDog", pt: "Mundo HasiDog" }, nav_hasidog_modi: { de: "Modi-Team", "de-CH": "Modi-Team", en: "Modi-Team", fr: "Modi-Team", pt: "Modi-Team" }, nav_hasidog_community: { de: "Community", "de-CH": "Community", en: "Community", fr: "Communauté", pt: "Comunidade" }, nav_hasidog_stimmen: { de: "Stimmen", "de-CH": "Stimme", en: "Voices", fr: "Témoignages", pt: "Depoimentos" }, nav_hasidog_streamplan: { de: "Streamplan", "de-CH": "Streamplan", en: "Stream schedule", fr: "Programme des streams", pt: "Programação das lives" }, nav_manager: { de: "Manager", "de-CH": "Manager", en: "Manager", fr: "Manager", pt: "Manager" }, nav_manager_dogfather: { de: "Manager DogFather", "de-CH": "Manager DogFather", en: "Manager DogFather", fr: "Manager DogFather", pt: "Manager DogFather" }, nav_manager_scouts: { de: "Scout-Team", "de-CH": "Scout-Team", en: "Scout Team", fr: "Équipe Scouts", pt: "Equipe Scouts" }, nav_manager_creator: { de: "Creator", "de-CH": "Creator", en: "Creator", fr: "Creator", pt: "Creator" }, nav_manager_werte: { de: "Werte", "de-CH": "Wärt", en: "Values", fr: "Valeurs", pt: "Valores" }, nav_manager_bewerben: { de: "Bewerben", "de-CH": "Bewärbe", en: "Apply", fr: "Postuler", pt: "Candidatar-se" }, nav_medien: { de: "Medien", "de-CH": "Medie", en: "Media", fr: "Médias", pt: "Mídia" }, nav_medien_dogfather: { de: "DogFather", "de-CH": "DogFather", en: "DogFather", fr: "DogFather", pt: "DogFather" }, nav_medien_hasidog: { de: "HasiDog", "de-CH": "HasiDog", en: "HasiDog", fr: "HasiDog", pt: "HasiDog" }, nav_medien_casper: { de: "Casper", "de-CH": "Casper", en: "Casper", fr: "Casper", pt: "Casper" }, nav_links: { de: "Links", "de-CH": "Links", en: "Links", fr: "Liens", pt: "Links" }, nav_cta_bewerben: { de: "Bewerben 🩵", "de-CH": "Bewärbe 🩵", en: "Apply 🩵", fr: "Postuler 🩵", pt: "Candidatar-se 🩵" }, nav_toggle_aria: { de: "Menü öffnen", "de-CH": "Menü uftue", en: "Open menu", fr: "Ouvrir le menu", pt: "Abrir menu" }, sprache_aria: { de: "Sprache wählen", "de-CH": "Sprach uswähle", en: "Choose language", fr: "Choisir la langue", pt: "Escolher idioma" }, brand_tagline: { de: "Streamer · Community · HasiDog · Manager", "de-CH": "Streamer · Community · HasiDog · Manager", en: "Streamer · Community · HasiDog · Manager", fr: "Streamer · Communauté · HasiDog · Manager", pt: "Streamer · Comunidade · HasiDog · Manager", }, footer_tagline: { de: "Streamer. Community. HasiDog. Manager. Gemeinsam stark.", "de-CH": "Streamer. Community. HasiDog. Manager. Zäme stark.", en: "Streamer. Community. HasiDog. Manager. Stronger together.", fr: "Streamer. Communauté. HasiDog. Manager. Plus forts ensemble.", pt: "Streamer. Comunidade. HasiDog. Manager. Mais fortes juntos.", }, footer_h4_hasidog_manager: { de: "HasiDog & Manager", "de-CH": "HasiDog & Manager", en: "HasiDog & Manager", fr: "HasiDog et Manager", pt: "HasiDog e Manager" }, footer_h4_mehr: { de: "Mehr", "de-CH": "Meh", en: "More", fr: "Plus", pt: "Mais" }, footer_scouts: { de: "Scouts", "de-CH": "Scouts", en: "Scouts", fr: "Scouts", pt: "Scouts" }, footer_alle_links: { de: "Alle Links", "de-CH": "Alli Links", en: "All links", fr: "Tous les liens", pt: "Todos os links" }, footer_kontakt: { de: "Kontakt", "de-CH": "Kontakt", en: "Contact", fr: "Contact", pt: "Contato" }, footer_copyright: { de: "© {jahr} DogFather Universe. Team Dogi ist Familie 🩵", "de-CH": "© {jahr} DogFather Universe. Team Dogi isch Familie 🩵", en: "© {jahr} DogFather Universe. Team Dogi is family 🩵", fr: "© {jahr} DogFather Universe. Team Dogi, c'est la famille 🩵", pt: "© {jahr} DogFather Universe. Team Dogi é família 🩵", }, footer_impressum: { de: "Impressum & Datenschutz", "de-CH": "Impressum & Datenschutz", en: "Legal notice & privacy", fr: "Mentions légales et confidentialité", pt: "Aviso legal e privacidade" }, music_title: { de: "Musik von Team Dogi 🎵", "de-CH": "Musig vo Team Dogi 🎵", en: "Music from Team Dogi 🎵", fr: "Musique de Team Dogi 🎵", pt: "Música do Team Dogi 🎵" }, music_close_aria: { de: "Musik-Feld schließen", "de-CH": "Musig-Feld zuemache", en: "Close music panel", fr: "Fermer le panneau musique", pt: "Fechar painel de música" }, music_intro: { de: "Läuft weiter, solange du auf dieser Seite bleibst. 🩵", "de-CH": "Laift wiiter, solang du uf dere Site bliibsch. 🩵", en: "Keeps playing as long as you stay on this page. 🩵", fr: "Continue de jouer tant que tu restes sur cette page. 🩵", pt: "Continua tocando enquanto você ficar nesta página. 🩵", }, music_toggle_title: { de: "Musik von Hasidog & Van-Van", "de-CH": "Musig vo Hasidog & Van-Van", en: "Music from Hasidog & Van-Van", fr: "Musique de Hasidog et Van-Van", pt: "Música de Hasidog e Van-Van" }, music_spotify_suffix: { de: "auf Spotify anhören", "de-CH": "uf Spotify alose", en: "listen on Spotify", fr: "écouter sur Spotify", pt: "ouvir no Spotify" }, }; function t(schluessel) { const eintrag = I18N_CORE[schluessel]; if (!eintrag) return schluessel; const sprache = getSprache(); return eintrag[sprache] || eintrag.de || schluessel; } /* Elemente mit data-i18n="schluessel" übersetzen — Wörterbuch kommt aus window.I18N_PAGE (seiteneigen, z.B. assets/js/i18n-index.js). Fehlt der Schlüssel oder die Sprache, bleibt der bestehende (deutsche) Text einfach stehen, statt kaputtzugehen. */ function applyTranslations() { const sprache = getSprache(); document.documentElement.setAttribute("lang", sprache); const seitenWoerterbuch = window.I18N_PAGE || {}; document.querySelectorAll("[data-i18n]").forEach((el) => { const eintrag = seitenWoerterbuch[el.getAttribute("data-i18n")]; if (!eintrag) return; const text = eintrag[sprache] || eintrag.de; if (text) el.innerHTML = text; }); // data-i18n-attr="alt:schluessel;title:andererSchluessel" — für Attribute // statt Textinhalt (z.B. Bild-Alt-Texte). document.querySelectorAll("[data-i18n-attr]").forEach((el) => { el.getAttribute("data-i18n-attr") .split(";") .map((teil) => teil.trim()) .filter(Boolean) .forEach((teil) => { const [attr, schluessel] = teil.split(":"); const eintrag = seitenWoerterbuch[schluessel]; if (!eintrag) return; const text = eintrag[sprache] || eintrag.de; if (text) el.setAttribute(attr, text); }); }); } /* ---------- Navigationsstruktur (an einer Stelle pflegen) ---------- */ const NAV = [ { key: "nav_start", href: "index.html" }, { key: "nav_dogfather", children: [ { key: "nav_dogfather_person", href: "dogfather.html" }, { key: "nav_dogfather_streamer", href: "streamer.html" }, { key: "nav_dogfather_casper", href: "casper.html" }, { key: "nav_dogfather_vanvan", href: "vanvan.html" }, { key: "nav_dogfather_zeitreise", href: "zeitreise.html" }, ], }, { key: "nav_hasidog", children: [ { key: "nav_hasidog_welt", href: "hasidog.html" }, { key: "nav_hasidog_modi", href: "team-modis.html" }, { key: "nav_hasidog_community", href: "community.html" }, { key: "nav_hasidog_stimmen", href: "stimmen.html" }, // Streamplan zurück unter HasiDog — Wunsch Dogi. { key: "nav_hasidog_streamplan", href: "streamplan.html" }, ], }, { key: "nav_manager", children: [ { key: "nav_manager_dogfather", href: "manager.html" }, { key: "nav_manager_scouts", href: "team-scouts.html" }, { key: "nav_manager_creator", href: "creator.html" }, { key: "nav_manager_werte", href: "werte.html" }, { key: "nav_manager_bewerben", href: "bewerben.html" }, ], }, { // Medien ist bewusst nach den 3 Welten aufgeteilt statt nach // Foto/Video/Aktionen getrennt zu sein — Wunsch von Dogi: pro Welt // (DogFather/HasiDog/Casper) gibt es EINE Seite mit allem // kategorisiert (Fotos, Videos, Events), siehe medien-*.html. key: "nav_medien", children: [ { key: "nav_medien_dogfather", href: "medien-dogfather.html" }, { key: "nav_medien_hasidog", href: "medien-hasidog.html" }, { key: "nav_medien_casper", href: "medien-casper.html" }, ], }, { key: "nav_links", href: "links.html" }, ]; /* Aktuelle Datei — wird beim nahtlosen Seitenwechsel mit aktualisiert. */ let currentFile = (location.pathname.split("/").pop() || "index.html"); function isActive(href) { return href === currentFile; } function renderNavItem(item) { if (!item.children) { return `${t(item.key)}`; } const activeChild = item.children.some((c) => isActive(c.href)); return `
`; } /* Sprachumschalter — eigener nav-group-artiger Dropdown, zeigt die aktuell gewählte Sprache (Flagge + Kürzel) und listet beim Klick die übrigen 4 Sprachen auf. */ function renderSprachSchalter() { const aktuell = getSprache(); const aktiv = SPRACHEN.find((s) => s.code === aktuell) || SPRACHEN[0]; return ` `; } function renderHeader() { const el = document.getElementById("site-header"); if (!el) return; el.innerHTML = `${t("music_intro")}
${SPOTIFY_ARTISTS.map( (a) => `${a.name}
` ).join("")}