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.<timestamp>. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
35
CLAUDE.md
35
CLAUDE.md
@@ -50,6 +50,10 @@ STRUCTURE:
|
|||||||
- index.html: Hauptseite (EN)
|
- index.html: Hauptseite (EN)
|
||||||
- legal-notice.html: Impressum (EN, Hinweis "German version prevails")
|
- legal-notice.html: Impressum (EN, Hinweis "German version prevails")
|
||||||
- privacy.html: Datenschutz (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:
|
assets:
|
||||||
fonts: [Inter, Bebas Neue]
|
fonts: [Inter, Bebas Neue]
|
||||||
@@ -98,12 +102,23 @@ PAGES:
|
|||||||
product:
|
product:
|
||||||
- AccountForger Video-Demo
|
- AccountForger Video-Demo
|
||||||
lagen:
|
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 <html lang> und schaltet UI-Strings
|
||||||
|
automatisch um (lang.de / lang.en Dictionary).
|
||||||
redirect: /lagebild/ -> 301 -> /lagen/iran-konflikt/
|
redirect: /lagebild/ -> 301 -> /lagen/iran-konflikt/
|
||||||
aktiv:
|
aktiv:
|
||||||
- iran-konflikt: Live-Lagebild Irankonflikt (ehemals /lagebild/)
|
- iran-konflikt / iran-conflict: Live-Lagebild Irankonflikt
|
||||||
geplant:
|
- cyberangriffe / cyber-attacks: Live-Lagebild Cyberangriffe
|
||||||
- (2 weitere Lagen in Vorbereitung)
|
- deepfakes / deepfakes: Recherche-Briefing Deepfakes
|
||||||
vorschau:
|
vorschau:
|
||||||
url: /vorschau/
|
url: /vorschau/
|
||||||
zweck: Produktseite AegisSight Monitor (ersetzt spaeter die Hauptseite)
|
zweck: Produktseite AegisSight Monitor (ersetzt spaeter die Hauptseite)
|
||||||
@@ -122,7 +137,14 @@ DEVELOPMENT:
|
|||||||
sprachumschalter: css/lang-switcher.css
|
sprachumschalter: css/lang-switcher.css
|
||||||
pendant_urls: in jeder Seite hardcoded (funktioniert ohne JS)
|
pendant_urls: in jeder Seite hardcoded (funktioniert ohne JS)
|
||||||
cookie_banner: cookie-consent.js liest <html lang> selbststaendig
|
cookie_banner: cookie-consent.js liest <html lang> selbststaendig
|
||||||
open: contact-form.py ist noch DE-only (Validierungs- und Mailtexte)
|
lagen: lagebild.js liest <html lang> 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)"
|
large_files: "assets/videos/ (~300MB)"
|
||||||
design: mobile-first responsive
|
design: mobile-first responsive
|
||||||
|
|
||||||
@@ -152,6 +174,9 @@ CHANGE_LOG:
|
|||||||
- "i18n: Sprachumschalter DE/EN, neue Seiten unter /en/"
|
- "i18n: Sprachumschalter DE/EN, neue Seiten unter /en/"
|
||||||
- "Aufraeumen: js/translations.js, impressum-en.html, datenschutz-en.html entfernt"
|
- "Aufraeumen: js/translations.js, impressum-en.html, datenschutz-en.html entfernt"
|
||||||
- "data-translate Attribute aus Lagen-Seiten entfernt"
|
- "data-translate Attribute aus Lagen-Seiten entfernt"
|
||||||
|
- "EN-Lagen-Seiten unter /en/situations/{slug}/, teilen DE-Datenfiles"
|
||||||
|
- "lagebild.js: curLang() liest <html lang>, dataBase()-Helper neu, tote initLangToggle/switchContent entfernt"
|
||||||
|
- "Kontaktformular zweisprachig (Frontend + Backend)"
|
||||||
|
|
||||||
Last-Updated: 2026-05-06
|
Last-Updated: 2026-05-06
|
||||||
|
|
||||||
|
|||||||
@@ -110,9 +110,6 @@ var Lagebild = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
if (typeof initTranslations === 'function') {
|
|
||||||
try { initTranslations(); } catch(e) {}
|
|
||||||
}
|
|
||||||
this.initScrollProgress();
|
this.initScrollProgress();
|
||||||
this.initParticles();
|
this.initParticles();
|
||||||
try {
|
try {
|
||||||
@@ -134,7 +131,6 @@ var Lagebild = {
|
|||||||
};
|
};
|
||||||
this.render();
|
this.render();
|
||||||
this.initTabs();
|
this.initTabs();
|
||||||
this.initLangToggle();
|
|
||||||
this.initScrollReveal();
|
this.initScrollReveal();
|
||||||
this.initFloatingCta();
|
this.initFloatingCta();
|
||||||
this.initLiveFeed();
|
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 ===== */
|
/* ===== FLOATING CTA ===== */
|
||||||
initFloatingCta: function() {
|
initFloatingCta: function() {
|
||||||
var cta = document.createElement('div');
|
var cta = document.createElement('div');
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren