Add German translation and update language support

Added a new German (de) translation file and updated all language JSON files to include German in the language selection. Updated format quality color mapping in the GUI to recognize German quality terms. Ensured localization manager and UI support the new language.
This commit is contained in:
Your Name
2025-09-30 22:00:03 +03:00
parent 9005bb61c1
commit 47cdd06494
8 changed files with 342 additions and 6 deletions
+330
View File
@@ -0,0 +1,330 @@
{
"language": {
"display_name": "Deutsch (German)",
"select_language": "Sprache auswählen:",
"current_language": "Aktuelle Sprache: {language}",
"restart_required": "Sprachänderungen werden nach dem Neustart der Anwendung wirksam.",
"english": "Englisch",
"spanish": "Spanisch",
"portuguese": "Portugiesisch",
"russian": "Russisch",
"chinese": "Chinesisch",
"german": "Deutsch",
"help_text": "Wählen Sie Ihre bevorzugte Sprache für die Benutzeroberfläche.",
"restart_notice": "Die Sprachänderung wird nach dem Neustart der Anwendung wirksam."
},
"app": {
"title": "YTSage",
"version": "v{version}",
"ready": "Bereit"
},
"formats": {
"show_formats": "Formate anzeigen:",
"video_format": "Videoformat:",
"audio_format": "Audioformat:",
"no_formats": "Keine Formate verfügbar",
"loading": "Lade Formate...",
"select": "Auswählen",
"quality": "Qualität",
"extension": "Erweiterung",
"resolution": "Auflösung",
"file_size": "Dateigröße",
"codec": "Codec",
"audio": "Audio",
"notes": "Notizen",
"will_merge_audio": "Audio wird zusammengeführt",
"has_audio": "✓ Hat Audio",
"audio_only": "Nur Audio",
"large_size": "Große Größe",
"medium_size": "Mittlere Größe",
"standard_size": "Standardgröße",
"compatible": "Kompatibel",
"efficient": "Effizient",
"high_quality": "Hohe Qualität",
"best_4k": "Beste (4K)",
"best_2k": "Beste (2K)",
"high_1080p": "Hoch (1080p)",
"high_720p": "Hoch (720p)",
"medium_480p": "Mittel (480p)",
"low_quality": "Niedrige Qualität",
"best_audio": "Bestes Audio",
"high_audio": "Hohes Audio",
"medium_audio": "Mittleres Audio",
"low_audio": "Niedriges Audio",
"audio_only_resolution": "Nur Audio"
},
"buttons": {
"download": "Herunterladen",
"pause": "Pausieren",
"resume": "Fortsetzen",
"cancel": "Abbrechen",
"browse": "Durchsuchen",
"clear": "Löschen",
"ok": "OK",
"apply": "Anwenden",
"close": "Schließen",
"run_command": "Befehl ausführen",
"custom_command_help": "Hilfe",
"about": "Über",
"analyze": "Analysieren",
"paste_url": "URL einfügen",
"select_videos": "Videos auswählen...",
"video": "Video",
"audio_only": "Nur Audio",
"custom_options": "Benutzerdefinierte Optionen",
"trim_video": "Video schneiden",
"download_settings": "Download-Einstellungen",
"update": "yt-dlp aktualisieren",
"select_defaults": "Standard auswählen",
"select_all": "Alle auswählen",
"deselect_all": "Alle abwählen"
},
"dialogs": {
"custom_options": "Benutzerdefinierte Optionen",
"settings": "Einstellungen",
"select_folder": "Download-Ordner auswählen",
"sponsorblock_categories": "SponsorBlock-Kategorien",
"sponsorblock_description": "Wählen Sie aus, welche Arten von Videosegmenten während des Downloads automatisch entfernt werden sollen.\nSponsorBlock verwendet von der Community übermittelte Daten, um diese Segmente zu identifizieren.",
"select_subtitles": "Untertitel auswählen",
"filter_languages_placeholder": "Sprachen filtern (z.B. en, de)...",
"no_subtitles_available": "Keine Untertitel verfügbar",
"matching": "passend"
},
"tabs": {
"cookies": "Mit Cookies anmelden",
"custom_command": "Benutzerdefinierter Befehl",
"proxy": "Proxy",
"language": "Sprache"
},
"cookies": {
"help_text": "Wählen Sie aus, wie Cookies für die Anmeldung bereitgestellt werden sollen.\nDies ermöglicht das Herunterladen privater Videos und hochwertiger Audio-Dateien.",
"cookie_source": "Cookie-Quelle",
"use_cookie_file": "Cookie-Datei verwenden",
"extract_from_browser": "Aus Browser extrahieren",
"cookie_file": "Cookie-Datei",
"cookie_file_placeholder": "Pfad zur cookies.txt-Datei...",
"browser_selection": "Browser-Auswahl",
"browser_help": "Wählen Sie den Browser aus, aus dem Cookies extrahiert werden sollen:",
"browser_label": "Browser:",
"profile_label": "Profil:",
"profile_placeholder": "Standard",
"browser_extract_message": "Browser-Cookies werden beim Anwenden extrahiert",
"file_selected_message": "Cookie-Datei ausgewählt - Klicken Sie OK zum Anwenden",
"select_file_title": "Cookie-Datei auswählen",
"file_filter": "Cookie-Dateien (*.txt *.lwp)"
},
"custom_command": {
"help_text": "Geben Sie Ihren benutzerdefinierten yt-dlp-Befehl unten ein. Die aktuelle URL wird automatisch angehängt.<br><br>Für die vollständige Liste der Optionen und Verwendungsbeispiele <a href=\"{docs_url}\">klicken Sie hier, um die offizielle yt-dlp-Dokumentation anzuzeigen</a>.<br><br>Hinweis: Download-Pfad und Dateinamen-Vorlage werden automatisch behandelt.",
"input_label": "yt-dlp-Argumente:",
"input_placeholder": "Geben Sie yt-dlp-Argumente hier ein...\n\nz.B.: --extract-audio --audio-format mp3",
"output_label": "Befehlsausgabe:",
"output_placeholder": "Die Befehlsausgabe wird hier erscheinen...",
"command_placeholder": "Benutzerdefinierten yt-dlp-Befehl eingeben...",
"command_help": "Verfügbare Platzhalter:\n{url} - Video-URL\n{output} - Ausgabeordner\n\nBeispiel: --write-info-json --write-thumbnail",
"full_command": "🔧 Vollständiger Befehl: {command}",
"command_success": "✅ Benutzerdefinierter Befehl erfolgreich ausgeführt!",
"command_failed": "❌ Befehl fehlgeschlagen mit Exit-Code {code}",
"command_error": "❌ Fehler beim Ausführen des benutzerdefinierten Befehls: {error}"
},
"proxy": {
"help_text": "Proxy-Einstellungen für Downloads konfigurieren. Leer lassen für direkte Verbindung.",
"main_proxy": "Haupt-Proxy",
"main_proxy_help": "Primärer Proxy-Server für alle Downloads. Unterstützt HTTP/HTTPS- und SOCKS5-Protokolle.",
"proxy_url_label": "Proxy-URL:",
"proxy_url_placeholder": "http://proxy:port oder socks5://proxy:port",
"proxy_examples": "Beispiele:\n• HTTP: http://proxy.example.com:8080\n• SOCKS5: socks5://proxy.example.com:1080",
"geo_proxy": "Geo-Umgehungs-Proxy",
"geo_proxy_help": "Sekundärer Proxy speziell zur Umgehung geografischer Beschränkungen.",
"geo_proxy_url_label": "Geo-Umgehungs-Proxy-URL:",
"geo_proxy_url_placeholder": "http://geo-proxy:port",
"clear_main_proxy": "Haupt-Proxy löschen",
"clear_geo_proxy": "Geo-Proxy löschen",
"proxy_url": "Proxy-URL",
"proxy_placeholder": "http://proxy:port oder socks5://proxy:port",
"geo_bypass": "Geo-Umgehungs-Proxy (für geografische Beschränkungen)",
"geo_bypass_placeholder": "http://proxy:port zur Umgehung von Geo-Blockierungen",
"invalid_main_url": "Ungültiges Haupt-Proxy-URL-Format",
"invalid_geo_url": "Ungültiges Geo-Proxy-URL-Format",
"main_configured": "Haupt-Proxy konfiguriert",
"geo_configured": "Geo-Proxy konfiguriert"
},
"download": {
"preparing": "Download wird vorbereitet...",
"please_enter_url": "Bitte geben Sie zuerst eine URL ein.",
"please_set_path": "Bitte setzen Sie zuerst einen Download-Pfad.",
"please_enter_url_and_path": "Bitte geben Sie eine URL ein und setzen Sie einen Download-Pfad.",
"please_select_format": "Bitte wählen Sie zuerst ein Format aus."
},
"update": {
"title": "yt-dlp aktualisieren",
"checking": "Suche nach Updates...",
"update_available": "Update verfügbar!\nAktuelle Version: {current}\nNeueste Version: {latest}",
"up_to_date": "yt-dlp ist aktuell (Version {version})",
"could_not_determine": "Versionen konnten nicht bestimmt werden.",
"error_comparing": "Fehler beim Vergleichen der Versionen: {error}",
"update_available_failed": "Update verfügbar! (Vergleich fehlgeschlagen)\nAktuell: {current}\nNeuest: {latest}",
"updating": "Wird aktualisiert...",
"initializing": "🚀 Update-Prozess wird initialisiert...",
"checking_current": "🔍 Aktuelle Installation wird überprüft...",
"found_at": "📍 yt-dlp gefunden in: {path}",
"error_getting_path": "❌ Fehler beim Abrufen des yt-dlp-Pfads: {error}",
"updating_binary": "📦 App-verwaltete yt-dlp-Binärdatei wird aktualisiert...",
"updating_pip": "🐍 System-yt-dlp wird über pip aktualisiert...",
"update_failed": "❌ yt-dlp-Update fehlgeschlagen. Bitte versuchen Sie es erneut oder überprüfen Sie Ihre Internetverbindung.",
"binary_updated": "✅ Binärdatei erfolgreich aktualisiert!",
"update_failed_stderr": "❌ yt-dlp-Update fehlgeschlagen: {error}",
"update_timeout": "❌ yt-dlp-Update-Zeitüberschreitung.",
"unexpected_error": "❌ Unerwarteter Fehler während des Updates: {error}",
"checking_pip": "🔍 Aktuelle pip-Installation wird überprüft...",
"current_version": "📋 Aktuelle Version: {version}",
"not_found_pip": "⚠️ yt-dlp über pip nicht gefunden, Installation wird versucht...",
"checking_latest": "🌐 Neueste Version wird überprüft...",
"failed_check_updates": "❌ Überprüfung auf Updates fehlgeschlagen",
"latest_version": "🆕 Neueste Version: {version}",
"updating_from_to": "⬆️ Update von {current} auf {latest}...",
"running_pip_install": "📦 pip install --upgrade wird ausgeführt...",
"pip_completed": "✅ Pip-Update erfolgreich abgeschlossen!",
"pip_failed": "❌ Pip-Update fehlgeschlagen: {error}"
},
"about": {
"title": "Über YTSage",
"version": "Version {version}",
"description": "Moderner YouTube-Downloader mit sauberer PySide6-Oberfläche.",
"author": "Von: {author}",
"github": "GitHub: {repo}",
"system_info": "Systeminformationen",
"loading": "🔄 Systeminformationen werden geladen...",
"refresh": "🔄",
"refreshing": "🔄 Wird aktualisiert...",
"refresh_failed": "Aktualisierung fehlgeschlagen",
"refresh_failed_message": "Versionsinformationen konnten nicht aktualisiert werden.",
"detected": "✓ Erkannt",
"missing": "✗ Fehlend",
"not_available": "Nicht verfügbar"
},
"time_range": {
"title": "Video schneiden",
"time_range_group": "Zeitbereich",
"start_time": "Startzeit (HH:MM:SS)",
"end_time": "Endzeit (HH:MM:SS)",
"start_placeholder": "00:00:00",
"end_placeholder": "00:00:00",
"start_time_placeholder": "Startzeit (HH:MM:SS)",
"end_time_placeholder": "Endzeit (HH:MM:SS)",
"force_keyframes": "Keyframes an Schnittpunkten erzwingen",
"help_text": "Setzen Sie Start- und Endzeit, um das Video zu schneiden.\nLeer lassen, um das vollständige Video herunterzuladen.",
"invalid_format": "Ungültiges Zeitformat. Verwenden Sie das Format HH:MM:SS.",
"start_after_end": "Startzeit kann nicht nach der Endzeit liegen."
},
"settings": {
"title": "Download-Einstellungen",
"download_path": "Download-Pfad",
"browse": "Durchsuchen...",
"speed_limit": "Geschwindigkeitsbegrenzung",
"speed_limit_placeholder": "Keine",
"auto_update_ytdlp": "yt-dlp automatisch aktualisieren",
"enable_auto_updates": "Automatische yt-dlp-Updates aktivieren",
"update_frequency": "Update-Häufigkeit:",
"check_startup": "Bei jedem Start prüfen (mindestens 1 Stunde zwischen Prüfungen)",
"check_daily": "Täglich prüfen",
"check_weekly": "Wöchentlich prüfen",
"check_updates_now": "Jetzt nach Updates suchen",
"update_check_title": "Update-Prüfung",
"could_not_determine_version": "Aktuelle yt-dlp-Version konnte nicht bestimmt werden.",
"update_available_dialog": "Update verfügbar!\n\nAktuell: {current}\nNeuest: {latest}\n\nVerwenden Sie die Schaltfläche 'yt-dlp aktualisieren' im Hauptfenster zum Aktualisieren.",
"up_to_date_dialog": "yt-dlp ist aktuell!\n\nAktuelle Version: {version}",
"error_checking_updates": "Fehler bei der Update-Prüfung: {error}",
"settings_saved_title": "Einstellungen gespeichert",
"settings_saved_message": "Auto-Update-Einstellungen wurden erfolgreich gespeichert!",
"error_title": "Fehler",
"failed_save_settings": "Speichern der Auto-Update-Einstellungen fehlgeschlagen.",
"error_saving_settings": "Fehler beim Speichern der Auto-Update-Einstellungen: {error}",
"auto_update_title": "Auto-Update-Einstellungen",
"auto_update_header": "🔄 Auto-Update-Einstellungen",
"auto_update_description": "Konfigurieren Sie automatische Updates für yt-dlp, um sicherzustellen, dass Sie immer die neuesten Funktionen und Fehlerbehebungen haben.",
"current_status": "Aktueller Status",
"current_version_label": "Aktuelle yt-dlp-Version: Wird überprüft...",
"last_check_label": "Letzte Update-Prüfung: Nie",
"next_check_label": "Nächste Prüfung: Basierend auf Einstellungen",
"manual_check_button": "🔍 Jetzt nach Updates suchen",
"update_frequency_group": "Update-Häufigkeit",
"save_settings": "Einstellungen speichern",
"settings_saved_successfully": "✅ Einstellungen erfolgreich gespeichert!",
"error_saving": "❌ Fehler beim Speichern der Einstellungen: {error}"
},
"main_ui": {
"url_placeholder": "YouTube-Video- oder Playlist-URL eingeben",
"merge_subtitles": "Untertitel zusammenführen",
"save_thumbnail": "Thumbnail speichern",
"save_description": "Beschreibung speichern",
"embed_chapters": "Kapitel einbetten",
"subtitles_selected": "{count} ausgewählt",
"all_selected": "Alle ausgewählt",
"select_videos_all": "Videos auswählen... (Alle ausgewählt)",
"please_enter_url": "Bitte geben Sie zuerst eine URL ein",
"cookie_file_selected_title": "Cookie-Datei ausgewählt",
"cookie_file_selected_message": "Cookie-Datei ausgewählt: {path}",
"browser_cookies_selected_title": "Browser-Cookies ausgewählt",
"browser_cookies_selected_message": "Browser-Cookies werden aus folgendem Browser extrahiert: {browser}",
"error_no_format_info": "Fehler: Keine Formatinformationen verfügbar.",
"error_extract_info": "Fehler: Grundlegende Videoinformationen konnten nicht extrahiert werden. Bitte überprüfen Sie Ihren Link.",
"analyzing_preparing": "Analysiere (0%)... Anfrage wird vorbereitet",
"analyzing_extracting_basic": "Analysiere (15%)... Grundlegende Informationen werden extrahiert",
"analyzing_extracting_detailed": "Analysiere (30%)... Detaillierte Informationen werden extrahiert",
"analyzing_processing_video": "Analysiere (45%)... Videodaten werden verarbeitet",
"analyzing_processing_formats": "Analysiere (60%)... Formate werden verarbeitet",
"analyzing_loading_thumbnail": "Analysiere (75%)... Thumbnail wird geladen",
"analyzing_processing_subtitles": "Analysiere (85%)... Untertitel werden verarbeitet",
"analyzing_updating_table": "Analysiere (95%)... Formattabelle wird aktualisiert",
"analysis_complete": "Analyse abgeschlossen!",
"analyzing_extracting_ytdlp": "Analysiere (30%)... Informationen mit yt-dlp-Ausführbarer Datei werden extrahiert",
"analyzing_processing_data": "Analysiere (60%)... Daten werden verarbeitet",
"analyzing_processing_formats_ytdlp": "Analysiere (75%)... Formate werden verarbeitet",
"analyzing_loading_thumbnail_ytdlp": "Analysiere (85%)... Thumbnail wird geladen",
"analyzing_processing_subtitles_ytdlp": "Analysiere (90%)... Untertitel werden verarbeitet",
"select_subtitles": "Untertitel auswählen...",
"sponsorblock_categories": "SponsorBlock-Kategorien..."
},
"sponsorblock": {
"sponsor": "Sponsor",
"sponsor_desc": "Bezahlte Werbung, bezahlte Empfehlungen und direkte Werbung",
"selfpromo": "Unbezahlte/Eigenwerbung",
"selfpromo_desc": "Unbezahlte Werbung für eigene Inhalte der Ersteller",
"interaction": "Interaktions-Erinnerung",
"interaction_desc": "Zuschauer werden gebeten zu liken, zu abonnieren oder sozialen Medien zu folgen",
"intro": "Intro",
"intro_desc": "Video-Einleitung, die übersprungen werden kann",
"outro": "Outro/Abspann-Karten",
"outro_desc": "Credits oder wenn das Video endet",
"preview": "Vorschau/Zusammenfassung",
"preview_desc": "Kurze Zusammenfassung vorheriger Videos oder Vorschau auf kommende Inhalte",
"music_offtopic": "Nicht-Musik-Bereich",
"music_offtopic_desc": "Nur für Musikvideos. Markiert Nicht-Musik-Bereiche",
"filler": "Füller-Exkurs",
"filler_desc": "Abschweifende Szenen, die nur als Füller oder für Humor hinzugefügt wurden"
},
"video_info": {
"channel": "Kanal",
"views": "Aufrufe",
"likes": "Gefällt mir",
"upload_date": "Upload-Datum",
"duration": "Dauer",
"unknown_channel": "Unbekannter Kanal",
"unknown_date": "Unbekanntes Datum",
"unknown_title": "Unbekannter Titel"
},
"command": {
"running": "Läuft...",
"run_command": "Befehl ausführen"
},
"selection": {
"none_selected": "0 ausgewählt",
"one_selected": "1 Kategorie ausgewählt",
"count_selected": "{count} ausgewählt"
},
"status": {
"ready": "Bereit",
"file_exists": "⚠️ Datei existiert bereits",
"cancelling": "Download wird abgebrochen..."
}
}
+1
View File
@@ -9,6 +9,7 @@
"portuguese": "Português (Portuguese)",
"russian": "Русский (Russian)",
"chinese": "中文 (简体) (Chinese Simplified)",
"german": "Deutsch (German)",
"help_text": "Select your preferred language for the interface.",
"restart_notice": "Language change will take effect after restarting the application."
},
+2 -1
View File
@@ -8,7 +8,8 @@
"spanish": "Español (Spanish)",
"portuguese": "Português (Portuguese)",
"russian": "Русский (Russian)",
"chinese": "中文 (简体) (Chinese Simplified)"
"chinese": "中文 (简体) (Chinese Simplified)",
"german": "Deutsch (German)"
},
"app": {
"title": "YTSage",
+1
View File
@@ -9,6 +9,7 @@
"portuguese": "Português",
"russian": "Русский (Russian)",
"chinese": "中文 (简体) (Chinese Simplified)",
"german": "Alemão",
"help_text": "Selecione seu idioma preferido para a interface.",
"restart_notice": "A alteração de idioma terá efeito após reiniciar a aplicação."
},
+1
View File
@@ -9,6 +9,7 @@
"portuguese": "Португальский",
"russian": "Русский",
"chinese": "中文 (简体) (Chinese Simplified)",
"german": "Немецкий",
"help_text": "Выберите предпочитаемый язык для интерфейса.",
"restart_notice": "Изменение языка вступит в силу после перезапуска приложения."
},
+1
View File
@@ -9,6 +9,7 @@
"portuguese": "葡萄牙语",
"russian": "俄语",
"chinese": "中文",
"german": "德语",
"help_text": "选择您喜欢的界面语言。",
"restart_notice": "语言更改将在重启应用程序后生效。"
},
+4 -4
View File
@@ -265,13 +265,13 @@ class FormatTableMixin:
quality_text = self.get_quality_label(f)
quality_item = QTableWidgetItem(quality_text)
# Set color based on quality (check English, Spanish, Portuguese, Russian, and Chinese terms)
if any(term in quality_text for term in ["Best", "Óptima", "Mejor", "Melhor", "Лучшее", "最佳"]):
if any(term in quality_text for term in ["Best", "Óptima", "Mejor", "Melhor", "Лучшее", "最佳", "Beste"]):
quality_item.setForeground(QColor("#00ff00")) # Green for best quality
elif any(term in quality_text for term in ["High", "Alta", "Alto", "Áudio Alto", "Audio Alto", "Высокое", "高清", "高质量"]):
elif any(term in quality_text for term in ["High", "Alta", "Alto", "Áudio Alto", "Audio Alto", "Высокое", "高清", "高质量", "Hoch"]):
quality_item.setForeground(QColor("#00cc00")) # Light green for high quality
elif any(term in quality_text for term in ["Medium", "Media", "Medio", "Média", "Áudio Médio", "Audio Medio", "Среднее", "中等"]):
elif any(term in quality_text for term in ["Medium", "Media", "Medio", "Média", "Áudio Médio", "Audio Medio", "Среднее", "中等", "Mittel"]):
quality_item.setForeground(QColor("#ffaa00")) # Orange for medium quality
elif any(term in quality_text for term in ["Low", "Baja", "Bajo", "Baixa", "Áudio Baixo", "Audio Bajo", "Низкое", "低质量"]):
elif any(term in quality_text for term in ["Low", "Baja", "Bajo", "Baixa", "Áudio Baixo", "Audio Bajo", "Низкое", "低质量", "Niedrig", "Niedriges Audio"]):
quality_item.setForeground(QColor("#ff5555")) # Red for low quality
self.format_table.setItem(row, 1, quality_item)
+2 -1
View File
@@ -84,7 +84,8 @@ class LocalizationManager:
"spanish": "Español (Spanish)",
"portuguese": "Português (Portuguese)",
"russian": "Русский (Russian)",
"chinese": "中文 (简体) (Chinese Simplified)"
"chinese": "中文 (简体) (Chinese Simplified)",
"german": "Deutsch (German)"
},
"download": {
"preparing": "🚀 Preparing your download...",