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:
@@ -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">×</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') + '">×</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] + ';">●</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">→</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">×</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>';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren