diff --git a/src/apps/officer-web/lib/locales.ts b/src/apps/officer-web/lib/locales.ts index c1ee8d54..e232eb03 100644 --- a/src/apps/officer-web/lib/locales.ts +++ b/src/apps/officer-web/lib/locales.ts @@ -19,7 +19,7 @@ const autonym = (code: string): string => { return name.charAt(0).toUpperCase() + name.slice(1); }; -export const SHIPPED_LOCALES: ShippedLocale[] = ['en-GB', 'pt-PT', 'fr-FR'].map((code) => ({ +export const SHIPPED_LOCALES: ShippedLocale[] = ['en-GB', 'pt-PT', 'fr-FR', 'de-DE'].map((code) => ({ code, label: autonym(code), })); diff --git a/src/apps/officer-web/locales/de-DE.json b/src/apps/officer-web/locales/de-DE.json new file mode 100644 index 00000000..502b9119 --- /dev/null +++ b/src/apps/officer-web/locales/de-DE.json @@ -0,0 +1,704 @@ +{ + "common": { + "save": "Speichern", + "saving": "Wird gespeichert...", + "cancel": "Abbrechen" + }, + "settings": { + "profile": { + "userData": { + "email": "E-Mail", + "username": "Benutzername", + "name": "Name", + "namePlaceholder": "Ihr Name", + "updated": "Profil aktualisiert", + "updateFailed": "Profil konnte nicht aktualisiert werden", + "selectImage": "Bitte wählen Sie eine Bilddatei aus", + "imageTooLarge": "Das Bild muss kleiner als 384 KB sein" + }, + "apiKeys": { + "intro": "Ein API-Schlüssel meldet Sie an, ohne Passwort und ohne Ablauf. Ein Schlüssel funktioniert überall — ein Schlüssel ist nicht an eine App gebunden. Jedem Gerät einen eigenen zu geben, dient nur dazu, einen abzuschalten, ohne die anderen anzutasten. Senden Sie ihn als", + "loading": "Schlüssel werden geladen…", + "mintedTitle": "Schlüssel für “{{name}}” — wird nur einmal angezeigt", + "savedIt": "Ich habe ihn gespeichert", + "copyKey": "Schlüssel kopieren", + "copied": "Schlüssel kopiert", + "copyFailed": "Kopieren nicht möglich — bitte manuell auswählen und kopieren", + "newKey": "Neuer Schlüssel", + "namePlaceholder": "iPhone, Musik-App, Laptop-CLI…", + "create": "Erstellen", + "createFailed": "Der Schlüssel konnte nicht erstellt werden", + "noneYet": "Noch keine Schlüssel.", + "noneInUse": "Keine Schlüssel in Verwendung.", + "revoked": "widerrufen", + "expired": "abgelaufen", + "lastUsed": "zuletzt verwendet am {{date}}", + "neverUsed": "nie verwendet", + "forget": "Diesen Eintrag entfernen", + "forgetFailed": "Entfernen nicht möglich", + "revoke": "Widerrufen", + "revokeDone": "Widerrufen — alles, was diesen Schlüssel verwendet hat, wurde abgemeldet", + "revokeFailed": "Widerrufen nicht möglich", + "hideDead": "Widerrufene und abgelaufene ausblenden", + "showDead": { + "one": "{{count}} widerrufenen oder abgelaufenen Schlüssel anzeigen", + "other": "{{count}} widerrufene oder abgelaufene Schlüssel anzeigen" + } + }, + "voice": { + "label": "Stimme", + "refresh": "Stimmen aktualisieren", + "serverDefault": "Server-Standard", + "hint": "Wählen Sie eine Stimme für die Sprachausgabe (Text-to-Speech). Belassen Sie es beim Server-Standard, um die vom Administrator konfigurierte Stimme zu verwenden.", + "stop": "Stopp", + "listen": "Anhören" + }, + "dock": { + "visible": "Sichtbar", + "hidden": "Ausgeblendet", + "dragToShow": "Elemente hierher ziehen, um sie im Dock anzuzeigen", + "allVisible": "Alle Elemente sichtbar", + "reset": "Auf Standard zurücksetzen" + }, + "languages": { + "spokenLabel": "Sprachen, die Sie sprechen", + "addLanguage": "Sprache hinzufügen...", + "defaultLabel": "Standardsprache", + "defaultHint": "Wird für die Lokalisierung der Oberfläche verwendet.", + "translateToLabel": "Übersetzen nach", + "translateToHint": "Zielsprache beim Übersetzen von Inhalten, die Sie nicht sprechen." + }, + "changePassword": { + "currentPasswordLabel": "Aktuelles Passwort", + "currentPasswordPlaceholder": "Aktuelles Passwort", + "newPasswordLabel": "Neues Passwort", + "newPasswordPlaceholder": "Neues Passwort", + "confirmPasswordLabel": "Neues Passwort bestätigen", + "confirmPasswordPlaceholder": "Neues Passwort bestätigen", + "changeButton": "Passwort ändern", + "changingButton": "Wird geändert...", + "passwordChanged": "Passwort geändert", + "passwordChangeFailed": "Passwort konnte nicht geändert werden" + }, + "models": { + "defaultModel": "Standardmodell", + "sameAsChat": "Wie Chat-Standard", + "taskDefaultsSaved": "Aufgaben-Standardeinstellungen gespeichert", + "saveFailed": "Einstellungen konnten nicht gespeichert werden", + "defaultChat": "Standard-Chat-Modell", + "defaultChatHint": "Wird beim Starten eines neuen Chats vom Startbildschirm verwendet", + "defaultProject": "Standard-Projektmodell", + "defaultProjectHint": "Wird beim Starten eines neuen Chats innerhalb eines Projekt-Dashboards verwendet", + "defaultTask": "Standard-Aufgabenmodell", + "defaultTaskHint": "Wird beim Ausführen von Aufgaben aus dem Datei-Browser verwendet", + "aiDefaultsSaved": "KI-Modell-Standardeinstellungen gespeichert" + } + }, + "sections": { + "profile": { + "label": "Profil", + "hint": "Avatar, Name, E-Mail", + "description": "Avatar, Name und E-Mail" + }, + "changePassword": { + "label": "Passwort ändern", + "description": "Aktualisieren Sie Ihr Passwort" + }, + "apiKeys": { + "label": "API-Schlüssel", + "hint": "Schlüssel, die sich als Sie anmelden", + "description": "Schlüssel, die sich als Sie anmelden, einzeln widerrufbar" + }, + "languages": { + "label": "Sprachen", + "hint": "gesprochen und Übersetzung", + "description": "Gesprochen, Standard und Übersetzung" + }, + "voice": { + "label": "Stimme", + "hint": "Text-zu-Sprache", + "description": "Einstellung für die Sprachausgabe (Text-to-Speech)" + }, + "dock": { + "label": "Dock", + "hint": "auswählen und anordnen", + "description": "Dock-Elemente auswählen und anordnen" + }, + "myModels": { + "label": "Meine Modelle", + "description": "Modelle für sich selbst anzeigen oder ausblenden" + }, + "channelModels": { + "label": "Kanalmodelle", + "description": "Modelle, die für Konten ohne Eigentümerrechte erreichbar sind" + }, + "defaultModels": { + "label": "Standardmodelle", + "description": "Standardmodelle für Chat, Projekte und Aufgaben" + }, + "providers": { + "label": "Anbieter", + "hint": "Harnesses", + "description": "Entfernte und lokale KI-Anbieter" + }, + "tts": { + "label": "Text-zu-Sprache", + "description": "TTS-Anbieter und Stimme" + }, + "stt": { + "label": "Sprache-zu-Text", + "description": "Whisper-Server-URL" + }, + "ocr": { + "label": "OCR", + "description": "Vision-Modell für Textextraktion" + }, + "maintenance": { + "label": "Neu erstellen & neu starten", + "hint": "Wartung", + "description": "Änderungen laden, ohne ein Terminal zu benötigen" + }, + "smtp": { + "label": "SMTP", + "hint": "ausgehende E-Mail", + "description": "Anbieter für E-Mail-Zustellung" + }, + "googleOauth": { + "label": "Google OAuth", + "description": "Client-ID und Secret für Google-APIs" + }, + "apify": { + "label": "Apify", + "description": "API-Token für Web-Scraping-Actors" + }, + "davSync": { + "label": "Kalender- und Kontaktabgleich", + "hint": "App-Passwörter", + "description": "Geräteweise Passwörter für CalDAV-/CardDAV-Clients" + }, + "accounts": { + "label": "Konten", + "hint": "Benutzer", + "description": "Wer Zugriff hat, und worauf" + }, + "permissions": { + "label": "Berechtigungen", + "description": "Was jede Rolle erreichen kann" + } + }, + "searchPlaceholder": "Einstellungen durchsuchen…", + "selectSection": "Wählen Sie einen Bereich aus", + "groups": { + "models": "Modelle", + "defaults": "Standardwerte", + "providers": "Anbieter", + "ai": "KI", + "maintenance": "Wartung", + "email": "E-Mail" + }, + "nav": { + "profile": "Profil", + "ai": "KI", + "system": "System", + "integrations": "Integrationen", + "users": "Benutzer" + }, + "ai": { + "noModels": "Keine Modelle verfügbar. Konfigurieren Sie API-Schlüssel unter Anbieter.", + "dragToShow": "Modelle hierher ziehen, um sie anzuzeigen", + "allVisible": "Alle Modelle sichtbar", + "dragToEnable": "Modelle hierher ziehen, um sie zu aktivieren", + "allEnabled": "Alle Modelle aktiviert", + "visible": "Sichtbar", + "hidden": "Ausgeblendet", + "enabled": "Aktiviert", + "disabled": "Deaktiviert", + "refresh": "Modelle von Anbietern aktualisieren", + "refreshed": "Modelle aktualisiert", + "refreshFailed": "Modelle konnten nicht aktualisiert werden" + }, + "integrations": { + "enterprise": "Unternehmen", + "personal": "Persönlich" + }, + "server": { + "loading": "Wird geladen…", + "provider": "Anbieter", + "model": "Modell", + "voice": "Stimme", + "ocr": { + "serverUrl": "Server-URL des Vision-Modells", + "refreshModels": "Modelle aktualisieren", + "selectModel": "Wählen Sie ein Modell aus", + "saved": "OCR-Einstellungen gespeichert", + "saveFailed": "OCR-Einstellungen konnten nicht gespeichert werden", + "reachable": "Vision-Modell-Server ist erreichbar" + }, + "stt": { + "serverUrl": "Whisper-Server-URL", + "saved": "STT-Einstellungen gespeichert", + "saveFailed": "STT-Einstellungen konnten nicht gespeichert werden", + "reachable": "Whisper-Server ist erreichbar" + }, + "tts": { + "openaiCompatible": "OpenAI-kompatibel (Kokoro, OpenAI usw.)", + "elevenLabs": "ElevenLabs", + "refreshVoices": "Stimmen aktualisieren", + "selectVoice": "Wählen Sie eine Stimme aus", + "saved": "TTS-Einstellungen gespeichert", + "saveFailed": "TTS-Einstellungen konnten nicht gespeichert werden", + "playing": "Testaudio wird abgespielt", + "testFailed": "Test fehlgeschlagen — TTS-Server nicht erreichbar" + }, + "smtp": { + "mailhog": "MailHog (lokaler Test)", + "resend": "Resend", + "custom": "Benutzerdefiniertes SMTP", + "apiKey": "API-Schlüssel", + "host": "Host", + "port": "Port", + "username": "Benutzername", + "password": "Passwort", + "tls": "TLS / SSL", + "fromName": "Absendername", + "fromEmail": "Absender-E-Mail", + "sendTest": "Test-E-Mail senden", + "userExample": "benutzer@beispiel.de", + "recipientExample": "empfänger@beispiel.de", + "saved": "SMTP-Einstellungen gespeichert", + "saveFailed": "SMTP-Einstellungen konnten nicht gespeichert werden", + "connected": "Verbindung erfolgreich", + "testSent": "Test-E-Mail an {{email}} gesendet" + }, + "maintenance": { + "updateTitle": "Plattform aktualisieren", + "updateHint": "Ändert nichts, was gerade läuft. Was das Update benötigt, ist hier aufgeführt, und die Entscheidung liegt bei Ihnen.", + "rebuild": "Frontend neu erstellen", + "restart": "Server neu starten", + "upToDate": "Bereits aktuell", + "rebuilt": "Frontend neu erstellt — laden Sie diese Seite neu, um es zu sehen", + "restarting": "Wird neu gestartet — die Seite verbindet sich von selbst wieder", + "pulled": { + "one": "{{count}} Commit abgerufen", + "other": "{{count}} Commits abgerufen" + } + }, + "harnesses": { + "piMono": "Pi Mono", + "checking": "Wird geprüft…", + "localProviders": "Lokale Anbieter", + "remoteProviders": "Entfernte Anbieter", + "connect": "Verbinden", + "authenticate": "Authentifizieren", + "connectLocal": "Lokalen Anbieter verbinden", + "connectProvider": "Anbieter verbinden", + "none": "Keine Anbieter gefunden.", + "updatePiMono": "Pi Mono aktualisieren", + "removeProvider": "Anbieter entfernen", + "namePlaceholder": "Name (z. B. Mein Ollama)", + "username": "Benutzername", + "password": "Passwort", + "apiKey": "API-Schlüssel", + "editKey": "Schlüssel bearbeiten", + "disconnect": "Anbieter trennen", + "saveKey": "Schlüssel speichern", + "enterKey": "API-Schlüssel eingeben", + "search": "Anbieter durchsuchen…", + "connectFailed": "Verbindung fehlgeschlagen", + "authFailed": "Authentifizierung fehlgeschlagen", + "saveFailed": "Anbieter konnte nicht gespeichert werden", + "connectedTo": "Mit {{name}} verbunden" + } + }, + "users": { + "loadingPermissions": "Berechtigungen werden geladen…", + "permissionsFailed": "Berechtigungen konnten nicht geladen werden.", + "deniedUnlessGranted": "Alles ist verweigert, sofern es hier nicht gewährt wird.", + "read": "Lesen", + "full": "Vollständig", + "noAccess": "Kein Zugriff", + "role": "Rolle", + "permissionsSaved": "Gespeichert, was {{role}}s erreichen können", + "copyBeforeClosing": "Kopieren Sie, was Sie brauchen, bevor Sie schließen — nichts davon kann erneut angezeigt werden.", + "password": "Passwort", + "linuxAccount": "Linux-Konto", + "sshKey": "Ihr öffentlicher SSH-Schlüssel", + "addToGitea": "Fügen Sie dies zu ihrem Gitea-Konto hinzu", + "linuxIncomplete": "Das Konto funktioniert, aber die Linux-Seite wurde nicht fertiggestellt", + "done": "Fertig", + "addAccount": "Konto hinzufügen", + "newAccount": "Neues Konto", + "email": "E-Mail", + "name": "Name", + "username": "Benutzername", + "usernameHint": "Buchstaben, Zahlen, Punkte, Bindestriche und Unterstriche.", + "generatePassword": "Ein Passwort generieren", + "copyPassword": "Passwort kopieren", + "passwordHint": "Mindestens 12 Zeichen, mit Groß- und Kleinbuchstaben, einer Zahl und einem Symbol.", + "sshPlaceholder": "ssh-ed25519 AAAAC3Nza… ana@laptop", + "passwordCopied": "Passwort kopiert", + "loadingAccounts": "Konten werden geladen…", + "accountsFailed": "Konten konnten nicht geladen werden.", + "removeAccount": "Konto entfernen", + "generateNewPassword": "Ein neues Passwort generieren", + "serverOwner": "Servereigentümer", + "copySshTitle": "Ihren öffentlichen SSH-Schlüssel kopieren (fügen Sie ihn zu ihrem Gitea-Konto hinzu)", + "resetPasswordTitle": "Ein neues Passwort generieren — wird nur einmal angezeigt und meldet sie überall ab", + "copyNewPassword": "Das neue Passwort kopieren", + "publicKeyCopied": "Öffentlicher Schlüssel kopiert", + "copyFailed": "Kopieren nicht möglich — bitte manuell auswählen und kopieren", + "repairFor": "Linux-Konto von {{email}} reparieren", + "linuxAccountFor": "Linux-Konto: {{osUser}} — klicken, um es zu reparieren oder den SSH-Schlüssel zu ersetzen", + "copySshFor": "Öffentlichen SSH-Schlüssel von {{email}} kopieren", + "resetPasswordFor": "Passwort von {{email}} zurücksetzen", + "removeFor": "{{email}} entfernen", + "provisionPrompt": "Linux-Konto für {{email}}.\n\nFügen Sie einen öffentlichen SSH-Schlüssel ein, um SSH-Zugriff zu erlauben, oder lassen Sie das Feld leer, um den aktuellen zu behalten.", + "createLinux": "Ein Linux-Konto erstellen", + "noLinux": "Kein Linux-Konto — klicken, um eines zu erstellen", + "removeTitle": "{{email}} entfernen?", + "removeBody": "Dies löscht das Konto und alles, was dazugehört — Passkeys, Dashboards, gespeicherte Layouts und alles, was ein installiertes Plugin für dieses Konto speichert. Dies kann nicht rückgängig gemacht werden.", + "resetTitle": "Passwort für {{email}} zurücksetzen?", + "resetBody": "Ein neues Passwort wird generiert und Ihnen einmalig angezeigt — es wird nirgendwo gespeichert und kann danach nicht mehr abgerufen werden. Das bisherige Passwort funktioniert sofort nicht mehr, und die Person wird überall abgemeldet.", + "resetLinuxNote": "Das Linux-Konto ({{osUser}}) ist davon nicht betroffen: Es hat kein Passwort, und die SSH-Schlüssel bleiben unverändert." + }, + "dav": { + "newDevice": "Neues Gerät", + "create": "Erstellen", + "none": "Noch keine Geräte.", + "placeholder": "Pixel 9, iPad, Thunderbird…", + "revoke": "Widerrufen", + "delete": "Löschen", + "copyFailed": "Kopieren nicht möglich — bitte manuell auswählen und kopieren", + "createFailed": "Das App-Passwort konnte nicht erstellt werden", + "revoked": "Widerrufen — dieses Gerät synchronisiert nicht mehr", + "revokeFailed": "Widerrufen nicht möglich", + "deleteFailed": "Löschen nicht möglich", + "copyField": "{{field}} kopieren", + "copied": "{{what}} kopiert" + }, + "google": { + "guideToggle": "Schritt-für-Schritt-Anleitung", + "step1": { + "title": "Ein Google-Cloud-Projekt erstellen", + "body": "Öffnen Sie die Seite zur Projekterstellung, geben Sie ihm einen Namen (zum Beispiel “Officer”) und klicken Sie auf:", + "link": "New Project" + }, + "step2": { + "title": "Die APIs aktivieren", + "body": "Öffnen Sie die API-Bibliothek, suchen Sie nach jeder dieser APIs und klicken Sie auf:", + "link": "API Library" + }, + "step3": { + "title": "Den OAuth-Zustimmungsbildschirm konfigurieren", + "link": "OAuth Branding", + "appName": "Legen Sie den Namen Ihrer Organisation oder “Officer” fest als:", + "supportEmail": "Legen Sie die E-Mail-Adresse Ihres Administrators fest als:", + "devContact": "Fügen Sie die E-Mail-Adresse Ihres Administrators hinzu unter:", + "save": "Klicken Sie dann auf:" + }, + "step4": { + "title": "Die Zielgruppe festlegen", + "link": "OAuth Audience", + "internal": "Wenn Ihr Team Google Workspace verwendet, wählen Sie dies — keine Überprüfung nötig:", + "external": "Andernfalls wählen Sie dies und fügen Sie die E-Mail-Adressen Ihres Teams unter Test users hinzu (erforderlich, solange die App nicht verifiziert ist; Grenze von 100 Testnutzern):" + }, + "step5": { + "title": "Bereiche hinzufügen", + "link": "Data Access", + "body": "Öffnen Sie den Datenzugriff, suchen Sie die unten stehenden Bereiche, fügen Sie sie hinzu und klicken Sie dann auf:", + "note": "Google stuft den Kalenderbereich als sensibel und den Gmail-Bereich als eingeschränkt ein. Das ist unproblematisch für Internal-Apps (Google Workspace) und für External-Apps im Testmodus; die Veröffentlichung in Produktion mit eingeschränkten Bereichen erfordert eine Google-Verifizierung." + }, + "step6": { + "title": "OAuth-Anmeldedaten erstellen", + "link": "Clients", + "body": "Öffnen Sie die Clients-Seite und klicken Sie auf:", + "appType": "Anwendungstyp:", + "nameAnything": "Name: beliebig (zum Beispiel “Officer”)", + "redirectUris": "Autorisierte Weiterleitungs-URIs — hinzufügen:", + "thenClick": "Klicken Sie dann auf:" + }, + "step7": { + "title": "Die Anmeldedaten kopieren", + "body": "Ein Dialogfeld zeigt Ihre Client-ID und Ihr Client-Secret. Kopieren Sie beide und fügen Sie sie in die untenstehenden Felder ein." + }, + "scopeGmail": "E-Mails lesen", + "scopeCalendar": "Kalenderereignisse lesen", + "verifying": "Anmeldedaten werden überprüft…", + "valid": "Anmeldedaten gültig", + "invalid": "Ungültige Anmeldedaten", + "verifyFailed": "Überprüfungsanfrage fehlgeschlagen", + "clientId": "Client-ID", + "clientSecret": "Client-Secret", + "redirectUri": "Weiterleitungs-URI", + "redirectUriHint": "Fügen Sie diese URI zu den autorisierten Weiterleitungs-URIs Ihres Google-OAuth-Clients hinzu", + "saved": "Google-OAuth-Konfiguration gespeichert", + "saveFailed": "Google-OAuth-Konfiguration konnte nicht gespeichert werden" + }, + "googleAccount": { + "title": "Google-Konto", + "hint": "Verbinden Sie Ihr Google-Konto für Kalender, Kontakte und andere Google-Dienste.", + "connected": "Verbunden", + "disconnect": "Trennen", + "connect": "Google-Konto verbinden", + "connectedToast": "Google-Konto verbunden", + "connectFailed": "Google-Konto konnte nicht verbunden werden", + "disconnectedToast": "Google-Konto getrennt", + "disconnectFailed": "Google-Konto konnte nicht getrennt werden" + }, + "apify": { + "token": "API-Token", + "saved": "Apify-API-Token gespeichert", + "saveFailed": "Apify-API-Token konnte nicht gespeichert werden" + } + }, + "header": { + "userMenu": { + "profile": "Profil", + "systemSettings": "Systemeinstellungen", + "signOut": "Abmelden", + "ai": "KI", + "integrations": "Integrationen", + "userManagement": "Benutzerverwaltung" + }, + "tabName": "Tab-Name", + "tabNameHint": "Klicken, um diesen Tab umzubenennen — leeren, um zum Seitennamen zurückzukehren", + "logoAlt": "Officer", + "navigation": "Navigation", + "jobsRunning": "Job läuft", + "jobsNothingRunning": "Nichts läuft", + "jobsQueued": "Jobs in Warteschlange" + }, + "nav": { + "home": "Start", + "files": "Dateien", + "chat": "Chat", + "commandHq": "Command HQ", + "editor": "Editor", + "jobs": "Jobs", + "terminal": "Terminal", + "browser": "Browser", + "monitor": "Monitor", + "activity": "Aktivität", + "dashboards": "Dashboards", + "sendOff": "SendOff", + "calendar": "Kalender", + "contacts": "Kontakte", + "appStore": "App Store", + "marketplace": "Marketplace", + "codeEditor": "Code-Editor" + }, + "theme": { + "pillTitle": "Design: {{name}} · Strg+Umschalt+←/→ durchblättern · Strg+Umschalt+Leertaste durchsuchen · Strg+Umschalt+F {{starAction}}", + "pillLabel": "Design: {{name}}", + "star": "markieren", + "unstar": "Markierung aufheben", + "cycleHint": "Strg+Umschalt+←/→ durchblättern · Strg+Umschalt+Leertaste durchsuchen", + "everyShortcutHint": "Strg+? für alle Tastenkombinationen", + "favouritesOnly": "Nur Favoriten ({{count}})", + "favourites": "Favoriten ({{count}})", + "noFavourites": "Noch keine Favoriten — markieren Sie einen mit der Schaltfläche in seiner Zeile.", + "starNamed": "{{name}} markieren", + "unstarNamed": "Markierung von {{name}} aufheben", + "addToFavourites": "Zu Favoriten hinzufügen", + "removeFromFavourites": "Aus Favoriten entfernen", + "addToFavouritesKey": "Zu Favoriten hinzufügen (f)", + "removeFromFavouritesKey": "Aus Favoriten entfernen (f)", + "active": "aktiv", + "browseHint": "j/k oder ↑/↓ bewegen · l oder → Vorschau · f markieren · h oder ← zurücksetzen · Eingabetaste behalten · Esc abbrechen" + }, + "spotlight": { + "placeholder": "Gehe zu…", + "noResults": "Keine Treffer für “{{query}}”." + }, + "shortcutsModal": { + "title": "Tastenkombinationen", + "hint": "Strg+? · Esc zum Schließen" + }, + "screenError": { + "title": "Dieser Bildschirm konnte nicht angezeigt werden", + "description": "Nichts ist verloren gegangen — das ist ein Anzeigefehler, kein Datenfehler. Agenten-Transkripte, Jobs und Dateien sind unberührt.", + "unknownError": "Unbekannter Fehler", + "tryAgain": "Erneut versuchen", + "reload": "Neu laden", + "goHome": "Zum Start", + "resetHint": "Wenn es an derselben Stelle erneut fehlschlägt, ist meist ein gespeichertes Panel-Layout die Ursache. Zurücksetzen bringt die Panels aller Bildschirme auf ihre Standardwerte zurück.", + "dashboardsSafe": "Ihre Dashboards sind davon nicht betroffen.", + "resetting": "Wird zurückgesetzt…", + "resetConfirm": "Ja — Layout aller Bildschirme zurücksetzen", + "reset": "Bildschirm-Layouts zurücksetzen" + }, + "rescan": { + "label": "Elemente erneut scannen", + "title": "officer-items erneut scannen (Änderungen übernehmen, ohne neu zu starten)", + "failed": "Elemente konnten nicht erneut gescannt werden", + "done": "Elemente erneut gescannt — {{summary}}", + "counts": { + "tasks": { + "one": "{{count}} Aufgabe", + "other": "{{count}} Aufgaben" + }, + "agents": { + "one": "{{count}} Agent", + "other": "{{count}} Agenten" + }, + "tools": { + "one": "{{count}} Werkzeug", + "other": "{{count}} Werkzeuge" + }, + "skills": { + "one": "{{count}} Skill", + "other": "{{count}} Skills" + }, + "processes": { + "one": "{{count}} Prozess", + "other": "{{count}} Prozesse" + }, + "affordances": { + "one": "{{count}} Affordance", + "other": "{{count}} Affordances" + } + }, + "newChatsOnly": "Gilt für neue Chats — ein bereits geöffneter behält, was er beim Start hatte.", + "noDescription": { + "one": "{{count}} Skill hat keine Beschreibung, daher wird sie keinem Agenten angeboten.", + "other": "{{count}} Skills haben keine Beschreibung, daher werden sie keinem Agenten angeboten." + } + }, + "bugReport": { + "label": "Fehler melden", + "title": "Fehler melden", + "describePlaceholder": "Beschreiben Sie, was schiefgelaufen ist...", + "screenshot": "Screenshot", + "noScreenshot": "Kein Screenshot aufgenommen", + "collectedNote": "Konsolenprotokolle, Browserinformationen und aktuelle API-Fehler werden automatisch erfasst.", + "submitted": "Fehlerbericht gesendet", + "failed": "Fehlerbericht konnte nicht gesendet werden", + "submit": "Senden" + }, + "auth": { + "signInTitle": "Willkommen zurück", + "signInSubtitle": "Melden Sie sich bei Ihrem Konto an", + "emailOrUsername": "E-Mail oder Benutzername", + "password": "Passwort", + "forgotPassword": "Passwort vergessen?", + "emailPlaceholder": "name@beispiel.de", + "passwordPlaceholder": "Ihr Passwort", + "forgotTitle": "Passwort vergessen", + "forgotSubtitle": "Geben Sie Ihre E-Mail-Adresse ein, um einen Link zum Zurücksetzen zu erhalten", + "email": "E-Mail", + "backToLogin": "Zurück zur Anmeldung", + "checkEmail": "Prüfen Sie Ihre E-Mails", + "checkEmailHint": "Klicken Sie darauf, um Ihr Passwort zurückzusetzen.", + "resetOk": "Passwort erfolgreich zurückgesetzt. Bitte melden Sie sich an.", + "verifying": "Wird überprüft…", + "invalidLink": "Ungültiger Link", + "invalidLinkHint": "Dieser Link zum Zurücksetzen ist ungültig oder abgelaufen.", + "resetTitle": "Passwort zurücksetzen", + "resetSubtitle": "Geben Sie Ihr neues Passwort ein", + "confirmPassword": "Passwort bestätigen", + "minChars": "Mindestens 12 Zeichen", + "confirmPlaceholder": "Bestätigen Sie Ihr Passwort", + "bootstrapTitle": "Willkommen, Administrator", + "bootstrapSubtitle": "Erstellen Sie Ihr Administratorkonto", + "name": "Name", + "username": "Benutzername", + "namePlaceholder": "Ihr Name", + "adminEmailPlaceholder": "admin@beispiel.de", + "bootstrapOk": "Administratorkonto erstellt. Bitte melden Sie sich an.", + "debug": { + "controls": "Steuerung:", + "camera": "Kamera:", + "model": "Modell:" + } + }, + "shortcuts": { + "navigation": "Navigation", + "spotlight": "Spotlight — zu jedem Bildschirm, Plugin oder jeder Einstellung per Namen springen", + "thisList": "Diese Liste", + "themes": "Designs", + "themesNote": "Der Browser wendet die Änderung an, während Sie sich bewegen, sodass Sie sehen, wie sich die App verändert, statt Namen zu lesen.", + "openBrowser": "Den Design-Browser öffnen", + "prevNextTheme": "Vorheriges / nächstes Design, ohne etwas zu öffnen", + "starCurrent": "Das aktuelle Design von überall markieren oder die Markierung aufheben", + "inBrowser": "Im Design-Browser", + "moveList": "Durch die Liste bewegen", + "applyKeepBrowsing": "Das fokussierte Design anwenden und weiter durchsuchen", + "restoreStart": "Das Design wiederherstellen, mit dem Sie begonnen haben", + "starFocused": "Das fokussierte Design markieren oder die Markierung aufheben", + "keepLooking": "Behalten, was Sie sich gerade ansehen", + "cancelRestore": "Abbrechen und wiederherstellen", + "inSpotlight": "In Spotlight", + "moveResults": "Durch die Ergebnisse bewegen", + "goThere": "Dorthin gehen", + "close": "Schließen", + "chat": "Chat", + "chatNote": "Der Verlaufsabruf reagiert nur bei LEEREM Eingabefeld auf die Pfeiltaste, und jede andere Taste beendet ihn — so wird ein Entwurf nie überschrieben.", + "prevNextPrompt": "Vorheriger / nächster gesendeter Prompt, wie in einer Shell", + "send": "Senden · bei leerem Eingabefeld mit etwas in der Warteschlange wird das jetzt gesendet", + "newline": "Zeilenumbruch", + "stopTurn": "Den gerade laufenden Turn stoppen" + }, + "jobs": { + "runningQueued": "In Ausführung und in Warteschlange", + "loading": "Wird geladen…", + "nothingRunning": "Nichts läuft", + "history": "Verlauf", + "clearAll": "Alles löschen", + "selectJob": "Wählen Sie einen Job aus", + "notFound": "Job nicht gefunden.", + "backToJobs": "Zurück zu den Jobs", + "stop": "Stopp", + "testNotification": "Eine Testbenachrichtigung an alle konfigurierten Kanäle senden", + "search": "Suchen…", + "deleteFinished": "Alle abgeschlossenen Jobs löschen", + "noChannels": "Keine Kanäle konfiguriert", + "notifyFailed": "Benachrichtigung konnte nicht gesendet werden", + "stopRequested": "Stopp angefordert", + "stopFailed": "Stopp fehlgeschlagen", + "titles": "Titel", + "download": "Herunterladen", + "input": "Eingabe", + "output": "Ausgabe", + "steps": "Schritte", + "selectStep": "Wählen Sie einen Schritt oder eine Unteraufgabe, um die Ausgabe anzuzeigen", + "noOutput": "Noch keine Ausgabe", + "tokens": "Tokens:", + "cost": "Kosten:", + "status": { + "running": "Läuft", + "queued": "In Warteschlange", + "completed": "Abgeschlossen", + "failed": "Fehlgeschlagen", + "stopped": "Gestoppt", + "interrupted": "Unterbrochen" + }, + "failedWithCode": "Fehlgeschlagen (Exit {{code}})" + }, + "activity": { + "title": "Aktivität", + "backgroundTasks": "Hintergrundaufgaben", + "detached": "Abgekoppelt", + "backToList": "Zurück zur Liste", + "selectTask": "Wählen Sie eine Aufgabe aus, um ihre Live-Ausgabe zu verfolgen", + "noneRunning": "keine läuft" + }, + "passkeyGate": { + "setUp": "Richten Sie Ihren Passkey ein" + }, + "chatHistory": { + "loadFailed": "Diese Unterhaltung konnte nicht geladen werden: {{reason}}" + }, + "capability": { + "frontmatter": "Frontmatter", + "noMatches": "Keine Treffer", + "emptyFile": "Leere Datei", + "createFailed": "{{kind}} konnte nicht erstellt werden", + "deleteFailed": "{{kind}} konnte nicht gelöscht werden", + "searchPlaceholder": "{{kind}} durchsuchen…", + "selectOne": "{{kind}} auswählen", + "selectToView": "{{kind}} auswählen, um den Inhalt anzuzeigen", + "delete": "Löschen", + "createPrompt": "Hilf mir, den Inhalt für diese neue {{kind}}-Datei zu erstellen", + "improvePrompt": "Hilf mir, diese {{kind}}-Datei zu verstehen und zu verbessern" + } +} diff --git a/src/apps/officer-web/locales/parity.test.ts b/src/apps/officer-web/locales/parity.test.ts index 9c43d3fd..7246352c 100644 --- a/src/apps/officer-web/locales/parity.test.ts +++ b/src/apps/officer-web/locales/parity.test.ts @@ -3,11 +3,12 @@ import { findMissingKeys } from 'i18n'; import en from './en-GB.json'; import ptPT from './pt-PT.json'; import frFR from './fr-FR.json'; +import deDE from './de-DE.json'; // D2: every shipped locale ships a COMPLETE catalog. A key en-GB has and another locale lacks is a red // build, not a warning — there is no regional fallback to paper over the gap. describe('officer-web (app.*) locale catalogs', () => { test('every shipped locale has every key en-GB has', () => { - expect(findMissingKeys(en, { 'pt-PT': ptPT, 'fr-FR': frFR })).toEqual([]); + expect(findMissingKeys(en, { 'pt-PT': ptPT, 'fr-FR': frFR, 'de-DE': deDE })).toEqual([]); }); }); diff --git a/src/workspaces/components/locales/de-DE.json b/src/workspaces/components/locales/de-DE.json new file mode 100644 index 00000000..1e4159ba --- /dev/null +++ b/src/workspaces/components/locales/de-DE.json @@ -0,0 +1,81 @@ +{ + "button": { + "cancel": "Abbrechen", + "confirm": "Bestätigen", + "ok": "OK", + "close": "Schließen" + }, + "search": { + "placeholder": "Suchen", + "open": "Suche öffnen", + "close": "Suche schließen", + "clear": "Suche leeren" + }, + "select": { + "placeholder": "Auswählen..." + }, + "tabs": { + "filterPlaceholder": "Filtern" + }, + "commandBlock": { + "run": "Im Terminal ausführen", + "copy": "Befehl kopieren" + }, + "colorPicker": { + "placeholder": "Hex-Farbe" + }, + "state": { + "loading": "Wird geladen…" + }, + "dataTable": { + "empty": "Keine Daten gefunden.", + "pagination": { + "showingPage": "Seite {{current}} von {{total}}", + "showingPageShort": "S. {{current}}/{{total}}", + "rowsPerPage": "Zeilen pro Seite", + "perPage": "{{size}} / Seite", + "perPageShort": "{{size}}/S.", + "first": "Erste", + "prev": "Zurück", + "next": "Weiter", + "last": "Letzte" + } + }, + "pagination": { + "label": "Seitennummerierung", + "previous": "Zurück", + "next": "Weiter", + "morePages": "Weitere Seiten", + "goToPrevious": "Zur vorherigen Seite", + "goToNext": "Zur nächsten Seite" + }, + "carousel": { + "previous": "Vorherige Folie", + "next": "Nächste Folie" + }, + "breadcrumb": { + "more": "Mehr" + }, + "theme": { + "toggle": "Farbmodus umschalten" + }, + "error": { + "forbidden": { + "title": "Zugriff nicht autorisiert", + "description": "Sie sind nicht berechtigt, diese Aktion auszuführen.", + "hint": "Wenn Sie das für einen Fehler halten, wenden Sie sich an Ihre zuständige Person." + }, + "unauthorized": { + "title": "Ungültige Anmeldedaten", + "description": "Ihr Zugriffstoken ist abgelaufen", + "hint": "Bitte melden Sie sich erneut an" + }, + "server": { + "title": "Serverfehler" + } + }, + "logo": { + "icon": "Officer-Symbol", + "logo": "Officer-Logo" + } +} diff --git a/src/workspaces/components/locales/parity.test.ts b/src/workspaces/components/locales/parity.test.ts index 655ed439..c7eac9a3 100644 --- a/src/workspaces/components/locales/parity.test.ts +++ b/src/workspaces/components/locales/parity.test.ts @@ -3,11 +3,12 @@ import { findMissingKeys } from 'i18n'; import en from './en-GB.json'; import ptPT from './pt-PT.json'; import frFR from './fr-FR.json'; +import deDE from './de-DE.json'; // D2: every shipped locale ships a COMPLETE catalog. A key en-GB has and another locale lacks is a red // build, not a warning — there is no regional fallback to paper over the gap. describe('shared components (ui.*) locale catalogs', () => { test('every shipped locale has every key en-GB has', () => { - expect(findMissingKeys(en, { 'pt-PT': ptPT, 'fr-FR': frFR })).toEqual([]); + expect(findMissingKeys(en, { 'pt-PT': ptPT, 'fr-FR': frFR, 'de-DE': deDE })).toEqual([]); }); }); diff --git a/src/workspaces/officerdev/src/locales/de-DE.json b/src/workspaces/officerdev/src/locales/de-DE.json new file mode 100644 index 00000000..d4f0e11c --- /dev/null +++ b/src/workspaces/officerdev/src/locales/de-DE.json @@ -0,0 +1,652 @@ +{ + "common": { + "save": "Speichern", + "delete": "Löschen" + }, + "minesweeper": { + "notInstalled": "Minesweeper ist auf diesem Server nicht installiert.", + "needs": "Es benötigt Wine, ein 32-Bit-Prefix und dieses Paket neben der Plattform:", + "notRunning": "Die Minesweeper-Sitzung läuft nicht.", + "error": { + "connectionFailed": "Die Verbindung zur Minesweeper-Sitzung ist fehlgeschlagen.", + "refused": "Der VNC-Server hat die Verbindung abgelehnt.", + "authUnsupported": "Der VNC-Server verlangt eine Authentifizierung, die dieser Client nicht unterstützt.", + "handshakeRejected": "Der VNC-Server hat den Handshake abgelehnt.", + "unknownMessage": "Der VNC-Server hat einen unbekannten Nachrichtentyp gesendet ({{type}}).", + "unknownEncoding": "Der VNC-Server hat die Kodierung {{encoding}} verwendet, die dieser Client nicht angefordert hat." + } + }, + "qrTransfer": { + "chooseFile": "Wählen Sie eine Datei zum Senden", + "startScanning": "Scannen starten", + "receiveAnother": "Weitere empfangen", + "stop": "Stopp" + }, + "dav": { + "empty": "Noch nichts hier. Fügen Sie eines von einem Telefon- oder Desktop-Client über CalDAV/CardDAV hinzu.", + "calendar": "Kalender", + "contacts": "Kontakte", + "readFailed": "{{name}} konnte nicht gelesen werden: {{reason}}" + }, + "terminal": { + "title": "Terminal", + "find": "Suchen", + "runningShells": "Laufende Shells", + "loading": "Wird geladen…", + "noShells": "Keine laufenden Shells.", + "refresh": "Aktualisieren", + "kill": "Diese Shell beenden" + }, + "appStore": { + "loading": "Wird geladen", + "loadFailed": "Der App Store konnte nicht geladen werden.", + "installed": "Installiert", + "available": "Verfügbar", + "needsYou": "Braucht Sie", + "needsYouShort": "braucht Sie", + "selectApp": "Wählen Sie eine App aus", + "installFailed": "Installation fehlgeschlagen", + "uninstall": "Deinstallieren", + "enable": "Aktivieren", + "disable": "Deaktivieren", + "enabled": "aktiviert", + "disabled": "deaktiviert", + "removalNote": "Deaktivieren stoppt den Sidecar und seinen Container. Deinstallieren entfernt auch die Container — Ihre Daten, die Konfiguration und die Tabellen dieser App bleiben in beiden Fällen erhalten.", + "installing": "wird installiert", + "failed": "fehlgeschlagen", + "installedIcon": "installiert" + }, + "systemMonitor": { + "cpuPackage": "CPU-Paket", + "user": "Benutzer", + "cpuPct": "CPU%", + "memPct": "MEM%", + "command": "Befehl", + "memory": "Arbeitsspeicher", + "disks": "Laufwerke", + "temperature": "Temperatur", + "network": "Netzwerk", + "power": "Energie", + "topProcesses": "Top-Prozesse", + "filterPlaceholder": "nach Name oder Image filtern…", + "name": "Name", + "status": "Status", + "mem": "Mem", + "uptime": "Laufzeit", + "scopeDockers": "dockers" + }, + "codeEditor": { + "closeFile": "{{name}} schließen", + "loading": "Wird geladen…", + "noFiles": "Keine Dateien", + "explorer": "Explorer", + "openAFile": "Öffnen Sie eine Datei im Explorer, um mit dem Bearbeiten zu beginnen", + "refresh": "Baum aktualisieren und unveränderte geöffnete Dateien neu laden", + "readFailed": "Datei konnte nicht gelesen werden", + "saved": "Datei gespeichert", + "saveFailed": "Datei konnte nicht gespeichert werden", + "title": "Code-Editor" + }, + "widgets": { + "resync": "Widgets neu synchronisieren (neu laden, um neu bereitgestellte Widgets zu übernehmen)" + }, + "preview": { + "title": "Vorschau", + "reload": "Neu laden", + "changeUrl": "URL ändern", + "openNewTab": "In neuem Tab öffnen", + "pointAtApp": "Dieses Panel auf eine laufende App richten", + "open": "Öffnen", + "hint": "Alles, was der Browser erreichen kann. Bleibt in diesem Panel erhalten und übersteht ein Neuladen.", + "connecting": "Verbindung wird hergestellt…" + }, + "sendOff": { + "files": "Dateien", + "where": "Wohin", + "loading": "Wird geladen…", + "landsIn": "Landet in deren", + "landedIn": "Gelandet in", + "whoMaySend": "Wer mir senden darf", + "allowedLandIn": "Dateien von allen, die Sie zulassen, landen in", + "removeFile": "{{name}} entfernen", + "sendTo": "An {{name}} senden", + "turningOff": "Jemanden abzuschalten verhindert künftige Sendungen und lässt in Ruhe, was bereits gesendet wurde." + }, + "panelName": { + "appStore": "App Store", + "appDetail": "App-Detail", + "calendar": "Kalender", + "contacts": "Kontakte", + "categories": "Kategorien", + "chat": "Chat", + "chatSessions": "Sitzungen", + "codeEditor": "Code-Editor", + "commander": "Commander", + "commanders": "Commander", + "dashboardPreview": "Dashboard-Vorschau", + "dashboards": "Dashboards", + "fileBrowser": "Dateibrowser", + "pluginDetail": "Plugin-Detail", + "plugins": "Plugins", + "preview": "Vorschau", + "qrReceive": "QR-Empfang", + "qrSend": "QR-Versand", + "scope": "Bereich", + "systemMonitor": "Systemmonitor", + "widgets": "Widgets", + "terminal": "Terminal", + "hostTerminal": "Host-Terminal", + "runningShells": "Laufende Shells", + "pm2Processes": "pm2-Prozesse" + }, + "dashboards": { + "title": "Dashboards", + "new": "Neues Dashboard", + "delete": "Dashboard löschen", + "confirmDelete": "Sind Sie sicher, dass Sie löschen möchten", + "search": "Dashboards durchsuchen", + "name": "Name", + "description": "Beschreibung", + "open": "Dashboard öffnen", + "selectOne": "Wählen Sie ein Dashboard aus oder erstellen Sie ein neues", + "namePlaceholder": "Mein Dashboard", + "descriptionPlaceholder": "Wofür ist dieses Dashboard?", + "template": "Vorlage", + "create": "Erstellen", + "templates": { + "single": "Einzeln", + "twoColumns": "2 Spalten", + "mainSide": "Haupt + Seite", + "sidebar": "Seitenleiste", + "grid": "2x2-Raster", + "colsBottom": "Spalten + Unten" + } + }, + "fileViewer": { + "readAloud": "Vorlesen", + "ocr": "Text extrahieren (OCR)", + "transcribe": "Transkribieren", + "extractAudio": "Audio extrahieren", + "extract": "Extrahieren", + "saveNextTo": "Neben dem Original speichern", + "download": "Herunterladen", + "pdfViewer": "PDF-Betrachter", + "videoFailed": "Video konnte nicht geladen werden", + "imageFailed": "Bild konnte nicht geladen werden", + "audioFailed": "Audiodatei konnte nicht geladen werden", + "audioTrack": "Audiospur", + "subtitles": "Untertitel", + "track": "Spur {{n}}", + "saved": "Datei gespeichert", + "saveFailed": "Datei konnte nicht gespeichert werden", + "scrollTop": "Nach oben scrollen", + "speechFailed": "Sprachaudio konnte nicht erzeugt werden", + "ocrFailed": "Text konnte nicht aus dem Bild extrahiert werden", + "transcribeFailed": "Audio konnte nicht transkribiert werden", + "extractAudioFailed": "Audio konnte nicht aus dem Video extrahiert werden", + "extractFailed": "Archiv konnte nicht extrahiert werden", + "savedAs": "Gespeichert als “{{name}}”", + "extractedTo": "Extrahiert nach “{{name}}”", + "downloadInstead": "Stattdessen herunterladen", + "archiveFile": "Archivdatei" + }, + "plugins": { + "loading": "Wird geladen…", + "onThisMachine": "Auf diesem Rechner", + "noPluginsIn": "Keine Plugins in", + "available": "Verfügbar", + "needsOnThisMachine": "Benötigt auf diesem Rechner", + "install": "Installieren", + "clonesInto": "Klont das Repository nach", + "deleteData": "Auch alle zugehörigen Daten löschen", + "noTables": "Dieses Plugin deklariert keine Tabellen, daher gibt es keine Daten zu behalten.", + "selectOne": "Wählen Sie ein Plugin aus.", + "disable": "Deaktivieren", + "enable": "Aktivieren", + "publisher": "Herausgeber", + "version": "Version", + "needsPlatform": "Benötigt Plattform", + "wouldMount": "Würde einbinden", + "ships": "Enthält", + "permissions": "Berechtigungen", + "source": "Quelle", + "mountsAt": "Bindet ein unter", + "sidecar": "Sidecar", + "deleteNamed": "{{name}} löschen", + "updateTo": "Auf {{version}} aktualisieren" + }, + "commandHq": { + "selectOne": "Wählen Sie einen Commander aus oder starten Sie einen neuen.", + "startConversation": "Unterhaltung starten", + "name": "Name", + "nameHint": "Wird der Unterhaltung bei ihrem Start zugewiesen, statt sie vom Harness anhand Ihrer ersten Nachricht benennen zu lassen.", + "workingDirectory": "Arbeitsverzeichnis", + "cwdHint": "Von hier aus werden alle ausgeführten Befehle aufgelöst, und hier wird der Verlauf gespeichert. Kann später nicht verschoben werden.", + "new": "Neuer Commander", + "spawned": "Gestartet", + "deleteQ": "Löschen?", + "uncategorised": "Nicht kategorisiert", + "loading": "Wird geladen…", + "platformDeploys": "Plattform-Deployments", + "endSession": "Sitzung beenden — gibt sie frei, damit sie andernorts fortgesetzt werden kann", + "confirmDeleteHint": "Löschen bestätigen — entfernt auch die Unterhaltung, nicht nur den Command-HQ-Eintrag", + "confirmDelete": "Löschen bestätigen", + "cancelDelete": "Löschen abbrechen", + "deleteCommander": "Commander löschen", + "none": "Noch keine Commander hier.", + "startOne": "Einen starten", + "confirmDeleteNamed": "Löschen von {{name}} bestätigen", + "deleteNamed": "{{name}} löschen", + "categories": "Kategorien", + "noCategories": "Noch keine Kategorien", + "newCategory": "Neue Kategorie", + "allCommanders": "Alle Commander", + "categoryName": "Kategoriename", + "guide": { + "whatIsIt": "Was ein Commander ist", + "starting": "Einen starten", + "examples": "Beispiele für eine erste Nachricht", + "whileRunning": "Während er läuft", + "whatIsItBody1": "Ein Agent, der weiterarbeitet, wenn Sie nicht hier sind — er wartet, bis etwas passiert, handelt danach und meldet zurück.", + "whatIsItBody2": "Es ist eine ganz normale Unterhaltung. Sie beginnen, indem Sie ihm in eigenen Worten sagen, worauf er achten und was er dabei tun soll.", + "startingBody1": "Beschreiben Sie hier die Aufgabe, wie Sie es jedem anderen erklären würden. Sagen Sie, worauf er achten soll, wo, und was zu tun ist, wenn es eintritt.", + "startingBody2": "TODO: die konkreten Schritte, sobald der Erstellungsablauf feststeht. Dies ersetzt “den Dialog für Hintergrundjobs öffnen und einen Beobachter scharfschalten”, was niemand hätte erraten können.", + "examplesBody1": "TODO: zwei oder drei Beispiele für Eröffnungs-Prompts, sobald der Erstellungsablauf feststeht. Sie sind es, die aus “die Aufgabe beschreiben” eine Anweisung machen, nach der ein Erstnutzer tatsächlich handeln kann.", + "whileRunningBody1": "TODO: was der Eigentümer sieht — wo die Kosten angezeigt werden, wie man erkennt, was die von ihm gestarteten Agenten gerade tun, und wie man ihn stoppt.", + "draft": "Entwurf" + }, + "startHint": "Er sieht sich zunächst in diesem Verzeichnis um und fragt Sie dann, worauf Sie achten möchten.", + "startBlocked": "{{missing}} — dann startet dies ihn.", + "confirmDeletingNamed": "Löschen von {{name}} bestätigen" + }, + "chatHistory": { + "newChat": "Neuer Chat", + "tryAgain": "Erneut versuchen", + "refresh": "Aktualisieren", + "refreshSessions": "Sitzungen aktualisieren", + "newChatInDir": "Neuer Chat in einem Verzeichnis…", + "loadFailed": "Sitzungen konnten nicht geladen werden", + "reading": "Transkripte werden gelesen…", + "noSessions": "Noch keine Sitzungen", + "liveFailed": "Aktive Sitzungen konnten nicht gelesen werden", + "asking": "Der Agent wird gefragt…", + "tabs": { + "tree": "Baum", + "latest": "Neueste", + "live": "Aktiv", + "agents": "Agenten", + "commanders": "Commander" + }, + "notifyPreference": "Benachrichtigungseinstellung", + "notify": { + "everyTurn": "Nach jedem Turn", + "inputNeeded": "Nur wenn eine Eingabe nötig ist", + "none": "Keine" + }, + "notificationsLabel": "Benachrichtigungen: {{choice}}", + "chooseDir": "Wählen Sie ein Arbeitsverzeichnis", + "create": "Erstellen", + "newFolder": "Neuer Ordner", + "selectFolder": "Diesen Ordner auswählen", + "newFolderName": "Name des neuen Ordners", + "noSubfolders": { + "one": "Keine sichtbaren Unterordner — {{count}} versteckter wird herausgefiltert", + "other": "Keine sichtbaren Unterordner — {{count}} versteckte werden herausgefiltert" + }, + "showHidden": "Versteckte anzeigen", + "showHiddenCount": "Versteckte anzeigen ({{count}})", + "selectSession": "Wählen Sie eine Sitzung zum Anzeigen", + "endSession": "Sitzung beenden — beendet jeden laufenden Turn und gibt sie frei, damit sie andernorts fortgesetzt werden kann", + "noReadable": "Keine lesbaren Unterhaltungen hier.", + "noConversations": "Noch keine Unterhaltungen", + "newChatIn": "Neuer Chat in {{path}}", + "sessionTitle": "Sitzungstitel", + "saveTitle": "Titel speichern", + "cancelRename": "Umbenennen abbrechen", + "confirmDelete": "Löschen bestätigen", + "cancelDelete": "Löschen abbrechen", + "rename": "Umbenennen", + "deleteSession": "Sitzung löschen", + "renameFailed": "Die Sitzung konnte nicht umbenannt werden: {{reason}}", + "deleteFailed": "Die Sitzung konnte nicht gelöscht werden: {{reason}}", + "deleteAll": "Alle {{count}} löschen?", + "confirmDeletingNamed": "Löschen von {{name}} bestätigen", + "renameNamed": "{{name}} umbenennen", + "deleteNamed": "{{name}} löschen", + "newChatTitle": "Neuer Chat", + "renameHint": "Klicken, um diesen Chat umzubenennen", + "hideHidden": "Versteckte ausblenden" + }, + "chat": { + "newChat": "Neuer Chat", + "rename": "Umbenennen", + "deleteQ": "“{{title}}” löschen?", + "duplicateAgent": "Es gibt bereits einen Agenten namens “{{name}}” auf diesem Dashboard", + "composerPlaceholder": "Woran möchten Sie jetzt arbeiten?", + "turnFinished": "Turn beendet · keine Abschlussnachricht", + "job": { + "title": "Hintergrundjob", + "runsIn": "Läuft in", + "command": "Befehl — genau das ausführen", + "prompt": "Prompt — beschreiben Sie es, der Agent findet den Weg", + "watch": "Auf etwas achten", + "watchHint": "In freiem Text. Der Agent fragt vor dem Scharfschalten nach, wenn etwas unklar ist.", + "handBack": "Beenden und an den Agenten zurückgeben, dann erneut scharfschalten", + "keepGoing": "Weitermachen — jedes Mal handeln und fortfahren", + "stopAfter": "Stoppen nach", + "start": "Starten", + "watchExample": "unsere Gitea-Repositories beobachten; bei jedem neuen Push, ihn holen und zum GitHub-Spiegel pushen", + "startJob": "Einen Hintergrundjob oder Beobachter starten" + }, + "tasks": { + "restart": "Neu starten", + "pinned": "Angeheftet", + "clearFinished": "Alle abgeschlossenen löschen", + "clearFinishedTasks": "Alle abgeschlossenen Aufgaben löschen", + "stopJob": "Diesen Job stoppen", + "dismiss": "Verwerfen", + "rerun": "Stoppen und denselben Befehl erneut ausführen", + "collapse": "Einklappen", + "collapseDetail": "Aufgabendetail einklappen", + "stopNamed": "{{label}} stoppen", + "dismissNamed": "{{label}} verwerfen", + "status": "Aufgabe {{status}}." + }, + "usage": { + "noSignIn": "Keine gespeicherte Anmeldung — führen Sie /login aus, um diese zu verwenden", + "updating": "Wird aktualisiert…", + "unreadable": "Die Nutzung auf diesem Rechner konnte nicht gelesen werden.", + "loading": "Wird geladen…", + "limits": "Limits", + "byDay": "Tokens pro Tag", + "byModel": "Tokens pro Modell", + "title": "Nutzung und Limits", + "modelBreakdown": "Ein {{input}} · aus {{output}} · Cache-Lesevorgänge {{cacheRead}} · Cache-Schreibvorgänge {{cacheWrite}}", + "switchTo": "Zu {{account}} wechseln", + "switchToOrg": "Zu {{account}} ({{org}}) wechseln", + "signInExpired": "{{account}} — Anmeldung abgelaufen, führen Sie /login aus" + }, + "attach": { + "image": "Bild", + "textFile": "Textdatei", + "webpageUrl": "Webseiten-URL", + "attach": "Anhängen", + "readFailed": "{{name}} konnte nicht gelesen werden: {{reason}}", + "unknownError": "unbekannter Fehler", + "webpageTitle": "Webseite anhängen", + "webpageHint": "Geben Sie eine URL ein, um sie abzurufen und als Kontext anzuhängen.", + "scrapeFailed": "Webseite konnte nicht abgerufen werden", + "uploadFailed": "Bild konnte nicht hochgeladen werden", + "dropImages": "Bilder hier ablegen, um sie anzuhängen" + }, + "signIn": { + "title": "Bei Claude anmelden", + "done": "Angemeldet. Neue Turns verwenden diese Anmeldedaten — kein Neustart nötig.", + "asking": "Die CLI wird nach einem Anmeldelink gefragt…", + "openHint": "Öffnen Sie diesen, autorisieren Sie, und fügen Sie den erhaltenen Code wieder ein.", + "authorise": "Auf claude.com autorisieren", + "copyLink": "Den Link kopieren, um ihn in einem anderen Browser oder auf dem Smartphone zu öffnen", + "pasteCode": "den Code einfügen" + }, + "message": { + "copyCode": "Den Code kopieren", + "copyMarkdown": "Als Markdown-Block kopieren", + "showMore": "Mehr anzeigen ({{count}} weitere Zeilen)", + "subagent": "Subagent", + "outputError": "Ausgabe — Fehler", + "contextCleared": "Kontext geleert — nichts davor ist noch im Gedächtnis", + "interrupted": "Vom Benutzer unterbrochen", + "agentRestarted": "Agent neu gestartet — Turn abgebrochen", + "retry": "Erneut versuchen", + "planUnchanged": "Planmodus unverändert", + "approve": "Genehmigen", + "frontmatter": "Frontmatter", + "systemPrompt": "System-Prompt", + "reviseHint": "Was soll sich ändern? Der Agent überarbeitet den Plan auf dieser Grundlage.", + "waiting": "Wartet auf eine Antwort", + "narrationFailed": "Die Sprachausgabe wurde erzeugt, ließ sich aber nicht abspielen.", + "readAloudFailed": "Diese Nachricht konnte nicht vorgelesen werden: {{reason}}", + "compacted": "Kontext komprimiert", + "compactedAuto": "Kontext automatisch komprimiert", + "answerSent": "Antwort gesendet — wartet auf den Agenten", + "other": "Andere..." + }, + "composer": { + "stop": "Stopp", + "sendIntoTurn": "In den bereits laufenden Turn einfügen", + "removeFromQueue": "Aus der Warteschlange entfernen", + "send": "Senden", + "startHint": "Senden Sie eine Nachricht, um zu beginnen", + "jumpToLatest": "Zur neuesten Nachricht springen", + "noAudio": "Es wurde kein Audio aufgenommen" + }, + "agent": { + "gone": "Der Agent dieses Panels existiert nicht mehr.", + "forget": "Vergessen", + "name": "Diesen Agenten benennen", + "peers": "Peers: {{names}}" + }, + "copy": "Kopieren" + }, + "files": { + "folderGone": "Dieser Ordner existiert nicht mehr — zurück zum Anfang", + "searchFailed": "Suche fehlgeschlagen", + "createFolderFailed": "Ordner konnte nicht erstellt werden", + "createFileFailed": "Datei konnte nicht erstellt werden", + "uploadFailed": "Dateien konnten nicht hochgeladen werden", + "renameFailed": "Umbenennen fehlgeschlagen", + "deleteFailed": "Löschen fehlgeschlagen", + "deleteSomeFailed": "Einige Elemente konnten nicht gelöscht werden", + "downloadFailed": "Herunterladen fehlgeschlagen", + "pathCopied": "Pfad kopiert", + "generatingSpeech": "Sprachaudio wird erzeugt…", + "speechFailed": "Sprachaudio konnte nicht erzeugt werden", + "extracting": "Archiv wird extrahiert…", + "extractFailed": "Archiv konnte nicht extrahiert werden", + "cloned": "Repository geklont", + "cloneFailed": "Repository konnte nicht geklont werden", + "cloning": "Wird geklont…", + "duplicateFailed": "Duplizieren fehlgeschlagen", + "compressing": "Wird komprimiert…", + "compressFailed": "Komprimieren fehlgeschlagen", + "pasteFailed": "Einfügen fehlgeschlagen", + "pasteNeedsSecure": "Einfügen aus der Zwischenablage erfordert einen sicheren Kontext (https). Ziehen Sie die Datei stattdessen per Drag-and-Drop hierher.", + "copiedItems": { + "one": "{{count}} Element kopiert", + "other": "{{count}} Elemente kopiert" + }, + "cutItems": { + "one": "{{count}} Element ausgeschnitten", + "other": "{{count}} Elemente ausgeschnitten" + }, + "pastedItems": { + "one": "{{count}} Element eingefügt", + "other": "{{count}} Elemente eingefügt" + }, + "uploadedFiles": { + "one": "{{count}} Datei hochgeladen", + "other": "{{count}} Dateien hochgeladen" + }, + "deleteItemsQ": { + "one": "{{count}} Element löschen?", + "other": "{{count}} Elemente löschen?" + }, + "deletedItems": { + "one": "{{count}} Element gelöscht", + "other": "{{count}} Elemente gelöscht" + }, + "createdFolder": "Ordner “{{name}}” erstellt", + "created": "“{{name}}” erstellt", + "renamedTo": "Umbenannt in “{{name}}”", + "deleteQ": "“{{name}}” löschen?", + "deleted": "“{{name}}” gelöscht", + "extractedTo": "Extrahiert nach “{{name}}”", + "duplicated": "“{{name}}” dupliziert", + "pastedInto": "Eingefügt in “{{name}}”", + "unpinned": "“{{name}}” nicht mehr angeheftet", + "pinned": "“{{name}}” angeheftet", + "menu": { + "copyPath": "Pfad kopieren", + "chatAboutThis": "Darüber chatten", + "paste": "Einfügen", + "newFile": "Neue Datei", + "newFolder": "Neuer Ordner", + "uploadFiles": "Dateien hochladen", + "uploadFolder": "Ordner hochladen", + "cloneRepository": "Repository klonen", + "hideHiddenFiles": "Versteckte Dateien ausblenden", + "showHiddenFiles": "Versteckte Dateien anzeigen", + "createDashboardHere": "Dashboard hier erstellen", + "downloadVideo": "Video herunterladen", + "dictate": "Diktieren", + "dropToUpload": "Dateien hier ablegen, um sie hochzuladen", + "openFolder": "Ordner öffnen", + "showLocation": "Speicherort anzeigen", + "download": "Herunterladen", + "noResults": "Keine Ergebnisse gefunden", + "open": "Öffnen", + "openInEditor": "Im Editor öffnen", + "openInEditorTooLarge": "Im Editor öffnen (zu groß)", + "pasteIntoFolder": "In Ordner einfügen", + "readAloud": "Vorlesen", + "extract": "Extrahieren", + "runTask": "Aufgabe ausführen", + "runAgent": "Agent ausführen", + "cut": "Ausschneiden", + "copy": "Kopieren", + "duplicate": "Duplizieren", + "rename": "Umbenennen", + "compress": "Komprimieren", + "compressSelection": "Auswahl komprimieren", + "unpin": "Loslösen", + "pin": "Anheften", + "chat": "Chat...", + "delete": "Löschen", + "gitClone": "Git-Klon", + "searchFiles": "Dateien durchsuchen...", + "clearSelection": "Auswahl aufheben", + "selected": "ausgewählt", + "refresh": "Aktualisieren" + }, + "grid": { + "empty": "Dieser Ordner ist leer", + "sort": "Sortieren:", + "name": "Name", + "type": "Typ", + "size": "Größe", + "date": "Datum" + } + }, + "taskRunner": { + "stop": "Stopp", + "taskFailed": "Aufgabe fehlgeschlagen", + "taskComplete": "Aufgabe abgeschlossen", + "noSubtitles": "Keine Untertitel", + "none": "Keine", + "noVideos": "In diesem Ordner wurden keine Videos gefunden.", + "differentLayout": "Unterschiedliches Layout — diese separat ausführen:", + "skipped": "Übersprungen (separat konvertieren):", + "analyzing": "Dateien werden analysiert…", + "close": "Schließen", + "runningOn": "Läuft auf", + "queue": "Warteschlange", + "concurrency": "Parallelität", + "model": "Modell", + "steps": "Schritte", + "stopPipeline": "Pipeline stoppen", + "pipelineFailed": "Pipeline fehlgeschlagen", + "pipelineComplete": "Pipeline abgeschlossen", + "viewInJobs": "In Jobs anzeigen", + "copyOutput": "Ausgabe kopieren", + "track": "Spur {{n}}", + "runFromStep": "Ab Schritt {{n}} ausführen" + }, + "newEntry": { + "nameReserved": "Dieser Name ist reserviert", + "nameSlash": "Der Name darf kein \"/\" enthalten", + "nameExists": "“{{name}}” existiert hier bereits", + "urlSpaces": "Eine URL darf keine Leerzeichen enthalten", + "cancel": "Abbrechen", + "file": { + "title": "Neue Datei", + "description": "Geben Sie die Dateiendung an — anhand dieser wählt der Editor die Sprache. Öffnet sich, sobald sie erstellt ist.", + "label": "Dateiname", + "placeholder": "notizen.txt", + "submit": "Erstellen und öffnen" + }, + "folder": { + "title": "Neuer Ordner", + "description": "Wird im aktuell angezeigten Ordner erstellt.", + "label": "Ordnername", + "placeholder": "dokumente", + "submit": "Ordner erstellen" + }, + "clone": { + "title": "Repository klonen", + "description": "Wird unter eigenem Namen in den aktuell angezeigten Ordner geklont.", + "label": "Repository-URL", + "placeholder": "https://github.com/owner/repo.git", + "submit": "Klonen" + } + }, + "videoDownload": { + "title": "Video herunterladen", + "descriptionInput": "Fügen Sie eine Video- oder Playlist-URL ein — die Details werden vor dem Herunterladen abgerufen.", + "descriptionPreview": "Überprüfen und herunterladen.", + "urlPlaceholder": "https://www.youtube.com/watch?v=… oder …/playlist?list=…", + "audioOnly": "Nur Audio extrahieren (mp3)", + "fetch": "Abrufen", + "back": "Zurück", + "audioOnlyLabel": "Nur Audio", + "video": "Video", + "itemCount": { + "one": "{{count}} Element", + "other": "{{count}} Elemente" + }, + "subfolderPlaceholder": "Unterordner (optional) — leer lassen für diesen Ordner", + "downloadAll": "Alle herunterladen", + "couldNotFetch": "Abrufen nicht möglich", + "downloading": "Wird heruntergeladen…", + "saving": "Wird gespeichert…", + "saved": "Gespeichert", + "retry": "Erneut versuchen", + "download": "Herunterladen", + "couldNotFetchInfo": "Informationen konnten nicht abgerufen werden", + "timedOut": "Zeitüberschreitung", + "downloadFailed": "Herunterladen fehlgeschlagen", + "couldNotStart": "Der Download konnte nicht gestartet werden" + }, + "fileBrowserWidget": { + "title": "Dateibrowser", + "search": "Suchen...", + "browse": "Durchsuchen", + "recent": "Zuletzt verwendet", + "pinned": "Angeheftet", + "noResults": "Keine Ergebnisse", + "emptyDirectory": "Leeres Verzeichnis", + "noPinnedFiles": "Keine angehefteten Dateien", + "noRecentFiles": "Keine kürzlich verwendeten Dateien", + "uploading": "Wird hochgeladen...", + "empty": "Dieser Ordner ist leer", + "sort": "Sortieren:" + }, + "agentRunner": { + "agentRunning": "Agent läuft", + "keepsGoing": "Läuft weiter, egal ob dieses Fenster geöffnet bleibt. Verfolgen Sie ihn im Chat — die neueste Sitzung steht oben.", + "openChat": "Chat öffnen", + "target": "Ziel", + "starting": "Wird gestartet…", + "runAgent": "Agent ausführen", + "startFailed": "Der Agent konnte nicht gestartet werden" + }, + "dictate": { + "title": "Diktieren", + "description": "Audio wird aufgenommen. Drücken Sie Enter oder klicken Sie auf Stopp, um zu speichern.", + "recording": "Wird aufgenommen...", + "startingStatus": "Wird gestartet...", + "stopSave": "Stoppen & Speichern", + "noAudioCaptured": "Es wurde kein Audio aufgenommen", + "micAccessFailed": "Zugriff auf das Mikrofon nicht möglich", + "recordingFailed": "Aufnahme fehlgeschlagen" + } +} diff --git a/src/workspaces/officerdev/src/locales/parity.test.ts b/src/workspaces/officerdev/src/locales/parity.test.ts index 008e8a60..147995fb 100644 --- a/src/workspaces/officerdev/src/locales/parity.test.ts +++ b/src/workspaces/officerdev/src/locales/parity.test.ts @@ -3,11 +3,12 @@ import { findMissingKeys } from 'i18n'; import en from './en-GB.json'; import ptPT from './pt-PT.json'; import frFR from './fr-FR.json'; +import deDE from './de-DE.json'; // D2: every shipped locale ships a COMPLETE catalog. A key en-GB has and another locale lacks is a red // build, not a warning — there is no regional fallback to paper over the gap. describe('officerdev (panel.*) locale catalogs', () => { test('every shipped locale has every key en-GB has', () => { - expect(findMissingKeys(en, { 'pt-PT': ptPT, 'fr-FR': frFR })).toEqual([]); + expect(findMissingKeys(en, { 'pt-PT': ptPT, 'fr-FR': frFR, 'de-DE': deDE })).toEqual([]); }); });