feat: support importing emails from .zip archives

This commit is contained in:
Linus Rath
2026-05-22 15:22:33 +02:00
parent e7bded82fb
commit 52f5a5b42c
20 changed files with 128 additions and 51 deletions
+12 -4
View File
@@ -57,6 +57,7 @@ import { FilePreviewModal } from "@/components/files/file-preview-modal";
import { isFilePreviewable } from "@/lib/file-preview"; import { isFilePreviewable } from "@/lib/file-preview";
import { appendPlainTextSignature } from "@/lib/signature-utils"; import { appendPlainTextSignature } from "@/lib/signature-utils";
import { computeReplyThreadingHeaders } from "@/lib/email-threading"; import { computeReplyThreadingHeaders } from "@/lib/email-threading";
import { EML_IMPORT_ACCEPT, expandImportableEmails } from "@/lib/eml-import";
import { resolveReplyFrom } from "@/lib/reply-identity"; import { resolveReplyFrom } from "@/lib/reply-identity";
import { Search, Filter, ChevronDown, X, Paperclip, Star, Mail, MailOpen, RotateCcw, PenSquare, PenLine, CheckSquare, Square, AlertTriangle } from "lucide-react"; import { Search, Filter, ChevronDown, X, Paperclip, Star, Mail, MailOpen, RotateCcw, PenSquare, PenLine, CheckSquare, Square, AlertTriangle } from "lucide-react";
import { ResizeHandle } from "@/components/layout/resize-handle"; import { ResizeHandle } from "@/components/layout/resize-handle";
@@ -1753,17 +1754,24 @@ export default function Home() {
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'file'; input.type = 'file';
input.accept = '.eml,message/rfc822'; input.accept = EML_IMPORT_ACCEPT;
input.multiple = true; input.multiple = true;
input.onchange = async (e) => { input.onchange = async (e) => {
const files = Array.from((e.target as HTMLInputElement).files ?? []); const files = Array.from((e.target as HTMLInputElement).files ?? []);
if (files.length === 0) return; if (files.length === 0) return;
let emails;
try {
emails = await expandImportableEmails(files);
} catch {
toast.error(t('notifications.import_email_error'));
return;
}
let imported = 0; let imported = 0;
let failed = 0; let failed = 0;
for (const file of files) { for (const { blob } of emails) {
try { try {
const blob = new Blob([await file.arrayBuffer()], { type: 'message/rfc822' });
await client.importRawEmail(blob, { [targetMailboxId]: true }, { '$seen': true }); await client.importRawEmail(blob, { [targetMailboxId]: true }, { '$seen': true });
imported++; imported++;
} catch { } catch {
@@ -1775,7 +1783,7 @@ export default function Home() {
toast.success(t('notifications.import_email_success')); toast.success(t('notifications.import_email_success'));
if (selectedMailbox) await fetchEmails(client, selectedMailbox); if (selectedMailbox) await fetchEmails(client, selectedMailbox);
} }
if (failed > 0) { if (failed > 0 || (imported === 0 && emails.length === 0)) {
toast.error(t('notifications.import_email_error')); toast.error(t('notifications.import_email_error'));
} }
}; };
+34 -13
View File
@@ -4,6 +4,7 @@ import { useState, useEffect, useLayoutEffect, useMemo, useRef, useCallback } fr
import DOMPurify from "dompurify"; import DOMPurify from "dompurify";
import { Email, ContactCard, Mailbox } from "@/lib/jmap/types"; import { Email, ContactCard, Mailbox } from "@/lib/jmap/types";
import { emailExportFilename, attachmentDownloadFilename, DEFAULT_EMAIL_TEMPLATE, DEFAULT_ATTACHMENT_TEMPLATE } from "@/lib/download-filename"; import { emailExportFilename, attachmentDownloadFilename, DEFAULT_EMAIL_TEMPLATE, DEFAULT_ATTACHMENT_TEMPLATE } from "@/lib/download-filename";
import { EML_IMPORT_ACCEPT, expandImportableEmails } from "@/lib/eml-import";
import { EMAIL_IFRAME_SANITIZE_CONFIG, collapseBlockedImageContainers, escapeHtml, plainTextToSafeHtml, sanitizeEmailHtml, sanitizePlainTextRenderedHtml } from "@/lib/email-sanitization"; import { EMAIL_IFRAME_SANITIZE_CONFIG, collapseBlockedImageContainers, escapeHtml, plainTextToSafeHtml, sanitizeEmailHtml, sanitizePlainTextRenderedHtml } from "@/lib/email-sanitization";
import { hasMeaningfulHtmlBody } from "@/lib/signature-utils"; import { hasMeaningfulHtmlBody } from "@/lib/signature-utils";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@@ -3096,28 +3097,48 @@ export function EmailViewer({
} }
}; };
// Import email from .eml file // Import email from .eml file or .zip archive containing .eml files
const handleImportEmail = () => { const handleImportEmail = () => {
if (!client) return; if (!client) return;
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'file'; input.type = 'file';
input.accept = '.eml,message/rfc822'; input.accept = EML_IMPORT_ACCEPT;
input.multiple = true;
input.onchange = async (e) => { input.onchange = async (e) => {
const file = (e.target as HTMLInputElement).files?.[0]; const files = Array.from((e.target as HTMLInputElement).files ?? []);
if (!file) return; if (files.length === 0) return;
const { selectedMailbox, mailboxes, fetchEmails } = useEmailStore.getState();
const mailbox = mailboxes.find(mb => mb.id === selectedMailbox);
const mailboxId = mailbox?.originalId || selectedMailbox;
if (!mailboxId) {
toast.error(tNotifications('import_email_error'));
return;
}
let emails;
try { try {
const { selectedMailbox, mailboxes, fetchEmails } = useEmailStore.getState(); emails = await expandImportableEmails(files);
const mailbox = mailboxes.find(mb => mb.id === selectedMailbox); } catch {
const mailboxId = mailbox?.originalId || selectedMailbox; toast.error(tNotifications('import_email_error'));
if (!mailboxId) { return;
toast.error(tNotifications('import_email_error')); }
return;
let imported = 0;
let failed = 0;
for (const { blob } of emails) {
try {
await client.importRawEmail(blob, { [mailboxId]: true }, { '$seen': true });
imported++;
} catch {
failed++;
} }
const blob = new Blob([await file.arrayBuffer()], { type: 'message/rfc822' }); }
await client.importRawEmail(blob, { [mailboxId]: true }, { '$seen': true });
if (imported > 0) {
toast.success(tNotifications('import_email_success')); toast.success(tNotifications('import_email_success'));
await fetchEmails(client); await fetchEmails(client);
} catch { }
if (failed > 0 || emails.length === 0) {
toast.error(tNotifications('import_email_error')); toast.error(tNotifications('import_email_error'));
} }
}; };
+48
View File
@@ -0,0 +1,48 @@
export interface ImportableEmail {
name: string;
blob: Blob;
}
const EMAIL_MIME = "message/rfc822";
function isEmlName(name: string): boolean {
return /\.eml$/i.test(name);
}
function isZipName(name: string): boolean {
return /\.zip$/i.test(name);
}
async function extractEmlsFromZip(file: File): Promise<ImportableEmail[]> {
const { default: JSZip } = await import("jszip");
const zip = await JSZip.loadAsync(await file.arrayBuffer());
const out: ImportableEmail[] = [];
const entries = Object.values(zip.files);
for (const entry of entries) {
if (entry.dir) continue;
if (!isEmlName(entry.name)) continue;
const data = await entry.async("arraybuffer");
out.push({
name: entry.name.split(/[\\/]/).pop() || entry.name,
blob: new Blob([data], { type: EMAIL_MIME }),
});
}
return out;
}
export async function expandImportableEmails(
files: File[],
): Promise<ImportableEmail[]> {
const out: ImportableEmail[] = [];
for (const file of files) {
if (isZipName(file.name) || file.type === "application/zip") {
out.push(...(await extractEmlsFromZip(file)));
continue;
}
const blob = new Blob([await file.arrayBuffer()], { type: EMAIL_MIME });
out.push({ name: file.name, blob });
}
return out;
}
export const EML_IMPORT_ACCEPT = ".eml,.zip,message/rfc822,application/zip";
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Tisk", "print": "Tisk",
"view_source": "Zobrazit zdrojový kód", "view_source": "Zobrazit zdrojový kód",
"export_email": "Exportovat jako .eml", "export_email": "Exportovat jako .eml",
"import_email": "Importovat .eml", "import_email": "Importovat .eml nebo .zip",
"keyboard_shortcuts": "Klávesové zkratky (?)", "keyboard_shortcuts": "Klávesové zkratky (?)",
"email_source": "Zdrojový kód zprávy", "email_source": "Zdrojový kód zprávy",
"draft_banner": "Tato zpráva je koncept", "draft_banner": "Tato zpráva je koncept",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Nová podsložka...", "new_subfolder": "Nová podsložka...",
"new_folder": "Nová složka...", "new_folder": "Nová složka...",
"rename": "Přejmenovat...", "rename": "Přejmenovat...",
"import_email": "Importovat .eml...", "import_email": "Importovat .eml nebo .zip...",
"empty_folder": "Vyprázdnit složku", "empty_folder": "Vyprázdnit složku",
"empty_folder_generic": "Vyprázdnit složku", "empty_folder_generic": "Vyprázdnit složku",
"delete_folder": "Smazat složku", "delete_folder": "Smazat složku",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Udskriv", "print": "Udskriv",
"view_source": "Vis kilde", "view_source": "Vis kilde",
"export_email": "Eksportér som .eml", "export_email": "Eksportér som .eml",
"import_email": "Importér .eml", "import_email": "Importér .eml eller .zip",
"keyboard_shortcuts": "Tastaturgenveje (?)", "keyboard_shortcuts": "Tastaturgenveje (?)",
"email_source": "E-mail-kilde", "email_source": "E-mail-kilde",
"draft_banner": "Denne besked er en kladde", "draft_banner": "Denne besked er en kladde",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Ny undermappe...", "new_subfolder": "Ny undermappe...",
"new_folder": "Ny mappe...", "new_folder": "Ny mappe...",
"rename": "Omdøb...", "rename": "Omdøb...",
"import_email": "Importér .eml...", "import_email": "Importér .eml eller .zip...",
"empty_folder": "Tøm mappe", "empty_folder": "Tøm mappe",
"empty_folder_generic": "Tøm mappe", "empty_folder_generic": "Tøm mappe",
"delete_folder": "Slet mappe", "delete_folder": "Slet mappe",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Drucken", "print": "Drucken",
"view_source": "Quelltext anzeigen", "view_source": "Quelltext anzeigen",
"export_email": "Als .eml exportieren", "export_email": "Als .eml exportieren",
"import_email": ".eml importieren", "import_email": ".eml oder .zip importieren",
"keyboard_shortcuts": "Tastaturkürzel (?)", "keyboard_shortcuts": "Tastaturkürzel (?)",
"email_source": "E-Mail-Quelltext", "email_source": "E-Mail-Quelltext",
"draft_banner": "Diese Nachricht ist ein Entwurf", "draft_banner": "Diese Nachricht ist ein Entwurf",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Neuer Unterordner...", "new_subfolder": "Neuer Unterordner...",
"new_folder": "Neuer Ordner...", "new_folder": "Neuer Ordner...",
"rename": "Umbenennen...", "rename": "Umbenennen...",
"import_email": ".eml importieren...", "import_email": ".eml oder .zip importieren...",
"empty_folder": "Ordner leeren", "empty_folder": "Ordner leeren",
"empty_folder_generic": "Ordner leeren", "empty_folder_generic": "Ordner leeren",
"delete_folder": "Ordner löschen", "delete_folder": "Ordner löschen",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Print", "print": "Print",
"view_source": "View source", "view_source": "View source",
"export_email": "Export as .eml", "export_email": "Export as .eml",
"import_email": "Import .eml", "import_email": "Import .eml or .zip",
"keyboard_shortcuts": "Keyboard shortcuts (?)", "keyboard_shortcuts": "Keyboard shortcuts (?)",
"email_source": "Email Source", "email_source": "Email Source",
"draft_banner": "This message is a draft", "draft_banner": "This message is a draft",
@@ -1794,7 +1794,7 @@
"new_subfolder": "New subfolder...", "new_subfolder": "New subfolder...",
"new_folder": "New folder...", "new_folder": "New folder...",
"rename": "Rename...", "rename": "Rename...",
"import_email": "Import .eml...", "import_email": "Import .eml or .zip...",
"empty_folder": "Empty folder", "empty_folder": "Empty folder",
"empty_folder_generic": "Empty folder", "empty_folder_generic": "Empty folder",
"delete_folder": "Delete folder", "delete_folder": "Delete folder",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Imprimir", "print": "Imprimir",
"view_source": "Ver código fuente", "view_source": "Ver código fuente",
"export_email": "Exportar como .eml", "export_email": "Exportar como .eml",
"import_email": "Importar .eml", "import_email": "Importar .eml o .zip",
"keyboard_shortcuts": "Atajos de teclado (?)", "keyboard_shortcuts": "Atajos de teclado (?)",
"email_source": "Código Fuente del Correo", "email_source": "Código Fuente del Correo",
"draft_banner": "Este mensaje es un borrador", "draft_banner": "Este mensaje es un borrador",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Nueva subcarpeta...", "new_subfolder": "Nueva subcarpeta...",
"new_folder": "Nueva carpeta...", "new_folder": "Nueva carpeta...",
"rename": "Renombrar...", "rename": "Renombrar...",
"import_email": "Importar .eml...", "import_email": "Importar .eml o .zip...",
"empty_folder": "Vaciar carpeta", "empty_folder": "Vaciar carpeta",
"empty_folder_generic": "Vaciar carpeta", "empty_folder_generic": "Vaciar carpeta",
"delete_folder": "Eliminar carpeta", "delete_folder": "Eliminar carpeta",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Imprimer", "print": "Imprimer",
"view_source": "Voir la source", "view_source": "Voir la source",
"export_email": "Exporter en .eml", "export_email": "Exporter en .eml",
"import_email": "Importer un .eml", "import_email": "Importer .eml ou .zip",
"keyboard_shortcuts": "Raccourcis clavier (?)", "keyboard_shortcuts": "Raccourcis clavier (?)",
"email_source": "Source de l'email", "email_source": "Source de l'email",
"draft_banner": "Ce message est un brouillon", "draft_banner": "Ce message est un brouillon",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Nouveau sous-dossier...", "new_subfolder": "Nouveau sous-dossier...",
"new_folder": "Nouveau dossier...", "new_folder": "Nouveau dossier...",
"rename": "Renommer...", "rename": "Renommer...",
"import_email": "Importer un .eml...", "import_email": "Importer .eml ou .zip...",
"empty_folder": "Vider le dossier", "empty_folder": "Vider le dossier",
"empty_folder_generic": "Vider le dossier", "empty_folder_generic": "Vider le dossier",
"delete_folder": "Supprimer le dossier", "delete_folder": "Supprimer le dossier",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Stampa", "print": "Stampa",
"view_source": "Visualizza sorgente", "view_source": "Visualizza sorgente",
"export_email": "Esporta come .eml", "export_email": "Esporta come .eml",
"import_email": "Importa .eml", "import_email": "Importa .eml o .zip",
"keyboard_shortcuts": "Scorciatoie da tastiera (?)", "keyboard_shortcuts": "Scorciatoie da tastiera (?)",
"email_source": "Sorgente del messaggio", "email_source": "Sorgente del messaggio",
"draft_banner": "Questo messaggio è una bozza", "draft_banner": "Questo messaggio è una bozza",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Nuova sottocartella...", "new_subfolder": "Nuova sottocartella...",
"new_folder": "Nuova cartella...", "new_folder": "Nuova cartella...",
"rename": "Rinomina...", "rename": "Rinomina...",
"import_email": "Importa .eml...", "import_email": "Importa .eml o .zip...",
"empty_folder": "Svuota cartella", "empty_folder": "Svuota cartella",
"empty_folder_generic": "Svuota cartella", "empty_folder_generic": "Svuota cartella",
"delete_folder": "Elimina cartella", "delete_folder": "Elimina cartella",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "印刷", "print": "印刷",
"view_source": "ソースを表示", "view_source": "ソースを表示",
"export_email": ".emlとしてエクスポート", "export_email": ".emlとしてエクスポート",
"import_email": ".emlをインポート", "import_email": ".eml または .zip をインポート",
"keyboard_shortcuts": "キーボードショートカット (?)", "keyboard_shortcuts": "キーボードショートカット (?)",
"email_source": "メールソース", "email_source": "メールソース",
"draft_banner": "このメッセージは下書きです", "draft_banner": "このメッセージは下書きです",
@@ -1794,7 +1794,7 @@
"new_subfolder": "新しいサブフォルダー...", "new_subfolder": "新しいサブフォルダー...",
"new_folder": "新しいフォルダー...", "new_folder": "新しいフォルダー...",
"rename": "名前を変更...", "rename": "名前を変更...",
"import_email": ".eml をインポート...", "import_email": ".eml または .zip をインポート...",
"empty_folder": "フォルダーを空にする", "empty_folder": "フォルダーを空にする",
"empty_folder_generic": "フォルダーを空にする", "empty_folder_generic": "フォルダーを空にする",
"delete_folder": "フォルダーを削除", "delete_folder": "フォルダーを削除",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "인쇄", "print": "인쇄",
"view_source": "원본 보기", "view_source": "원본 보기",
"export_email": ".eml 파일로 내보내기", "export_email": ".eml 파일로 내보내기",
"import_email": ".eml 파일 가져오기", "import_email": ".eml 또는 .zip 가져오기",
"keyboard_shortcuts": "단축키 (?)", "keyboard_shortcuts": "단축키 (?)",
"email_source": "메일 원본", "email_source": "메일 원본",
"draft_banner": "작성 중인 임시보관 메일이에요", "draft_banner": "작성 중인 임시보관 메일이에요",
@@ -1794,7 +1794,7 @@
"new_subfolder": "새 하위 폴더...", "new_subfolder": "새 하위 폴더...",
"new_folder": "새 폴더...", "new_folder": "새 폴더...",
"rename": "이름 바꾸기...", "rename": "이름 바꾸기...",
"import_email": ".eml 가져오기...", "import_email": ".eml 또는 .zip 가져오기...",
"empty_folder": "폴더 비우기", "empty_folder": "폴더 비우기",
"empty_folder_generic": "폴더 비우기", "empty_folder_generic": "폴더 비우기",
"delete_folder": "폴더 삭제", "delete_folder": "폴더 삭제",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Drukāt", "print": "Drukāt",
"view_source": "Skatīt avota kodu", "view_source": "Skatīt avota kodu",
"export_email": "Eksportēt kā .eml", "export_email": "Eksportēt kā .eml",
"import_email": "Importēt .eml", "import_email": "Importēt .eml vai .zip",
"keyboard_shortcuts": "Īsinājumtaustiņi (?)", "keyboard_shortcuts": "Īsinājumtaustiņi (?)",
"email_source": "Vēstules avota kods", "email_source": "Vēstules avota kods",
"draft_banner": "Šī vēstule ir melnraksts", "draft_banner": "Šī vēstule ir melnraksts",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Jauna apakšmape...", "new_subfolder": "Jauna apakšmape...",
"new_folder": "Jauna mape...", "new_folder": "Jauna mape...",
"rename": "Pārsaukt...", "rename": "Pārsaukt...",
"import_email": "Importēt .eml...", "import_email": "Importēt .eml vai .zip...",
"empty_folder": "Iztukšot mapi", "empty_folder": "Iztukšot mapi",
"empty_folder_generic": "Iztukšot mapi", "empty_folder_generic": "Iztukšot mapi",
"delete_folder": "Dzēst mapi", "delete_folder": "Dzēst mapi",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Afdrukken", "print": "Afdrukken",
"view_source": "Bron bekijken", "view_source": "Bron bekijken",
"export_email": "Exporteren als .eml", "export_email": "Exporteren als .eml",
"import_email": ".eml importeren", "import_email": ".eml of .zip importeren",
"keyboard_shortcuts": "Sneltoetsen (?)", "keyboard_shortcuts": "Sneltoetsen (?)",
"email_source": "E-mailbron", "email_source": "E-mailbron",
"draft_banner": "Dit bericht is een concept", "draft_banner": "Dit bericht is een concept",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Nieuwe submap...", "new_subfolder": "Nieuwe submap...",
"new_folder": "Nieuwe map...", "new_folder": "Nieuwe map...",
"rename": "Hernoemen...", "rename": "Hernoemen...",
"import_email": ".eml importeren...", "import_email": ".eml of .zip importeren...",
"empty_folder": "Map leegmaken", "empty_folder": "Map leegmaken",
"empty_folder_generic": "Map leegmaken", "empty_folder_generic": "Map leegmaken",
"delete_folder": "Map verwijderen", "delete_folder": "Map verwijderen",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Drukuj", "print": "Drukuj",
"view_source": "Pokaż źródło", "view_source": "Pokaż źródło",
"export_email": "Eksportuj jako .eml", "export_email": "Eksportuj jako .eml",
"import_email": "Importuj .eml", "import_email": "Importuj .eml lub .zip",
"keyboard_shortcuts": "Skróty klawiszowe (?)", "keyboard_shortcuts": "Skróty klawiszowe (?)",
"email_source": "Źródło wiadomości", "email_source": "Źródło wiadomości",
"draft_banner": "Ta wiadomość jest szkicem", "draft_banner": "Ta wiadomość jest szkicem",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Nowy podfolder...", "new_subfolder": "Nowy podfolder...",
"new_folder": "Nowy folder...", "new_folder": "Nowy folder...",
"rename": "Zmień nazwę...", "rename": "Zmień nazwę...",
"import_email": "Importuj .eml...", "import_email": "Importuj .eml lub .zip...",
"empty_folder": "Opróżnij folder", "empty_folder": "Opróżnij folder",
"empty_folder_generic": "Opróżnij folder", "empty_folder_generic": "Opróżnij folder",
"delete_folder": "Usuń folder", "delete_folder": "Usuń folder",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Imprimir", "print": "Imprimir",
"view_source": "Ver código-fonte", "view_source": "Ver código-fonte",
"export_email": "Exportar como .eml", "export_email": "Exportar como .eml",
"import_email": "Importar .eml", "import_email": "Importar .eml ou .zip",
"keyboard_shortcuts": "Atalhos de teclado (?)", "keyboard_shortcuts": "Atalhos de teclado (?)",
"email_source": "Código-fonte do E-mail", "email_source": "Código-fonte do E-mail",
"draft_banner": "Esta mensagem é um rascunho", "draft_banner": "Esta mensagem é um rascunho",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Nova subpasta...", "new_subfolder": "Nova subpasta...",
"new_folder": "Nova pasta...", "new_folder": "Nova pasta...",
"rename": "Renomear...", "rename": "Renomear...",
"import_email": "Importar .eml...", "import_email": "Importar .eml ou .zip...",
"empty_folder": "Esvaziar pasta", "empty_folder": "Esvaziar pasta",
"empty_folder_generic": "Esvaziar pasta", "empty_folder_generic": "Esvaziar pasta",
"delete_folder": "Excluir pasta", "delete_folder": "Excluir pasta",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Распечатать", "print": "Распечатать",
"view_source": "Просмотреть исходный код", "view_source": "Просмотреть исходный код",
"export_email": "Экспортировать как .eml", "export_email": "Экспортировать как .eml",
"import_email": "Импортировать .eml", "import_email": "Импортировать .eml или .zip",
"keyboard_shortcuts": "Сочетания клавиш (?)", "keyboard_shortcuts": "Сочетания клавиш (?)",
"email_source": "Исходный код письма", "email_source": "Исходный код письма",
"draft_banner": "Это письмо является черновиком", "draft_banner": "Это письмо является черновиком",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Новая вложенная папка...", "new_subfolder": "Новая вложенная папка...",
"new_folder": "Новая папка...", "new_folder": "Новая папка...",
"rename": "Переименовать...", "rename": "Переименовать...",
"import_email": "Импортировать .eml...", "import_email": "Импортировать .eml или .zip...",
"empty_folder": "Очистить папку", "empty_folder": "Очистить папку",
"empty_folder_generic": "Очистить папку", "empty_folder_generic": "Очистить папку",
"delete_folder": "Удалить папку", "delete_folder": "Удалить папку",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Yazdır", "print": "Yazdır",
"view_source": "Kaynağı görüntüle", "view_source": "Kaynağı görüntüle",
"export_email": ".eml olarak dışa aktar", "export_email": ".eml olarak dışa aktar",
"import_email": ".eml içe aktar", "import_email": ".eml veya .zip içe aktar",
"keyboard_shortcuts": "Klavye kısayolları (?)", "keyboard_shortcuts": "Klavye kısayolları (?)",
"email_source": "E-posta Kaynağı", "email_source": "E-posta Kaynağı",
"draft_banner": "Bu ileti bir taslaktır", "draft_banner": "Bu ileti bir taslaktır",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Yeni alt klasör...", "new_subfolder": "Yeni alt klasör...",
"new_folder": "Yeni klasör...", "new_folder": "Yeni klasör...",
"rename": "Yeniden adlandır...", "rename": "Yeniden adlandır...",
"import_email": ".eml içe aktar...", "import_email": ".eml veya .zip içe aktar...",
"empty_folder": "Klasörü boşalt", "empty_folder": "Klasörü boşalt",
"empty_folder_generic": "Klasörü boşalt", "empty_folder_generic": "Klasörü boşalt",
"delete_folder": "Klasörü sil", "delete_folder": "Klasörü sil",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "Роздрукувати", "print": "Роздрукувати",
"view_source": "Переглянути джерело", "view_source": "Переглянути джерело",
"export_email": "Експортувати як .eml", "export_email": "Експортувати як .eml",
"import_email": "Імпорт .eml", "import_email": "Імпорт .eml або .zip",
"keyboard_shortcuts": "Комбінації клавіш (?)", "keyboard_shortcuts": "Комбінації клавіш (?)",
"email_source": "Джерело електронної пошти", "email_source": "Джерело електронної пошти",
"draft_banner": "Це повідомлення є чернеткою", "draft_banner": "Це повідомлення є чернеткою",
@@ -1794,7 +1794,7 @@
"new_subfolder": "Нова вкладена папка...", "new_subfolder": "Нова вкладена папка...",
"new_folder": "Нова папка...", "new_folder": "Нова папка...",
"rename": "Перейменувати...", "rename": "Перейменувати...",
"import_email": "Імпортувати .eml...", "import_email": "Імпортувати .eml або .zip...",
"empty_folder": "Очистити папку", "empty_folder": "Очистити папку",
"empty_folder_generic": "Очистити папку", "empty_folder_generic": "Очистити папку",
"delete_folder": "Видалити папку", "delete_folder": "Видалити папку",
+2 -2
View File
@@ -270,7 +270,7 @@
"print": "打印", "print": "打印",
"view_source": "查看源码", "view_source": "查看源码",
"export_email": "导出为 .eml", "export_email": "导出为 .eml",
"import_email": "导入 .eml", "import_email": "导入 .eml 或 .zip",
"keyboard_shortcuts": "键盘快捷键(?)", "keyboard_shortcuts": "键盘快捷键(?)",
"email_source": "邮件源码", "email_source": "邮件源码",
"draft_banner": "这是一封草稿邮件", "draft_banner": "这是一封草稿邮件",
@@ -1794,7 +1794,7 @@
"new_subfolder": "新建子文件夹...", "new_subfolder": "新建子文件夹...",
"new_folder": "新建文件夹...", "new_folder": "新建文件夹...",
"rename": "重命名...", "rename": "重命名...",
"import_email": "导入 .eml...", "import_email": "导入 .eml 或 .zip...",
"empty_folder": "清空文件夹", "empty_folder": "清空文件夹",
"empty_folder_generic": "清空文件夹", "empty_folder_generic": "清空文件夹",
"delete_folder": "删除文件夹", "delete_folder": "删除文件夹",