From 47cdd0649400d19c1346ea9964d3b7700278ad62 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 30 Sep 2025 22:00:03 +0300 Subject: [PATCH] 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. --- languages/de.json | 330 +++++++++++++++++++++++++++++ languages/en.json | 1 + languages/es.json | 3 +- languages/pt.json | 1 + languages/ru.json | 1 + languages/zh.json | 1 + src/gui/ytsage_gui_format_table.py | 8 +- src/utils/ytsage_localization.py | 3 +- 8 files changed, 342 insertions(+), 6 deletions(-) create mode 100644 languages/de.json diff --git a/languages/de.json b/languages/de.json new file mode 100644 index 0000000..17fd0ee --- /dev/null +++ b/languages/de.json @@ -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.

Für die vollständige Liste der Optionen und Verwendungsbeispiele klicken Sie hier, um die offizielle yt-dlp-Dokumentation anzuzeigen.

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..." + } +} \ No newline at end of file diff --git a/languages/en.json b/languages/en.json index 2becc63..a852430 100644 --- a/languages/en.json +++ b/languages/en.json @@ -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." }, diff --git a/languages/es.json b/languages/es.json index 78411b5..4339bad 100644 --- a/languages/es.json +++ b/languages/es.json @@ -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", diff --git a/languages/pt.json b/languages/pt.json index 9692b3f..29f9727 100644 --- a/languages/pt.json +++ b/languages/pt.json @@ -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." }, diff --git a/languages/ru.json b/languages/ru.json index c29b222..e48501d 100644 --- a/languages/ru.json +++ b/languages/ru.json @@ -9,6 +9,7 @@ "portuguese": "Португальский", "russian": "Русский", "chinese": "中文 (简体) (Chinese Simplified)", + "german": "Немецкий", "help_text": "Выберите предпочитаемый язык для интерфейса.", "restart_notice": "Изменение языка вступит в силу после перезапуска приложения." }, diff --git a/languages/zh.json b/languages/zh.json index ae7910c..96ea952 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -9,6 +9,7 @@ "portuguese": "葡萄牙语", "russian": "俄语", "chinese": "中文", + "german": "德语", "help_text": "选择您喜欢的界面语言。", "restart_notice": "语言更改将在重启应用程序后生效。" }, diff --git a/src/gui/ytsage_gui_format_table.py b/src/gui/ytsage_gui_format_table.py index 89529d5..e3180c0 100644 --- a/src/gui/ytsage_gui_format_table.py +++ b/src/gui/ytsage_gui_format_table.py @@ -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) diff --git a/src/utils/ytsage_localization.py b/src/utils/ytsage_localization.py index 79a90bc..a31c4c8 100644 --- a/src/utils/ytsage_localization.py +++ b/src/utils/ytsage_localization.py @@ -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...",