Lagen-Seiten: Englische Übersetzung + Sprachwechsel-Logik

- LANG-Objekt mit de/en Strings für ~40 UI-Elemente
- t() Hilfsfunktion + getLocale() + getHeadline()
- switchContent(): Lädt current_en.json bei Sprachwechsel
- Fallback auf deutsche Version wenn EN nicht verfügbar
- Datumsformatierung sprachabhängig (de-DE / en-GB)
- Artikel-Headlines: Original bei EN, Übersetzung bei DE
- Snapshot-Hinweis bei EN (Historical data in German only)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
Claude Code
2026-04-12 04:12:47 +02:00
Ursprung 3872d32d8f
Commit 932ff9c049

Datei anzeigen

@@ -14,6 +14,78 @@ var Lagebild = {
timelineGroups: null,
/* ===== Inline SVG Icons ===== */
/* ===== LANGUAGE SUPPORT ===== */
lang: {
de: {
hero: "LAGEBILD", heroResearch: "RECHERCHE",
tabBriefing: "Lagebild", tabBriefingResearch: "Recherche",
tabMap: "Karte", tabFactchecks: "Faktenchecks", tabSources: "Quellen",
statArticles: "Artikel", statSources: "Quellen", statFactchecks: "Faktenchecks",
dataSource: "Daten bereitgestellt durch AegisSight Monitor",
timelineCurrent: "Aktuell", timelineArticles: "Artikel", timelineFcs: "Faktenchecks",
srcArticlesFrom: "{count} Artikel aus {sources} Quellen",
srcArticle: "Artikel", srcClose: "Schlie\u00dfen",
mapNoData: "Keine Standortdaten verf\u00fcgbar", mapLegend: "Legende", mapArticles: "Artikel",
fcTotal: "Gesamt", fcConfirmed: "Best\u00e4tigt", fcOpen: "Offen", fcContradicted: "Widerlegt",
fcEvidence: "Evidenz:", fcProgression: "Verlauf:", fcSources: "unabh\u00e4ngige Quellen",
fcNone: "Keine Faktenchecks verf\u00fcgbar.",
fcCleaned: "{count} von {total} Faktenchecks verf\u00fcgbar (\u00e4ltere wurden bereinigt)",
ctaText: "AegisSight Monitor f\u00fcr Ihre Organisation", ctaButton: "Kontakt aufnehmen \u2192",
errorLoad: "Das Lagebild konnte nicht geladen werden. Bitte versuchen Sie es sp\u00e4ter erneut.",
snapshotHint: "",
standPrefix: "Stand: ", standSuffix: " Uhr",
stConfirmed: "Best\u00e4tigt", stUnconfirmed: "Unbest\u00e4tigt", stContradicted: "Widerlegt",
stDeveloping: "Unklar", stEstablished: "Gesichert", stDisputed: "Umstritten",
stFalse: "Falsch", stUnverified: "Nicht verifiziert",
sourceRef: "Quelle",
lastUpdate: "Letzte Aktualisierung: ",
minAgo: "vor {n} Min", hrsAgo: "vor {n} Std",
},
en: {
hero: "SITUATION REPORT", heroResearch: "RESEARCH BRIEFING",
tabBriefing: "Briefing", tabBriefingResearch: "Research",
tabMap: "Map", tabFactchecks: "Fact Checks", tabSources: "Sources",
statArticles: "Articles", statSources: "Sources", statFactchecks: "Fact Checks",
dataSource: "Data provided by AegisSight Monitor",
timelineCurrent: "Current", timelineArticles: "Articles", timelineFcs: "Fact Checks",
srcArticlesFrom: "{count} articles from {sources} sources",
srcArticle: "Articles", srcClose: "Close",
mapNoData: "No location data available", mapLegend: "Legend", mapArticles: "Articles",
fcTotal: "Total", fcConfirmed: "Confirmed", fcOpen: "Open", fcContradicted: "Contradicted",
fcEvidence: "Evidence:", fcProgression: "History:", fcSources: "independent sources",
fcNone: "No fact checks available.",
fcCleaned: "{count} of {total} fact checks available (older ones were cleaned up)",
ctaText: "AegisSight Monitor for your organization", ctaButton: "Contact us \u2192",
errorLoad: "The briefing could not be loaded. Please try again later.",
snapshotHint: "Historical data available in German only",
standPrefix: "As of: ", standSuffix: "",
stConfirmed: "Confirmed", stUnconfirmed: "Unconfirmed", stContradicted: "Contradicted",
stDeveloping: "Developing", stEstablished: "Established", stDisputed: "Disputed",
stFalse: "False", stUnverified: "Unverified",
sourceRef: "Source",
lastUpdate: "Last update: ",
minAgo: "{n} min ago", hrsAgo: "{n} hrs ago",
}
},
curLang: function() {
return (typeof getCurrentLanguage === 'function') ? getCurrentLanguage() : 'de';
},
t: function(key) {
var cl = this.curLang();
return (this.lang[cl] && this.lang[cl][key]) || this.lang.de[key] || key;
},
getLocale: function() {
return this.curLang() === 'en' ? 'en-GB' : 'de-DE';
},
getHeadline: function(article) {
if (this.curLang() === 'en') return article.headline || article.headline_de || '';
return article.headline_de || article.headline || '';
},
icons: {
clock: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>',
fileText: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>',
@@ -29,7 +101,10 @@ var Lagebild = {
this.initScrollProgress();
this.initParticles();
try {
var resp = await fetch('data/current.json?t=' + Date.now());
var savedLang = (typeof getCurrentLanguage === 'function') ? getCurrentLanguage() : 'de';
var jsonFile = savedLang === 'en' ? 'data/current_en.json' : 'data/current.json';
var resp = await fetch(jsonFile + '?t=' + Date.now());
if (!resp.ok && savedLang === 'en') { resp = await fetch('data/current.json?t=' + Date.now()); }
if (!resp.ok) throw new Error('HTTP ' + resp.status);
this.data = await resp.json();
this.currentView = {
@@ -147,11 +222,11 @@ var Lagebild = {
var d = this.data;
var genDate = new Date(this.toUTC(d.generated_at));
var diffMin = Math.max(1, Math.round((Date.now() - genDate.getTime()) / 60000));
var diffText = diffMin < 60 ? ('vor ' + diffMin + ' Min') : ('vor ' + Math.round(diffMin / 60) + ' Std');
var diffText = diffMin < 60 ? this.t('minAgo').replace('{n}', diffMin) : this.t('hrsAgo').replace('{n}', Math.round(diffMin / 60));
container.innerHTML = '<div class="live-feed-item active">'
+ '<span class="live-feed-dot"></span>'
+ '<span>Letzte Aktualisierung: ' + diffText + '</span>'
+ '<span>' + this.t('lastUpdate') + diffText + '</span>'
+ '</div>';
},
@@ -160,13 +235,13 @@ var Lagebild = {
var d = this.data;
document.getElementById('incident-title').innerHTML =
this.esc(this.fixUmlauts(d.incident.title)) +
' <span class="hero-date-info">\u2013 Stand: ' + this.fmtDateOnly(d.generated_at) + ', ' + this.fmtTimeOnly(d.generated_at) + ' Uhr</span>';
' <span class="hero-date-info">\u2013 ' + this.t('standPrefix') + this.fmtDateOnly(d.generated_at) + ', ' + this.fmtTimeOnly(d.generated_at) + this.t('standSuffix') + '</span>';
// Stat Cards (3: Artikel, Quellen, Faktenchecks)
var statsHtml = '';
statsHtml += this.statCard(this.icons.fileText, '<span class="count-up" id="hero-art-count" data-target="' + d.incident.article_count + '">0</span>', 'Artikel');
statsHtml += this.statCard(this.icons.globe, '<span class="count-up" id="hero-src-count" data-target="' + d.incident.source_count + '">0</span>', 'Quellen');
statsHtml += this.statCard(this.icons.shieldCheck, '<span class="count-up" id="hero-fc-count" data-target="' + d.incident.factcheck_count + '">0</span>', 'Faktenchecks');
statsHtml += this.statCard(this.icons.fileText, '<span class="count-up" id="hero-art-count" data-target="' + d.incident.article_count + '">0</span>', this.t("statArticles"));
statsHtml += this.statCard(this.icons.globe, '<span class="count-up" id="hero-src-count" data-target="' + d.incident.source_count + '">0</span>', this.t("statSources"));
statsHtml += this.statCard(this.icons.shieldCheck, '<span class="count-up" id="hero-fc-count" data-target="' + d.incident.factcheck_count + '">0</span>', this.t("statFactchecks"));
document.getElementById('hero-stats').innerHTML = statsHtml;
// Start count-up animations
@@ -196,7 +271,7 @@ var Lagebild = {
var progress = Math.min(elapsed / duration, 1);
var eased = 1 - Math.pow(1 - progress, 3); // easeOutCubic
var current = Math.round(target * eased);
element.textContent = current.toLocaleString('de-DE');
element.textContent = current.toLocaleString(Lagebild.getLocale());
if (progress < 1) {
requestAnimationFrame(update);
}
@@ -271,13 +346,13 @@ var Lagebild = {
h += '>';
if (isActive) h += '<span class="timeline-dot"></span>';
h += '<span class="timeline-day-num">' + d.getUTCDate() + '</span>';
h += '<span class="timeline-day-month">' + d.toLocaleDateString('de-DE', { month: 'short', timeZone: 'UTC' }) + '</span>';
h += '<span class="timeline-day-month">' + d.toLocaleDateString(this.getLocale(), { month: 'short', timeZone: 'UTC' }) + '</span>';
h += '<span class="timeline-day-count">' + defaultSnap.article_count + '</span>';
if (daySnaps.length > 1) {
h += '<span class="timeline-day-updates">' + daySnaps.length + 'x</span>';
}
if (isActive) {
h += '<span class="timeline-day-label">Aktuell</span>';
h += '<span class="timeline-day-label">' + this.t('timelineCurrent') + '</span>';
}
h += '</button>';
}
@@ -378,8 +453,8 @@ var Lagebild = {
h += ' data-snapshot-id="' + snap.id + '">';
h += '<span class="h-timeline-time">' + this.fmtTimeOnly(snap.created_at) + '</span>';
h += '<span class="h-timeline-dot"></span>';
h += '<span class="h-timeline-meta">' + snap.article_count + ' Artikel</span>';
h += '<span class="h-timeline-meta">' + (snap.fact_check_count || 0) + ' Faktenchecks</span>';
h += '<span class="h-timeline-meta">' + snap.article_count + ' ' + this.t('timelineArticles') + '</span>';
h += '<span class="h-timeline-meta">' + (snap.fact_check_count || 0) + ' ' + this.t('timelineFcs') + '</span>';
h += '</button>';
}
h += '</div>';
@@ -453,11 +528,11 @@ var Lagebild = {
var fcCount = this.currentView.fact_check_count || (this.currentView.fact_checks || []).length;
var heroArt = document.getElementById('hero-art-count');
if (heroArt) heroArt.textContent = artCount.toLocaleString('de-DE');
if (heroArt) heroArt.textContent = artCount.toLocaleString(this.getLocale());
var heroSrc = document.getElementById('hero-src-count');
if (heroSrc) heroSrc.textContent = srcCount.toLocaleString('de-DE');
if (heroSrc) heroSrc.textContent = srcCount.toLocaleString(this.getLocale());
var heroFc = document.getElementById('hero-fc-count');
if (heroFc) heroFc.textContent = fcCount.toLocaleString('de-DE');
if (heroFc) heroFc.textContent = fcCount.toLocaleString(this.getLocale());
var fcBadge = document.getElementById('tab-badge-faktenchecks');
if (fcBadge) fcBadge.textContent = fcCount;
@@ -484,7 +559,7 @@ var Lagebild = {
if (src && src.url) {
return '<a class="citation-ref" href="' + self.esc(src.url) + '" target="_blank" rel="noopener" title="' + self.esc(src.name || '') + '">[' + nr + ']</a>';
}
return '<a class="citation-ref" title="Quelle ' + nr + '">[' + nr + ']</a>';
return '<a class="citation-ref" title="' + self.t('sourceRef') + ' ' + nr + '">[' + nr + ']</a>';
});
document.getElementById('summary-content').innerHTML = html;
@@ -504,7 +579,7 @@ var Lagebild = {
var sourceMap = {};
for (var i = 0; i < articles.length; i++) {
var a = articles[i];
var name = a.source || 'Unbekannt';
var name = a.source || 'Unknown';
if (!sourceMap[name]) sourceMap[name] = { count: 0, articles: [], languages: {}, domain: null };
sourceMap[name].count++;
sourceMap[name].articles.push(a);
@@ -531,7 +606,7 @@ var Lagebild = {
// Header
h += '<div class="sources-overview-header">';
h += '<span class="sources-overview-title">' + articles.length + ' Artikel aus ' + sources.length + ' Quellen</span>';
h += '<span class="sources-overview-title">' + this.t('srcArticlesFrom').replace('{count}', articles.length).replace('{sources}', sources.length) + '</span>';
h += '<div class="sources-lang-chips">';
var langKeys = Object.keys(langTotals).sort(function(a, b) { return langTotals[b] - langTotals[a]; });
for (var i = 0; i < langKeys.length; i++) {
@@ -613,15 +688,15 @@ var Lagebild = {
h += '<img class="source-tile-favicon" src="https://www.google.com/s2/favicons?domain=' + encodeURIComponent(src.data.domain) + '&sz=16" width="16" height="16" alt="" loading="lazy"> ';
}
h += this.esc(src.name) + '</span>';
h += '<span class="source-detail-count">' + src.data.count + ' Artikel</span>';
h += '<button class="source-detail-close" aria-label="Schließen">&times;</button>';
h += '<span class="source-detail-count">' + src.data.count + ' ' + Lagebild.t('srcArticle') + '</span>';
h += '<button class="source-detail-close" aria-label="' + Lagebild.t('srcClose') + '">&times;</button>';
h += '</div>';
h += '<div class="source-detail-articles">';
for (var j = 0; j < arts.length; j++) {
var a = arts[j];
var dt = a.published_at || a.collected_at || '';
var dObj = dt ? new Date(this.toUTC(dt)) : null;
var hl = this.fixUmlauts(a.headline_de || a.headline || '');
var hl = this.fixUmlauts(Lagebild.getHeadline(a));
h += '<div class="source-detail-article">';
if (a.source_url) {
h += '<a href="' + this.esc(a.source_url) + '" target="_blank" rel="noopener" class="source-detail-article-title">' + this.esc(hl) + ' ' + this.icons.externalLink + '</a>';
@@ -629,7 +704,7 @@ var Lagebild = {
h += '<span class="source-detail-article-title">' + this.esc(hl) + '</span>';
}
if (dObj && !isNaN(dObj.getTime())) {
h += '<span class="source-detail-article-date">' + dObj.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', timeZone: TIMEZONE }) + '</span>';
h += '<span class="source-detail-article-date">' + dObj.toLocaleDateString(Lagebild.getLocale(), { day: '2-digit', month: '2-digit', year: 'numeric', timeZone: TIMEZONE }) + '</span>';
}
h += '</div>';
}
@@ -712,7 +787,7 @@ var Lagebild = {
if (locs.length === 0) {
var emptyDiv = document.createElement('div');
emptyDiv.style.cssText = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:1000;background:#151D2E;padding:20px 30px;border-radius:8px;border:1px solid #1E2D45;color:#8896AB;text-align:center;';
emptyDiv.innerHTML = 'Keine Standortdaten verfuegbar';
emptyDiv.innerHTML = Lagebild.t('mapNoData');
document.getElementById('map-container').appendChild(emptyDiv);
}
@@ -736,7 +811,7 @@ var Lagebild = {
// Popup mit Artikel-Links
var popupText = '<strong style="color:#E8ECF4;">' + (l.name || '') + '</strong>';
if (l.country_code) popupText += ' <span style="color:#8896AB;font-size:0.8rem;">(' + l.country_code + ')</span>';
popupText += '<br><span style="font-size:0.85rem;color:#8896AB;">' + (l.article_count || 0) + ' Artikel</span>';
popupText += '<br><span style="font-size:0.85rem;color:#8896AB;">' + (l.article_count || 0) + ' ' + Lagebild.t('mapArticles') + '</span>';
if (l.top_articles && l.top_articles.length > 0) {
popupText += '<div style="margin-top:6px;border-top:1px solid #1E2D45;padding-top:6px;">';
for (var j = 0; j < l.top_articles.length; j++) {
@@ -774,7 +849,7 @@ var Lagebild = {
legend.onAdd = function() {
var div = L.DomUtil.create('div', 'map-legend');
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 = '<strong style="color:#C8A851;">Legende</strong><br>';
var html = '<strong style="color:#C8A851;">' + Lagebild.t('mapLegend') + '</strong><br>';
['primary', 'secondary', 'tertiary', 'mentioned'].forEach(function(cat) {
if (usedCategories[cat] && categoryLabels[cat]) {
html += '<span style="color:' + categoryColors[cat] + ';">&#9679;</span> ' + categoryLabels[cat] + '<br>';
@@ -813,21 +888,12 @@ var Lagebild = {
unverified: '?'
},
fcLabels: {
confirmed: 'Bestätigt',
unconfirmed: 'Unbestätigt',
contradicted: 'Widerlegt',
developing: 'Unklar',
established: 'Gesichert',
disputed: 'Umstritten',
'false': 'Falsch',
unverified: 'Nicht verifiziert'
},
fcLabels: {},
renderFactChecksTab: function() {
var checks = this.currentView.fact_checks || [];
if (!checks.length) {
document.getElementById('factchecks-content').innerHTML = '<p style="color:#8896AB">Keine Faktenchecks verfügbar.</p>';
document.getElementById('factchecks-content').innerHTML = '<p style="color:#8896AB">' + this.t('fcNone') + '</p>';
return;
}
@@ -844,18 +910,18 @@ var Lagebild = {
// Stat cards (clickable filters)
var h = '<div class="fc-stats">';
h += '<button class="fc-stat active" data-filter="all"><span class="fc-stat-num">' + checks.length + '</span><span class="fc-stat-label">Gesamt</span></button>';
h += '<button class="fc-stat confirmed" data-filter="confirmed"><span class="fc-stat-num">' + confirmedTotal + '</span><span class="fc-stat-label">Bestätigt</span></button>';
h += '<button class="fc-stat unconfirmed" data-filter="unconfirmed"><span class="fc-stat-num">' + openTotal + '</span><span class="fc-stat-label">Offen</span></button>';
h += '<button class="fc-stat active" data-filter="all"><span class="fc-stat-num">' + checks.length + '</span><span class="fc-stat-label">' + this.t('fcTotal') + '</span></button>';
h += '<button class="fc-stat confirmed" data-filter="confirmed"><span class="fc-stat-num">' + confirmedTotal + '</span><span class="fc-stat-label">' + this.t('fcConfirmed') + '</span></button>';
h += '<button class="fc-stat unconfirmed" data-filter="unconfirmed"><span class="fc-stat-num">' + openTotal + '</span><span class="fc-stat-label">' + this.t('fcOpen') + '</span></button>';
if (contradictedTotal > 0)
h += '<button class="fc-stat contradicted" data-filter="contradicted"><span class="fc-stat-num">' + contradictedTotal + '</span><span class="fc-stat-label">Widerlegt</span></button>';
h += '<button class="fc-stat contradicted" data-filter="contradicted"><span class="fc-stat-num">' + contradictedTotal + '</span><span class="fc-stat-label">' + this.t('fcContradicted') + '</span></button>';
h += '</div>';
// Hinweis bei unvollständiger Liste
var storedFcCount = this.currentView.fact_check_count || 0;
if (storedFcCount > 0 && checks.length < storedFcCount) {
h += '<div style="padding:8px 12px;margin:8px 0;background:rgba(200,168,81,0.1);border:1px solid rgba(200,168,81,0.3);border-radius:6px;color:#C8A851;font-size:0.85rem;">';
h += checks.length + ' von ' + storedFcCount + ' Faktenchecks verfügbar (ältere wurden bereinigt)';
h += this.t('fcCleaned').replace('{count}', checks.length).replace('{total}', storedFcCount);
h += '</div>';
}
@@ -879,7 +945,7 @@ var Lagebild = {
var hasProg = fc.status_history && fc.status_history.length > 1;
var icon = this.fcIcons[status] || '?';
var label = this.fcLabels[status] || status;
var label = this.stLabel(status);
h += '<div class="fc-row" data-status-group="' + filterGroup + '">';
h += '<div class="fc-row-header" data-fc-index="' + i + '">';
@@ -893,17 +959,17 @@ var Lagebild = {
// Expandable detail
h += '<div class="fc-row-detail">';
h += '<div class="fc-row-detail-inner">';
h += '<div class="fc-detail-status"><span class="fc-icon ' + status + '">' + icon + '</span> <strong>' + label + '</strong> – ' + (fc.sources_count || 0) + ' unabhängige Quellen</div>';
h += '<div class="fc-detail-status"><span class="fc-icon ' + status + '">' + icon + '</span> <strong>' + label + '</strong> – ' + (fc.sources_count || 0) + ' ' + this.t('fcSources') + '</div>';
if (fc.evidence) {
var ev = this.fixUmlauts(fc.evidence);
ev = this.esc(ev).replace(/(https?:\/\/[^\s,)]+)/g, '<a href="$1" target="_blank" rel="noopener">$1</a>');
h += '<div class="fc-detail-evidence"><strong>Evidenz:</strong> ' + ev + '</div>';
h += '<div class="fc-detail-evidence"><strong>' + this.t('fcEvidence') + '</strong> ' + ev + '</div>';
}
if (hasProg) {
h += '<div class="fc-detail-progression">';
h += '<span class="fc-detail-prog-label">Verlauf:</span>';
h += '<span class="fc-detail-prog-label">' + this.t('fcProgression') + '</span>';
for (var j = 0; j < fc.status_history.length; j++) {
var step = fc.status_history[j];
if (j > 0) h += '<span class="progression-arrow">&rarr;</span>';
@@ -991,21 +1057,66 @@ var Lagebild = {
initLangToggle: function() {
var btn = document.querySelector('.lang-toggle');
if (!btn) return;
var self = this;
btn.addEventListener('click', function(e) {
e.preventDefault();
if (typeof switchLanguage === 'function') {
var cur = (typeof getCurrentLanguage === 'function') ? getCurrentLanguage() : 'de';
switchLanguage(cur === 'de' ? 'en' : 'de');
}
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 jsonFile = 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('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 === '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 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');
cta.className = 'floating-cta';
cta.innerHTML = '<span class="floating-cta-text">AegisSight Monitor f\u00fcr Ihre Organisation</span>'
+ '<a href="mailto:info@aegis-sight.de" class="floating-cta-btn">Kontakt aufnehmen \u2192</a>'
cta.innerHTML = '<span class="floating-cta-text">' + this.t('ctaText') + '</span>'
+ '<a href="mailto:info@aegis-sight.de" class="floating-cta-btn">' + this.t('ctaButton') + '</a>'
+ '<button class="floating-cta-close" aria-label="Schlie\u00dfen">&times;</button>';
document.body.appendChild(cta);
@@ -1115,9 +1226,8 @@ var Lagebild = {
},
stLabel: function(s) {
return { confirmed: 'Best\u00e4tigt', unconfirmed: 'Unbest\u00e4tigt', established: 'Gesichert',
unverified: 'Nicht verifiziert', contradicted: 'Widerlegt', disputed: 'Umstritten',
developing: 'In Entwicklung', 'false': 'Falsch' }[s] || s;
var key = 'st' + s.charAt(0).toUpperCase() + s.slice(1);
return this.t(key) || s;
},
mdToHtml: function(md) {
@@ -1163,11 +1273,12 @@ var Lagebild = {
var d = new Date(this.toUTC(iso));
if (isNaN(d.getTime())) return iso;
var opts = { timeZone: TIMEZONE, weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false };
var parts = new Intl.DateTimeFormat('de-DE', opts).formatToParts(d);
var locale = Lagebild.getLocale();
var parts = new Intl.DateTimeFormat(locale, opts).formatToParts(d);
var p = {};
parts.forEach(function(x) { p[x.type] = x.value; });
return p.weekday + ', ' + p.day + '. ' + p.month + ' ' + p.year
+ ' um ' + p.hour + ':' + p.minute + ' Uhr';
if (locale === 'en-GB') return p.weekday + ', ' + p.day + ' ' + p.month + ' ' + p.year + ', ' + p.hour + ':' + p.minute;
return p.weekday + ', ' + p.day + '. ' + p.month + ' ' + p.year + ' um ' + p.hour + ':' + p.minute + ' Uhr';
} catch(e) { return iso; }
},
@@ -1176,7 +1287,7 @@ var Lagebild = {
try {
var d = new Date(this.toUTC(iso));
if (isNaN(d.getTime())) return iso;
return d.toLocaleDateString('de-DE', { day: 'numeric', month: 'short', year: 'numeric', timeZone: TIMEZONE });
return d.toLocaleDateString(Lagebild.getLocale(), { day: 'numeric', month: 'short', year: 'numeric', timeZone: TIMEZONE });
} catch(e) { return iso; }
},
@@ -1185,19 +1296,19 @@ var Lagebild = {
try {
var d = new Date(this.toUTC(iso));
if (isNaN(d.getTime())) return iso;
return d.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', timeZone: TIMEZONE });
return d.toLocaleTimeString(Lagebild.getLocale(), { hour: '2-digit', minute: '2-digit', timeZone: TIMEZONE });
} catch(e) { return iso; }
},
fmtShort: function(iso) {
if (!iso) return '';
try { return new Date(this.toUTC(iso)).toLocaleDateString('de-DE', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit', timeZone: TIMEZONE }); }
try { return new Date(this.toUTC(iso)).toLocaleDateString(Lagebild.getLocale(), { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit', timeZone: TIMEZONE }); }
catch(e) { return iso; }
},
showError: function() {
document.getElementById('summary-content').innerHTML =
'<div class="lagebild-error"><p>Das Lagebild konnte nicht geladen werden. Bitte versuchen Sie es sp\u00e4ter erneut.</p></div>';
'<div class="lagebild-error"><p>' + this.t('errorLoad') + '</p></div>';
}
};