From ad8e352ad8b34bf48353381cf576a0bb4e71db52 Mon Sep 17 00:00:00 2001 From: Mario Soller <100125192+Mario-Soller@users.noreply.github.com> Date: Tue, 15 Sep 2026 11:21:08 +0200 Subject: [PATCH 1/2] feat: add German (de) locale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translates all 979 keys across the seven namespaces and registers `de` everywhere a locale list is read: SUPPORTED_LOCALES, the main process mini-i18n (menus, tray, native dialogs), the appx language list, and the static dialogs map in the tutorial-help test. The folder is the bare tag `de`, so the renderer's base-language matching in I18nContext routes de-DE, de-AT and de-CH to it. German-specific choices worth knowing when reviewing: - Du-Form throughout; buttons and menu commands use the infinitive, section headings are nouns. - No article before a placeholder whose gender is unknown at translation time — "{{format}} ist fertig", "Attribute von {{region}} kopiert", "Bereits belegt von „{{action}}“" — because format, region and action are substituted at runtime. - The dialogs.tutorial.* fragments are re-cut rather than translated slot-for-slot: German puts the participle last, so "abgedeckt" moves ahead of the clause-final verb while the surrounding fragments keep the exact leading/trailing spaces the JSX relies on. - effects.fitClipFew is unreachable for German (Intl.PluralRules has only one/other) but is filled in for key parity. - Typographic quotes „…“ everywhere, so no value carries a straight quote; brand and format tokens stay verbatim. README and AGENTS.md list Czech too — it was added but never listed. Co-Authored-By: Claude Opus 5 --- AGENTS.md | 4 +- README.md | 2 +- electron-builder.json5 | 3 +- electron/i18n.ts | 5 + .../ai-edition/RightPanes.i18n.test.tsx | 8 + .../tutorialHelpTranslations.test.ts | 2 + src/i18n/config.ts | 1 + src/i18n/locales/de/common.json | 74 ++++ src/i18n/locales/de/dialogs.json | 92 ++++ src/i18n/locales/de/editor.json | 404 ++++++++++++++++++ src/i18n/locales/de/launch.json | 99 +++++ src/i18n/locales/de/settings.json | 361 ++++++++++++++++ src/i18n/locales/de/shortcuts.json | 43 ++ src/i18n/locales/de/timeline.json | 108 +++++ 14 files changed, 1202 insertions(+), 4 deletions(-) create mode 100644 src/i18n/locales/de/common.json create mode 100644 src/i18n/locales/de/dialogs.json create mode 100644 src/i18n/locales/de/editor.json create mode 100644 src/i18n/locales/de/launch.json create mode 100644 src/i18n/locales/de/settings.json create mode 100644 src/i18n/locales/de/shortcuts.json create mode 100644 src/i18n/locales/de/timeline.json diff --git a/AGENTS.md b/AGENTS.md index 028be56a0..ad5157146 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,7 +12,7 @@ OpenScreen is a free, open-source screen recorder and video editor (Electron + R - Test (e2e): `npm run test:e2e` (Playwright) - Lint: `npm run lint` (Biome 2.4) - Format: `npm run format` (Biome, tabs, double quotes, 100-col) -- i18n check: `npm run i18n:check` (validates the 13 locale files) +- i18n check: `npm run i18n:check` (validates the 15 locale folders) **Use npm, not bun/pnpm/yarn/Deno.** Not a style preference. Node native modules are rebuilt against Electron's ABI by electron-builder + `@electron/rebuild`, which resolve the tree through `package-lock.json`. Another package manager writes a different lockfile, so that rebuild breaks. `packageManager` + `engines` in `package.json` pin the versions; CI installs with `npm ci`. Note what this does *not* cover: the standalone Swift (macOS) and C++ (Windows) capture helpers are separate executables, built by `npm run build:native:` and only *copied* into the package as `extraResources` — `build:win` even passes `--config.npmRebuild=false`. Nothing in a normal build compiles them. @@ -165,6 +165,6 @@ The one rule to know before you merge anything: **there is one release branch pe - **Native capture is platform-fragile**: macOS uses ScreenCaptureKit (Swift), Windows uses WGC (C++/Win32). CI runs on Linux only — manual smoke test on real macOS/Windows is required for native changes. - **Pixi.js v8** is the rendering engine. Filters come from `pixi-filters` and `@pixi/filter-drop-shadow`. GSAP + `motion` for animation. -- **i18n**: 13 locales in `src/i18n/locales//` (e.g. `src/i18n/locales/en/settings.json`). The `i18n:check` script validates them — run it after touching translation files. +- **i18n**: 15 locales in `src/i18n/locales//` (e.g. `src/i18n/locales/en/settings.json`). The `i18n:check` script validates them — run it after touching translation files. - **Build pipeline**: `npm run build` is full electron-builder. For iterating on renderer only, use `npm run build-vite` (Vite + tsc, no packaging). - **Product constraints**: the project is free forever and explicitly "not production-grade". Don't add paywalls, premium tiers, or logic that gates a feature on who the user is, and don't add upsell language to the README or UI copy. This is a hard constraint, not a judgement call. (A flag that hides an unfinished capture backend is fine — it gates on readiness, not on the user.) diff --git a/README.md b/README.md index c42587cb4..ab549f349 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ A raw capture goes in and comes out ready to post — on X, Reddit, YouTube, a d - Timeline snapping guides and an audio waveform to make trimming easier. - Customizable keyboard shortcuts. - Export to MP4 or GIF in multiple aspect ratios and resolutions, rendered and encoded on the GPU (Metal on macOS, D3D11 on Windows, Vulkan on Linux) with an automatic CPU fallback. -- Languages supported: Arabic, English, Spanish, French, Italian, Japanese, Korean, Portuguese (Brazil), Russian, Turkish, Vietnamese, Simplified Chinese, and Traditional Chinese. +- Languages supported: Arabic, Czech, English, Spanish, French, German, Italian, Japanese, Korean, Portuguese (Brazil), Russian, Turkish, Vietnamese, Simplified Chinese, and Traditional Chinese. ## Command-line interface (headless) diff --git a/electron-builder.json5 b/electron-builder.json5 index adf69f819..329592d3a 100644 --- a/electron-builder.json5 +++ b/electron-builder.json5 @@ -405,13 +405,14 @@ // Mirrors SUPPORTED_LOCALES in src/i18n/config.ts. This list is what the Store // shows as "supported languages" on the product page and what lets the listing // surface in each language's Store search — declaring only en-US/fr-FR advertised - // 2 of the 14 languages the app actually ships. Bare tags (ar, es, ...) match every + // 2 of the 15 languages the app actually ships. Bare tags (ar, es, ...) match every // region of that language, which is what the renderer's locale resolution does too. "languages": [ "en-US", "fr-FR", "ar", "cs", + "de", "es", "it", "ja-JP", diff --git a/electron/i18n.ts b/electron/i18n.ts index 9ea7ca119..8c8d55bff 100644 --- a/electron/i18n.ts +++ b/electron/i18n.ts @@ -5,6 +5,8 @@ import commonAr from "../src/i18n/locales/ar/common.json"; import dialogsAr from "../src/i18n/locales/ar/dialogs.json"; import commonCs from "../src/i18n/locales/cs/common.json"; import dialogsCs from "../src/i18n/locales/cs/dialogs.json"; +import commonDe from "../src/i18n/locales/de/common.json"; +import dialogsDe from "../src/i18n/locales/de/dialogs.json"; import commonEn from "../src/i18n/locales/en/common.json"; import dialogsEn from "../src/i18n/locales/en/dialogs.json"; import commonEs from "../src/i18n/locales/es/common.json"; @@ -34,6 +36,7 @@ type Locale = | "en" | "ar" | "cs" + | "de" | "es" | "fr" | "it" @@ -52,6 +55,7 @@ const messages: Record> = { en: { common: commonEn, dialogs: dialogsEn }, ar: { common: commonAr, dialogs: dialogsAr }, cs: { common: commonCs, dialogs: dialogsCs }, + de: { common: commonDe, dialogs: dialogsDe }, es: { common: commonEs, dialogs: dialogsEs }, fr: { common: commonFr, dialogs: dialogsFr }, it: { common: commonIt, dialogs: dialogsIt }, @@ -72,6 +76,7 @@ export function setMainLocale(locale: string) { locale === "en" || locale === "ar" || locale === "cs" || + locale === "de" || locale === "es" || locale === "fr" || locale === "it" || diff --git a/src/components/ai-edition/RightPanes.i18n.test.tsx b/src/components/ai-edition/RightPanes.i18n.test.tsx index 0be64122b..42a364e39 100644 --- a/src/components/ai-edition/RightPanes.i18n.test.tsx +++ b/src/components/ai-edition/RightPanes.i18n.test.tsx @@ -73,6 +73,14 @@ describe("right-rail panes are localized", () => { expect(screen.getByText("Masquer si inactif")).toBeInTheDocument(); }); + it("renders the cursor pane in German", () => { + renderIn("de", ); + expect(screen.getByRole("heading", { name: "Cursor" })).toBeInTheDocument(); + expect(screen.getByText("Glättung")).toBeInTheDocument(); + expect(screen.getByText("Klick-Federung")).toBeInTheDocument(); + expect(screen.getByText("Bei Inaktivität ausblenden")).toBeInTheDocument(); + }); + it("falls back to English when the locale is English", () => { renderIn("en", ); expect(screen.getByRole("heading", { name: "Composition" })).toBeInTheDocument(); diff --git a/src/i18n/__tests__/tutorialHelpTranslations.test.ts b/src/i18n/__tests__/tutorialHelpTranslations.test.ts index 877a9682f..fe9410370 100644 --- a/src/i18n/__tests__/tutorialHelpTranslations.test.ts +++ b/src/i18n/__tests__/tutorialHelpTranslations.test.ts @@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest"; import { type Locale, SUPPORTED_LOCALES } from "@/i18n/config"; import arDialogs from "@/i18n/locales/ar/dialogs.json"; import csDialogs from "@/i18n/locales/cs/dialogs.json"; +import deDialogs from "@/i18n/locales/de/dialogs.json"; import enDialogs from "@/i18n/locales/en/dialogs.json"; import esDialogs from "@/i18n/locales/es/dialogs.json"; import frDialogs from "@/i18n/locales/fr/dialogs.json"; @@ -44,6 +45,7 @@ const dialogsByLocale = { en: enDialogs, ar: arDialogs, cs: csDialogs, + de: deDialogs, es: esDialogs, fr: frDialogs, it: itDialogs, diff --git a/src/i18n/config.ts b/src/i18n/config.ts index c621c4379..b11ec6793 100644 --- a/src/i18n/config.ts +++ b/src/i18n/config.ts @@ -3,6 +3,7 @@ export const SUPPORTED_LOCALES = [ "en", "ar", "cs", + "de", "es", "fr", "it", diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json new file mode 100644 index 000000000..194818720 --- /dev/null +++ b/src/i18n/locales/de/common.json @@ -0,0 +1,74 @@ +{ + "actions": { + "cancel": "Abbrechen", + "save": "Speichern", + "delete": "Löschen", + "close": "Schließen", + "share": "Teilen", + "done": "Fertig", + "open": "Öffnen", + "checkForUpdates": "Nach Updates suchen", + "updateSettings": "Update-Einstellungen", + "updateModeNotify": "Benachrichtigen, wenn ein Update verfügbar ist", + "updateModeDownload": "Updates automatisch herunterladen", + "updateModeDownloadAndInstall": "Updates automatisch herunterladen und installieren", + "viewRelease": "Release ansehen", + "downloadUpdate": "Update herunterladen", + "restartNow": "Jetzt neu starten", + "upload": "Hochladen", + "export": "Exportieren", + "showInFolder": "Im Ordner anzeigen", + "file": "Datei", + "edit": "Bearbeiten", + "view": "Darstellung", + "window": "Fenster", + "help": "Hilfe", + "quit": "Beenden", + "stopRecording": "Aufnahme stoppen", + "undo": "Rückgängig", + "redo": "Wiederholen", + "cut": "Ausschneiden", + "copy": "Kopieren", + "paste": "Einfügen", + "selectAll": "Alles auswählen", + "minimize": "Minimieren", + "reload": "Neu laden", + "forceReload": "Neu laden erzwingen", + "toggleDevTools": "Entwicklertools ein-/ausblenden", + "actualSize": "Originalgröße", + "zoomIn": "Vergrößern", + "zoomOut": "Verkleinern", + "toggleFullScreen": "Vollbild ein-/ausschalten", + "recordingStatus": "Aufnahme: {{source}}", + "about": "Über OpenScreen", + "services": "Dienste", + "hide": "OpenScreen ausblenden", + "hideOthers": "Andere ausblenden", + "unhide": "Alle einblenden", + "saveDiagnostics": "Diagnosedaten speichern" + }, + "updates": { + "available": "OpenScreen {{latestVersion}} ist verfügbar. Du verwendest {{currentVersion}}.", + "current": "OpenScreen ist auf dem neuesten Stand ({{currentVersion}}).", + "readyToInstall": "OpenScreen {{latestVersion}} wurde heruntergeladen. Starte neu, um die Installation abzuschließen.", + "downloaded": "OpenScreen {{latestVersion}} wurde heruntergeladen.", + "blockedRecording": "Beende deine Aufnahme, bevor du das Update installierst.", + "blockedLocation": "Verschiebe OpenScreen in deinen Programme-Ordner, bevor du aktualisierst.", + "failed": "Nach Updates konnte nicht gesucht werden.", + "downloadFailed": "Das Update konnte nicht heruntergeladen werden." + }, + "units": { + "pixelsPerSecond": "{{value}} px/s", + "pixels": "{{value}} px" + }, + "locale": { + "name": "Deutsch", + "short": "DE" + }, + "recordingSource": { + "window": "Fenster", + "screen": "Bildschirm", + "virtual": "Virtueller Bildschirm", + "unknown": "Bildschirmaufnahme" + } +} diff --git a/src/i18n/locales/de/dialogs.json b/src/i18n/locales/de/dialogs.json new file mode 100644 index 000000000..2c5e70ccd --- /dev/null +++ b/src/i18n/locales/de/dialogs.json @@ -0,0 +1,92 @@ +{ + "export": { + "complete": "Export abgeschlossen", + "yourFormatReady": "{{format}} ist fertig", + "showInFolder": "Im Ordner anzeigen", + "finalizingVideo": "Video-Export wird abgeschlossen…", + "compilingGifProgress": "GIF wird erstellt… {{progress}} %", + "compilingGifWait": "GIF wird erstellt… Das kann eine Weile dauern", + "takeMoment": "Das kann einen Moment dauern…", + "failed": "Export fehlgeschlagen", + "tryAgain": "Bitte versuche es erneut", + "finalizingVideoTitle": "Video wird abgeschlossen", + "compilingGif": "GIF wird erstellt", + "exportingFormat": "{{format}} wird exportiert", + "compiling": "Wird erstellt", + "renderingFrames": "Bilder werden gerendert", + "processing": "Wird verarbeitet…", + "finalizing": "Wird abgeschlossen…", + "compilingStatus": "Wird erstellt…", + "status": "Status", + "format": "Format", + "frames": "Bilder", + "cancelExport": "Export abbrechen", + "savedSuccessfully": "{{format}} erfolgreich gespeichert!" + }, + "tutorial": { + "triggerLabel": "So funktioniert Trimmen", + "title": "So funktioniert Trimmen", + "description": "Verstehen, wie du unerwünschte Teile aus deinem Video herausschneidest.", + "explanationBefore": "Mit dem Trim-Werkzeug legst du die Abschnitte fest, die du", + "remove": "entfernen", + "explanationMiddle": " möchtest — alles, was von einem roten Trim-Bereich", + "covered": "abgedeckt", + "explanationAfter": "ist, wird beim Export herausgeschnitten.", + "visualExample": "Visuelles Beispiel", + "removed": "ENTFERNT", + "kept": "Behalten", + "part1": "Teil 1", + "part2": "Teil 2", + "part3": "Teil 3", + "finalVideo": "Fertiges Video", + "step1Title": "1. Trim hinzufügen", + "step1DescriptionBefore": "Drücke ", + "step1DescriptionAfter": " oder klicke auf das Scheren-Symbol, um einen Abschnitt zum Entfernen zu markieren.", + "step2Title": "2. Anpassen", + "step2Description": "Ziehe die Ränder des roten Bereichs so, dass er genau das abdeckt, was du herausschneiden willst." + }, + "unsavedChanges": { + "title": "Nicht gespeicherte Änderungen", + "message": "Du hast nicht gespeicherte Änderungen.", + "detail": "Möchtest du dein Projekt speichern, bevor du schließt?", + "saveAndClose": "Speichern & schließen", + "discardAndClose": "Verwerfen & schließen", + "detailNewProject": "Möchtest du dein Projekt speichern, bevor du ein neues anlegst?", + "saveAndNewProject": "Speichern & neues Projekt", + "discardAndNewProject": "Verwerfen & neues Projekt", + "detailLoadProject": "Möchtest du dein Projekt speichern, bevor du ein anderes lädst?", + "saveAndLoadProject": "Speichern & Projekt laden", + "discardAndLoadProject": "Verwerfen & Projekt laden", + "newProject": "Neues Projekt", + "importVideo": "Videodatei importieren…", + "loadProject": "Projekt laden…", + "saveProject": "Projekt speichern…", + "saveProjectAs": "Projekt speichern unter…", + "modal": { + "closeTitle": "Änderungen vor dem Schließen speichern?", + "closeBody": "Dein Projekt hat nicht gespeicherte Änderungen. Speichere sie jetzt, verwirf sie oder bleib im Editor.", + "newTitle": "Änderungen speichern, bevor du ein neues Projekt anlegst?", + "openTitle": "Änderungen speichern, bevor du ein anderes Projekt öffnest?", + "recordTitle": "Änderungen speichern, bevor du eine neue Aufnahme startest?", + "sharedBody": "Das aktuelle Projekt hat nicht gespeicherte Änderungen. Speichere sie zuerst, verwirf sie oder brich ab.", + "notSavedYet": "Das aktuelle Projekt wurde noch nicht auf der Festplatte gespeichert.", + "discard": "Verwerfen", + "saveAndContinue": "Speichern & fortfahren", + "saving": "Wird gespeichert…" + } + }, + "fileDialogs": { + "saveGif": "Exportiertes GIF speichern", + "saveVideo": "Exportiertes Video speichern", + "selectVideo": "Videodatei auswählen", + "selectAudio": "Audiodatei auswählen", + "saveProject": "OpenScreen-Projekt speichern", + "openProject": "OpenScreen-Projekt öffnen", + "gifImage": "GIF-Bild", + "mp4Video": "MP4-Video", + "videoFiles": "Videodateien", + "audioFiles": "Audiodateien", + "openscreenProject": "OpenScreen-Projekt", + "allFiles": "Alle Dateien" + } +} diff --git a/src/i18n/locales/de/editor.json b/src/i18n/locales/de/editor.json new file mode 100644 index 000000000..2d6057ef1 --- /dev/null +++ b/src/i18n/locales/de/editor.json @@ -0,0 +1,404 @@ +{ + "newRecording": { + "title": "Zurück zum Recorder", + "description": "Deine aktuelle Sitzung wurde gespeichert.", + "cancel": "Abbrechen", + "confirm": "Bestätigen" + }, + "loadingVideo": "Video wird geladen…", + "loadingEditor": "Editor wird geladen…", + "errors": { + "exportBackgroundLoadFailed": "Export fehlgeschlagen: Hintergrundbild konnte nicht geladen werden ({{url}})", + "exportFailed": "Export fehlgeschlagen", + "exportFailedWithError": "Export fehlgeschlagen: {{error}}", + "failedToRevealInFolder": "Fehler beim Anzeigen im Ordner: {{error}}", + "failedToSaveExport": "Export konnte nicht gespeichert werden", + "failedToSaveExportedVideo": "Exportiertes Video konnte nicht gespeichert werden", + "failedToSaveGif": "GIF konnte nicht gespeichert werden", + "failedToSaveVideo": "Video konnte nicht gespeichert werden", + "gifExportFailed": "GIF-Export fehlgeschlagen", + "noVideoLoaded": "Kein Video geladen", + "previewCompositorUnavailable": "Vorschau auf diesem Rechner nicht verfügbar", + "trimNoFilm": "Da gibt es nichts zu schneiden — unter diesen Wörtern liegt kein Film.", + "unableToDetermineSourcePath": "Pfad des Quellvideos konnte nicht ermittelt werden", + "videoNotReady": "Video nicht bereit", + "wordEditFailed": "Dieses Wort konnte nicht geändert werden", + "wordInsertFailed": "Dieses Wort konnte nicht hinzugefügt werden", + "wordRemoveFailed": "Dieses Wort konnte nicht gelöscht werden" + }, + "export": { + "canceled": "Export abgebrochen", + "exportedSuccessfully": "{{format}} erfolgreich exportiert" + }, + "project": { + "saveCanceled": "Speichern des Projekts abgebrochen", + "failedToSave": "Projekt konnte nicht gespeichert werden", + "savedTo": "Projekt gespeichert unter {{path}}", + "failedToLoad": "Projekt konnte nicht geladen werden", + "invalidFormat": "Ungültiges Format der Projektdatei", + "loadedFrom": "Projekt geladen aus {{path}}" + }, + "recording": { + "failedCameraAccess": "Der Kamerazugriff konnte nicht angefragt werden.", + "cameraBlocked": "Der Kamerazugriff ist blockiert. Aktiviere ihn in den Systemeinstellungen, um die Webcam zu nutzen.", + "systemAudioUnavailable": "Systemton nicht verfügbar. Die Aufnahme läuft ohne Systemton.", + "microphoneDenied": "Mikrofonzugriff verweigert. Die Aufnahme läuft ohne Ton weiter.", + "cameraDenied": "Kamerazugriff verweigert. Die Aufnahme läuft ohne Webcam weiter.", + "cameraDisconnected": "Webcam getrennt.", + "cameraNotFound": "Kamera nicht gefunden.", + "cameraCaptureUnavailable": "Die Kamera konnte nicht geöffnet werden. Die Aufnahme läuft ohne sie.", + "microphoneDefaulted": "Das gewählte Mikrofon konnte nicht identifiziert werden. Es wird der Standardeingang aufgenommen.", + "permissionDenied": "Aufnahmeberechtigung verweigert. Bitte erlaube die Bildschirmaufnahme.", + "accessibilityAllowAndRetry": "Erlaube OpenScreen den Zugriff auf die Bedienungshilfen und drücke dann erneut auf Aufnehmen, um den Countdown zu starten.", + "selectSource": "Bitte wähle eine Quelle für die Aufnahme" + }, + "emptyState": { + "title": "Kein Projekt geöffnet", + "description": "Erstelle ein neues Projekt oder öffne ein vorhandenes.", + "titleHasAsset": "Füge ein Video hinzu, um loszulegen", + "descriptionHasAsset": "Importiere eine Aufnahme, um mit dem Bearbeiten zu beginnen.", + "newProjectButton": "Neues Projekt + Video importieren", + "importVideoButton": "Video importieren", + "loadProjectButton": "Projekt öffnen", + "supportedFormats": "Unterstützte Formate: MP4, MOV, WebM, MKV, AVI, M4V, WMV", + "dragDropHint": "oder zieh eine .openscreen-Projektdatei hierher", + "dropOverlay": "Projektdatei ablegen zum Öffnen", + "dropErrors": { + "unsupportedFormatTitle": "Nicht unterstütztes Format", + "unsupportedFormatMessage": "Hier können nur .openscreen-Projektdateien abgelegt werden. Um eine Videodatei zu importieren, nutze auf diesem Bildschirm die Schaltfläche „Videodatei importieren…“.", + "couldNotOpenTitle": "Datei konnte nicht geöffnet werden", + "couldNotOpenMessage": "Die Projektdatei konnte nicht geöffnet werden. Das darin referenzierte Video wurde möglicherweise verschoben oder gelöscht." + } + }, + "regionClipboard": { + "copied": "Attribute von {{region}} kopiert", + "pasted": "Attribute von {{region}} eingefügt", + "nothingToCopy": "Wähle einen Bereich, um seine Attribute zu kopieren", + "nothingToPaste": "Noch keine Attribute kopiert", + "pasteAssetMissing": "Die Datei dieser Audiospur liegt nicht in diesem Projekt", + "kinds": { + "zoom": "Zoom", + "speed": "Tempo", + "annotation": "Text" + } + }, + "topbar": { + "toggleChatPanel": "Chat-Panel ein-/ausblenden", + "openProject": "Projekt öffnen", + "newProject": "Neues Projekt", + "saveProject": "Projekt speichern", + "unsaved": "Nicht gespeichert", + "saved": "Gespeichert", + "switchToLightTheme": "Zum hellen Design wechseln", + "switchToDarkTheme": "Zum dunklen Design wechseln", + "toggleTheme": "Design umschalten", + "export": "Export", + "renameProject": "Projekt umbenennen", + "noProject": "Kein Projekt", + "changeLanguage": "Sprache ändern", + "editorMode": "Editor-Modus", + "modes": { + "media": "Medien", + "edit": "Schnitt", + "rec": "Aufnahme" + } + }, + "rec": { + "source": "Quelle", + "systemPicker": "Dein System fragt gleich, was du teilen möchtest", + "systemAudio": "Systemton", + "microphone": "Mikrofon", + "camera": "Kamera", + "cursorHighlight": "Cursor hervorheben", + "on": "An", + "off": "Aus", + "loading": "Wird geladen…", + "noCameraFound": "Keine Kamera gefunden", + "cameraAccessError": "Auf diese Kamera konnte nicht zugegriffen werden", + "startingCamera": "Kamera wird gestartet…", + "turnOnCameraHint": "Schalte die Kamera ein, um eine Live-Vorschau zu sehen", + "entireScreen": "Ganzer Bildschirm", + "cancel": "Abbrechen", + "startRecording": "Aufnahme starten", + "startRecordingHint": "Öffnet das Aufnahme-Widget und schließt dieses Editorfenster.", + "sourceModal": { + "screens": "Bildschirme ({{count}})", + "windows": "Fenster ({{count}})", + "loadingSources": "Quellen werden geladen…", + "noScreensFound": "Keine Bildschirme gefunden", + "noWindowsFound": "Keine Fenster gefunden", + "cancel": "Abbrechen" + } + }, + "mediaStage": { + "openProjectFirst": "Öffne zuerst ein Projekt", + "couldNotAddAsset": "Asset konnte nicht hinzugefügt werden", + "searchPlaceholder": "Medien durchsuchen…", + "dragHint": "Zieh einen Clip auf die Timeline unten, um ihn hinzuzufügen", + "emptyHint": "Noch keine Medien — importiere eine Aufnahme, um loszulegen.", + "importMedia": "Medien importieren", + "added": "{{label}} hinzugefügt", + "addToTimeline": "Zur Timeline hinzufügen", + "addedToTimeline": "{{label}} zur Timeline hinzugefügt", + "sourceTranscript": "Quell-Transkript", + "close": "Schließen", + "transcriptReady": "Transkript bereit", + "transcribing": "Transkription läuft", + "downloadingModel": "Sprachmodell wird heruntergeladen", + "initializingModel": "Sprachmodell wird gestartet", + "pendingTranscription": "Transkription ausstehend", + "transcriptionFailed": "Transkription fehlgeschlagen", + "cpuBackendHint": "Läuft auf der CPU — etwa 2× langsamer als auf der GPU", + "noTranscript": "Kein Transkript", + "regenerateAs": "Neu erzeugen als", + "auto": "Auto", + "regenerate": "Neu erzeugen", + "transcriptEmpty": "Das Transkript ist leer.", + "notGeneratedHint": "Noch nicht erzeugt — wähle eine Sprache und klicke auf Neu erzeugen.", + "generationFailedHint": "Erzeugung fehlgeschlagen — wähle eine Sprache und erzeuge neu.", + "detectedLanguage": "Erkannte Sprache: {{language}}", + "noAudioTrack": "Keine Audiospur", + "noAudioTrackHint": "Dieses Medium hat keine Audiospur — es gibt nichts zu transkribieren.", + "noSpeechDetected": "Keine Sprache erkannt" + }, + "exportDialog": { + "title": "Export", + "subtitle": "Die Timeline in eine Datei rendern", + "addVideoBeforeExporting": "Füge vor dem Export ein Video hinzu.", + "quality": "Qualität", + "qualityMatchRecording": "Wie die Aufnahme", + "frameRate": "Bildrate", + "codec": "Codec", + "codecBestCompatibility": "Beste Kompatibilität", + "codecMaySupportVary": "Wird möglicherweise nicht von jedem System-Encoder unterstützt", + "size": "Größe", + "loopGif": "GIF wiederholen", + "loopOn": "Wiederholung an", + "loopOff": "Wiederholung aus", + "pickFormatAndExport": "Wähle ein Format und drücke auf Exportieren, um zu starten.", + "savedTo": "Gespeichert unter", + "exportFailedGeneric": "Export fehlgeschlagen.", + "writingFile": "Datei wird geschrieben…", + "renderingFrames": "Bilder werden gerendert", + "framesEta": "{{current}} / {{total}} Bilder · noch {{eta}} s", + "preparingEncoder": "Encoder wird vorbereitet…", + "close": "Schließen", + "cancel": "Abbrechen", + "rendering": "Wird gerendert…", + "saving": "Wird gespeichert…", + "starting": "Wird gestartet…", + "exportGif": "GIF exportieren", + "exportMp4": "MP4 exportieren", + "exportedGif": "GIF exportiert", + "exportedVideo": "Video exportiert", + "exportedVideoOf": "Video exportiert in", + "showInFolder": "Im Ordner anzeigen", + "exportFailed": "Export fehlgeschlagen", + "failedToWriteFile": "Datei konnte nicht geschrieben werden", + "qualityUpscaleWarning": "Hochskalierung", + "nothingToExport": "Nichts zu exportieren — die Timeline ist leer." + }, + "inspector": { + "resetFocusPoint": "Fokuspunkt zurücksetzen", + "setColor": "Farbe {{color}} festlegen", + "trimHiddenDuration": "{{duration}} s des Quellmaterials sind in der bearbeiteten Timeline ausgeblendet.", + "restoreDeleteTrim": "Wiederherstellen (Trim löschen)", + "collapseInspector": "Inspektor einklappen", + "captionsDescription": "Erzeuge wortgenaue Untertitel aus dem Transkript und leg sie auf die Timeline.", + "generateCaptions": "Untertitel erzeugen", + "cropDescription": "Rahme die Aufnahme neu — wähle ein Seitenverhältnis und zoome auf den Bereich, den du behalten willst.", + "openCrop": "Zuschneiden öffnen…", + "cameraFullscreenDescription": "Während dieser Bereich läuft, füllt die Kamera das ganze Bild — ohne Rahmen, ohne Rundung, ohne Hintergrund — und fährt am Ende sanft zurück. Zieh die Ränder des Bereichs auf der Timeline, um Start und Dauer zu ändern.", + "deleteRegion": "Bereich löschen", + "freehandRendersAsBox": "Im Export wird eine Freihandform von ihrem umschließenden Rechteck abgedeckt — eher zu viel als zu wenig." + }, + "chat": { + "changeProvider": "Anbieter wechseln", + "back": "Zurück", + "currentModel": "Aktuelles Modell:", + "notSelected": "Nicht ausgewählt", + "loadingModels": "Modelle werden geladen…", + "searchModels": "Modelle durchsuchen…", + "fetchModelsFailed": "Live-Modelle konnten nicht geladen werden ({{error}}); öffne die Anbieter-Einstellungen, um eine Modell-ID manuell einzugeben.", + "noModelsAvailable": "Von diesem Anbieter sind keine Modelle verfügbar.", + "noModelsMatch": "Keine Modelle passen zu dieser Suche.", + "noProvidersConnected": "Noch keine Anbieter verbunden.", + "selectModelFailed": "Modell konnte nicht ausgewählt werden", + "providerSettings": "Anbieter-Einstellungen…", + "applyEditsFailed": "Die Änderungen des Agenten konnten nicht angewendet werden", + "agentEditConflict": "Die Änderungen des Agenten wurden nicht angewendet, weil sich das Projekt während seiner Arbeit geändert hat.", + "applyAnyway": "Trotzdem anwenden", + "chatFailed": "Chat fehlgeschlagen", + "rewindFailed": "Zurückspulen fehlgeschlagen", + "rewoundSuccess": "Zum Anfang dieser Nachricht zurückgespult", + "notEnoughHistory": "Noch nicht genug Verlauf zum Verdichten.", + "compactedSuccess": "Früherer Kontext verdichtet", + "compactFailed": "Verdichten fehlgeschlagen", + "createSessionFailed": "Unterhaltung konnte nicht erstellt werden", + "deleteSessionFailed": "Unterhaltung konnte nicht gelöscht werden", + "renameSessionFailed": "Unterhaltung konnte nicht umbenannt werden", + "reasoningEffortUpdateFailed": "Denkaufwand konnte nicht aktualisiert werden", + "contextTooltip": "{{usedTokens}} / {{budgetTokens}} geschätzte Tokens", + "contextPercent": "{{percent}} % Kontext", + "compactContext": "Kontext verdichten", + "aiSettings": "KI-Einstellungen", + "history": "Verlauf", + "newConversation": "Neue Unterhaltung", + "untitledConversation": "Unterhaltung", + "clickToRename": "Zum Umbenennen klicken", + "renameConversation": "Unterhaltung umbenennen", + "deleteConversation": "Unterhaltung löschen", + "confirmDeleteConversation": "„{{title}}“ löschen?", + "emptyState": "Noch keine Nachrichten. Bitte den Agenten, Stille zu schneiden, Pausen zu straffen oder Untertitel hinzuzufügen.", + "welcome": { + "title": "Bring deine eigene KI mit", + "subtitle": "Der Chat bearbeitet dein Video, indem er mit einem Sprachmodell spricht. Wähle einen Anbieter, dem du vertraust, und verbinde einen API-Schlüssel, um loszulegen.", + "feature1": "Stille schneiden, Pausen straffen, Füllwörter entfernen", + "feature2": "Untertitel hinzufügen, auf die Kamera zoomen, einen Titel erzeugen", + "feature3": "Einen Abschnitt umschreiben, umformulieren oder auf Wunsch einen Clip teilen", + "cta": "Anbieter einrichten", + "disclaimer": "Das Transkript deines Videos wird an den Anbieter gesendet, den du wählst. Es wird nichts geteilt, bevor du einen verbindest." + }, + "authorUser": "Du", + "authorAssistant": "OpenScreen", + "rewindToMessage": "Zu dieser Nachricht zurückspulen", + "copyMessage": "Nachricht kopieren", + "copiedToClipboard": "In die Zwischenablage kopiert", + "copyFailed": "Kopieren fehlgeschlagen", + "appliedPrefix": "angewendet:", + "thinking": "Denkt nach…", + "composerPlaceholder": "Beschreibe die Änderung, die du möchtest.", + "composerDisabledNoProvider": "Richte einen Anbieter ein, um zu chatten.", + "modelLabel": "Modell", + "reasoningEffortLabel": "Denkaufwand", + "sendTitle": "Senden (Enter)", + "send": "Senden", + "rewindConfirmTitle": "Hierher zurückspulen?", + "rewindConfirmBody": "Die Änderungen des Agenten und alle folgenden Züge nach diesem Punkt werden zurückgenommen. Projekt, Unterhaltung und Agentenzustand werden wiederhergestellt. Auch die Änderungen, die du seitdem gemacht hast, werden ersetzt.", + "rewindConfirm": "Zurückspulen", + "configureModel": "KI-Modell konfigurieren", + "historyDialog": { + "title": "Unterhaltungsverlauf", + "subtitle": "Sitzungen wechseln oder anlegen", + "empty": "Noch keine Unterhaltungen.", + "msgsCount": "{{count}} Nachr. · {{date}}" + } + }, + "newProjectDialog": { + "title": "Neues Projekt", + "subtitle": "Wähle einen Startpunkt und gib ihm einen Namen", + "nameLabel": "Projektname", + "startingPointLabel": "Startpunkt", + "create": "Projekt erstellen", + "defaultTitle": "Unbenanntes Projekt", + "templates": { + "screenRecordingTitle": "Bildschirmaufnahme", + "screenRecordingDesc": "Systemaufnahme starten", + "importMediaDesc": "Video, Audio, Bilder von der Festplatte" + } + }, + "openProjectDialog": { + "title": "Projekt öffnen", + "subtitle": "Mach bei einem bestehenden Projekt weiter oder durchsuche deine Dateien", + "searchPlaceholder": "Projekte durchsuchen…", + "noMatches": "Keine Projekte passen zu „{{query}}“.", + "navigateHint": "zum Navigieren ·", + "openHint": "zum Öffnen", + "browseFiles": "Dateien durchsuchen…", + "deleteProject": "Projekt löschen", + "confirmDelete": "Dieses Projekt löschen? Deine Aufnahmen bleiben erhalten." + }, + "editClipDialog": { + "title": "Clip bearbeiten", + "adjustStart": "Clip-Anfang anpassen", + "adjustEnd": "Clip-Ende anpassen", + "originalDuration": "Ursprüngliche Dauer", + "trimRange": "Trim-Bereich", + "duration": "Endgültige Dauer", + "reset": "Zurücksetzen", + "apply": "Anwenden", + "pickClipTitle": "Wähle einen Clip zum Bearbeiten", + "clipLabel": "Clip {{index}}" + }, + "insertSourceDialog": { + "title": "Quelle einfügen", + "subtitle": "Wo soll „{{assetLabel}}“ auf der Timeline platziert werden?", + "addBefore": "Davor einfügen", + "addBeforeDesc": "Die ganze Quelle vor dem Ziel-Clip einfügen.", + "addAfter": "Danach einfügen", + "addAfterDesc": "Die ganze Quelle nach dem Ziel-Clip einfügen.", + "split": "Hier teilen und einfügen", + "splitDesc": "Den Ziel-Clip am Ablagepunkt teilen und die Quelle dazwischen einfügen." + }, + "cropDialog": { + "subtitle": "Zieh den Bereich oder seine Griffe, um den Ausschnitt anzupassen", + "fieldX": "X", + "fieldY": "Y", + "fieldW": "B", + "fieldH": "H" + }, + "transport": { + "playbackControls": "Wiedergabesteuerung", + "playPause": "Wiedergabe / Pause", + "playPauseTitle": "Wiedergabe / Pause (Leertaste)", + "previousClip": "Vorheriger Clip", + "nextClip": "Nächster Clip", + "loop": "Wiederholen", + "seekVideo": "Videoposition" + }, + "shell": { + "aiEditor": "KI-Editor", + "resizeChatPanel": "Größe des Chat-Panels ändern", + "previewStage": "Vorschaubereich", + "resizeTimeline": "Größe der Timeline ändern" + }, + "preview": { + "videoPreview": "Videovorschau", + "webcamPreview": "Webcam-Vorschau (zum Verschieben ziehen)", + "mediaError": { + "title": "Vorschau gestoppt", + "description": "Das Video konnte nicht dekodiert werden. Die Datei ist womöglich beschädigt, wird noch geschrieben oder liegt nicht mehr dort, wo das Projekt sie erwartet — dein Projekt selbst ist intakt.", + "retry": "Erneut versuchen", + "detail": "Details: {{detail}}" + } + }, + "annotationOverlay": { + "imageAlt": "Anmerkung", + "noImage": "Kein Bild", + "noArrowData": "Keine Pfeildaten" + }, + "providerSettings": { + "title": "KI-Einstellungen", + "subtitle": "Wähle einen Anbieter. Zugangsdaten werden im Schlüsselbund des Betriebssystems gespeichert (safeStorage).", + "loadFailed": "KI-Einstellungen konnten nicht geladen werden", + "saved": "{{provider}} gespeichert", + "connected": "{{provider}} verbunden", + "disconnected": "{{provider}} getrennt", + "pillConnected": "Verbunden", + "pillApiKey": "API-Schlüssel", + "notConnected": "Nicht verbunden", + "back": "Zurück", + "modelLabel": "Modell", + "modelHintLive": "Modelle aus deinem Konto, live geladen.", + "modelHintError": "Live-Modelle konnten nicht geladen werden ({{error}}); gib eine Modell-ID manuell ein.", + "modelHintLoading": "Live-Modelle werden geladen…", + "modelSavedOption": "{{model}} (gespeichert)", + "loadingModels": "Modelle werden geladen…", + "baseUrlLabel": "Basis-URL", + "baseUrlHint": "Leer lassen, um den Standard des Anbieters zu verwenden.", + "reasoningEffortLabel": "Denkaufwand", + "apiKeyLabel": "API-Schlüssel", + "apiKeyHintStored": "Wird in safeStorage gespeichert. Leer lassen, um den vorhandenen Eintrag zu behalten.", + "projectEditsLabel": "Projektänderungen", + "projectEditsHint": "Wenn aus, muss der Agent fragen, bevor er die Timeline ändert. Änderungen lassen sich immer rückgängig machen.", + "allowAgentEdits": "Dem Agenten erlauben, das Projekt zu bearbeiten", + "disconnect": "Trennen", + "cancel": "Abbrechen", + "save": "Speichern", + "saveAndUse": "Speichern & verwenden" + }, + "cpuCompositor": { + "notice": "Läuft ohne kompatible GPU — das Rendering erfolgt auf der CPU, die Wiedergabe ist daher langsamer.", + "exportWarning": "Keine kompatible GPU: Dieser Export läuft auf der CPU und dauert deutlich länger als üblich." + } +} diff --git a/src/i18n/locales/de/launch.json b/src/i18n/locales/de/launch.json new file mode 100644 index 000000000..0f2e8cc65 --- /dev/null +++ b/src/i18n/locales/de/launch.json @@ -0,0 +1,99 @@ +{ + "tooltips": { + "hideHUD": "HUD ausblenden", + "closeApp": "App schließen", + "restartRecording": "Aufnahme neu starten", + "cancelRecording": "Aufnahme abbrechen", + "pauseRecording": "Aufnahme pausieren", + "resumeRecording": "Aufnahme fortsetzen", + "useVerticalTray": "Vertikale Leiste verwenden", + "useHorizontalTray": "Horizontale Leiste verwenden", + "openStudio": "Studio öffnen", + "openNotes": "Notizen öffnen", + "openNotesPlaceholder": "Hier Notizen schreiben…", + "notesToolbar": { + "bold": "Fett", + "italic": "Kursiv", + "strikethrough": "Durchgestrichen", + "bulletList": "Aufzählung", + "numberedList": "Nummerierte Liste", + "blockquote": "Zitat", + "codeBlock": "Codeblock", + "play": "Auto-Scroll starten", + "pause": "Auto-Scroll pausieren", + "speed": "Scroll-Tempo", + "decreaseSpeed": "Scroll-Tempo verringern", + "increaseSpeed": "Scroll-Tempo erhöhen", + "fontSize": "Schriftgröße", + "decreaseFontSize": "Schrift verkleinern", + "increaseFontSize": "Schrift vergrößern", + "mirror": "Horizontal spiegeln" + } + }, + "audio": { + "enableSystemAudio": "Systemton aktivieren", + "disableSystemAudio": "Systemton deaktivieren", + "enableMicrophone": "Mikrofon aktivieren", + "disableMicrophone": "Mikrofon deaktivieren", + "defaultMicrophone": "Standardmikrofon", + "systemAudio": "Systemton", + "microphone": "Mikrofon", + "on": "An", + "off": "Aus", + "inputDevice": "Eingabegerät" + }, + "webcam": { + "enableWebcam": "Webcam aktivieren", + "disableWebcam": "Webcam deaktivieren", + "defaultCamera": "Standardkamera", + "searching": "Suche läuft…", + "noneFound": "Keine Kamera gefunden", + "unavailable": "Kamera nicht verfügbar", + "camera": "Kamera", + "cameraDevice": "Kameragerät" + }, + "cursor": { + "useEditableCursor": "Bearbeitbaren Cursor verwenden", + "useSystemCursor": "System-Cursor verwenden" + }, + "sourceSelector": { + "loading": "Quellen werden geladen…", + "screens": "Bildschirme ({{count}})", + "windows": "Fenster ({{count}})", + "emptyTitle": "Keine Bildschirme oder Fenster gefunden", + "emptyDescription": "Wenn du die Berechtigung zur Bildschirmaufnahme gerade erteilt hast, lade diese Auswahl neu. Unter macOS musst du OpenScreen eventuell neu öffnen.", + "loadFailedDescription": "OpenScreen konnte die Aufnahmequellen nicht laden. Lade diese Auswahl neu und versuche es erneut.", + "defaultSourceName": "Bildschirm" + }, + "recording": { + "selectSource": "Bitte wähle eine Quelle für die Aufnahme", + "systemPicker": "Dein System fragt gleich, was du teilen möchtest", + "inProgress": "Aufnahme läuft", + "saving": "Wird gespeichert…" + }, + "language": "Sprache", + "systemLanguagePrompt": { + "title": "Systemsprache verwenden?", + "description": "{{language}} wurde als deine Systemsprache erkannt. Soll OpenScreen auf {{language}} umgestellt werden?", + "switch": "Zu {{language}} wechseln", + "keepDefault": "Aktuelle Sprache behalten" + }, + "softwareEncoderFallback": { + "title": "Auf Software-Encoding umgestellt", + "description": "Der Standard-GPU-Encoder konnte nicht gestartet werden, deshalb ist OpenScreen auf Software-H.264-Encoding zurückgefallen. Die Aufnahme läuft normal weiter, die CPU-Auslastung kann aber höher sein.", + "dismiss": "Verstanden", + "dontShowAgain": "Nicht mehr anzeigen" + }, + "deviceSettings": { + "title": "Geräteeinstellungen", + "done": "Fertig", + "micLevel": "Eingangspegel", + "micHint": "Sprich, um dein Mikrofon zu prüfen", + "noMicrophones": "Kein Mikrofon gefunden", + "preview": "Vorschau", + "previewUnavailable": "Vorschau nicht verfügbar", + "about": "Über", + "version": "Version {{version}}", + "checkingForUpdates": "Wird geprüft…" + } +} diff --git a/src/i18n/locales/de/settings.json b/src/i18n/locales/de/settings.json new file mode 100644 index 000000000..8414b8088 --- /dev/null +++ b/src/i18n/locales/de/settings.json @@ -0,0 +1,361 @@ +{ + "background": { + "gradientLabel": "Verlauf {{index}}", + "uploadCustom": "Eigenes hochladen", + "unsupportedImage": "Nicht unterstütztes Bild. Verwende eine JPG- oder PNG-Datei.", + "title": "Hintergrund", + "imageLabel": "Hintergrund {{index}}", + "custom": "Eigenes", + "help": "Wähle, was hinter der Aufnahme zu sehen ist: ein mitgeliefertes Hintergrundbild, eine Volltonfarbe, einen Verlauf oder ein eigenes Bild von der Festplatte.", + "gradient": "Verlauf", + "colorLabel": "Farbe {{color}}", + "customWallpaper": "Eigenes Hintergrundbild", + "colorPalette": "Farbpalette", + "imageReadFailed": "Diese Bilddatei konnte nicht gelesen werden.", + "image": "Bild", + "presets": "Vorgaben", + "color": "Farbe", + "colorWheel": "Farbrad" + }, + "customFont": { + "namePlaceholder": "Meine eigene Schrift", + "failedToAdd": "Schrift konnte nicht hinzugefügt werden", + "addingButton": "Wird hinzugefügt…", + "errorInvalidUrl": "Bitte gib eine gültige Google-Fonts-URL ein", + "urlHelp": "So bekommst du sie bei Google Fonts: Schrift auswählen → auf „Get font“ klicken → die @import-URL kopieren", + "urlLabel": "Google-Fonts-Import-URL", + "successMessage": "Schrift „{{fontName}}“ erfolgreich hinzugefügt", + "nameLabel": "Anzeigename", + "errorEmptyName": "Bitte gib einen Schriftnamen ein", + "nameHelp": "So erscheint die Schrift in der Schriftauswahl", + "errorEmptyUrl": "Bitte gib eine Google-Fonts-Import-URL ein", + "errorExtractFailed": "Die Schriftfamilie konnte nicht aus der URL gelesen werden", + "urlPlaceholder": "https://fonts.googleapis.com/css2?family=Roboto&display=swap", + "dialogTitle": "Google-Schrift hinzufügen", + "errorTimeout": "Die Schrift hat zu lange zum Laden gebraucht. Prüfe die URL und versuche es erneut.", + "errorLoadFailed": "Die Schrift konnte nicht geladen werden. Prüfe, ob die Google-Fonts-URL korrekt ist.", + "addButton": "Schrift hinzufügen" + }, + "imageUpload": { + "invalidFileType": "Ungültiger Dateityp", + "failedToUpload": "Bild konnte nicht hochgeladen werden", + "jpgOnly": "Bitte lade eine JPG-, JPEG- oder PNG-Bilddatei hoch.", + "uploadSuccess": "Eigenes Bild erfolgreich hochgeladen!", + "errorReading": "Beim Lesen der Datei ist ein Fehler aufgetreten." + }, + "annotation": { + "supportedFormats": "Unterstützte Formate: JPG, PNG, GIF, WebP", + "blurShapeRectangle": "Rechteck", + "size": "Größe", + "tipShiftTabCycle": "Mit Shift+Tab rückwärts durchlaufen.", + "clearBackground": "Hintergrund entfernen", + "colorPalette": "Farbpalette", + "invalidImageType": "Ungültiger Dateityp", + "background": "Hintergrund", + "typeText": "Text", + "active": "Aktiv", + "color": "Farbe", + "blurShapeFreehand": "Freihand", + "arrowDirection": "Pfeilrichtung", + "blurTypeMosaic": "Mosaik", + "colorWheel": "Farbrad", + "textColor": "Textfarbe", + "title": "Anmerkungs-Einstellungen", + "blurType": "Weichzeichner-Typ", + "typeBlur": "Weichzeichner", + "blurIntensity": "Weichzeichner-Stärke", + "selectStyle": "Stil auswählen", + "textContent": "Textinhalt", + "typeArrow": "Pfeil", + "none": "Keine", + "blurColor": "Weichzeichner-Farbe", + "customFonts": "Eigene Schriften", + "imageUploadSuccess": "Bild erfolgreich hochgeladen!", + "type": "Typ", + "arrowColor": "Pfeilfarbe", + "textPlaceholder": "Gib deinen Text ein…", + "imageFormatsOnly": "Bitte lade eine JPG-, PNG-, GIF- oder WebP-Bilddatei hoch.", + "blurShape": "Weichzeichner-Form", + "uploadImage": "Bild hochladen", + "blurTypeBlur": "Gauß", + "tipTabCycle": "Mit Tab durch überlappende Elemente wechseln.", + "shortcutsAndTips": "Kürzel & Tipps", + "deleteAnnotation": "Anmerkung löschen", + "fontStyle": "Schriftstil", + "defaultText": "Hallo", + "mosaicBlockSize": "Mosaik-Blockgröße", + "blurColorBlack": "Schwarz", + "strokeWidth": "Strichstärke: {{width}} px", + "blurShapeOval": "Oval", + "blurColorWhite": "Weiß", + "tipMovePlayhead": "Bewege den Abspielkopf zum überlappenden Anmerkungsabschnitt und wähle ein Element aus.", + "typeImage": "Bild" + }, + "effects": { + "fitClipFew": "{{count}} Clips", + "title": "Komposition", + "shadow": "Schatten", + "off": "aus", + "on": "an", + "blurBg": "Hintergrund unscharf", + "help": "Rahmengestaltung der Aufnahme: Hintergrund-Unschärfe, Schlagschatten, Bewegungsunschärfe, Eckenrundung und Abstand um das Video.", + "fitClipOne": "{{count}} Clip", + "formatOriginal": "Original", + "fitClipMany": "{{count}} Clips", + "frame": "Rahmen", + "motion": "Bewegung", + "padding": "Abstand", + "format": "Format", + "fitClip": "Einpassen", + "motionBlur": "Bewegungsunschärfe", + "roundness": "Rundung" + }, + "transcript": { + "laneRecording": "Aufnahme", + "noTranscript": "Noch kein Transkript", + "title": "Transkript", + "restoreWord": "„{{word}}“ wiederherstellen", + "revertWord": "„{{original}}“ wiederherstellen", + "editingHint": "Doppelklick auf ein Wort korrigiert es, Backspace schneidet es aus dem Film.", + "restoreSilence": "Stille wiederherstellen ({{duration}} s)", + "help": "Zusammengeführtes Transkript aller Clips auf der Timeline. Backspace / Entf schneidet ein Wort oder eine Auswahl aus dem Film (rot). Doppelklick auf ein Wort korrigiert seinen Text. Zeig auf ein markiertes Wort, um die Markierung aufzuheben.", + "editWord": "„{{word}}“ bearbeiten", + "laneFeedsCaptions": "Die Untertitel werden aus dieser Spur gebrannt.", + "insertedWord": "Von dir hinzugefügt — kein Audio dahinter", + "whisperHint": "Die Transkription nutzt lokales Whisper — sie läuft auf deinem Computer, es verlassen keine Daten das Gerät.", + "insertAria": "Neues Wort", + "editorAria": "Transkript für {{filename}}", + "transcribeNow": "Jetzt transkribieren", + "transcribing": "Transkription läuft…", + "trimSilence": "Stille trimmen ({{duration}} s)", + "removeInserted": "„{{word}}“ löschen", + "laneLabel": "Transkript lesen aus", + "noClips": "Noch keine Clips", + "laneVoiceover": "Voiceover", + "silence": "[Stille {{duration}} s]", + "clipLabel": "Clip {{index}}", + "correctedWord": "Korrigiert — die Transkription hörte „{{original}}“", + "noClipTranscript": "Kein Transkript für diesen Clip — öffne die Asset-Karte und erzeuge es neu.", + "editingHintDev": "Doppelklick auf ein Wort korrigiert es, Backspace schneidet es aus dem Film, Tippen zwischen zwei Wörtern fügt eines hinzu.", + "noAudio": "Dieses Medium hat keine Audiospur", + "blankedWord": "geleert" + }, + "exportFormat": { + "mp4": "MP4", + "mp4Description": "Videodatei in hoher Qualität", + "gifAnimation": "GIF-Animation", + "mp4Video": "MP4-Video", + "gifDescription": "Animiertes Bild zum Teilen", + "gif": "GIF" + }, + "captions": { + "showBackground": "Hintergrund anzeigen", + "deleteTranslation": "Diese Übersetzung löschen", + "legacyAnnotations": "Dieses Projekt enthält noch Untertitel-Anmerkungen aus der alten Untertitel-Funktion ({{count}}). Sie werden über der Untertitel-Ebene gerendert.", + "backgroundOpacity": "Deckkraft", + "backgroundColor": "Hintergrundfarbe", + "alignCenter": "Zentriert", + "translationIsNonDestructive": "Übersetzungen werden neben dem Transkript gespeichert, nie darin — der Originaltext und seine Timings bleiben unangetastet.", + "distanceFromRight": "Abstand von rechts", + "language": "Sprache", + "text": "Text", + "anchorHintBottom": "Lange Untertitel wachsen nach oben — die Unterkante bleibt, wo sie ist.", + "distanceFromTop": "Abstand von oben", + "translateFailed": "Übersetzung fehlgeschlagen.", + "alignLeft": "Links", + "distanceFromBottom": "Abstand von unten", + "derivedFromTranscript": "{{count}} Untertitelzeilen, live aus dem Transkript abgeleitet.", + "translate": "Übersetzen", + "position": "Position", + "fontSize": "Größe", + "hiddenHint": "Untertitel stammen aus dem Transkript dieses Mediums. Schalte sie ein, um sie in der Vorschau und in Exporten zu sehen.", + "noTranscript": "Untertitel werden aus dem Medien-Transkript gelesen. Transkribiere dieses Video, um sie einzuschalten.", + "distanceFromLeft": "Abstand von links", + "anchorBottom": "Unten", + "transcribe": "Video transkribieren", + "bold": "Fett", + "alignRight": "Rechts", + "anchorTop": "Oben", + "minWords": "Min. Wörter pro Zeile", + "translateHint": "Das Transkript mit dem konfigurierten KI-Anbieter übersetzen", + "anchorHintTop": "Lange Untertitel wachsen nach unten — die Oberkante bleibt, wo sie ist.", + "displayLanguage": "Anzeige", + "removeLegacyAnnotations": "Alte Untertitel-Anmerkungen entfernen", + "background": "Hintergrund", + "lineLength": "Zeilenlänge", + "original": "Original (Transkript)", + "maxWords": "Max. Wörter pro Zeile", + "font": "Schrift", + "translating": "Übersetzung läuft…", + "show": "Untertitel anzeigen", + "textColor": "Textfarbe" + }, + "panes": { + "help": "Hilfe" + }, + "speed": { + "deleteRegion": "Tempo-Bereich löschen", + "maxSpeedError": "Das Tempo kann nicht höher als {{max}}× sein", + "selectRegion": "Wähle einen Tempo-Bereich zum Anpassen", + "playbackSpeed": "Wiedergabetempo", + "customPlaybackSpeed": "Eigenes Wiedergabetempo", + "previewFrameSteppingHint": "Über {{native}}× läuft die Vorschau Bild für Bild und stumm. Der Export ist davon nicht betroffen." + }, + "gifSettings": { + "frameRate": "GIF-Bildrate", + "loop": "GIF wiederholen", + "size": "GIF-Größe" + }, + "exportQuality": { + "title": "Export-Auflösung", + "low": "720p", + "high": "Quelle", + "medium": "1080p" + }, + "audioTrack": { + "defaultLabel": "Audiospur", + "importFailed": "Audio konnte nicht hinzugefügt werden", + "fadeOut": "Ausblenden", + "fadeIn": "Einblenden", + "remove": "Spur löschen", + "loop": "Wiederholen", + "slipHint": "Mit Alt ziehen, um das Audio darin zu verschieben", + "help": "Lautstärke, Blenden und Wiederholung für diese Audiospur. Sie wird in der Vorschau und im Export über die Aufnahme gemischt. Zieh die Spur auf der Timeline, um sie zu verschieben oder ihre Länge zu ändern, oder halte Alt und zieh, um das Audio darin zu verschieben.", + "add": "Audiospur hinzufügen", + "mute": "Stumm" + }, + "layout": { + "help": "Wie die Webcam mit dem Bildschirm komponiert wird: Bild in Bild, vertikal gestapelt, Doppelrahmen, Maskenform, Größe und Spiegelung.", + "mirrorWebcam": "Webcam spiegeln", + "webcamFraming": "Webcam-Ausschnitt", + "shapes": { + "rectangle": "Rechteck", + "rounded": "Gerundet", + "circle": "Kreis", + "square": "Quadrat" + }, + "selectPreset": "Vorgabe auswählen", + "bgModes": { + "custom": "Eigenes", + "none": "Original", + "blur": "Unschärfe", + "transparent": "Freisteller" + }, + "reactiveWebcamDescription": "Die Kamera verkleinert sich sanft, während das Video herangezoomt ist, damit sie nicht im Weg ist.", + "webcamBlurIntensity": "Unschärfe-Stärke", + "preset": "Vorgabe", + "webcamCropZoom": "Zoom", + "webcamSize": "Webcam-Größe", + "dualFrame": "Doppelrahmen", + "webcamCropY": "Vertikal verschieben", + "verticalStack": "Vertikal gestapelt", + "pictureInPicture": "Bild in Bild", + "webcamShape": "Kameraform", + "webcamCropX": "Horizontal verschieben", + "reactiveWebcam": "Bei Zoom verkleinern", + "webcamBackground": "Kamera-Hintergrund", + "helpNoWebcam": "Dieses Projekt hat keine Kamera, deshalb sind die Layout-Regler aus und die Vorgabe zeigt „Keine Webcam“. Dein gespeichertes Layout bleibt erhalten, falls später eine Kamera dazukommt.", + "title": "Kamera-Layout", + "noWebcam": "Keine Webcam" + }, + "textAnimation": { + "slideLeft": "Nach links schieben", + "pulse": "Pulsieren", + "typewriter": "Schreibmaschine", + "selectAnimation": "Animation auswählen", + "fade": "Überblenden", + "title": "Textanimation", + "none": "Keine", + "pop": "Pop", + "rise": "Aufsteigen" + }, + "facets": { + "transcript": "Transkript", + "captions": "Untertitel" + }, + "crop": { + "title": "Zuschneiden", + "free": "Frei", + "unlockAspectRatio": "Seitenverhältnis entsperren", + "dragInstruction": "Zieh an den Seiten, um den Ausschnitt anzupassen", + "done": "Fertig", + "ratio": "Verhältnis", + "cropVideo": "Video zuschneiden", + "lockAspectRatio": "Seitenverhältnis sperren" + }, + "zoom": { + "position": { + "y": "Y (%)", + "hint": "0 = ganz links / ganz oben, 100 = ganz rechts / ganz unten", + "title": "Fokusposition", + "x": "X (%)" + }, + "deleteZoom": "Zoom löschen", + "focusMode": { + "lockedDisclaimer": "Wird vom globalen Auto-Fokus-Schalter in der Timeline gesteuert. Schalte ihn aus, um den Fokusmodus pro Zoom festzulegen.", + "auto": "Auto", + "manual": "Manuell", + "autoDescription": "Die Kamera folgt der aufgezeichneten Cursorposition", + "title": "Fokusmodus" + }, + "threeD": { + "preset": { + "left": "Links", + "right": "Rechts", + "iso": "Iso" + }, + "none": "Keine", + "title": "3D-Rotation" + }, + "level": "Zoomstufe", + "previewHold": "Gedrückt halten für die Zoom-Vorschau", + "customScale": "Eigener Zoom", + "selectRegion": "Wähle einen Zoom-Bereich zum Anpassen", + "cursor": { + "title": "Cursor", + "show": "Sichtbar", + "hide": "Ausgeblendet" + } + }, + "audio": { + "outputGain": "Ausgangspegel", + "help": "Passe den Audio-Ausgangspegel an. Er gilt in der Vorschau und im Export identisch.", + "reset": "Audio zurücksetzen", + "title": "Audio" + }, + "language": { + "title": "Sprache" + }, + "project": { + "new": "Neues Projekt", + "load": "Projekt laden", + "save": "Projekt speichern" + }, + "support": { + "starOnGithub": "Stern auf GitHub geben", + "saveDiagnostics": "Diagnosedaten speichern", + "reportBug": "Fehler melden" + }, + "cursor": { + "smoothing": "Glättung", + "clickBounce": "Klick-Federung", + "help": "Cursor-Darstellung aus der aufgezeichneten Telemetrie: Stil, Größe, Glättung, Bewegungsunschärfe und Klick-Federung.", + "clipToBoundsDescription": "Hält den Cursor innerhalb des Videobilds. Schalte es aus, damit der Cursor über die Ränder hinausragen kann — nützlich beim Hineinzoomen oder Verschieben.", + "size": "Größe", + "title": "Cursor", + "show": "Cursor anzeigen", + "themeDefault": "Standard", + "clipToBounds": "Auf Canvas begrenzen", + "motionBlur": "Bewegungsunschärfe", + "theme": "Cursor-Stil", + "autoHide": "Bei Inaktivität ausblenden" + }, + "export": { + "gifButton": "GIF exportieren", + "chooseSaveLocation": "Speicherort wählen", + "videoButton": "Video exportieren" + }, + "trim": { + "deleteRegion": "Trim-Bereich löschen" + } +} diff --git a/src/i18n/locales/de/shortcuts.json b/src/i18n/locales/de/shortcuts.json new file mode 100644 index 000000000..e4a02bbe0 --- /dev/null +++ b/src/i18n/locales/de/shortcuts.json @@ -0,0 +1,43 @@ +{ + "title": "Tastaturkürzel", + "customize": "Anpassen", + "configurable": "Anpassbar", + "fixed": "Fest", + "pressKey": "Taste drücken…", + "clickToChange": "Zum Ändern klicken", + "pressEscToCancel": "Esc drücken zum Abbrechen", + "helpText": "Klicke auf ein Kürzel und drücke dann die neue Tastenkombination. Esc drücken zum Abbrechen.", + "resetToDefaults": "Auf Standard zurücksetzen", + "alreadyUsedBy": "Bereits belegt von „{{action}}“", + "swap": "Tauschen", + "reservedShortcut": "Dieses Kürzel ist für „{{label}}“ reserviert und kann nicht neu belegt werden.", + "savedToast": "Tastaturkürzel gespeichert", + "resetToast": "Auf Standardkürzel zurückgesetzt — klicke auf Speichern, um sie zu übernehmen", + "registrationFailed": "Kürzel konnte nicht registriert werden. Möglicherweise wird es von einer anderen App verwendet. Probiere eine andere Taste.", + "actions": { + "openApp": "App öffnen", + "addZoom": "Zoom hinzufügen", + "addTrim": "Trim hinzufügen", + "addSpeed": "Tempo hinzufügen", + "addAnnotation": "Anmerkung hinzufügen", + "addAudio": "Audio hinzufügen", + "addVoiceover": "Voiceover aufnehmen", + "addKeyframe": "Keyframe hinzufügen", + "addCameraFullscreen": "Vollbild-Kamera hinzufügen", + "deleteSelected": "Auswahl löschen", + "playPause": "Wiedergabe / Pause", + "copySelected": "Auswahl kopieren", + "paste": "Einfügen" + }, + "fixedActions": { + "undo": "Rückgängig", + "redo": "Wiederholen", + "cycleAnnotationsForward": "Anmerkungen vorwärts durchlaufen", + "cycleAnnotationsBackward": "Anmerkungen rückwärts durchlaufen", + "deleteSelectedAlt": "Auswahl löschen (Alternative)", + "panTimeline": "Timeline verschieben", + "zoomTimeline": "Timeline zoomen", + "frameBack": "Ein Bild zurück", + "frameForward": "Ein Bild vor" + } +} diff --git a/src/i18n/locales/de/timeline.json b/src/i18n/locales/de/timeline.json new file mode 100644 index 000000000..6ec2846c8 --- /dev/null +++ b/src/i18n/locales/de/timeline.json @@ -0,0 +1,108 @@ +{ + "buttons": { + "addZoom": "Zoom hinzufügen (Z)", + "suggestZooms": "Zooms aus Cursorbewegung vorschlagen", + "autoZoomOn": "Zoom-Vorschläge an — klicken, um vorgeschlagene Zooms zu entfernen", + "autoZoomOff": "Zoom-Vorschläge aus — klicken, um Zooms aus der Cursorbewegung vorzuschlagen", + "autoFocusAllOn": "Auto-Fokus für alle Zooms an — klicken, um alle auf manuell umzustellen", + "autoFocusAllOff": "Auto-Fokus für alle Zooms (Kamera folgt dem Cursor)", + "addTrim": "Trim hinzufügen (T)", + "addAnnotation": "Anmerkung hinzufügen (A)", + "addSpeed": "Tempo hinzufügen (S)", + "addCameraFullscreen": "Vollbild-Kamera hinzufügen (C)" + }, + "hints": { + "pressZoom": "Drücke Z, um einen Zoom hinzuzufügen", + "pressTrim": "Drücke T, um einen Trim hinzuzufügen", + "pressAnnotation": "Drücke A, um eine Anmerkung hinzuzufügen", + "pressAudio": "Drücke M für Audio, V für ein Voiceover", + "pressSpeed": "Drücke S, um ein Tempo hinzuzufügen", + "pressCameraFullscreen": "Drücke C, um einen Vollbild-Kamera-Abschnitt hinzuzufügen" + }, + "labels": { + "pan": "Verschieben", + "zoom": "Zoom", + "trim": "Trim", + "speed": "Tempo", + "zoomItem": "Zoom {{index}}", + "trimItem": "Trim {{index}}", + "speedItem": "Tempo {{index}}", + "annotationItem": "Anmerkung", + "imageItem": "Bild", + "emptyText": "Leerer Text", + "cameraFullscreen": "Vollbild-Kamera", + "cameraFullscreenItem": "Vollbild-Kamera {{index}}" + }, + "emptyState": { + "noVideo": "Kein Video geladen", + "dragAndDrop": "Zieh ein Video hierher, um mit dem Bearbeiten zu beginnen" + }, + "errors": { + "cannotPlaceZoom": "Zoom kann hier nicht platziert werden", + "zoomExistsAtLocation": "An dieser Stelle gibt es bereits einen Zoom oder es ist nicht genug Platz.", + "zoomSuggestionUnavailable": "Zoom-Vorschläge sind nicht verfügbar", + "noCursorTelemetry": "Keine Cursor-Telemetrie verfügbar", + "noCursorTelemetryDescription": "Nimm zuerst einen Screencast auf, um Vorschläge aus der Cursorbewegung zu erzeugen.", + "noUsableTelemetry": "Keine verwertbare Cursor-Telemetrie", + "noUsableTelemetryDescription": "Die Aufnahme enthält nicht genug Daten zur Cursorbewegung.", + "noDwellMoments": "Keine klaren Verweilmomente des Cursors gefunden", + "noDwellMomentsDescription": "Versuche eine Aufnahme, in der der Cursor bei wichtigen Aktionen länger verweilt.", + "noAutoZoomSlots": "Keine Plätze für Auto-Zoom verfügbar", + "noAutoZoomSlotsDescription": "Die erkannten Verweilpunkte überschneiden sich mit bestehenden Zoom-Bereichen.", + "cannotPlaceTrim": "Trim kann hier nicht platziert werden", + "trimExistsAtLocation": "An dieser Stelle gibt es bereits einen Trim oder es ist nicht genug Platz.", + "cannotPlaceSpeed": "Tempo kann hier nicht platziert werden", + "speedExistsAtLocation": "An dieser Stelle gibt es bereits einen Tempo-Bereich oder es ist nicht genug Platz.", + "cannotPlaceCameraFullscreen": "Vollbild-Kamera kann hier nicht platziert werden", + "cameraFullscreenExistsAtLocation": "An dieser Stelle gibt es bereits einen Vollbild-Kamera-Abschnitt oder es ist nicht genug Platz." + }, + "success": { + "addedZoomSuggestions": "{{count}} Zoom-Vorschlag aus der Cursorbewegung hinzugefügt", + "addedZoomSuggestionsPlural": "{{count}} Zoom-Vorschläge aus der Cursorbewegung hinzugefügt" + }, + "toolbar": { + "autoEnhance": "Automatisch verbessern", + "automaticZooms": "Automatische Zooms", + "automaticZoomsHint": "Aus der aufgezeichneten Cursorbewegung", + "smartZoomsAndCuts": "Smarte Schnitte", + "smartZoomsAndCutsHint": "Mit KI", + "comment": "Kommentar", + "timelineTools": "Timeline-Werkzeuge", + "arrangeClips": "Clips anordnen", + "arrangeClipsHint": "Zieh die Clips unten, um sie neu zu ordnen, oder leg neue hinein", + "newAnnotation": "Anmerkung", + "dragToReorderHint": "Ziehen zum Neuordnen · Doppelklick für In-/Out-Punkte", + "editInOutPoints": "In-/Out-Punkte bearbeiten", + "deleteClip": "Clip löschen", + "dropToAdd": "Ablegen, um zur Timeline hinzuzufügen", + "importRecordingFirst": "Importiere zuerst eine Aufnahme", + "noAutoZoomMoments": "Keine Auto-Zoom-Momente gefunden", + "noAutoZoomMomentsDescription": "Diese Aufnahme enthält keine Cursordaten, oder bestehende Zooms decken die aktiven Momente bereits ab.", + "addedAutoZoom": "{{count}} automatischer Zoom hinzugefügt", + "addedAutoZoomPlural": "{{count}} automatische Zooms hinzugefügt", + "autoZoomFailed": "Auto-Zoom fehlgeschlagen", + "aiEnhanceRequested": "Der KI-Agent wurde gebeten, die Leerlaufzeit herauszuschneiden", + "smartCutsWaiting": "Transkription läuft… gleich bereit", + "smartCutsNeedsTranscript": "Benötigt ein Transkript", + "smartCutsNoAudio": "Dieses Medium hat kein Audio", + "smartCutsNoSpeech": "Keine Sprache erkannt", + "smartCutsFailed": "Transkription fehlgeschlagen — starte sie unter „Medien“ neu", + "addAudioTooltip": "Audio hinzufügen", + "addedWord": "Wort hinzugefügt: „{{word}}“ — kein Audio dahinter" + }, + "audio": { + "addVoiceover": "Voiceover hinzufügen", + "addVoiceoverHint": "Sprich eine Erzählung über dein Video", + "subtitle": "Leg eine Voiceover- oder Hintergrundmusik-Spur auf die Timeline", + "record": "Voiceover aufnehmen", + "importFile": "Audiodatei importieren", + "importFileHint": "Musik oder eine Audiodatei einbinden", + "recording": "Aufnahme läuft", + "recordingHint": "Sprich zum Video — es läuft, während du aufnimmst", + "stop": "Stopp", + "micDenied": "Zugriff auf das Mikrofon wurde verweigert", + "recordingUnavailable": "Aufnahme ist hier nicht verfügbar", + "saveFailed": "Die Aufnahme konnte nicht gespeichert werden", + "importFailed": "Die Audiodatei konnte nicht importiert werden" + } +} From 65346627ef916b19e7f754c5e378926a570b9e72 Mon Sep 17 00:00:00 2001 From: EtienneLescot Date: Thu, 17 Sep 2026 10:59:28 +0200 Subject: [PATCH 2/2] fix(i18n): add missing German stylePresets strings and match import button label --- src/i18n/locales/de/editor.json | 2 +- src/i18n/locales/de/settings.json | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/i18n/locales/de/editor.json b/src/i18n/locales/de/editor.json index 2d6057ef1..05b497b55 100644 --- a/src/i18n/locales/de/editor.json +++ b/src/i18n/locales/de/editor.json @@ -65,7 +65,7 @@ "dropOverlay": "Projektdatei ablegen zum Öffnen", "dropErrors": { "unsupportedFormatTitle": "Nicht unterstütztes Format", - "unsupportedFormatMessage": "Hier können nur .openscreen-Projektdateien abgelegt werden. Um eine Videodatei zu importieren, nutze auf diesem Bildschirm die Schaltfläche „Videodatei importieren…“.", + "unsupportedFormatMessage": "Hier können nur .openscreen-Projektdateien abgelegt werden. Um eine Videodatei zu importieren, nutze auf diesem Bildschirm die Schaltfläche „Video importieren“.", "couldNotOpenTitle": "Datei konnte nicht geöffnet werden", "couldNotOpenMessage": "Die Projektdatei konnte nicht geöffnet werden. Das darin referenzierte Video wurde möglicherweise verschoben oder gelöscht." } diff --git a/src/i18n/locales/de/settings.json b/src/i18n/locales/de/settings.json index 8414b8088..fb496f293 100644 --- a/src/i18n/locales/de/settings.json +++ b/src/i18n/locales/de/settings.json @@ -110,6 +110,31 @@ "motionBlur": "Bewegungsunschärfe", "roundness": "Rundung" }, + "stylePresets": { + "button": "Vorgaben", + "menuLabel": "Stil-Vorgaben", + "factoryName": "OpenScreen", + "factoryBadge": "Integriert", + "empty": "Noch keine Vorgaben gespeichert", + "create": "Neue Vorgabe erstellen…", + "namePlaceholder": "Name der Vorgabe", + "save": "Speichern", + "moreActions": "Weitere Aktionen für „{{name}}“", + "revealMac": "Im Finder anzeigen", + "revealWindows": "Im Explorer anzeigen", + "revealLinux": "Im Ordner anzeigen", + "rename": "Umbenennen", + "update": "Aus aktuellem Projekt aktualisieren", + "delete": "Löschen", + "confirmDelete": "„{{name}}“ löschen?", + "applied": "„{{name}}“ angewendet", + "saved": "Vorgabe gespeichert", + "updated": "Vorgabe aktualisiert", + "nameRequired": "Bitte gib einen Namen ein", + "nameTaken": "Eine Vorgabe mit diesem Namen existiert bereits", + "loadFailed": "Vorgaben konnten nicht geladen werden", + "saveFailed": "Vorgabe konnte nicht gespeichert werden: {{error}}" + }, "transcript": { "laneRecording": "Aufnahme", "noTranscript": "Noch kein Transkript",