From 656cb26ae25e916fe66f70e91bf83a664ed26008 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Wed, 28 Oct 2026 05:34:34 +0100 Subject: [PATCH] feat: save an attachment to Files from the message --- .../__tests__/save-to-files-dialog.test.tsx | 32 ++++ components/email/email-viewer.tsx | 42 +++++ components/email/save-to-files-dialog.tsx | 155 ++++++++++++++++++ locales/ar/common.json | 13 +- locales/ca/common.json | 13 +- locales/cs/common.json | 13 +- locales/da/common.json | 13 +- locales/de/common.json | 13 +- locales/en/common.json | 11 ++ locales/es/common.json | 13 +- locales/et/common.json | 13 +- locales/fa/common.json | 13 +- locales/fr/common.json | 13 +- locales/he/common.json | 13 +- locales/hu/common.json | 13 +- locales/it/common.json | 13 +- locales/ja/common.json | 13 +- locales/ko/common.json | 13 +- locales/lv/common.json | 13 +- locales/mn/common.json | 13 +- locales/nb/common.json | 13 +- locales/nl/common.json | 13 +- locales/pl/common.json | 13 +- locales/pt/common.json | 13 +- locales/ro/common.json | 13 +- locales/ru/common.json | 13 +- locales/sk/common.json | 13 +- locales/th/common.json | 11 ++ locales/tr/common.json | 13 +- locales/uk/common.json | 13 +- locales/zh-TW/common.json | 13 +- locales/zh/common.json | 13 +- 32 files changed, 575 insertions(+), 27 deletions(-) create mode 100644 components/email/__tests__/save-to-files-dialog.test.tsx create mode 100644 components/email/save-to-files-dialog.tsx diff --git a/components/email/__tests__/save-to-files-dialog.test.tsx b/components/email/__tests__/save-to-files-dialog.test.tsx new file mode 100644 index 000000000..1e471a415 --- /dev/null +++ b/components/email/__tests__/save-to-files-dialog.test.tsx @@ -0,0 +1,32 @@ +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; +import type { IJMAPClient } from '@/lib/jmap/client-interface'; +import type { FileNode } from '@/lib/jmap/types'; +import { useToastStore } from '@/stores/toast-store'; +import { SaveToFilesDialog } from '../save-to-files-dialog'; + +// "Save to Files" files an attachment in a folder of the Files app by its +// blobId: no download, no upload. + +const folder = (id: string, name: string, parentId: string | null = null) => + ({ id, name, parentId, blobId: null, type: 'd', size: 0, created: '', modified: '' }) as FileNode; +const nodes = [folder('docs', 'Documents'), folder('invoices', 'Invoices', 'docs'), folder('hidden', '.trash')]; +const attachment = { name: 'invoice.pdf', type: 'application/pdf', size: 1234, blobId: 'blob-1' }; + +describe('SaveToFilesDialog', () => { + it('saves the attachment into the picked folder by its blob', async () => { + const createFileNode = vi.fn().mockResolvedValue({}); + const client = { listAllFileNodes: vi.fn().mockResolvedValue(nodes), createFileNode } as unknown as IJMAPClient; + const onClose = vi.fn(); + render(); + + fireEvent.click(await screen.findByText('Documents')); + expect(screen.queryByText('.trash')).toBeNull(); + fireEvent.click(await screen.findByText('Invoices')); + fireEvent.click(screen.getByRole('button', { name: 'save_here' })); + + await waitFor(() => expect(createFileNode).toHaveBeenCalledWith('invoice.pdf', 'blob-1', 'application/pdf', 1234, 'invoices')); + await waitFor(() => expect(onClose).toHaveBeenCalled()); + expect(useToastStore.getState().toasts.some((toast) => toast.title === 'saved')).toBe(true); + }); +}); diff --git a/components/email/email-viewer.tsx b/components/email/email-viewer.tsx index 62a052d49..a6407bfba 100644 --- a/components/email/email-viewer.tsx +++ b/components/email/email-viewer.tsx @@ -38,6 +38,8 @@ import { emailToReadView } from "@/lib/plugin-projection"; import type { EmailReadView, ExternalLinkContext } from "@/lib/plugin-types"; import { ViewSourceDialog } from "./view-source-dialog"; import { MoveTargetList } from "./move-target-list"; +import { SaveToFilesDialog, type SaveableAttachment } from "./save-to-files-dialog"; +import { usePolicyStore } from "@/stores/policy-store"; import { ScheduleSendDialog } from "./schedule-send-dialog"; import { Reply, @@ -1268,6 +1270,9 @@ export function EmailViewer({ const legacyBlobAccountId = isUnifiedView ? email?.sourceAccountId : undefined; const blobClient = blobSource ? blobSource.client : legacyBlobClient; const blobAccountId = blobSource ? blobSource.accountId : legacyBlobAccountId; + const filesFeatureEnabled = usePolicyStore((s) => s.isFeatureEnabled('filesEnabled')); + const canSaveToFiles = filesFeatureEnabled && !!client && blobClient === client + && !!client.supportsFiles?.() && (!blobAccountId || blobAccountId === client.getAccountId()); // List-Unsubscribe mailto: send the message ourselves - this is a webmail // client, handing a mailto: URL to the OS mail handler goes nowhere for @@ -1371,6 +1376,9 @@ export function EmailViewer({ }; const [showSourceModal, setShowSourceModal] = useState(false); const [moreMenuOpen, setMoreMenuOpen] = useState(false); + // "Save to Files" for an attachment: where the Files app is on and the + // message is in the login's own account, whose files hold the blob too. + const [saveToFilesTarget, setSaveToFilesTarget] = useState(null); // Reschedule picks the new time in the composer's Schedule send dialog. const [rescheduleOpen, setRescheduleOpen] = useState(false); // The mobile More panel sits off-canvas with a slide transition. Until @@ -5103,6 +5111,11 @@ export function EmailViewer({ )} + {canSaveToFiles && attachment.blobId && ( + { e.stopPropagation(); setSaveToFilesTarget(attachment); }}> + + + )} @@ -5165,6 +5178,11 @@ export function EmailViewer({ )} + {canSaveToFiles && attachment.blobId && ( + { e.stopPropagation(); setSaveToFilesTarget(attachment); }}> + + + )} @@ -5927,6 +5945,11 @@ export function EmailViewer({ )} + {canSaveToFiles && attachment.blobId && ( + { e.stopPropagation(); setSaveToFilesTarget(attachment); }}> + + + )} @@ -5989,6 +6012,11 @@ export function EmailViewer({ )} + {canSaveToFiles && attachment.blobId && ( + { e.stopPropagation(); setSaveToFilesTarget(attachment); }}> + + + )} @@ -6052,6 +6080,11 @@ export function EmailViewer({ {formatFileSize(attachment.size)} {/* Phones have no hover: the plugin menu stays visible. */} + {canSaveToFiles && attachment.blobId && ( + { e.stopPropagation(); setSaveToFilesTarget(attachment); }}> + + + )}
{formatFileSize(attachment.size)} + {canSaveToFiles && attachment.blobId && ( + { e.stopPropagation(); setSaveToFilesTarget(attachment); }}> + + + )}
+ + + } + > + +
+ {failed ? ( +

{t("load_failed")}

+ ) : !nodes ? ( + + ) : folders.length === 0 ? ( +

{t("no_folders")}

+ ) : ( +
    + {folders.map((folder) => ( +
  • + +
  • + ))} +
+ )} +
+ + ); +} diff --git a/locales/ar/common.json b/locales/ar/common.json index e8813d2c6..a799b0168 100644 --- a/locales/ar/common.json +++ b/locales/ar/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "إظهار لوحة الإضافة", "plugin_panel_hide": "إخفاء لوحة الإضافة", "copy": "نسخ", - "contact_added": "أُضيفت جهة الاتصال" + "contact_added": "أُضيفت جهة الاتصال", + "save_to_files": { + "title": "حفظ في الملفات", + "location": "المجلد", + "root": "ملفاتي", + "save_here": "حفظ هنا", + "saved": "حُفظ في الملفات", + "saved_to": "في {folder}", + "failed": "تعذّر الحفظ في الملفات", + "load_failed": "تعذّر تحميل مجلداتك. حاول مرة أخرى.", + "no_folders": "لا توجد مجلدات هنا. احفظ هنا أو ارجع للخلف." + } }, "email_composer": { "select_from_directory": "الاختيار من الدليل", diff --git a/locales/ca/common.json b/locales/ca/common.json index ccc3b3e70..77286e5b1 100644 --- a/locales/ca/common.json +++ b/locales/ca/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Mostra el tauler del connector", "plugin_panel_hide": "Amaga el tauler del connector", "copy": "Copia", - "contact_added": "S'ha afegit el contacte" + "contact_added": "S'ha afegit el contacte", + "save_to_files": { + "title": "Desa a Fitxers", + "location": "Carpeta", + "root": "Els meus fitxers", + "save_here": "Desa aquí", + "saved": "S'ha desat a Fitxers", + "saved_to": "A {folder}", + "failed": "No s'ha pogut desar a Fitxers", + "load_failed": "No s'han pogut carregar les carpetes. Torna-ho a provar.", + "no_folders": "Aquí no hi ha carpetes. Desa-ho aquí o torna enrere." + } }, "email_composer": { "select_from_directory": "Selecciona del directori", diff --git a/locales/cs/common.json b/locales/cs/common.json index 8a0bd177a..ea6097c2e 100644 --- a/locales/cs/common.json +++ b/locales/cs/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Zobrazit panel pluginu", "plugin_panel_hide": "Skrýt panel pluginu", "copy": "Kopírovat", - "contact_added": "Kontakt přidán" + "contact_added": "Kontakt přidán", + "save_to_files": { + "title": "Uložit do Souborů", + "location": "Složka", + "root": "Moje soubory", + "save_here": "Uložit sem", + "saved": "Uloženo do Souborů", + "saved_to": "Do složky {folder}", + "failed": "Nepodařilo se uložit do Souborů", + "load_failed": "Složky se nepodařilo načíst. Zkuste to znovu.", + "no_folders": "Nejsou tu žádné složky. Uložte sem nebo se vraťte." + } }, "email_composer": { "select_from_directory": "Vybrat z adresáře", diff --git a/locales/da/common.json b/locales/da/common.json index 557c1a695..0ba412712 100644 --- a/locales/da/common.json +++ b/locales/da/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Vis pluginpanel", "plugin_panel_hide": "Skjul pluginpanel", "copy": "Kopiér", - "contact_added": "Kontakt tilføjet" + "contact_added": "Kontakt tilføjet", + "save_to_files": { + "title": "Gem i Filer", + "location": "Mappe", + "root": "Mine filer", + "save_here": "Gem her", + "saved": "Gemt i Filer", + "saved_to": "I {folder}", + "failed": "Kunne ikke gemme i Filer", + "load_failed": "Mapperne kunne ikke indlæses. Prøv igen.", + "no_folders": "Der er ingen mapper her. Gem her, eller gå tilbage." + } }, "email_composer": { "select_from_directory": "Vælg fra adressefortegnelse", diff --git a/locales/de/common.json b/locales/de/common.json index 3621b9aaa..a3926c0b5 100644 --- a/locales/de/common.json +++ b/locales/de/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Plugin-Bereich einblenden", "plugin_panel_hide": "Plugin-Bereich ausblenden", "copy": "Kopieren", - "contact_added": "Kontakt hinzugefügt" + "contact_added": "Kontakt hinzugefügt", + "save_to_files": { + "title": "In Dateien speichern", + "location": "Ordner", + "root": "Meine Dateien", + "save_here": "Hier speichern", + "saved": "In Dateien gespeichert", + "saved_to": "In {folder}", + "failed": "Konnte nicht in Dateien gespeichert werden", + "load_failed": "Ihre Ordner konnten nicht geladen werden. Versuchen Sie es erneut.", + "no_folders": "Hier gibt es keine Ordner. Speichern Sie hier oder gehen Sie zurück." + } }, "email_composer": { "select_from_directory": "Aus Verzeichnis auswählen", diff --git a/locales/en/common.json b/locales/en/common.json index 266332e2c..47c3fb22f 100644 --- a/locales/en/common.json +++ b/locales/en/common.json @@ -697,6 +697,17 @@ "mv_position": "{index} of {total}", "copy": "Copy", "contact_added": "Contact added", + "save_to_files": { + "title": "Save to Files", + "location": "Folder", + "root": "My files", + "save_here": "Save here", + "saved": "Saved to Files", + "saved_to": "In {folder}", + "failed": "Couldn't save to Files", + "load_failed": "Couldn't load your folders. Try again.", + "no_folders": "No folders here. Save here or go back." + }, "plugin_panel_show": "Show plugin panel", "plugin_panel_hide": "Hide plugin panel" }, diff --git a/locales/es/common.json b/locales/es/common.json index a865fe717..7264aaadd 100644 --- a/locales/es/common.json +++ b/locales/es/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Mostrar el panel del complemento", "plugin_panel_hide": "Ocultar el panel del complemento", "copy": "Copiar", - "contact_added": "Contacto añadido" + "contact_added": "Contacto añadido", + "save_to_files": { + "title": "Guardar en Archivos", + "location": "Carpeta", + "root": "Mis archivos", + "save_here": "Guardar aquí", + "saved": "Guardado en Archivos", + "saved_to": "En {folder}", + "failed": "No se pudo guardar en Archivos", + "load_failed": "No se pudieron cargar tus carpetas. Vuelve a intentarlo.", + "no_folders": "Aquí no hay carpetas. Guarda aquí o vuelve atrás." + } }, "email_composer": { "select_from_directory": "Seleccionar del directorio", diff --git a/locales/et/common.json b/locales/et/common.json index b8fcf34b9..6b7d93914 100644 --- a/locales/et/common.json +++ b/locales/et/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Näita pistikprogrammi paneeli", "plugin_panel_hide": "Peida pistikprogrammi paneel", "copy": "Kopeeri", - "contact_added": "Kontakt lisatud" + "contact_added": "Kontakt lisatud", + "save_to_files": { + "title": "Salvesta failidesse", + "location": "Kaust", + "root": "Minu failid", + "save_here": "Salvesta siia", + "saved": "Salvestatud failidesse", + "saved_to": "Kausta {folder}", + "failed": "Failidesse salvestamine ei õnnestunud", + "load_failed": "Kaustu ei õnnestunud laadida. Proovige uuesti.", + "no_folders": "Siin pole kaustu. Salvestage siia või minge tagasi." + } }, "email_composer": { "select_from_directory": "Vali kataloogist", diff --git a/locales/fa/common.json b/locales/fa/common.json index b3554bb23..74a62eb57 100644 --- a/locales/fa/common.json +++ b/locales/fa/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "نمایش پنل افزونه", "plugin_panel_hide": "پنهان کردن پنل افزونه", "copy": "کپی", - "contact_added": "مخاطب افزوده شد" + "contact_added": "مخاطب افزوده شد", + "save_to_files": { + "title": "ذخیره در فایل‌ها", + "location": "پوشه", + "root": "فایل‌های من", + "save_here": "ذخیره در اینجا", + "saved": "در فایل‌ها ذخیره شد", + "saved_to": "در {folder}", + "failed": "ذخیره در فایل‌ها ممکن نشد", + "load_failed": "پوشه‌ها بارگذاری نشدند. دوباره امتحان کنید.", + "no_folders": "اینجا پوشه‌ای نیست. همین‌جا ذخیره کنید یا برگردید." + } }, "email_composer": { "select_from_directory": "انتخاب از فهرست", diff --git a/locales/fr/common.json b/locales/fr/common.json index fcf232d02..5121d1a45 100644 --- a/locales/fr/common.json +++ b/locales/fr/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Afficher le panneau du plugin", "plugin_panel_hide": "Masquer le panneau du plugin", "copy": "Copier", - "contact_added": "Contact ajouté" + "contact_added": "Contact ajouté", + "save_to_files": { + "title": "Enregistrer dans Fichiers", + "location": "Dossier", + "root": "Mes fichiers", + "save_here": "Enregistrer ici", + "saved": "Enregistré dans Fichiers", + "saved_to": "Dans {folder}", + "failed": "Impossible d'enregistrer dans Fichiers", + "load_failed": "Impossible de charger vos dossiers. Réessayez.", + "no_folders": "Aucun dossier ici. Enregistrez ici ou revenez en arrière." + } }, "email_composer": { "select_from_directory": "Choisir dans l'annuaire", diff --git a/locales/he/common.json b/locales/he/common.json index a2ed9d9d3..a9430418d 100644 --- a/locales/he/common.json +++ b/locales/he/common.json @@ -663,7 +663,18 @@ "plugin_panel_show": "הצגת חלונית התוסף", "plugin_panel_hide": "הסתרת חלונית התוסף", "copy": "העתק", - "contact_added": "איש הקשר נוסף" + "contact_added": "איש הקשר נוסף", + "save_to_files": { + "title": "שמירה בקבצים", + "location": "תיקייה", + "root": "הקבצים שלי", + "save_here": "שמירה כאן", + "saved": "נשמר בקבצים", + "saved_to": "ב{folder}", + "failed": "לא ניתן היה לשמור בקבצים", + "load_failed": "לא ניתן היה לטעון את התיקיות. נסו שוב.", + "no_folders": "אין כאן תיקיות. שמרו כאן או חזרו אחורה." + } }, "email_composer": { "select_from_directory": "בחירה מהספרייה", diff --git a/locales/hu/common.json b/locales/hu/common.json index 65d3ee272..b8651028d 100644 --- a/locales/hu/common.json +++ b/locales/hu/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Bővítménypanel megjelenítése", "plugin_panel_hide": "Bővítménypanel elrejtése", "copy": "Másolás", - "contact_added": "Névjegy hozzáadva" + "contact_added": "Névjegy hozzáadva", + "save_to_files": { + "title": "Mentés a Fájlokba", + "location": "Mappa", + "root": "Saját fájlok", + "save_here": "Mentés ide", + "saved": "Mentve a Fájlokba", + "saved_to": "Ide: {folder}", + "failed": "Nem sikerült menteni a Fájlokba", + "load_failed": "Nem sikerült betölteni a mappákat. Próbálja újra.", + "no_folders": "Itt nincsenek mappák. Mentsen ide, vagy lépjen vissza." + } }, "email_composer": { "select_from_directory": "Kiválasztás a címtárból", diff --git a/locales/it/common.json b/locales/it/common.json index 42efac83b..103260fa6 100644 --- a/locales/it/common.json +++ b/locales/it/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Mostra il pannello del plugin", "plugin_panel_hide": "Nascondi il pannello del plugin", "copy": "Copia", - "contact_added": "Contatto aggiunto" + "contact_added": "Contatto aggiunto", + "save_to_files": { + "title": "Salva in File", + "location": "Cartella", + "root": "I miei file", + "save_here": "Salva qui", + "saved": "Salvato in File", + "saved_to": "In {folder}", + "failed": "Impossibile salvare in File", + "load_failed": "Impossibile caricare le cartelle. Riprova.", + "no_folders": "Nessuna cartella qui. Salva qui o torna indietro." + } }, "email_composer": { "select_from_directory": "Seleziona dalla rubrica aziendale", diff --git a/locales/ja/common.json b/locales/ja/common.json index 96c5b10b1..c7827c098 100644 --- a/locales/ja/common.json +++ b/locales/ja/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "プラグインパネルを表示", "plugin_panel_hide": "プラグインパネルを隠す", "copy": "コピー", - "contact_added": "連絡先を追加しました" + "contact_added": "連絡先を追加しました", + "save_to_files": { + "title": "ファイルに保存", + "location": "フォルダ", + "root": "マイファイル", + "save_here": "ここに保存", + "saved": "ファイルに保存しました", + "saved_to": "{folder} に保存", + "failed": "ファイルに保存できませんでした", + "load_failed": "フォルダを読み込めませんでした。もう一度お試しください。", + "no_folders": "ここにはフォルダがありません。ここに保存するか、戻ってください。" + } }, "email_composer": { "select_from_directory": "ディレクトリから選択", diff --git a/locales/ko/common.json b/locales/ko/common.json index c24e26834..73cea7c75 100644 --- a/locales/ko/common.json +++ b/locales/ko/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "플러그인 패널 표시", "plugin_panel_hide": "플러그인 패널 숨기기", "copy": "복사", - "contact_added": "연락처를 추가했어요" + "contact_added": "연락처를 추가했어요", + "save_to_files": { + "title": "파일에 저장", + "location": "폴더", + "root": "내 파일", + "save_here": "여기에 저장", + "saved": "파일에 저장했어요", + "saved_to": "{folder}에 저장", + "failed": "파일에 저장하지 못했어요", + "load_failed": "폴더를 불러오지 못했어요. 다시 시도하세요.", + "no_folders": "여기에는 폴더가 없어요. 여기에 저장하거나 뒤로 가세요." + } }, "email_composer": { "select_from_directory": "디렉터리에서 선택", diff --git a/locales/lv/common.json b/locales/lv/common.json index 0dd480735..640efe9ff 100644 --- a/locales/lv/common.json +++ b/locales/lv/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Rādīt spraudņa paneli", "plugin_panel_hide": "Slēpt spraudņa paneli", "copy": "Kopēt", - "contact_added": "Kontakts pievienots" + "contact_added": "Kontakts pievienots", + "save_to_files": { + "title": "Saglabāt failos", + "location": "Mape", + "root": "Mani faili", + "save_here": "Saglabāt šeit", + "saved": "Saglabāts failos", + "saved_to": "Mapē {folder}", + "failed": "Neizdevās saglabāt failos", + "load_failed": "Neizdevās ielādēt mapes. Mēģiniet vēlreiz.", + "no_folders": "Šeit nav mapju. Saglabājiet šeit vai atgriezieties." + } }, "email_composer": { "select_from_directory": "Izvēlēties no kataloga", diff --git a/locales/mn/common.json b/locales/mn/common.json index 257df32c3..1b6081c13 100644 --- a/locales/mn/common.json +++ b/locales/mn/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Залгаасын самбарыг харуулах", "plugin_panel_hide": "Залгаасын самбарыг нуух", "copy": "Хуулах", - "contact_added": "Харилцагч нэмэгдлээ" + "contact_added": "Харилцагч нэмэгдлээ", + "save_to_files": { + "title": "Файлд хадгалах", + "location": "Хавтас", + "root": "Миний файлууд", + "save_here": "Энд хадгалах", + "saved": "Файлд хадгаллаа", + "saved_to": "{folder}-д", + "failed": "Файлд хадгалж чадсангүй", + "load_failed": "Хавтсуудыг ачаалж чадсангүй. Дахин оролдоно уу.", + "no_folders": "Энд хавтас алга. Энд хадгалах эсвэл буцна уу." + } }, "email_composer": { "select_from_directory": "Лавлахаас сонгох", diff --git a/locales/nb/common.json b/locales/nb/common.json index a6cca4c89..6546aafc0 100644 --- a/locales/nb/common.json +++ b/locales/nb/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Vis tilleggspanel", "plugin_panel_hide": "Skjul tilleggspanel", "copy": "Kopier", - "contact_added": "Kontakt lagt til" + "contact_added": "Kontakt lagt til", + "save_to_files": { + "title": "Lagre i Filer", + "location": "Mappe", + "root": "Mine filer", + "save_here": "Lagre her", + "saved": "Lagret i Filer", + "saved_to": "I {folder}", + "failed": "Kunne ikke lagre i Filer", + "load_failed": "Kunne ikke laste inn mappene. Prøv igjen.", + "no_folders": "Ingen mapper her. Lagre her eller gå tilbake." + } }, "email_composer": { "select_from_directory": "Velg fra katalog", diff --git a/locales/nl/common.json b/locales/nl/common.json index 63dfdff4b..89cfe6bb2 100644 --- a/locales/nl/common.json +++ b/locales/nl/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Plug-inpaneel tonen", "plugin_panel_hide": "Plug-inpaneel verbergen", "copy": "Kopiëren", - "contact_added": "Contact toegevoegd" + "contact_added": "Contact toegevoegd", + "save_to_files": { + "title": "Opslaan in Bestanden", + "location": "Map", + "root": "Mijn bestanden", + "save_here": "Hier opslaan", + "saved": "Opgeslagen in Bestanden", + "saved_to": "In {folder}", + "failed": "Kon niet opslaan in Bestanden", + "load_failed": "Kon je mappen niet laden. Probeer het opnieuw.", + "no_folders": "Hier zijn geen mappen. Sla hier op of ga terug." + } }, "email_composer": { "select_from_directory": "Kiezen uit adresboek van de organisatie", diff --git a/locales/pl/common.json b/locales/pl/common.json index f01c91c0b..acff1c7ed 100644 --- a/locales/pl/common.json +++ b/locales/pl/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Pokaż panel wtyczki", "plugin_panel_hide": "Ukryj panel wtyczki", "copy": "Kopiuj", - "contact_added": "Dodano kontakt" + "contact_added": "Dodano kontakt", + "save_to_files": { + "title": "Zapisz w Plikach", + "location": "Folder", + "root": "Moje pliki", + "save_here": "Zapisz tutaj", + "saved": "Zapisano w Plikach", + "saved_to": "W folderze {folder}", + "failed": "Nie udało się zapisać w Plikach", + "load_failed": "Nie udało się wczytać folderów. Spróbuj ponownie.", + "no_folders": "Brak folderów. Zapisz tutaj lub wróć." + } }, "email_composer": { "select_from_directory": "Wybierz z katalogu", diff --git a/locales/pt/common.json b/locales/pt/common.json index fb4a669ca..f406b5733 100644 --- a/locales/pt/common.json +++ b/locales/pt/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Mostrar o painel do plugin", "plugin_panel_hide": "Ocultar o painel do plugin", "copy": "Copiar", - "contact_added": "Contacto adicionado" + "contact_added": "Contacto adicionado", + "save_to_files": { + "title": "Guardar em Ficheiros", + "location": "Pasta", + "root": "Os meus ficheiros", + "save_here": "Guardar aqui", + "saved": "Guardado em Ficheiros", + "saved_to": "Em {folder}", + "failed": "Não foi possível guardar em Ficheiros", + "load_failed": "Não foi possível carregar as pastas. Tente novamente.", + "no_folders": "Não há pastas aqui. Guarde aqui ou volte atrás." + } }, "email_composer": { "select_from_directory": "Selecionar do diretório", diff --git a/locales/ro/common.json b/locales/ro/common.json index 01675ae2d..13ea2275e 100644 --- a/locales/ro/common.json +++ b/locales/ro/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Afișează panoul pluginului", "plugin_panel_hide": "Ascunde panoul pluginului", "copy": "Copiază", - "contact_added": "Contact adăugat" + "contact_added": "Contact adăugat", + "save_to_files": { + "title": "Salvează în Fișiere", + "location": "Dosar", + "root": "Fișierele mele", + "save_here": "Salvează aici", + "saved": "Salvat în Fișiere", + "saved_to": "În {folder}", + "failed": "Nu s-a putut salva în Fișiere", + "load_failed": "Dosarele nu au putut fi încărcate. Încearcă din nou.", + "no_folders": "Nu există dosare aici. Salvează aici sau întoarce-te." + } }, "email_composer": { "select_from_directory": "Selectează din director", diff --git a/locales/ru/common.json b/locales/ru/common.json index 9f2b57369..1702c15ad 100644 --- a/locales/ru/common.json +++ b/locales/ru/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Показать панель плагина", "plugin_panel_hide": "Скрыть панель плагина", "copy": "Копировать", - "contact_added": "Контакт добавлен" + "contact_added": "Контакт добавлен", + "save_to_files": { + "title": "Сохранить в «Файлы»", + "location": "Папка", + "root": "Мои файлы", + "save_here": "Сохранить сюда", + "saved": "Сохранено в «Файлы»", + "saved_to": "В папку {folder}", + "failed": "Не удалось сохранить в «Файлы»", + "load_failed": "Не удалось загрузить папки. Повторите попытку.", + "no_folders": "Здесь нет папок. Сохраните сюда или вернитесь назад." + } }, "email_composer": { "select_from_directory": "Выбрать из справочника", diff --git a/locales/sk/common.json b/locales/sk/common.json index 7f5081545..e7541b0eb 100644 --- a/locales/sk/common.json +++ b/locales/sk/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Zobraziť panel doplnku", "plugin_panel_hide": "Skryť panel doplnku", "copy": "Kopírovať", - "contact_added": "Kontakt pridaný" + "contact_added": "Kontakt pridaný", + "save_to_files": { + "title": "Uložiť do Súborov", + "location": "Priečinok", + "root": "Moje súbory", + "save_here": "Uložiť sem", + "saved": "Uložené do Súborov", + "saved_to": "Do priečinka {folder}", + "failed": "Nepodarilo sa uložiť do Súborov", + "load_failed": "Priečinky sa nepodarilo načítať. Skúste to znova.", + "no_folders": "Nie sú tu žiadne priečinky. Uložte sem alebo sa vráťte." + } }, "email_composer": { "select_from_directory": "Vybrať z adresára", diff --git a/locales/th/common.json b/locales/th/common.json index a4dc7bc53..3f2cb0f84 100644 --- a/locales/th/common.json +++ b/locales/th/common.json @@ -1452,6 +1452,17 @@ "mv_position": "{index} จาก {total}", "copy": "คัดลอก", "contact_added": "เพิ่มผู้ติดต่อแล้ว", + "save_to_files": { + "title": "บันทึกลงไฟล์", + "location": "โฟลเดอร์", + "root": "ไฟล์ของฉัน", + "save_here": "บันทึกที่นี่", + "saved": "บันทึกลงไฟล์แล้ว", + "saved_to": "ใน {folder}", + "failed": "ไม่สามารถบันทึกลงไฟล์ได้", + "load_failed": "ไม่สามารถโหลดโฟลเดอร์ได้ ลองอีกครั้ง", + "no_folders": "ไม่มีโฟลเดอร์ที่นี่ บันทึกที่นี่หรือย้อนกลับ" + }, "plugin_panel_show": "แสดงแถบปลั๊กอิน", "plugin_panel_hide": "ซ่อนแถบปลั๊กอิน" }, diff --git a/locales/tr/common.json b/locales/tr/common.json index 8f75bf639..174f49dba 100644 --- a/locales/tr/common.json +++ b/locales/tr/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Eklenti panelini göster", "plugin_panel_hide": "Eklenti panelini gizle", "copy": "Kopyala", - "contact_added": "Kişi eklendi" + "contact_added": "Kişi eklendi", + "save_to_files": { + "title": "Dosyalar'a kaydet", + "location": "Klasör", + "root": "Dosyalarım", + "save_here": "Buraya kaydet", + "saved": "Dosyalar'a kaydedildi", + "saved_to": "{folder} içine", + "failed": "Dosyalar'a kaydedilemedi", + "load_failed": "Klasörler yüklenemedi. Yeniden deneyin.", + "no_folders": "Burada klasör yok. Buraya kaydedin veya geri dönün." + } }, "email_composer": { "select_from_directory": "Dizinden seç", diff --git a/locales/uk/common.json b/locales/uk/common.json index a2d3411f6..06992b710 100644 --- a/locales/uk/common.json +++ b/locales/uk/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "Показати панель плагіна", "plugin_panel_hide": "Сховати панель плагіна", "copy": "Копіювати", - "contact_added": "Контакт додано" + "contact_added": "Контакт додано", + "save_to_files": { + "title": "Зберегти у «Файли»", + "location": "Тека", + "root": "Мої файли", + "save_here": "Зберегти сюди", + "saved": "Збережено у «Файли»", + "saved_to": "У теку {folder}", + "failed": "Не вдалося зберегти у «Файли»", + "load_failed": "Не вдалося завантажити теки. Спробуйте ще раз.", + "no_folders": "Тут немає тек. Збережіть сюди або поверніться назад." + } }, "email_composer": { "select_from_directory": "Вибрати з довідника", diff --git a/locales/zh-TW/common.json b/locales/zh-TW/common.json index b1fc15387..b8c9d01c4 100644 --- a/locales/zh-TW/common.json +++ b/locales/zh-TW/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "顯示外掛程式面板", "plugin_panel_hide": "隱藏外掛程式面板", "copy": "複製", - "contact_added": "已新增聯絡人" + "contact_added": "已新增聯絡人", + "save_to_files": { + "title": "儲存到檔案", + "location": "資料夾", + "root": "我的檔案", + "save_here": "儲存在這裡", + "saved": "已儲存到檔案", + "saved_to": "在 {folder} 中", + "failed": "無法儲存到檔案", + "load_failed": "無法載入資料夾。請再試一次。", + "no_folders": "這裡沒有資料夾。儲存在這裡或返回。" + } }, "email_composer": { "select_from_directory": "從目錄中選取", diff --git a/locales/zh/common.json b/locales/zh/common.json index 4f40a57ae..99ecfbb8c 100644 --- a/locales/zh/common.json +++ b/locales/zh/common.json @@ -698,7 +698,18 @@ "plugin_panel_show": "显示插件面板", "plugin_panel_hide": "隐藏插件面板", "copy": "复制", - "contact_added": "已添加联系人" + "contact_added": "已添加联系人", + "save_to_files": { + "title": "保存到文件", + "location": "文件夹", + "root": "我的文件", + "save_here": "保存到此处", + "saved": "已保存到文件", + "saved_to": "在 {folder} 中", + "failed": "无法保存到文件", + "load_failed": "无法加载文件夹。请重试。", + "no_folders": "此处没有文件夹。保存到此处或返回。" + } }, "email_composer": { "select_from_directory": "从目录中选择",