console-error-scanner 1.16.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. console_error_scanner/__init__.py +5 -0
  2. console_error_scanner/__main__.py +370 -0
  3. console_error_scanner/app.py +1870 -0
  4. console_error_scanner/app.tcss +91 -0
  5. console_error_scanner/i18n.py +74 -0
  6. console_error_scanner/locale/de.json +417 -0
  7. console_error_scanner/locale/en.json +417 -0
  8. console_error_scanner/models/__init__.py +1 -0
  9. console_error_scanner/models/history.py +220 -0
  10. console_error_scanner/models/robots.py +154 -0
  11. console_error_scanner/models/scan_result.py +265 -0
  12. console_error_scanner/models/settings.py +242 -0
  13. console_error_scanner/models/sitemap.py +347 -0
  14. console_error_scanner/models/whitelist.py +226 -0
  15. console_error_scanner/screens/__init__.py +1 -0
  16. console_error_scanner/screens/diet_advisor.py +128 -0
  17. console_error_scanner/screens/error_detail.py +164 -0
  18. console_error_scanner/screens/history.py +187 -0
  19. console_error_scanner/screens/scan_summary.py +234 -0
  20. console_error_scanner/screens/settings.py +292 -0
  21. console_error_scanner/screens/top_errors.py +304 -0
  22. console_error_scanner/screens/whitelist.py +154 -0
  23. console_error_scanner/services/__init__.py +1 -0
  24. console_error_scanner/services/image_clipboard.py +104 -0
  25. console_error_scanner/services/preview_service.py +291 -0
  26. console_error_scanner/services/rate_limit.py +56 -0
  27. console_error_scanner/services/reporter.py +561 -0
  28. console_error_scanner/services/scanner.py +965 -0
  29. console_error_scanner/services/site_score.py +151 -0
  30. console_error_scanner/widgets/__init__.py +1 -0
  31. console_error_scanner/widgets/bar_chart.py +60 -0
  32. console_error_scanner/widgets/preview_panel.py +356 -0
  33. console_error_scanner/widgets/results_table.py +594 -0
  34. console_error_scanner/widgets/stats_panel.py +387 -0
  35. console_error_scanner/widgets/summary_panel.py +176 -0
  36. console_error_scanner-1.16.3.dist-info/METADATA +509 -0
  37. console_error_scanner-1.16.3.dist-info/RECORD +41 -0
  38. console_error_scanner-1.16.3.dist-info/WHEEL +5 -0
  39. console_error_scanner-1.16.3.dist-info/entry_points.txt +2 -0
  40. console_error_scanner-1.16.3.dist-info/licenses/LICENSE +202 -0
  41. console_error_scanner-1.16.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,91 @@
1
+ /* Console Error Scanner - Textual CSS */
2
+
3
+ Screen {
4
+ layout: vertical;
5
+ }
6
+
7
+ #summary {
8
+ height: auto;
9
+ }
10
+
11
+ #main-container {
12
+ height: 1fr;
13
+ layout: horizontal;
14
+ }
15
+
16
+ #left-panel {
17
+ width: 60%;
18
+ min-width: 40;
19
+ height: 1fr;
20
+ layout: vertical;
21
+ }
22
+
23
+ #main-splitter {
24
+ width: 1;
25
+ height: 1fr;
26
+ }
27
+
28
+ #results-table {
29
+ height: 4fr;
30
+ min-height: 10;
31
+ }
32
+
33
+ #log-splitter {
34
+ height: 1;
35
+ }
36
+
37
+ #log-splitter.hidden {
38
+ display: none;
39
+ }
40
+
41
+ #scan-log {
42
+ height: 1fr;
43
+ min-height: 5;
44
+ max-height: 40;
45
+ }
46
+
47
+ #right-panel {
48
+ width: 1fr;
49
+ height: 1fr;
50
+ layout: vertical;
51
+ border-left: solid $accent;
52
+ }
53
+
54
+ /* Preview oben, Splitter (ohne Border), darunter StatsPanel. */
55
+ #preview-panel {
56
+ width: 1fr;
57
+ height: 1fr;
58
+ min-height: 10;
59
+ }
60
+
61
+ #preview-splitter {
62
+ width: 1fr;
63
+ height: 1;
64
+ }
65
+
66
+ #preview-splitter.hidden {
67
+ display: none;
68
+ }
69
+
70
+ #stats-panel {
71
+ width: 1fr;
72
+ height: 1fr;
73
+ min-height: 8;
74
+ }
75
+
76
+ /* Tasten, die gerade nicht gehen, ganz ausblenden statt nur auszugrauen.
77
+ Textual vergibt .-disabled, sobald check_action None liefert - so steht
78
+ 'Scan abbrechen' nur waehrend eines Laufs im Fuss und 'Crawl' nur ausserhalb. */
79
+ Footer FooterKey.-disabled {
80
+ display: none;
81
+ }
82
+
83
+ /* Aufmerksamkeits-Blink fuer die Scan-Taste, wenn nach Sitemap-Laden oder
84
+ History-Auswahl startklar. Die Klasse wird per Timer an/aus geschaltet
85
+ (_tick_attention) - terminal-robust statt unzuverlaessigem ANSI-blink. */
86
+ Footer FooterKey.-attention .footer-key--key,
87
+ Footer FooterKey.-attention .footer-key--description {
88
+ background: $accent;
89
+ color: auto;
90
+ text-style: bold;
91
+ }
@@ -0,0 +1,74 @@
1
+ """i18n — Einfache Internationalisierung ueber JSON-Sprachdateien."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import contextlib
6
+ import json
7
+ import locale
8
+ import logging
9
+ import os
10
+ from importlib import resources
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ _strings: dict[str, str] = {}
15
+ _current_lang: str = "de"
16
+
17
+ SUPPORTED_LANGUAGES = ("de", "en")
18
+ DEFAULT_LANGUAGE = "de"
19
+
20
+
21
+ def detect_language() -> str:
22
+ """Leitet die Startsprache aus der Systemumgebung ab.
23
+
24
+ Nur beim allerersten Start relevant - danach steht die Sprache in den
25
+ Einstellungen. Deutsch wird nur bei einer nachweislich deutschsprachigen
26
+ Umgebung gewaehlt. Jeder andere Fall - unbekannte Sprache, leere Umgebung
27
+ oder ein Fehler beim Auslesen (locale.getlocale() wirft auf manchen
28
+ Systemen) - fuehrt zu Englisch, der Sprache der Projektdokumentation.
29
+
30
+ Returns:
31
+ "de" fuer eine deutschsprachige Umgebung, sonst immer "en".
32
+ """
33
+ code = ""
34
+ with contextlib.suppress(Exception):
35
+ code = locale.getlocale()[0] or ""
36
+ if not code:
37
+ with contextlib.suppress(Exception):
38
+ code = os.environ.get("LC_ALL") or os.environ.get("LANG") or ""
39
+ return "de" if code.lower().startswith("de") else "en"
40
+
41
+
42
+ def load_locale(lang: str) -> None:
43
+ """Laedt eine Sprachdatei (z.B. 'de', 'en')."""
44
+ global _strings, _current_lang
45
+
46
+ if lang not in SUPPORTED_LANGUAGES:
47
+ logger.warning("Sprache '%s' nicht unterstuetzt, verwende '%s'", lang, DEFAULT_LANGUAGE)
48
+ lang = DEFAULT_LANGUAGE
49
+
50
+ try:
51
+ locale_files = resources.files("console_error_scanner") / "locale" / f"{lang}.json"
52
+ raw = locale_files.read_text(encoding="utf-8")
53
+ _strings = json.loads(raw)
54
+ _current_lang = lang
55
+ except Exception:
56
+ logger.exception("Fehler beim Laden der Sprachdatei '%s'", lang)
57
+ _strings = {}
58
+ _current_lang = lang
59
+
60
+
61
+ def current_language() -> str:
62
+ """Gibt die aktuell geladene Sprache zurueck."""
63
+ return _current_lang
64
+
65
+
66
+ def t(key: str, **kwargs: object) -> str:
67
+ """Uebersetzt einen Schluessel. Platzhalter via {name} und kwargs."""
68
+ template = _strings.get(key, key)
69
+ if kwargs:
70
+ try:
71
+ return template.format(**kwargs)
72
+ except (KeyError, IndexError):
73
+ return template
74
+ return template
@@ -0,0 +1,417 @@
1
+ {
2
+ "binding.quit": "Beenden",
3
+ "binding.crawl": "Crawl",
4
+ "binding.load_sitemap": "Sitemap laden",
5
+ "binding.history": "History",
6
+ "binding.report": "Report",
7
+ "binding.jira": "JIRA-Tabelle",
8
+ "binding.top_errors": "Top 10 Fehler",
9
+ "binding.summary": "Zusammenfassung",
10
+ "binding.whitelist": "Whitelist",
11
+ "binding.log": "Log",
12
+ "binding.errors_only": "Nur Fehler anzeigen",
13
+ "binding.errors_show_all": "Alle anzeigen",
14
+ "binding.filter": "Filter",
15
+ "binding.clear_filter": "Filter leeren",
16
+ "binding.copy_details": "Details kopieren",
17
+ "binding.http_codes": "HTTP-Codes",
18
+ "binding.info": "Info",
19
+ "binding.settings": "Einstellungen",
20
+ "binding.theme": "Theme",
21
+ "binding.close": "Schließen",
22
+
23
+ "tooltip.quit": "Beendet die Anwendung.",
24
+ "tooltip.crawl": "Startet einen neuen Scan-Lauf. Wenn keine Sitemap geladen ist, wird die URL abgefragt.",
25
+ "tooltip.load_sitemap": "Öffnet einen Datei-Dialog zum Laden einer lokalen sitemap.xml.",
26
+ "tooltip.history": "Öffnet die Liste vergangener Scans (URL übernehmen).",
27
+ "tooltip.report": "Speichert HTML- und JSON-Reports der aktuellen Scan-Ergebnisse.",
28
+ "tooltip.jira": "Erzeugt eine JIRA-Tabelle der Fehler-Seiten - landet in der Zwischenablage und kann direkt in ein Ticket eingefügt werden. Format (Markdown für Jira Cloud oder Wiki Markup) in den Einstellungen unter Export.",
29
+ "tooltip.top_errors": "Zeigt die zehn häufigsten Fehler als Balkendiagramm.",
30
+ "tooltip.summary": "Öffnet die Scan-Zusammenfassung erneut: Site-Score, Findings, größte Seiten und Speicherfresser. Nur nach abgeschlossenem Scan verfügbar.",
31
+ "tooltip.whitelist": "Zeigt die geladenen Whitelist-Patterns.",
32
+ "tooltip.log": "Blendet das Log-Panel ein oder aus.",
33
+ "tooltip.errors_only": "Filtert die Tabelle auf Seiten mit Fehlern.",
34
+ "tooltip.copy_details": "Kopiert die rechte Detail-Ansicht in die Zwischenablage.",
35
+ "tooltip.http_codes": "Öffnet eine Nachschlage-Tabelle aller gängigen HTTP-Statuscodes (2xx/3xx/4xx/5xx) mit Bedeutung und Erklärung.",
36
+ "tooltip.info": "Zeigt den Info-Dialog mit Version und Lizenz.",
37
+ "tooltip.settings": "Öffnet die Einstellungen (Sprache, Consent, Scroll, Concurrency, Whitelist, …).",
38
+ "tooltip.theme": "Wechselt zum nächsten Retro-Theme. Volle Auswahl unter Strg+P → \"theme\".",
39
+
40
+ "notify.no_urls": "Keine URLs gefunden!",
41
+ "notify.scan_running": "Scan läuft bereits!",
42
+ "notify.no_urls_loaded": "Keine URLs geladen! Bitte zuerst eine Sitemap laden.",
43
+ "notify.scan_error": "Scan-Fehler: {error}",
44
+ "notify.no_results": "Keine Ergebnisse vorhanden!",
45
+ "notify.not_scanned": "Noch keine Seiten gescannt!",
46
+ "notify.reports_saved": "Reports gespeichert: {json_path}, {html_path}",
47
+ "notify.no_url_selected": "Keine URL ausgewählt.",
48
+ "notify.details_copied": "Details kopiert",
49
+ "notify.jira_copied": "JIRA-Tabelle mit {count} Fehler-Seiten kopiert",
50
+ "notify.json_copied": "JSON von {count} Seiten in die Zwischenablage kopiert",
51
+ "notify.text_copied": "Text von {count} Seiten in die Zwischenablage kopiert",
52
+ "notify.no_errors_jira": "Keine Fehler - nichts zu exportieren.",
53
+ "notify.theme": "Theme: {name}",
54
+ "notify.no_whitelist": "Keine Whitelist geladen. Pfad in den Einstellungen (s) setzen.",
55
+ "notify.no_results_for_top": "Noch keine Ergebnisse für die Top-10-Auswertung.",
56
+
57
+ "log.version": "Console Error Scanner v{version}",
58
+ "log.theme_active": "Theme: {name}",
59
+ "log.theme_unknown": "Theme \"{name}\" ist nicht bekannt - Standard verwendet",
60
+ "log.config": "Concurrency: {concurrency} | Timeout: {timeout}s | Console-Level: {level} | {consent} | {scroll}",
61
+ "log.consent_on": "Consent: AN",
62
+ "log.consent_off": "Consent: AUS",
63
+ "log.scroll_on": "Scroll: AN",
64
+ "log.scroll_off": "Scroll: AUS",
65
+ "log.robots_blocked": "robots.txt: {blocked} von {total} Seiten gesperrt - werden übersprungen",
66
+ "log.robots_clear": "robots.txt beachtet - keine Seite gesperrt",
67
+ "log.robots_ignored": "robots.txt: AUS (wird ignoriert)",
68
+ "log.whitelist_loaded": "Whitelist geladen: {count} Patterns aus {path}",
69
+ "log.whitelist_error": "Whitelist-Fehler: {error}",
70
+ "log.loading_sitemap": "Lade Sitemap…",
71
+ "log.loading_local_sitemap": "Lade lokale Sitemap: {url}",
72
+ "log.searching_sitemap": "Suche Sitemap für: {url}",
73
+ "log.sitemap_error": "Sitemap-Fehler: {error}",
74
+ "log.loading_sitemap_url": "Lade Sitemap: {url}",
75
+ "log.unexpected_error": "Unerwarteter Fehler: {error}",
76
+ "log.no_urls_in_sitemap": "Keine URLs in der Sitemap gefunden.",
77
+ "log.urls_loaded": "{count} URLs geladen",
78
+ "log.history_updated": "History aktualisiert",
79
+ "log.scan_complete": "Scan abgeschlossen in {duration}",
80
+ "log.site_score": "Site-Score: {score}% ({grade})",
81
+ "log.scan_result": "Ergebnis: {errors_pages} Seiten mit Fehlern | Console: {console} | 404: {http_404} | 4xx: {http_4xx} | 5xx: {http_5xx}{ignored}",
82
+ "log.whitelist_suppressed": "{count} Fehler per Whitelist unterdrückt",
83
+ "log.json_report": "JSON-Report: {path}",
84
+ "log.html_report": "HTML-Report: {path}",
85
+ "log.jira_copied": "JIRA-Tabelle mit {count} Fehler-Seiten in die Zwischenablage kopiert.",
86
+ "log.no_errors_jira": "Keine Fehler gefunden - keine JIRA-Tabelle erzeugt.",
87
+ "log.history_params": "History: Parameter übernommen",
88
+ "log.sitemap_label": "Sitemap: {url}",
89
+ "log.cookies_label": "Cookies: {cookies}",
90
+ "log.filter_label": "Filter: {filter}",
91
+ "log.settings_saved": "Einstellungen gespeichert",
92
+ "log.whitelist_reloaded": "Whitelist neu geladen: {count} Patterns",
93
+ "log.whitelist_cleared": "Whitelist entfernt",
94
+ "log.sitemap_still_loading": "… Lade Sitemap ({seconds}s) …",
95
+ "log.setting_changed": "{label}: {old} → {new}",
96
+ "log.no_settings_changed": "Einstellungen unverändert",
97
+
98
+ "subtitle.loading_sitemap": "Lade Sitemap…",
99
+ "subtitle.loading_sitemap_dots": "Lade Sitemap{dots}",
100
+ "subtitle.urls_count": "{count} URLs",
101
+ "subtitle.scan_complete": "{count} URLs · Scan abgeschlossen",
102
+ "subtitle.scanning": "Scanning {bar} {pct}% ({current}/{total}) · ~{remaining} · ⌀ {avg}s/Seite",
103
+ "subtitle.scanning_start": "Scanning {bar} 0% (0/{total})",
104
+
105
+ "sitemap_error.title": "Fehler",
106
+ "sitemap_error.footer": "ESC = Schließen",
107
+ "sitemap_error.sitemap_error": "Sitemap-Fehler:\n\n{error}",
108
+ "sitemap_error.unexpected_error": "Unerwarteter Fehler:\n\n{error}",
109
+
110
+ "about.description": "Scannt Websites auf JavaScript-\nConsole-Errors und HTTP-Fehler (404, 5xx).",
111
+
112
+ "error_detail_screen.title": "Fehlerdetails: {url}",
113
+ "error_detail_screen.footer": "ESC / q = Schließen",
114
+ "error_detail_screen.http_status": "HTTP Status: {code}",
115
+ "error_detail_screen.load_time": "Ladezeit: {time}ms",
116
+ "error_detail_screen.retries": "Retries: {count}",
117
+ "error_detail_screen.total_errors": "Fehler gesamt: {total}{ignored}",
118
+ "error_detail_screen.no_errors": "Keine Fehler.",
119
+ "error_detail_screen.source": " Quelle: {source}",
120
+ "error_detail_screen.whitelist_hits": "Whitelist-Treffer ({count})",
121
+
122
+ "history.title": "Scan-History",
123
+ "history.empty": "Noch keine Scans in der History.\n\nStarte einen Scan mit einer Sitemap-URL,\ndann erscheint er hier.",
124
+ "history.col_number": "#",
125
+ "history.col_date": "Datum",
126
+ "history.col_url": "URL",
127
+ "history.col_params": "Parameter",
128
+ "history.btn_select": "Auswählen",
129
+ "history.btn_close": "Schließen",
130
+
131
+ "top_errors.title": "Top 10 Fehler",
132
+ "top_errors.footer": "ESC / q = Schließen",
133
+ "top_errors.no_errors": "Keine Fehler gefunden.",
134
+ "top_errors.total": "Gesamt: {count} Fehler auf ",
135
+ "top_errors.pages": "{count} Seiten",
136
+ "top_errors.most_errors": "Seiten mit den meisten Fehlern",
137
+ "top_errors.empty": "(leer)",
138
+
139
+ "whitelist.title": "Whitelist",
140
+ "whitelist.empty": "Keine Whitelist geladen.\n\nIn den Einstellungen (Taste s) den Pfad zu einer\nwhitelist.json eintragen, dann erscheinen die Patterns hier.",
141
+ "whitelist.path": "Pfad: {path}",
142
+ "whitelist.active": "Aktiv: {count} Pattern(s)",
143
+ "whitelist.col_number": "#",
144
+ "whitelist.col_pattern": "Pattern",
145
+ "whitelist.col_hits": "Treffer",
146
+ "whitelist.footer": "ESC / q = Schließen",
147
+
148
+ "header.title": "Console Error Scanner",
149
+ "header.sitemap": "Sitemap",
150
+ "header.urls": "URLs",
151
+ "header.scanned": "Gescannt",
152
+ "header.duration": "Dauer",
153
+ "header.score": "Score",
154
+ "header.concurrency": "Threads",
155
+ "header.timeout": "Timeout",
156
+ "header.level": "Console-Level",
157
+ "header.consent": "Cookie-Consent",
158
+ "header.scroll": "Scroll",
159
+ "header.whitelist": "Whitelist",
160
+ "header.with_errors": "Mit Fehlern",
161
+ "header.console_err": "Console-Errors",
162
+ "header.console_warn": "Console-Warnings",
163
+ "header.http_404": "404",
164
+ "header.http_4xx": "4xx",
165
+ "header.http_5xx": "5xx",
166
+ "header.timeouts": "Timeouts",
167
+ "header.ignored": "Ignoriert",
168
+ "header.value_on": "AN",
169
+ "header.value_off": "AUS",
170
+ "header.value_none": "—",
171
+
172
+ "summary.no_sitemap": "Keine Sitemap geladen.",
173
+
174
+ "detail.no_url": "Keine URL ausgewählt.\n\nWähle links eine URL aus der Liste, um die Details zu sehen.",
175
+ "detail.url_header": "URL",
176
+ "detail.url": "URL",
177
+ "detail.http": "HTTP",
178
+ "detail.load_time": "Ladezeit (Load)",
179
+ "detail.dom_content_loaded": "DOMContentLoaded",
180
+ "detail.requests": "Requests",
181
+ "detail.size": "Größe",
182
+ "detail.retries_label": "Retries",
183
+ "detail.content_type": "Content-Type",
184
+ "detail.last_modified": "Last-Modified",
185
+ "detail.timeout": "Timeout beim Laden der Seite.",
186
+ "detail.page_heading": "Seite",
187
+ "detail.http_heading": "HTTP-Header",
188
+ "detail.http_collapsed_hint": "{count} Header eingeklappt — Klick auf den Titel zum Aufklappen.",
189
+ "detail.errors_heading": "Fehler ({count})",
190
+ "detail.warnings_heading": "Warnungen ({count})",
191
+ "detail.whitelist_heading": "Whitelist ({count})",
192
+ "detail.info_heading": "Info",
193
+ "detail.status": "Status: ",
194
+ "detail.retries": "{count} Retries",
195
+ "detail.error_summary": "Fehler: {errors} Errors, {warns} Warns, {http_404} 404, {http_4xx} 4xx, {http_5xx} 5xx",
196
+ "detail.ignored_suffix": ", {count} ignored",
197
+ "detail.no_errors": "Keine Fehler gefunden.",
198
+ "detail.scanning": "Scan läuft…",
199
+ "detail.not_scanned": "Noch nicht gescannt.",
200
+ "detail.console_errors": "Console Errors ({count})",
201
+ "detail.console_warnings": "Console Warnings ({count})",
202
+ "detail.csp_violations": "CSP Violations ({count})",
203
+ "detail.http_404": "HTTP 404 ({count})",
204
+ "detail.http_4xx": "HTTP 4xx ({count})",
205
+ "detail.http_5xx": "HTTP 5xx ({count})",
206
+ "detail.whitelist_hits": "Whitelist-Treffer ({count})",
207
+ "detail.more_lines": "… ({count} weitere Zeilen)",
208
+ "detail.source": " Quelle: ",
209
+ "detail.no_text": "(kein Text)",
210
+
211
+ "table.filter_placeholder": "Filter (URL, Status …)",
212
+ "table.count": " {count} URLs",
213
+ "table.count_filtered": " {shown} von {total} URLs (gefiltert)",
214
+ "table.col_number": "#",
215
+ "table.col_status": "Status",
216
+ "table.col_url": "URL",
217
+ "table.col_http": "HTTP",
218
+ "table.col_time": "Zeit",
219
+ "table.col_size": "Größe",
220
+ "table.col_requests": "Req",
221
+ "table.tooltip_size": "Tatsächliche Transfergröße aller Ressourcen vom selben Host, die beim Scan geladen wurden (ungecacht). Pro Ressource zählt die größte Antwort (kein Mehrfachzählen); gestreamte Videos/Audios werden nicht mitgezählt. Das ist nicht die HTML-Dokumentgröße, sondern das Gesamtgewicht des Hosts.",
222
+ "table.tooltip_time": "Browser-Ladezeit bis zum Load-Event (Navigation Timing API, gleiche Semantik wie DevTools 'Load'). Hinweis: beim parallelen Scan teilen sich mehrere Tabs CPU und Bandbreite - die absoluten Werte sind dadurch höher als eine DevTools-Einzelmessung und nur für den relativen Vergleich innerhalb desselben Scans gedacht.",
223
+ "table.tooltip_requests": "Anzahl ALLER Requests, die die Seite beim Scan ausgelöst hat (Dokument, Skripte, Bilder, Fonts, XHR, ...) - entspricht der Request-Zahl im Edge-Netzwerkmonitor.",
224
+ "table.col_errors": "Errors",
225
+ "table.col_warns": "Warns",
226
+ "table.col_404": "404",
227
+ "table.col_4xx": "4xx",
228
+ "table.col_5xx": "5xx",
229
+ "table.col_ignored": "Ignoriert",
230
+
231
+ "scanner.start": "Starte Scan von {total} URLs (Concurrency: {concurrency}, Timeout: {timeout}s)",
232
+ "scanner.browser_started": "Browser gestartet",
233
+ "scanner.scanning_url": "Scanne ({current}/{total}): {url}",
234
+ "scanner.result_errors": " | {count} Fehler",
235
+ "scanner.critical_error": "Kritischer Fehler: {error}",
236
+ "scanner.browser_closed": "Browser geschlossen",
237
+ "scanner.retry": "Retry {attempt}/{max} für {url} in {wait}s ({error})",
238
+ "scanner.waiting_network": "Warte auf Netzwerk…",
239
+ "scanner.browser_recovery": "Browser-Recovery…",
240
+ "scanner.browser_recovery_failed": "Browser-Recovery fehlgeschlagen: {error}",
241
+ "scanner.failed_after_retries": "Fehlgeschlagen nach {max} Versuchen: {error}",
242
+ "scanner.hard_timeout": "Harter Timeout - Seite hat nicht reagiert, übersprungen: {url}",
243
+ "scanner.consent_hidden": "Consent-Banner versteckt (kein Consent akzeptiert)",
244
+ "scanner.consent_accepted": "Consent akzeptiert ({provider})",
245
+ "scanner.consent_button_clicked": "Consent-Button geklickt: {selector}",
246
+ "scanner.no_scroll_needed": "Kein Scroll nötig (Seite passt in Viewport)",
247
+ "scanner.lazy_loading_done": "Lazy-Loading: {steps} Scroll-Schritte ausgeführt",
248
+ "scanner.lazy_loading_failed": "Lazy-Loading-Scroll fehlgeschlagen: {error}",
249
+
250
+ "sitemap.fetch_failed": "Sitemap konnte nach {retries} Versuchen nicht geladen werden: {error}",
251
+ "sitemap.file_read_error": "Datei konnte nicht gelesen werden: {path} ({error})",
252
+ "sitemap.xml_parse_error": "Sitemap-XML konnte nicht geparst werden: {error}",
253
+ "sitemap.discovery_robots_search": "Suche Sitemap in robots.txt: {url}",
254
+ "sitemap.discovery_robots_entry": "robots.txt-Eintrag gefunden: {url}",
255
+ "sitemap.discovery_found": "Sitemap gefunden: {url}",
256
+ "sitemap.discovery_unreachable": "{url} nicht erreichbar, weiter …",
257
+ "sitemap.discovery_robots_unreachable": "robots.txt nicht erreichbar",
258
+ "sitemap.discovery_trying_paths": "Probiere typische Sitemap-Pfade …",
259
+ "sitemap.discovery_testing": "Teste: {url}",
260
+ "sitemap.discovery_not_found": "Keine Sitemap gefunden für {url}\n\nGetestet: robots.txt + {count} typische Pfade.\nBitte gib die Sitemap-URL direkt an, z. B.:\n {example}\n\nTipp: Mit dem Sitemap Generator kannst du eine Sitemap erstellen:\n https://michaelblaess.github.io/sitemap-generator",
261
+
262
+ "report.title": "Console Error Scanner Report",
263
+ "report.created": "Erstellt: {timestamp} | Sitemap: {url}",
264
+ "report.urls_total": "URLs gesamt",
265
+ "report.scanned": "Gescannt",
266
+ "report.with_errors": "Mit Fehlern",
267
+ "report.site_score": "Site-Score",
268
+ "report.avg_size": "Ø Seitengröße",
269
+ "report.load_time": "Ladezeit",
270
+ "report.dom_content_loaded": "DOMContentLoaded",
271
+ "report.requests": "Requests",
272
+ "report.duration": "Dauer",
273
+ "report.whitelist_hits": "Whitelist-Treffer ({count})",
274
+
275
+ "settings.tab_scanner": "Scanner",
276
+ "settings.tab_export": "Export",
277
+ "settings.jira_format_label": "JIRA-Tabellenformat:",
278
+ "settings.jira_format_tip": "Format der JIRA-Tabelle beim Export (Taste j). Markdown für Jira Cloud, Wiki Markup für ältere Server/Data-Center-Instanzen.",
279
+ "settings.jira_format_markdown": "Markdown (Jira Cloud)",
280
+ "settings.jira_format_wiki": "Wiki Markup (Server/DC)",
281
+ "settings.jira_format_hint": "Format für den JIRA-Export (Taste j). Markdown = Jira Cloud (z.B. example.atlassian.net): eine Markdown-Tabelle wird beim Einfügen ins Kommentarfeld automatisch in eine echte Tabelle umgewandelt. Das alte Wiki Markup versteht der Cloud-Editor nicht mehr. Wiki Markup = ältere Jira-Server/Data-Center-Instanzen.",
282
+ "jira.header": "||URL||HTTP||Status||Console||404||4xx||5xx||Details||",
283
+ "settings.tab_network": "Netzwerk",
284
+ "settings.proxy_url_label": "Proxy-URL",
285
+ "settings.proxy_url_tip": "Optionaler HTTP-Proxy für Crawl, Sitemap und Vorschau-Browser, z.B. http://proxy.example.com:8080 (Corporate-Proxy/Zscaler). Leer lassen für Direktverbindung.",
286
+ "settings.proxy_hint": "Hinter einem Firmen-Proxy (z.B. Zscaler) hier den Proxy eintragen, sonst schlagen Verbindungen mit \"All connection attempts failed\" fehl. Format: http://HOST:PORT. Gilt für httpx UND den Playwright-Browser.",
287
+ "settings.consent_label": "Cookie-Consent",
288
+ "settings.consent_checkbox": "Consent automatisch akzeptieren",
289
+ "settings.consent_tip": "Klickt Cookie-Banner (Usercentrics, OneTrust, Cookiebot, …) automatisch weg, sodass Tracking-Scripts geladen werden und ihre Fehler sichtbar sind. Aus = Banner werden nur visuell versteckt.",
290
+ "settings.scroll_label": "Lazy-Loading",
291
+ "settings.scroll_checkbox": "Lazy-Loading aktivieren",
292
+ "settings.scroll_tip": "Scrollt jede Seite einmal komplett bis zum Ende durch und wartet, bis lazy-geladene Bilder und Inhalte sichtbar werden. Ohne diesen Schritt bleiben 404-Bilder unterhalb des ersten Viewports unerkannt.",
293
+ "settings.robots_label": "robots.txt",
294
+ "settings.robots_checkbox": "robots.txt beachten",
295
+ "settings.robots_tip": "Gesperrte Sitemap-Seiten (Disallow) werden übersprungen; die Anzahl steht im Log. Geprüft werden nur Seiten, nicht die von ihnen geladenen Ressourcen. Aus nur für Deine eigenen Seiten sinnvoll, etwa wenn ein Testsystem pauschal alles sperrt.",
296
+ "settings.concurrency_label": "Threads",
297
+ "settings.rate_label": "Rate-Limit",
298
+ "settings.rate_tip": "Begrenzt, wie viele Seiten pro Minute geprüft werden. Ohne Limit arbeitet der Scanner so schnell, wie das Ziel antwortet - bei einer großen Sitemap sind das schnell mehrere hundert Aufrufe pro Minute. Da jede Seite durch einen echten Browser läuft und dabei auch Skripte, Schriften und Bilder lädt, wiegt ein Aufruf ein Vielfaches eines einfachen Abrufs. Auf einem Produktivsystem kann das die Antwortzeiten spürbar verschlechtern. Standardmäßig aktiv.",
299
+ "settings.rate_checkbox": "Aufrufe drosseln",
300
+ "settings.rate_value": "{count} Seiten/Minute - {step}",
301
+ "settings.rate_step_gentle": "sehr schonend",
302
+ "settings.rate_step_careful": "schonend, für Produktivsysteme empfohlen",
303
+ "settings.rate_step_brisk": "zügig",
304
+ "settings.rate_step_reckless": "ohne Rücksicht, nur für Test-/Entwicklungssysteme",
305
+ "log.rate_on": "Rate-Limit aktiv: max. {count} Seiten/Minute",
306
+ "log.rate_off": "Kein Rate-Limit - bis zu {count} Seiten gleichzeitig, so schnell wie das Ziel antwortet. Für Produktivsysteme in den Einstellungen ein Rate-Limit aktivieren.",
307
+ "settings.concurrency_tip": "Anzahl paralleler Browser-Tabs. Mehr = schneller, aber höhere CPU-/RAM-Last und größere Gefahr von Rate-Limits.",
308
+ "settings.timeout_label": "Timeout (s)",
309
+ "settings.timeout_tip": "Maximale Wartezeit pro Seite (in Sekunden), bevor der Scan dieser URL als Timeout abgebrochen wird.",
310
+ "settings.size_warn_label": "Größen-Warnung (MB)",
311
+ "settings.size_warn_tip": "Ab dieser Seitengröße (in MB) wird die URL in der Liste rot hervorgehoben und mit einem Warn-Symbol markiert. 0 = aus.",
312
+ "settings.score_weight_label": "Score-Gewicht Fehler (%)",
313
+ "settings.score_weight_tip": "Gewicht der Fehlerquote im Site-Score (0-100 %). Der Rest entfällt auf die Seitengröße. Z.B. 60 = 60 % Fehler, 40 % Größe.",
314
+ "diet.title": "Diät-Ratgeber: {url}",
315
+ "diet.subtitle": "Größte Ressourcen ({size} gesamt)",
316
+ "diet.none": "Keine Ressourcendaten vorhanden - bitte die Seite neu scannen.",
317
+ "diet.tip": "Tipp: Bilder als WebP/AVIF und passend skaliert ausliefern bringt meist am meisten.",
318
+ "summary.title": "Scan abgeschlossen",
319
+ "summary.score_label": "Site-Score:",
320
+ "summary.score_breakdown": "Fehler {err}% (Gewicht {err_w}%) · Größe {size}% (Gewicht {size_w}%)",
321
+ "summary.findings": "Findings",
322
+ "summary.pages": "Seiten: {total} gesamt, {clean} fehlerfrei, {err} mit Fehlern",
323
+ "summary.errors": "Fehler: {errors} · Warnungen: {warnings}",
324
+ "summary.avg_size": "Ø Seitengröße: {size}",
325
+ "summary.biggest_pages": "Größte Seiten",
326
+ "summary.big_fish": "Speicherfresser (größte Ressourcen)",
327
+ "settings.console_level_label": "Console-Level",
328
+ "settings.console_level_tip": "Welche console.*-Meldungen werden erfasst: error = nur Errors; warn = Errors + Warnings (Default); all = zusätzlich info/log/debug. Info/Log/Debug werden NICHT erfasst, solange Level „warn“ ist.",
329
+ "settings.preview_label": "Seiten-Vorschau",
330
+ "settings.preview_checkbox": "Screenshot der gewählten Seite anzeigen",
331
+ "settings.preview_tip": "Rendert in der Detail-Ansicht einen Screenshot der markierten URL. Screenshots werden im Hintergrund per Playwright-Sidecar erstellt und auf Disk gecacht (HTTP-Validator + TTL). Rechtsklick auf das Bild kopiert es in die Zwischenablage.",
332
+ "settings.headless_label": "Browser",
333
+ "settings.headless_checkbox": "Browser sichtbar starten (für Debugging)",
334
+ "settings.headless_tip": "Standardmäßig läuft Chromium unsichtbar im Hintergrund. Aktivieren, um den Browser beim Scan zu sehen — nur zum Debuggen sinnvoll.",
335
+ "settings.user_agent_label": "User-Agent",
336
+ "settings.user_agent_placeholder": "Leer = realistischer Chrome-Default",
337
+ "settings.user_agent_tip": "Eigener User-Agent für die Browser-Requests. Leer = realistischer Chrome 131 auf Windows (umgeht viele Bot-Detection-Heuristiken).",
338
+ "settings.whitelist_label": "Whitelist-Pfad",
339
+ "settings.whitelist_placeholder": "Pfad zu whitelist.json (leer = aus)",
340
+ "settings.whitelist_tip": "JSON-Datei mit Wildcard-Patterns (fnmatch-Syntax), die als bekannte Fehler ignoriert werden. Leer = keine Whitelist. Wird sofort übernommen.",
341
+ "settings.cookies_label": "Cookies",
342
+ "settings.cookies_placeholder": "name=value; name2=value2",
343
+ "settings.cookies_tip": "Cookies, die vor jedem Scan im Browser gesetzt werden. Format: name=value; mehrere mit ; oder , trennen.",
344
+ "settings.app_hint": "Die Einstellungen gelten ab dem nächsten Scan; aktuelle Scan-Daten bleiben erhalten.",
345
+ "settings.info_icon": "(?)",
346
+ "settings.storage.config": "Einstellungen (settings.json)",
347
+ "settings.storage.history": "Scan-History",
348
+ "settings.storage.whitelist": "Whitelist (whitelist.json)",
349
+ "settings.storage.fault": "Harte Abstürze (fault.log)",
350
+ "settings.storage.crash": "Absturzberichte",
351
+ "settings.storage.preview_cache": "Vorschau-Cache",
352
+
353
+ "preview.select": "URL aus der Liste wählen, dann erscheint hier eine Vorschau.",
354
+ "preview.loading": "Screenshot wird erstellt",
355
+ "preview.loading_hint": "Kann 2-3 Sekunden dauern - Cookie-Consent wird akzeptiert und Bilder werden nachgeladen (Lazy-Loading).",
356
+ "preview.phase.navigate": "Seite wird geladen",
357
+ "preview.phase.consent": "Cookie-Consent wird akzeptiert",
358
+ "preview.phase.render": "Bilder werden nachgeladen",
359
+ "preview.phase.capture": "Screenshot wird erstellt",
360
+ "preview.none": "Keine Vorschau verfügbar.",
361
+ "preview.error": "Vorschau fehlgeschlagen.",
362
+ "preview.menu_copy": "In Zwischenablage kopieren",
363
+ "preview.menu_save": "Als PNG speichern…",
364
+ "preview.tooltip": "Rechtsklick: in Zwischenablage kopieren · Umschalt + Rechtsklick: als PNG speichern",
365
+
366
+ "ctx.open_url": "URL im Browser öffnen",
367
+ "ctx.copy_url": "URL kopieren",
368
+ "ctx.show_details": "Details anzeigen",
369
+ "ctx.diet": "Diät-Ratgeber",
370
+ "ctx.copy_details": "Details kopieren",
371
+ "ctx.export_jira": "Export JIRA",
372
+ "ctx.export_json": "Export JSON",
373
+ "ctx.export_text": "Export Text (Zwischenablage)",
374
+ "ctx.rescan": "URL erneut scannen",
375
+ "ctx.show_errors_only": "Nur Fehler anzeigen",
376
+ "ctx.show_all": "Alle anzeigen",
377
+ "ctx.url_copied": "URL kopiert",
378
+ "ctx.rescanning": "Scanne erneut: {url}",
379
+ "ctx.rescan_busy": "Bitte warten — laufender Scan blockiert Einzel-Rescan.",
380
+ "ctx.wl_add": "Zur Whitelist: {msg}",
381
+ "ctx.wl_remove": "Aus Whitelist entfernen: {msg}",
382
+ "ctx.wl_added": "Zur Whitelist hinzugefügt: {pattern}",
383
+ "ctx.wl_removed": "{count} Pattern aus Whitelist entfernt",
384
+ "ctx.wl_already": "Schon in der Whitelist.",
385
+ "ctx.wl_none_removed": "Kein passendes Whitelist-Pattern gefunden.",
386
+ "ctx.wl_no_file": "Keine Whitelist-Datei verfügbar.",
387
+ "ctx.wl_save_failed": "Whitelist konnte nicht gespeichert werden.",
388
+ "preview.copied": "Screenshot in Zwischenablage kopiert",
389
+ "preview.copy_failed": "Kopieren fehlgeschlagen: {error}",
390
+ "preview.saved": "Screenshot gespeichert: {path}",
391
+ "preview.no_image": "Kein Screenshot vorhanden.",
392
+
393
+ "url_input.title": "URL eingeben",
394
+ "url_input.prompt": "Website-URL, Sitemap-URL oder lokale sitemap.xml:",
395
+ "url_input.placeholder": "https://www.example.com",
396
+
397
+ "file_picker.title": "Sitemap-Datei auswählen",
398
+ "file_picker.open_button": "Öffnen",
399
+ "file_picker.cancel_button": "Abbrechen",
400
+ "file_picker.filter_xml": "Sitemap (*.xml)",
401
+ "file_picker.filter_all": "Alle Dateien",
402
+
403
+ "cli.banner_1": "Console Error Scanner v{version}",
404
+ "cli.banner_2": "Scannt Websites auf Console-Errors und HTTP-Fehler (404, 5xx)",
405
+ "cli.examples": "Beispiele:",
406
+ "cli.keybindings": "Tastenkürzel in der TUI:",
407
+ "cli.invalid_cookie": "Ungültig: --cookie {cookie} (Format: NAME=VALUE)",
408
+ "binding.cancel_scan": "Scan abbrechen",
409
+ "tooltip.cancel_scan": "Beendet den laufenden Scan - die bereits geprüften Seiten bleiben in der Tabelle stehen",
410
+ "notify.scan_cancelling": "Scan wird abgebrochen ...",
411
+ "notify.scan_cancelled": "Abgebrochen - {count} geprüfte Seiten bleiben sichtbar.",
412
+ "notify.no_scan_active": "Es läuft gerade kein Scan.",
413
+ "log.cancel_requested": "Abbruch angefordert - laufende Seiten werden noch beendet ...",
414
+ "log.scan_cancelled": "Scan abgebrochen - {count} Seiten geprüft, Ergebnisse bleiben in der Tabelle.",
415
+ "subtitle.cancelling": "Abbruch läuft ...",
416
+ "subtitle.cancelled": "Scan abgebrochen"
417
+ }