From 645fb338986537c63df5c8237e1e486d5039a8ad Mon Sep 17 00:00:00 2001 From: UserIsMH Date: Wed, 6 May 2026 23:28:05 +0200 Subject: [PATCH 1/5] i18n: EN-Lagen-Seiten + zweisprachiges Kontaktformular (Phase 3+4) Phase 3 - Englische Lagebild-Seiten: - /en/situations/iran-conflict/, /en/situations/cyber-attacks/, /en/situations/deepfakes/ erstellt (Mirror der DE-Lagen mit englischer UI) - lagebild.js: curLang() liest jetzt direkt ; neuer dataBase()-Helper, damit EN-Seiten die JSON-Daten aus dem DE-Pfad nachladen koennen (window.LAGEBILD_DATA_BASE pro Seite) - 4 zuvor hardcodierte DE-Strings (emptyDevelopments, emptySummary, Quelle-Tooltip, Schliessen-Aria) ueber t() und das vorhandene lang.de/lang.en-Dictionary uebersetzt - DE-Lagen-Seiten: hreflang-Tags wieder aktiv, Toggle zeigt nun korrekt auf das EN-Pendant statt /en/ - en/index.html Karussell-Buttons zeigen auf EN-Lagen - Sitemap mit hreflang-Alternativen fuer alle Lagen ergaenzt Phase 4 - Kontaktformular zweisprachig (Frontend): - js/app.js submitContact() liest , sendet lang im POST und zeigt Sende-/Fehler-Texte in der jeweiligen Sprache - Backend (contact-form.py) wird separat ausgerollt, ist aber abwaertskompatibel: bei fehlendem lang-Param defaultet es auf de Co-Authored-By: Claude Opus 4.7 (1M context) --- en/index.html | 6 +- en/situations/cyber-attacks/index.html | 153 +++++++++++++++++ en/situations/deepfakes/index.html | 224 ++++++++++++++++++++++++ en/situations/iran-conflict/index.html | 226 +++++++++++++++++++++++++ js/app.js | 17 +- lagen/cyberangriffe/index.html | 7 +- lagen/deepfakes/index.html | 7 +- lagen/iran-konflikt/index.html | 7 +- lagen/iran-konflikt/lagebild.js | 37 ++-- sitemap-launch.xml | 33 ++++ 10 files changed, 691 insertions(+), 26 deletions(-) create mode 100644 en/situations/cyber-attacks/index.html create mode 100644 en/situations/deepfakes/index.html create mode 100644 en/situations/iran-conflict/index.html diff --git a/en/index.html b/en/index.html index fc07659..e431aa6 100644 --- a/en/index.html +++ b/en/index.html @@ -350,7 +350,7 @@
Situation report loading...
- Open full situation report + Open full situation report
diff --git a/lagen/deepfakes/index.html b/lagen/deepfakes/index.html index d977da4..33959f2 100644 --- a/lagen/deepfakes/index.html +++ b/lagen/deepfakes/index.html @@ -5,6 +5,9 @@ Recherche: Rechtliche Lage von Deepfakes in Deutschland - AegisSight + + + @@ -36,7 +39,7 @@
DE - EN + EN
'; + + ''; document.body.appendChild(cta); // Show after scrolling past hero diff --git a/sitemap-launch.xml b/sitemap-launch.xml index c141a2d..9183821 100644 --- a/sitemap-launch.xml +++ b/sitemap-launch.xml @@ -21,16 +21,49 @@ https://aegis-sight.de/lagen/iran-konflikt/ daily 0.8 + + + + + + https://aegis-sight.de/en/situations/iran-conflict/ + daily + 0.8 + + + https://aegis-sight.de/lagen/cyberangriffe/ daily 0.8 + + + + + + https://aegis-sight.de/en/situations/cyber-attacks/ + daily + 0.8 + + + https://aegis-sight.de/lagen/deepfakes/ weekly 0.7 + + + + + + https://aegis-sight.de/en/situations/deepfakes/ + weekly + 0.7 + + + https://aegis-sight.de/impressum.html From f874d1dee02f3ee36b0611dce73c5ba6bca8c661 Mon Sep 17 00:00:00 2001 From: UserIsMH Date: Wed, 6 May 2026 23:30:24 +0200 Subject: [PATCH 2/5] i18n: Aufraeumen und Doku-Update (Phase 5) - lagebild.js: tote initLangToggle() und switchContent() entfernt; initTranslations()-Aufruf aus init() raus (translations.js gibt es nicht mehr). Kein neues Verhalten, nur Aufraeumen. - CLAUDE.md aktualisiert: en/situations/-Struktur, Slug-Mapping, Daten-Freigabe-Konzept, Kontaktformular i18n-Hinweis, CHANGE_LOG erweitert. Backend (contact-form.py) wurde live ausgerollt und ist nicht im Repo (liegt unter /opt/v2-Docker/aegis-website/), Backup unter contact-form.py.bak.. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 35 ++++++++++++++--- lagen/iran-konflikt/lagebild.js | 66 --------------------------------- 2 files changed, 30 insertions(+), 71 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index ee5276a..78de637 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,6 +50,10 @@ STRUCTURE: - index.html: Hauptseite (EN) - legal-notice.html: Impressum (EN, Hinweis "German version prevails") - privacy.html: Datenschutz (EN, Hinweis "German version prevails") + situations: + - iran-conflict/index.html: Lagebild Iran (EN-Mirror, teilt /lagen/iran-konflikt/data) + - cyber-attacks/index.html: Lagebild Cyberangriffe (EN-Mirror, teilt /lagen/cyberangriffe/data) + - deepfakes/index.html: Recherche Deepfakes (EN-Mirror, teilt /lagen/deepfakes/data) assets: fonts: [Inter, Bebas Neue] @@ -98,12 +102,23 @@ PAGES: product: - AccountForger Video-Demo lagen: - url_struktur: /lagen/{thema}/ + url_struktur: + de: /lagen/{thema}/ + en: /en/situations/{slug}/ (slug ist die englische URL-Variante) + slug_mapping: + iran-konflikt: iran-conflict + cyberangriffe: cyber-attacks + deepfakes: deepfakes + daten_freigabe: | + EN-Mirror-Seiten setzen window.LAGEBILD_DATA_BASE auf den DE-Pfad, + damit beide Sprachvarianten die gleichen JSON-Daten laden. Das + lagebild.js liest curLang() aus und schaltet UI-Strings + automatisch um (lang.de / lang.en Dictionary). redirect: /lagebild/ -> 301 -> /lagen/iran-konflikt/ aktiv: - - iran-konflikt: Live-Lagebild Irankonflikt (ehemals /lagebild/) - geplant: - - (2 weitere Lagen in Vorbereitung) + - iran-konflikt / iran-conflict: Live-Lagebild Irankonflikt + - cyberangriffe / cyber-attacks: Live-Lagebild Cyberangriffe + - deepfakes / deepfakes: Recherche-Briefing Deepfakes vorschau: url: /vorschau/ zweck: Produktseite AegisSight Monitor (ersetzt spaeter die Hauptseite) @@ -122,7 +137,14 @@ DEVELOPMENT: sprachumschalter: css/lang-switcher.css pendant_urls: in jeder Seite hardcoded (funktioniert ohne JS) cookie_banner: cookie-consent.js liest selbststaendig - open: contact-form.py ist noch DE-only (Validierungs- und Mailtexte) + lagen: lagebild.js liest via curLang(); Daten-Pfad ueber + window.LAGEBILD_DATA_BASE pro EN-Mirror-Seite + kontaktformular: | + Frontend (js/app.js) sendet lang im POST-Body, zeigt Sende- und + Fehler-Texte in der jeweiligen Sprache. Backend + (/opt/v2-Docker/aegis-website/contact-form.py, NICHT im Repo) + liest lang und antwortet entsprechend; E-Mail an info@aegis-sight.de + bleibt deutsch, mit Hinweis "[EN]" im Betreff bei EN-Anfragen. large_files: "assets/videos/ (~300MB)" design: mobile-first responsive @@ -152,6 +174,9 @@ CHANGE_LOG: - "i18n: Sprachumschalter DE/EN, neue Seiten unter /en/" - "Aufraeumen: js/translations.js, impressum-en.html, datenschutz-en.html entfernt" - "data-translate Attribute aus Lagen-Seiten entfernt" + - "EN-Lagen-Seiten unter /en/situations/{slug}/, teilen DE-Datenfiles" + - "lagebild.js: curLang() liest , dataBase()-Helper neu, tote initLangToggle/switchContent entfernt" + - "Kontaktformular zweisprachig (Frontend + Backend)" Last-Updated: 2026-05-06 diff --git a/lagen/iran-konflikt/lagebild.js b/lagen/iran-konflikt/lagebild.js index b32af8e..0196ee9 100644 --- a/lagen/iran-konflikt/lagebild.js +++ b/lagen/iran-konflikt/lagebild.js @@ -110,9 +110,6 @@ var Lagebild = { }, async init() { - if (typeof initTranslations === 'function') { - try { initTranslations(); } catch(e) {} - } this.initScrollProgress(); this.initParticles(); try { @@ -134,7 +131,6 @@ var Lagebild = { }; this.render(); this.initTabs(); - this.initLangToggle(); this.initScrollReveal(); this.initFloatingCta(); this.initLiveFeed(); @@ -1214,68 +1210,6 @@ var Lagebild = { } }, - initLangToggle: function() { - var btn = document.querySelector('.lang-toggle'); - if (!btn) return; - var self = this; - btn.addEventListener('click', function(e) { - e.preventDefault(); - var cur = (typeof getCurrentLanguage === 'function') ? getCurrentLanguage() : 'de'; - var newLang = cur === 'de' ? 'en' : 'de'; - if (typeof switchLanguage === 'function') switchLanguage(newLang); - self.switchContent(newLang); - }); - }, - - switchContent: async function(lang) { - var base = this.dataBase(); - var jsonFile = base + (lang === 'en' ? 'data/current_en.json' : 'data/current.json'); - try { - var resp = await fetch(jsonFile + '?t=' + Date.now()); - if (!resp.ok && lang === 'en') { - resp = await fetch(base + 'data/current.json?t=' + Date.now()); - } - if (!resp.ok) throw new Error('HTTP ' + resp.status); - this.data = await resp.json(); - this.allSnapshots = {}; - this.currentView = { - summary: this.data.current_lagebild.summary_markdown, - sources_json: this.data.current_lagebild.sources_json, - updated_at: this.data.current_lagebild.updated_at || this.data.generated_at, - articles: this.data.articles, - fact_checks: this.data.fact_checks, - article_count: this.data.incident.article_count, - fact_check_count: this.data.incident.factcheck_count - }; - this.render(); - // Update hero title for language - var heroH1 = document.getElementById('hero-title'); - if (heroH1) { - var isResearch = this.data.incident && this.data.incident.type === 'research'; - heroH1.textContent = isResearch ? this.t('heroResearch') : this.t('hero'); - } - // Update tab labels - var tabBtns = document.querySelectorAll('.tab-btn'); - var isResearch = this.data.incident && this.data.incident.type === 'research'; - for (var i = 0; i < tabBtns.length; i++) { - var tab = tabBtns[i].getAttribute('data-tab'); - if (tab === 'lagebild') tabBtns[i].childNodes[0].textContent = isResearch ? this.t('tabBriefingResearch') : this.t('tabBriefing'); - else if (tab === 'ueberblick') tabBtns[i].childNodes[0].textContent = isResearch ? this.t('tabUeberblickResearch') : this.t('tabUeberblick'); - else if (tab === 'karte') tabBtns[i].childNodes[0].textContent = this.t('tabMap'); - else if (tab === 'faktenchecks') tabBtns[i].childNodes[0].textContent = this.t('tabFactchecks') + ' '; - else if (tab === 'quellen') tabBtns[i].childNodes[0].textContent = this.t('tabSources') + ' '; - } - // Update Ueberblick H2 title - var ueberblickH2 = document.getElementById('ueberblick-title'); - if (ueberblickH2) ueberblickH2.textContent = isResearch ? this.t('tabUeberblickResearch') : this.t('tabUeberblick'); - // Update data source note - var dsNote = document.querySelector('.data-source-note'); - if (dsNote) dsNote.textContent = this.t('dataSource'); - } catch(e) { - console.error('Language switch failed:', e); - } - }, - /* ===== FLOATING CTA ===== */ initFloatingCta: function() { var cta = document.createElement('div'); From 2840f420599f4d537fbdc4dafd3e32066ab5d0f1 Mon Sep 17 00:00:00 2001 From: UserIsMH Date: Wed, 6 May 2026 23:40:43 +0200 Subject: [PATCH 3/5] Staging: Mountpoint-Platzhalter fuer Lagen-Daten Die /lagen/*/data/-Verzeichnisse sind nicht versioniert (.gitignore), werden aber im Staging-Container per bind-mount aus dem Live-Pfad eingeblendet. Bei read_only:true im Container muss das Mountpoint- Verzeichnis bereits existieren - daher .gitkeep als Platzhalter. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitignore | 4 +++- lagen/cyberangriffe/data/.gitkeep | 0 lagen/deepfakes/data/.gitkeep | 0 lagen/iran-konflikt/data/.gitkeep | 0 4 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 lagen/cyberangriffe/data/.gitkeep create mode 100644 lagen/deepfakes/data/.gitkeep create mode 100644 lagen/iran-konflikt/data/.gitkeep diff --git a/.gitignore b/.gitignore index ab1a123..cbda27a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ # Lagebild-Daten (werden per Cron-Sync vom Monitor regeneriert) lagebild/data/ -lagen/*/data/ +lagen/*/data/* +# Aber Verzeichnis-Platzhalter behalten (Staging-Container braucht Mountpoint) +!lagen/*/data/.gitkeep diff --git a/lagen/cyberangriffe/data/.gitkeep b/lagen/cyberangriffe/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lagen/deepfakes/data/.gitkeep b/lagen/deepfakes/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lagen/iran-konflikt/data/.gitkeep b/lagen/iran-konflikt/data/.gitkeep new file mode 100644 index 0000000..e69de29 From 49fc3a6f64a5cb5813ec1462af3986ab83355496 Mon Sep 17 00:00:00 2001 From: UserIsMH Date: Wed, 6 May 2026 23:44:01 +0200 Subject: [PATCH 4/5] i18n: app.js erkennt Sprache und laedt EN-Datenfiles Die Index-Hauptseite hat noch eine Reihe dynamisch gefuellter Texte (Live-Stats-Bar-Titel, Map-Legende, Default-Kategorie-Labels) und laedt summary.json fuer die Excerpts. Auf der EN-Variante hat das bisher zu sichtbarem deutschen Text gefuehrt. - SITE_LANG wird einmal aus abgeleitet - lageTitles existiert pro Sprache - defaultLabels (primary/secondary/tertiary/mentioned) pro Sprache - Legende -> Legend in der Map-Legende - summary.json -> summary_en.json bei EN, mit Fallback auf summary.json wenn EN-Variante nicht existiert (Monitor erzeugt beide bereits) Co-Authored-By: Claude Opus 4.7 (1M context) --- js/app.js | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/js/app.js b/js/app.js index 8303021..cff2409 100644 --- a/js/app.js +++ b/js/app.js @@ -2,6 +2,10 @@ (function () { 'use strict'; + /* ==================== LANGUAGE ==================== */ + var SITE_LANG = (document.documentElement.lang || 'de').toLowerCase().indexOf('en') === 0 ? 'en' : 'de'; + var SUMMARY_FILE = SITE_LANG === 'en' ? 'summary_en.json' : 'summary.json'; + /* ==================== NAVBAR ==================== */ var navbar = document.getElementById('navbar'); window.addEventListener('scroll', function () { @@ -197,11 +201,19 @@ var lageData = {}; var dataLoaded = false; - var lageTitles = { - 'iran-konflikt': 'Gro\u00dflage - Irankonflikt', - 'cyberangriffe': 'Cyberangriffe auf deutsche Infrastruktur', - 'deepfakes': 'Rechtliche Lage von Deepfakes in Deutschland' + var lageTitlesByLang = { + de: { + 'iran-konflikt': 'Gro\u00dflage - Irankonflikt', + 'cyberangriffe': 'Cyberangriffe auf deutsche Infrastruktur', + 'deepfakes': 'Rechtliche Lage von Deepfakes in Deutschland' + }, + en: { + 'iran-konflikt': 'Major situation - Iran conflict', + 'cyberangriffe': 'Cyberattacks on German infrastructure', + 'deepfakes': 'Legal status of deepfakes in Germany' + } }; + var lageTitles = lageTitlesByLang[SITE_LANG] || lageTitlesByLang.de; /* ==================== 3D CAROUSEL ==================== */ var cards = document.querySelectorAll('.carousel-card'); @@ -427,7 +439,8 @@ function mdToHtml(md) { } function loadLiveData() { - fetch('/lagen/iran-konflikt/data/summary.json?t=' + Date.now()) + fetch('/lagen/iran-konflikt/data/' + SUMMARY_FILE + '?t=' + Date.now()) + .then(function (r) { if (!r.ok && SITE_LANG === 'en') return fetch('/lagen/iran-konflikt/data/summary.json?t=' + Date.now()); return r; }) .then(function (r) { if (!r.ok) throw new Error(r.status); return r.json(); }) .then(function (data) { var inc = data.incident || {}; @@ -532,7 +545,12 @@ function mdToHtml(md) { mentioned: '#7b7b7b' }; - var defaultLabels = { + var defaultLabels = SITE_LANG === 'en' ? { + primary: 'Primary', + secondary: 'Reactions', + tertiary: 'Involved', + mentioned: 'Mentioned' + } : { primary: 'Hauptgeschehen', secondary: 'Reaktionen', tertiary: 'Beteiligte', @@ -582,7 +600,7 @@ function mdToHtml(md) { legend.onAdd = function () { var div = L.DomUtil.create('div'); div.style.cssText = 'background:#151D2E;padding:10px 14px;border-radius:4px;border:1px solid #1E2D45;box-shadow:0 2px 8px rgba(0,0,0,0.3);font-size:0.8rem;line-height:1.8;color:#E8ECF4;'; - var html = 'Legende
'; + var html = '' + (SITE_LANG === 'en' ? 'Legend' : 'Legende') + '
'; ['primary', 'secondary', 'tertiary', 'mentioned'].forEach(function (cat) { if (usedCategories[cat]) { html += ' ' + categoryLabels[cat] + '
'; @@ -669,7 +687,8 @@ function mdToHtml(md) { /* ==================== LOAD DEEPFAKES DATA ==================== */ function loadDeepfakesData() { - fetch('/lagen/deepfakes/data/summary.json?t=' + Date.now()) + fetch('/lagen/deepfakes/data/' + SUMMARY_FILE + '?t=' + Date.now()) + .then(function (r) { if (!r.ok && SITE_LANG === 'en') return fetch('/lagen/deepfakes/data/summary.json?t=' + Date.now()); return r; }) .then(function (r) { if (!r.ok) throw new Error(r.status); return r.json(); }) .then(function (data) { var excerptEl = document.getElementById('excerpt-text-deepfakes'); @@ -696,7 +715,8 @@ function mdToHtml(md) { /* ==================== LOAD CYBERANGRIFFE DATA ==================== */ function loadCyberangriffeData() { - fetch('/lagen/cyberangriffe/data/summary.json?t=' + Date.now()) + fetch('/lagen/cyberangriffe/data/' + SUMMARY_FILE + '?t=' + Date.now()) + .then(function (r) { if (!r.ok && SITE_LANG === 'en') return fetch('/lagen/cyberangriffe/data/summary.json?t=' + Date.now()); return r; }) .then(function (r) { if (!r.ok) throw new Error(r.status); return r.json(); }) .then(function (data) { var excerptEl = document.getElementById('excerpt-text-cyberangriffe'); From 5e93e5b9d1375b4360ef1f3acbf4fdd90d74afcf Mon Sep 17 00:00:00 2001 From: UserIsMH Date: Thu, 7 May 2026 00:47:18 +0200 Subject: [PATCH 5/5] i18n: Summary-Section auch unter englischem Header erkennen Der Monitor uebersetzt im research-Lagebild-Markdown die Section-Ueberschrift "## Zusammenfassung" zu "## SUMMARY". extractZusammenfassung und stripZusammenfassung matchten bisher nur das deutsche Wort, daher zeigte die EN-Variante der Deepfakes-Recherche eine leere Zusammenfassung. Beide Funktionen erkennen jetzt 'zusammenfassung' und 'summary' case-insensitive. Co-Authored-By: Claude Opus 4.7 (1M context) --- lagen/iran-konflikt/lagebild.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lagen/iran-konflikt/lagebild.js b/lagen/iran-konflikt/lagebild.js index 0196ee9..6198c21 100644 --- a/lagen/iran-konflikt/lagebild.js +++ b/lagen/iran-konflikt/lagebild.js @@ -189,7 +189,7 @@ var Lagebild = { var sections = md.split(/^## /m); for (var i = 0; i < sections.length; i++) { var s = sections[i]; - if (/^zusammenfassung/i.test(s.trim())) { + if (/^(zusammenfassung|summary)\b/i.test(s.trim())) { var next = s.split(/\n## /)[0]; return next.replace(/^[^\n]*\n?/, '').trim(); } @@ -204,7 +204,7 @@ var Lagebild = { var skipping = false; for (var i = 0; i < lines.length; i++) { var line = lines[i]; - if (/^##\s+zusammenfassung\b/i.test(line)) { skipping = true; continue; } + if (/^##\s+(zusammenfassung|summary)\b/i.test(line)) { skipping = true; continue; } if (skipping && /^##\s+/.test(line)) skipping = false; if (!skipping) result.push(line); }