{t(
- "settings.appPreferences.folderScope",
- "Changing this location affects future recordings. Existing files stay in their current folders.",
+ "settings.storage.description",
+ "Choose where Recordly saves each kind of file. New files use the folder you pick; existing files stay where they are.",
)}
+ {tSettings(
+ "storage.description",
+ "Choose where Recordly saves each kind of file. New files use the folder you pick; existing files stay where they are.",
+ )}
+
+
+
+
diff --git a/src/components/video-editor/settings/StorageLocationsSettings.tsx b/src/components/video-editor/settings/StorageLocationsSettings.tsx
new file mode 100644
index 000000000..d5129ba15
--- /dev/null
+++ b/src/components/video-editor/settings/StorageLocationsSettings.tsx
@@ -0,0 +1,227 @@
+import { Button } from "@/components/ui/button";
+import { useI18n } from "@/contexts/I18nContext";
+import { useEffect, useState } from "react";
+import type {
+ StorageFolder,
+ StorageFolderId,
+ StorageFoldersResponse,
+} from "@/types/storageFolders";
+import { SettingsRow } from "../SettingsRow";
+
+type FolderRow = {
+ id: StorageFolderId;
+ titleKey: string;
+ titleFallback: string;
+ descriptionKey: string;
+ descriptionFallback: string;
+};
+
+/**
+ * Listed in the order a creator meets them: where recordings land first, then
+ * the files produced from a recording, then background data.
+ */
+const FOLDER_ROWS: FolderRow[] = [
+ {
+ id: "recordings",
+ titleKey: "settings.storage.recordings",
+ titleFallback: "Recordings",
+ descriptionKey: "settings.storage.recordingsDescription",
+ descriptionFallback:
+ "Screen captures, system audio, microphone tracks and cursor data. Existing recordings stay where they are.",
+ },
+ {
+ id: "projects",
+ titleKey: "settings.storage.projects",
+ titleFallback: "Projects and drafts",
+ descriptionKey: "settings.storage.projectsDescription",
+ descriptionFallback:
+ "Saved .recordly projects, their previews and autosaves. Kept inside the recordings folder.",
+ },
+ {
+ id: "exports",
+ titleKey: "settings.storage.exports",
+ titleFallback: "Exported videos",
+ descriptionKey: "settings.storage.exportsDescription",
+ descriptionFallback:
+ "Folder the save dialog opens in when you export an MP4 or GIF.",
+ },
+ {
+ id: "temp",
+ titleKey: "settings.storage.temp",
+ titleFallback: "Temporary files",
+ descriptionKey: "settings.storage.tempDescription",
+ descriptionFallback:
+ "Scratch data while recording and exporting. Point this at a larger drive if your system drive is small.",
+ },
+ {
+ id: "captionModels",
+ titleKey: "settings.storage.captionModels",
+ titleFallback: "Caption models",
+ descriptionKey: "settings.storage.captionModelsDescription",
+ descriptionFallback:
+ "Downloaded speech-to-text models used for automatic captions.",
+ },
+ {
+ id: "cache",
+ titleKey: "settings.storage.cache",
+ titleFallback: "Cache",
+ descriptionKey: "settings.storage.cacheDescription",
+ descriptionFallback:
+ "Regenerated data such as wallpaper thumbnails and project previews. Safe to relocate or clear.",
+ },
+];
+
+/**
+ * Every folder Recordly writes into, in one place.
+ *
+ * The main process owns validation and persistence; this component only reflects
+ * the returned folder map so the UI can never show a path the app did not accept.
+ */
+export function StorageLocationsSettings() {
+ const { t } = useI18n();
+ const [folders, setFolders] = useState();
+ const [error, setError] = useState();
+ const [busy, setBusy] = useState();
+
+ const applyResponse = (result: StorageFoldersResponse) => {
+ if (!result.success || !result.folders) {
+ setError(
+ result.error ||
+ t("settings.storage.loadFailed", "Could not read storage locations."),
+ );
+ return;
+ }
+ setError(undefined);
+ setFolders(result.folders);
+ };
+
+ useEffect(() => {
+ let active = true;
+ void window.electronAPI
+ .getStorageFolders()
+ .then((result) => {
+ if (active) applyResponse(result);
+ })
+ .catch((failure: unknown) => {
+ if (active) setError(failure instanceof Error ? failure.message : String(failure));
+ });
+ return () => {
+ active = false;
+ };
+ // applyResponse only closes over setState and translators, which are stable.
+ // biome-ignore lint/correctness/useExhaustiveDependencies: load once on mount.
+ }, [t]);
+
+ const run = async (id: StorageFolderId | "all", action: () => Promise) => {
+ if (busy) return;
+ setBusy(id);
+ setError(undefined);
+ try {
+ applyResponse(await action());
+ } catch (failure) {
+ setError(failure instanceof Error ? failure.message : String(failure));
+ } finally {
+ setBusy(undefined);
+ }
+ };
+
+ if (error && !folders) {
+ return (
+
+ );
+}
diff --git a/src/i18n/locales/de/native.json b/src/i18n/locales/de/native.json
index 378553cdc..485f3edc3 100644
--- a/src/i18n/locales/de/native.json
+++ b/src/i18n/locales/de/native.json
@@ -18,6 +18,7 @@
"saveFailedTitle": "Projekt konnte nicht gespeichert werden",
"saveFailedMessage": "Das Speichern ist fehlgeschlagen oder reagiert nicht. Ungespeicherte Änderungen verwerfen und schließen?",
"welcome": "Willkommen bei Recordly",
+ "chooseFolder": "Ordner auswählen",
"chooseRecordings": "Aufnahmeordner auswählen",
"saveRecordlyProject": "Recordly-Projekt speichern",
"recordlyProject": "Recordly-Projekt",
diff --git a/src/i18n/locales/de/settings.json b/src/i18n/locales/de/settings.json
index a65c877d2..395887977 100644
--- a/src/i18n/locales/de/settings.json
+++ b/src/i18n/locales/de/settings.json
@@ -598,5 +598,28 @@
},
"annotation": {
"delete": "Anmerkung löschen"
+ },
+ "storage": {
+ "title": "Speicherorte",
+ "description": "Lege fest, wo Recordly welche Dateien ablegt. Neue Dateien nutzen den gewählten Ordner; vorhandene bleiben, wo sie sind.",
+ "recordings": "Aufnahmen",
+ "recordingsDescription": "Bildschirmaufnahmen mit Systemton, Mikrofonspuren und Cursordaten.",
+ "projects": "Projekte und Entwürfe",
+ "projectsDescription": "Gespeicherte Projekte, ihre Vorschauen und automatische Sicherungen. Liegt im Aufnahmeordner.",
+ "exports": "Exportierte Videos",
+ "exportsDescription": "Ordner, den der Speichern-Dialog beim Export von MP4 oder GIF öffnet.",
+ "temp": "Temporäre Dateien",
+ "tempDescription": "Zwischendaten beim Aufnehmen und Exportieren. Wähle ein größeres Laufwerk, wenn die Systemplatte knapp ist.",
+ "captionModels": "Untertitelmodelle",
+ "captionModelsDescription": "Heruntergeladene Spracherkennungsmodelle für automatische Untertitel.",
+ "cache": "Cache",
+ "cacheDescription": "Neu erzeugbare Daten wie Hintergrundminiaturen und Projektvorschauen. Kann verschoben oder geleert werden.",
+ "change": "Ändern…",
+ "open": "Öffnen",
+ "reset": "Zurücksetzen",
+ "resetAll": "Alle Standardorte wiederherstellen",
+ "usingDefault": "Derzeit der Standardort.",
+ "loading": "Ordnerpfad wird geladen…",
+ "loadFailed": "Speicherorte konnten nicht gelesen werden."
}
}
diff --git a/src/i18n/locales/en/native.json b/src/i18n/locales/en/native.json
index a9a00b2eb..43ffe9a39 100644
--- a/src/i18n/locales/en/native.json
+++ b/src/i18n/locales/en/native.json
@@ -18,6 +18,7 @@
"saveFailedTitle": "Project could not be saved",
"saveFailedMessage": "Saving failed or did not respond. Discard unsaved changes and close?",
"welcome": "Welcome to Recordly",
+ "chooseFolder": "Choose folder",
"chooseRecordings": "Choose recordings folder",
"saveRecordlyProject": "Save Recordly Project",
"recordlyProject": "Recordly Project",
diff --git a/src/i18n/locales/en/settings.json b/src/i18n/locales/en/settings.json
index dd2762750..84ce9d643 100644
--- a/src/i18n/locales/en/settings.json
+++ b/src/i18n/locales/en/settings.json
@@ -598,5 +598,28 @@
},
"annotation": {
"delete": "Delete Annotation"
+ },
+ "storage": {
+ "title": "Storage locations",
+ "description": "Choose where Recordly saves each kind of file. New files use the folder you pick; existing files stay where they are.",
+ "recordings": "Recordings",
+ "recordingsDescription": "Screen captures with their system audio, microphone tracks and cursor data.",
+ "projects": "Projects and drafts",
+ "projectsDescription": "Saved projects, their previews and autosaves. Lives inside the recordings folder.",
+ "exports": "Exported videos",
+ "exportsDescription": "Folder the save dialog opens in when you export an MP4 or GIF.",
+ "temp": "Temporary files",
+ "tempDescription": "Scratch data while recording and exporting. Point this at a larger drive if your system drive is small.",
+ "captionModels": "Caption models",
+ "captionModelsDescription": "Downloaded speech-to-text models used for automatic captions.",
+ "cache": "Cache",
+ "cacheDescription": "Regenerated data such as wallpaper thumbnails and project previews. Safe to relocate or clear.",
+ "change": "Change…",
+ "open": "Open",
+ "reset": "Reset",
+ "resetAll": "Restore all default locations",
+ "usingDefault": "Currently the default location.",
+ "loading": "Loading folder location…",
+ "loadFailed": "Could not read storage locations."
}
}
diff --git a/src/i18n/locales/es/native.json b/src/i18n/locales/es/native.json
index 3f8b1bbf6..219564dd9 100644
--- a/src/i18n/locales/es/native.json
+++ b/src/i18n/locales/es/native.json
@@ -18,6 +18,7 @@
"saveFailedTitle": "No se pudo guardar el proyecto",
"saveFailedMessage": "El guardado falló o no respondió. ¿Descartar los cambios sin guardar y cerrar?",
"welcome": "Te damos la bienvenida a Recordly",
+ "chooseFolder": "Elegir carpeta",
"chooseRecordings": "Elegir carpeta de grabaciones",
"saveRecordlyProject": "Guardar proyecto de Recordly",
"recordlyProject": "Proyecto de Recordly",
diff --git a/src/i18n/locales/es/settings.json b/src/i18n/locales/es/settings.json
index df6e3af22..6f1eda6d9 100644
--- a/src/i18n/locales/es/settings.json
+++ b/src/i18n/locales/es/settings.json
@@ -598,5 +598,28 @@
},
"annotation": {
"delete": "Eliminar anotación"
+ },
+ "storage": {
+ "title": "Ubicaciones de almacenamiento",
+ "description": "Elige dónde guarda Recordly cada tipo de archivo. Los archivos nuevos usan la carpeta que elijas; los existentes se quedan donde están.",
+ "recordings": "Grabaciones",
+ "recordingsDescription": "Grabaciones de pantalla con audio del sistema, pistas de micrófono y datos del cursor.",
+ "projects": "Proyectos y borradores",
+ "projectsDescription": "Proyectos guardados, sus vistas previas y guardados automáticos. Vive dentro de la carpeta de grabaciones.",
+ "exports": "Vídeos exportados",
+ "exportsDescription": "Carpeta que se abre al guardar cuando exportas un MP4 o un GIF.",
+ "temp": "Archivos temporales",
+ "tempDescription": "Datos temporales durante la grabación y la exportación. Úsalo en un disco más grande si el sistema está lleno.",
+ "captionModels": "Modelos de subtítulos",
+ "captionModelsDescription": "Modelos de voz a texto descargados para los subtítulos automáticos.",
+ "cache": "Caché",
+ "cacheDescription": "Datos que se regeneran, como miniaturas de fondos y vistas previas. Puedes moverlo o vaciarlo.",
+ "change": "Cambiar…",
+ "open": "Abrir",
+ "reset": "Restablecer",
+ "resetAll": "Restaurar todas las ubicaciones predeterminadas",
+ "usingDefault": "Actualmente es la ubicación predeterminada.",
+ "loading": "Cargando la ubicación de la carpeta…",
+ "loadFailed": "No se pudieron leer las ubicaciones de almacenamiento."
}
}
diff --git a/src/i18n/locales/fr/native.json b/src/i18n/locales/fr/native.json
index 81a82b1de..8960a043f 100644
--- a/src/i18n/locales/fr/native.json
+++ b/src/i18n/locales/fr/native.json
@@ -18,6 +18,7 @@
"saveFailedTitle": "Le projet n’a pas pu être enregistré",
"saveFailedMessage": "L’enregistrement a échoué ou ne répond pas. Ignorer les modifications non enregistrées et fermer ?",
"welcome": "Bienvenue dans Recordly",
+ "chooseFolder": "Choisir un dossier",
"chooseRecordings": "Choisir le dossier des enregistrements",
"saveRecordlyProject": "Enregistrer un projet Recordly",
"recordlyProject": "Projet Recordly",
diff --git a/src/i18n/locales/fr/settings.json b/src/i18n/locales/fr/settings.json
index f98b18bb1..cbc3efc0e 100644
--- a/src/i18n/locales/fr/settings.json
+++ b/src/i18n/locales/fr/settings.json
@@ -598,5 +598,28 @@
},
"annotation": {
"delete": "Supprimer l’annotation"
+ },
+ "storage": {
+ "title": "Emplacements de stockage",
+ "description": "Choisissez où Recordly enregistre chaque type de fichier. Les nouveaux fichiers utilisent le dossier choisi ; les fichiers existants restent en place.",
+ "recordings": "Enregistrements",
+ "recordingsDescription": "Captures d'écran avec le son du système, les pistes micro et les données du curseur.",
+ "projects": "Projets et brouillons",
+ "projectsDescription": "Projets enregistrés, leurs aperçus et les sauvegardes automatiques. Se trouve dans le dossier des enregistrements.",
+ "exports": "Vidéos exportées",
+ "exportsDescription": "Dossier ouvert par la boîte d'enregistrement lors d'un export MP4 ou GIF.",
+ "temp": "Fichiers temporaires",
+ "tempDescription": "Données temporaires pendant l'enregistrement et l'export. Choisissez un disque plus grand si votre disque système est petit.",
+ "captionModels": "Modèles de sous-titres",
+ "captionModelsDescription": "Modèles de reconnaissance vocale téléchargés pour les sous-titres automatiques.",
+ "cache": "Cache",
+ "cacheDescription": "Données régénérées comme les miniatures de fond d'écran et les aperçus. Vous pouvez les déplacer ou les vider.",
+ "change": "Modifier…",
+ "open": "Ouvrir",
+ "reset": "Réinitialiser",
+ "resetAll": "Rétablir tous les emplacements par défaut",
+ "usingDefault": "Emplacement par défaut actuellement.",
+ "loading": "Chargement de l'emplacement…",
+ "loadFailed": "Impossible de lire les emplacements de stockage."
}
}
diff --git a/src/i18n/locales/it/native.json b/src/i18n/locales/it/native.json
index eb7300ef5..b61b68cc4 100644
--- a/src/i18n/locales/it/native.json
+++ b/src/i18n/locales/it/native.json
@@ -18,6 +18,7 @@
"saveFailedTitle": "Impossibile salvare il progetto",
"saveFailedMessage": "Il salvataggio non è riuscito o non risponde. Scartare le modifiche non salvate e chiudere?",
"welcome": "Ti diamo il benvenuto in Recordly",
+ "chooseFolder": "Scegli cartella",
"chooseRecordings": "Scegli la cartella delle registrazioni",
"saveRecordlyProject": "Salva progetto Recordly",
"recordlyProject": "Progetto Recordly",
diff --git a/src/i18n/locales/it/settings.json b/src/i18n/locales/it/settings.json
index 4ba04ae62..0c8f56d0e 100644
--- a/src/i18n/locales/it/settings.json
+++ b/src/i18n/locales/it/settings.json
@@ -598,5 +598,28 @@
},
"annotation": {
"delete": "Elimina annotazione"
+ },
+ "storage": {
+ "title": "Percorsi di archiviazione",
+ "description": "Scegli dove Recordly salva ogni tipo di file. I nuovi file usano la cartella scelta; quelli esistenti restano dove sono.",
+ "recordings": "Registrazioni",
+ "recordingsDescription": "Registrazioni dello schermo con audio di sistema, tracce microfono e dati del cursore.",
+ "projects": "Progetti e bozze",
+ "projectsDescription": "Progetti salvati, anteprime e salvataggi automatici. Si trova nella cartella delle registrazioni.",
+ "exports": "Video esportati",
+ "exportsDescription": "Cartella aperta dalla finestra di salvataggio quando esporti MP4 o GIF.",
+ "temp": "File temporanei",
+ "tempDescription": "Dati temporanei durante registrazione ed esportazione. Scegli un disco più grande se quello di sistema è piccolo.",
+ "captionModels": "Modelli per i sottotitoli",
+ "captionModelsDescription": "Modelli di riconoscimento vocale scaricati per i sottotitoli automatici.",
+ "cache": "Cache",
+ "cacheDescription": "Dati rigenerabili come miniature degli sfondi e anteprime dei progetti. Puoi spostarli o svuotarli.",
+ "change": "Cambia…",
+ "open": "Apri",
+ "reset": "Ripristina",
+ "resetAll": "Ripristina tutti i percorsi predefiniti",
+ "usingDefault": "Attualmente è il percorso predefinito.",
+ "loading": "Caricamento del percorso…",
+ "loadFailed": "Impossibile leggere i percorsi di archiviazione."
}
}
diff --git a/src/i18n/locales/ja/native.json b/src/i18n/locales/ja/native.json
index a069093ea..38a8f12d2 100644
--- a/src/i18n/locales/ja/native.json
+++ b/src/i18n/locales/ja/native.json
@@ -18,6 +18,7 @@
"saveFailedTitle": "プロジェクトを保存できませんでした",
"saveFailedMessage": "保存に失敗したか、応答がありません。未保存の変更を破棄して閉じますか?",
"welcome": "Recordlyへようこそ",
+ "chooseFolder": "フォルダを選択",
"chooseRecordings": "録画フォルダを選択",
"saveRecordlyProject": "Recordlyプロジェクトを保存",
"recordlyProject": "Recordlyプロジェクト",
diff --git a/src/i18n/locales/ja/settings.json b/src/i18n/locales/ja/settings.json
index 0d1e59c0c..7a8d5ada9 100644
--- a/src/i18n/locales/ja/settings.json
+++ b/src/i18n/locales/ja/settings.json
@@ -598,5 +598,28 @@
},
"annotation": {
"delete": "注釈を削除"
+ },
+ "storage": {
+ "title": "保存場所",
+ "description": "Recordly がファイルの種類ごとに保存する場所を選択します。新しいファイルは選んだフォルダーに保存され、既存のファイルはそのまま残ります。",
+ "recordings": "録画",
+ "recordingsDescription": "システム音声、マイク音声、カーソルデータを含む画面録画です。",
+ "projects": "プロジェクトと下書き",
+ "projectsDescription": "保存したプロジェクト、プレビュー、自動保存です。録画フォルダー内にあります。",
+ "exports": "書き出した動画",
+ "exportsDescription": "MP4 や GIF を書き出すときに保存ダイアログが開くフォルダーです。",
+ "temp": "一時ファイル",
+ "tempDescription": "録画と書き出し中の一時データです。システムドライブが小さい場合は大きいドライブを指定してください。",
+ "captionModels": "字幕モデル",
+ "captionModelsDescription": "自動字幕に使用する音声認識モデルです。",
+ "cache": "キャッシュ",
+ "cacheDescription": "壁紙のサムネイルやプロジェクトのプレビューなど再生成できるデータです。移動や削除が可能です。",
+ "change": "変更…",
+ "open": "開く",
+ "reset": "リセット",
+ "resetAll": "すべて既定の場所に戻す",
+ "usingDefault": "現在は既定の場所です。",
+ "loading": "フォルダーの場所を読み込み中…",
+ "loadFailed": "保存場所を読み取れませんでした。"
}
}
diff --git a/src/i18n/locales/ko/native.json b/src/i18n/locales/ko/native.json
index 5f567eff4..c75f8f997 100644
--- a/src/i18n/locales/ko/native.json
+++ b/src/i18n/locales/ko/native.json
@@ -18,6 +18,7 @@
"saveFailedTitle": "프로젝트를 저장할 수 없습니다",
"saveFailedMessage": "저장에 실패했거나 응답이 없습니다. 저장하지 않은 변경 사항을 버리고 닫을까요?",
"welcome": "Recordly에 오신 것을 환영합니다",
+ "chooseFolder": "폴더 선택",
"chooseRecordings": "녹화 폴더 선택",
"saveRecordlyProject": "Recordly 프로젝트 저장",
"recordlyProject": "Recordly 프로젝트",
diff --git a/src/i18n/locales/ko/settings.json b/src/i18n/locales/ko/settings.json
index 6828404a6..2eb23d197 100644
--- a/src/i18n/locales/ko/settings.json
+++ b/src/i18n/locales/ko/settings.json
@@ -598,5 +598,28 @@
},
"annotation": {
"delete": "주석 삭제"
+ },
+ "storage": {
+ "title": "저장 위치",
+ "description": "Recordly가 파일 종류별로 저장할 위치를 선택하세요. 새 파일은 선택한 폴더를 사용하며 기존 파일은 그대로 남습니다.",
+ "recordings": "녹화",
+ "recordingsDescription": "시스템 오디오, 마이크 트랙, 커서 데이터가 포함된 화면 녹화입니다.",
+ "projects": "프로젝트 및 초안",
+ "projectsDescription": "저장된 프로젝트, 미리보기, 자동 저장 파일입니다. 녹화 폴더 안에 있습니다.",
+ "exports": "내보낸 동영상",
+ "exportsDescription": "MP4 또는 GIF를 내보낼 때 저장 창이 열리는 폴더입니다.",
+ "temp": "임시 파일",
+ "tempDescription": "녹화와 내보내기 중 사용하는 임시 데이터입니다. 시스템 드라이브가 작으면 더 큰 드라이브를 지정하세요.",
+ "captionModels": "자막 모델",
+ "captionModelsDescription": "자동 자막에 사용하는 음성 인식 모델입니다.",
+ "cache": "캐시",
+ "cacheDescription": "배경 미리보기와 프로젝트 미리보기처럼 다시 생성되는 데이터입니다. 이동하거나 비워도 됩니다.",
+ "change": "변경…",
+ "open": "열기",
+ "reset": "초기화",
+ "resetAll": "모든 기본 위치 복원",
+ "usingDefault": "현재 기본 위치입니다.",
+ "loading": "폴더 위치를 불러오는 중…",
+ "loadFailed": "저장 위치를 읽을 수 없습니다."
}
}
diff --git a/src/i18n/locales/nl/native.json b/src/i18n/locales/nl/native.json
index b8529ad5b..5c625a69c 100644
--- a/src/i18n/locales/nl/native.json
+++ b/src/i18n/locales/nl/native.json
@@ -18,6 +18,7 @@
"saveFailedTitle": "Project kon niet worden opgeslagen",
"saveFailedMessage": "Opslaan is mislukt of reageert niet. Niet-opgeslagen wijzigingen verwerpen en sluiten?",
"welcome": "Welkom bij Recordly",
+ "chooseFolder": "Map kiezen",
"chooseRecordings": "Opnamemap kiezen",
"saveRecordlyProject": "Recordly-project opslaan",
"recordlyProject": "Recordly-project",
diff --git a/src/i18n/locales/nl/settings.json b/src/i18n/locales/nl/settings.json
index 738194eda..3aae200e1 100644
--- a/src/i18n/locales/nl/settings.json
+++ b/src/i18n/locales/nl/settings.json
@@ -598,5 +598,28 @@
},
"annotation": {
"delete": "Annotatie verwijderen"
+ },
+ "storage": {
+ "title": "Opslaglocaties",
+ "description": "Kies waar Recordly elk soort bestand opslaat. Nieuwe bestanden gebruiken de gekozen map; bestaande bestanden blijven staan.",
+ "recordings": "Opnames",
+ "recordingsDescription": "Schermopnames met systeemgeluid, microfoonsporen en cursorwaarden.",
+ "projects": "Projecten en concepten",
+ "projectsDescription": "Opgeslagen projecten, hun voorbeelden en automatische opslag. Staat in de opnamemap.",
+ "exports": "Geëxporteerde video’s",
+ "exportsDescription": "Map die het opslaanvenster opent bij het exporteren van MP4 of GIF.",
+ "temp": "Tijdelijke bestanden",
+ "tempDescription": "Tijdelijke data tijdens opnemen en exporteren. Kies een grotere schijf als je systeemschijf klein is.",
+ "captionModels": "Ondertitelmodellen",
+ "captionModelsDescription": "Gedownloade spraak-naar-tekstmodellen voor automatische ondertitels.",
+ "cache": "Cache",
+ "cacheDescription": "Opnieuw te maken data zoals achtergrondminiaturen en projectvoorbeelden. Veilig te verplaatsen of te wissen.",
+ "change": "Wijzigen…",
+ "open": "Openen",
+ "reset": "Herstellen",
+ "resetAll": "Alle standaardlocaties herstellen",
+ "usingDefault": "Dit is momenteel de standaardlocatie.",
+ "loading": "Maplocatie laden…",
+ "loadFailed": "Opslaglocaties konden niet worden gelezen."
}
}
diff --git a/src/i18n/locales/pt-BR/native.json b/src/i18n/locales/pt-BR/native.json
index 3afb806bd..bf0f2861a 100644
--- a/src/i18n/locales/pt-BR/native.json
+++ b/src/i18n/locales/pt-BR/native.json
@@ -18,6 +18,7 @@
"saveFailedTitle": "Não foi possível salvar o projeto",
"saveFailedMessage": "O salvamento falhou ou não respondeu. Descartar as alterações não salvas e fechar?",
"welcome": "Boas-vindas ao Recordly",
+ "chooseFolder": "Escolher pasta",
"chooseRecordings": "Escolher pasta de gravações",
"saveRecordlyProject": "Salvar projeto do Recordly",
"recordlyProject": "Projeto do Recordly",
diff --git a/src/i18n/locales/pt-BR/settings.json b/src/i18n/locales/pt-BR/settings.json
index 5bf7aedb2..5bf6fd33d 100644
--- a/src/i18n/locales/pt-BR/settings.json
+++ b/src/i18n/locales/pt-BR/settings.json
@@ -598,5 +598,28 @@
},
"annotation": {
"delete": "Excluir anotação"
+ },
+ "storage": {
+ "title": "Locais de armazenamento",
+ "description": "Escolha onde o Recordly salva cada tipo de arquivo. Arquivos novos usam a pasta escolhida; os existentes ficam onde estão.",
+ "recordings": "Gravações",
+ "recordingsDescription": "Gravações de tela com áudio do sistema, faixas de microfone e dados do cursor.",
+ "projects": "Projetos e rascunhos",
+ "projectsDescription": "Projetos salvos, suas prévias e salvamentos automáticos. Fica dentro da pasta de gravações.",
+ "exports": "Vídeos exportados",
+ "exportsDescription": "Pasta que a janela de salvar abre ao exportar um MP4 ou GIF.",
+ "temp": "Arquivos temporários",
+ "tempDescription": "Dados temporários durante a gravação e a exportação. Use um disco maior se o disco do sistema for pequeno.",
+ "captionModels": "Modelos de legenda",
+ "captionModelsDescription": "Modelos de fala para texto baixados para legendas automáticas.",
+ "cache": "Cache",
+ "cacheDescription": "Dados regeneráveis como miniaturas de papel de parede e prévias de projetos. Pode mover ou limpar.",
+ "change": "Alterar…",
+ "open": "Abrir",
+ "reset": "Redefinir",
+ "resetAll": "Restaurar todos os locais padrão",
+ "usingDefault": "Atualmente é o local padrão.",
+ "loading": "Carregando o local da pasta…",
+ "loadFailed": "Não foi possível ler os locais de armazenamento."
}
}
diff --git a/src/i18n/locales/zh-CN/native.json b/src/i18n/locales/zh-CN/native.json
index db76741c0..25fea40e0 100644
--- a/src/i18n/locales/zh-CN/native.json
+++ b/src/i18n/locales/zh-CN/native.json
@@ -18,6 +18,7 @@
"saveFailedTitle": "无法保存项目",
"saveFailedMessage": "保存失败或未响应。要放弃未保存的更改并关闭吗?",
"welcome": "欢迎使用 Recordly",
+ "chooseFolder": "选择文件夹",
"chooseRecordings": "选择录制文件夹",
"saveRecordlyProject": "保存 Recordly 项目",
"recordlyProject": "Recordly 项目",
diff --git a/src/i18n/locales/zh-CN/settings.json b/src/i18n/locales/zh-CN/settings.json
index e23159388..091e7d09b 100644
--- a/src/i18n/locales/zh-CN/settings.json
+++ b/src/i18n/locales/zh-CN/settings.json
@@ -598,5 +598,28 @@
},
"annotation": {
"delete": "删除注释"
+ },
+ "storage": {
+ "title": "存储位置",
+ "description": "选择 Recordly 各类文件的保存位置。新文件使用你选择的文件夹,已有文件保持原地不动。",
+ "recordings": "录制视频",
+ "recordingsDescription": "屏幕录制,含系统声音、麦克风音轨与光标数据。",
+ "projects": "项目与草稿",
+ "projectsDescription": "保存的项目、预览图与自动保存,位于录制文件夹内。",
+ "exports": "导出视频",
+ "exportsDescription": "导出 MP4 或 GIF 时保存对话框默认打开的文件夹。",
+ "temp": "临时文件",
+ "tempDescription": "录制与导出过程中的中间数据。系统盘空间不足时可指向更大的磁盘。",
+ "captionModels": "字幕模型",
+ "captionModelsDescription": "自动字幕使用的语音识别模型。",
+ "cache": "缓存",
+ "cacheDescription": "可重新生成的数据,如壁纸缩略图与项目预览。可迁移或清理。",
+ "change": "更改…",
+ "open": "打开",
+ "reset": "重置",
+ "resetAll": "全部恢复默认位置",
+ "usingDefault": "当前为默认位置。",
+ "loading": "正在读取文件夹位置…",
+ "loadFailed": "无法读取存储位置。"
}
}
diff --git a/src/i18n/locales/zh-TW/native.json b/src/i18n/locales/zh-TW/native.json
index b8401a319..5c6951616 100644
--- a/src/i18n/locales/zh-TW/native.json
+++ b/src/i18n/locales/zh-TW/native.json
@@ -18,6 +18,7 @@
"saveFailedTitle": "無法儲存專案",
"saveFailedMessage": "儲存失敗或沒有回應。要捨棄未儲存的變更並關閉嗎?",
"welcome": "歡迎使用 Recordly",
+ "chooseFolder": "選擇資料夾",
"chooseRecordings": "選擇錄製資料夾",
"saveRecordlyProject": "儲存 Recordly 專案",
"recordlyProject": "Recordly 專案",
diff --git a/src/i18n/locales/zh-TW/settings.json b/src/i18n/locales/zh-TW/settings.json
index 3d9533759..dc329e7b6 100644
--- a/src/i18n/locales/zh-TW/settings.json
+++ b/src/i18n/locales/zh-TW/settings.json
@@ -598,5 +598,28 @@
},
"annotation": {
"delete": "刪除註釋"
+ },
+ "storage": {
+ "title": "儲存位置",
+ "description": "選擇 Recordly 各類檔案的儲存位置。新檔案使用你選擇的資料夾,既有檔案維持在原地。",
+ "recordings": "錄製影片",
+ "recordingsDescription": "螢幕錄製,包含系統聲音、麥克風音軌與游標資料。",
+ "projects": "專案與草稿",
+ "projectsDescription": "已儲存的專案、預覽圖與自動儲存,位於錄製資料夾內。",
+ "exports": "匯出影片",
+ "exportsDescription": "匯出 MP4 或 GIF 時儲存對話框預設開啟的資料夾。",
+ "temp": "暫存檔案",
+ "tempDescription": "錄製與匯出過程中的暫存資料。系統碟空間不足時可指向更大的磁碟。",
+ "captionModels": "字幕模型",
+ "captionModelsDescription": "自動字幕使用的語音辨識模型。",
+ "cache": "快取",
+ "cacheDescription": "可重新產生的資料,如桌布縮圖與專案預覽。可搬移或清理。",
+ "change": "變更…",
+ "open": "開啟",
+ "reset": "重設",
+ "resetAll": "全部恢復預設位置",
+ "usingDefault": "目前為預設位置。",
+ "loading": "正在讀取資料夾位置…",
+ "loadFailed": "無法讀取儲存位置。"
}
}
diff --git a/src/types/storageFolders.ts b/src/types/storageFolders.ts
new file mode 100644
index 000000000..90a2df638
--- /dev/null
+++ b/src/types/storageFolders.ts
@@ -0,0 +1,39 @@
+/**
+ * Storage folders as the renderer sees them.
+ *
+ * Declared here rather than under `electron/` so the settings UI can import the
+ * shape without reaching into the main-process tree, matching how other shared
+ * renderer types (for example `recordingLibrary`) are organised.
+ */
+
+export const STORAGE_FOLDER_IDS = [
+ "recordings",
+ "projects",
+ "exports",
+ "temp",
+ "captionModels",
+ "cache",
+] as const;
+
+export type StorageFolderId = (typeof STORAGE_FOLDER_IDS)[number];
+
+export type StorageFolder = {
+ id: StorageFolderId;
+ /** Folder currently in use. */
+ path: string;
+ /** Folder used when nothing is configured. */
+ fallback: string;
+ /** True when `path` comes from the user's settings. */
+ configured: boolean;
+};
+
+export type StorageFoldersResponse = {
+ success: boolean;
+ folders?: Record;
+ error?: string;
+};
+
+export type StorageFolderMutationResponse = StorageFoldersResponse & {
+ canceled?: boolean;
+ path?: string;
+};