chore: support bulk restore emails

This commit is contained in:
rustmailer
2026-01-21 01:09:38 +08:00
parent fcd19b1c9f
commit e1f471b8f4
23 changed files with 342 additions and 137 deletions
+27 -2
View File
@@ -19,7 +19,7 @@
import { useRef } from 'react'
import { X, Trash2 } from 'lucide-react'
import { X, Trash2, Upload } from 'lucide-react'
import { cn } from '@/lib/utils'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
@@ -37,7 +37,7 @@ type MailBulkActionsProps = {
}
export function MailBulkActions({ children }: MailBulkActionsProps) {
const { selected, setSelected, setOpen, setToDelete } = useSearchContext()
const { selected, setSelected, setOpen, setToDelete, setCurrentEnvelope } = useSearchContext()
const toolbarRef = useRef<HTMLDivElement>(null)
const { t } = useTranslation()
@@ -60,6 +60,12 @@ export function MailBulkActions({ children }: MailBulkActionsProps) {
setOpen('delete')
}
const handleRestore = () => {
setCurrentEnvelope(undefined);
setOpen('restore')
}
const handleKeyDown = (e: React.KeyboardEvent) => {
const buttons = toolbarRef.current?.querySelectorAll('button')
if (!buttons || buttons.length === 0) return
@@ -161,7 +167,26 @@ export function MailBulkActions({ children }: MailBulkActionsProps) {
</div>
<Separator orientation="vertical" className="h-5" />
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="secondary"
size="sm"
onClick={handleRestore}
className="gap-1"
>
<Upload className="h-3.5 w-3.5" />
<span className="hidden sm:inline">
{t('restore_message.restore_to_imap', 'Restore Mail')}
</span>
</Button>
</TooltipTrigger>
<TooltipContent>
{t('search.bulkActions.restoreDesc')}
</TooltipContent>
</Tooltip>
<Separator orientation="vertical" className="h-5" />
{/* Delete */}
<Tooltip>
<TooltipTrigger asChild>
-8
View File
@@ -95,14 +95,6 @@ export default function Search() {
>
<div className="mx-auto w-full px-4">
<div className="flex gap-6">
{/* <aside className="hidden lg:block w-64 flex-shrink-0">
<div className="rounded-lg border bg-card p-4">
<EnvelopeTags
selectedTags={selectedTags}
onTagToggle={handleTagToggle}
/>
</div>
</aside> */}
<div className="flex-1 min-w-0 space-y-4">
{isLoading && (
<Card>
+18 -2
View File
@@ -19,7 +19,7 @@
import { useEffect, useState } from 'react';
import { useMutation } from '@tanstack/react-query';
import { Loader, Download, Trash2, MessageSquareMore, FileText, FileImage, FileVideo, FileArchive, FileSpreadsheet, FileCode, FileIcon, FileAudio } from 'lucide-react';
import { Loader, Download, Trash2, MessageSquareMore, FileText, FileImage, FileVideo, FileArchive, FileSpreadsheet, FileCode, FileIcon, FileAudio, Upload } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Separator } from '@/components/ui/separator';
@@ -119,7 +119,7 @@ export function MailMessageView({
showHeader = true
}: MailMessageViewProps) {
const { t } = useTranslation()
const { setToDelete, setOpen } = useSearchContext();
const { setToDelete, setOpen, setSelected } = useSearchContext();
const [content, setContent] = useState<string | null>(null);
const [contentType, setContentType] = useState<'Plain' | 'Html' | null>(null);
@@ -280,6 +280,22 @@ export function MailMessageView({
</TooltipTrigger>
<TooltipContent>{t('mail.viewThread')}</TooltipContent>
</Tooltip>
<Separator orientation="vertical" className="h-5" />
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => {
setSelected(new Map())
setOpen('restore')
}}
>
<Upload className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>{t('restore_message.restore_to_imap', 'Restore Mail')}</TooltipContent>
</Tooltip>
</div>
</>
)}
@@ -25,6 +25,52 @@ import { AxiosError } from 'axios'
import { useTranslation } from 'react-i18next'
import { ToastAction } from '@/components/ui/toast'
import { useSearchContext } from './context'
import { EmailEnvelope } from '@/api'
function MessageSummary({ envelope, t }: { envelope: EmailEnvelope, t: (key: string) => string }) {
return (
<div className="mt-3 rounded-md border bg-muted/20 p-3 text-sm overflow-hidden">
<div className="grid grid-cols-[auto_1fr] gap-x-2 gap-y-1.5">
<span className="font-medium text-muted-foreground">{t("mail.subject")}:</span>
<div className="break-words font-medium">
{envelope.subject || <em className="italic opacity-70">(No subject)</em>}
</div>
<span className="font-medium text-muted-foreground">{t("mail.from")}:</span>
<div className="break-all text-foreground/90">
{envelope.from}
</div>
{envelope.to?.length > 0 && (
<>
<span className="font-medium text-muted-foreground">{t("mail.to")}:</span>
<div className="break-all text-foreground/90">
{envelope.to.slice(0, 2).join(", ")}
{envelope.to.length > 2 && " …"}
</div>
</>
)}
<span className="font-medium text-muted-foreground">{t("mail.date")}:</span>
<div className="text-foreground/90">
{new Date(envelope.date).toLocaleString()}
</div>
{envelope.mailbox_name && (
<>
<span className="font-medium text-muted-foreground">{t("search.mailbox")}:</span>
<div className="truncate text-foreground/90" title={envelope.mailbox_name}>
{envelope.mailbox_name}
</div>
</>
)}
</div>
</div>
);
}
interface RestoreMessageDialogProps {
open: boolean
@@ -36,12 +82,26 @@ export function RestoreMessageDialog({
onOpenChange
}: RestoreMessageDialogProps) {
const { t } = useTranslation()
const { currentEnvelope } = useSearchContext()
const { currentEnvelope, selected } = useSearchContext()
const accountsWithSelection = Array.from(selected.entries()).filter(([_, ids]) => ids.size > 0);
const selectedCount = accountsWithSelection.reduce((sum, [_, set]) => sum + set.size, 0);
const accountCount = accountsWithSelection.length;
const isBulk = selectedCount > 0;
const restoreMutation = useMutation({
mutationFn: () =>
restore_message(currentEnvelope!.account_id, [currentEnvelope!.id]),
mutationFn: async () => {
if (isBulk) {
const promises = accountsWithSelection.map(([accountId, ids]) =>
restore_message(accountId, Array.from(ids))
);
return Promise.all(promises);
} else if (currentEnvelope) {
return restore_message(currentEnvelope.account_id, [currentEnvelope.id]);
}
},
onSuccess: handleRestoreSuccess,
onError: handleRestoreError,
});
@@ -90,16 +150,37 @@ export function RestoreMessageDialog({
<ConfirmDialog
open={open}
onOpenChange={onOpenChange}
title={t('restore_message.title', 'Restore messages')}
desc={t(
'restore_message.desc',
'This action will append the selected messages from Bichon to their corresponding mailboxes on the IMAP server.'
)}
title={isBulk ? t('restore_message.bulkTitle', 'Restore multiple messages') : t('restore_message.title', 'Restore message')}
desc={<div className="space-y-3">
<p className="text-sm text-muted-foreground">
{t(
'restore_message.desc',
'This action will append the selected messages to their corresponding mailboxes on the IMAP server.'
)}
</p>
{isBulk ? (
<div className="rounded-md bg-primary/5 border border-primary/20 p-3 text-sm">
<div className="flex justify-between items-center text-primary font-medium">
<span>{t('restore_message.summary', 'Summary')}</span>
<span className="bg-primary/10 px-2 py-0.5 rounded text-xs">
{selectedCount} {t('restore_message.messages', 'messages')}
</span>
</div>
<div className="mt-2 text-xs space-y-1 text-muted-foreground">
<p> {t('restore_message.accountsInvolved', 'Accounts involved')}: {accountCount}</p>
<p> {t('restore_message.bulkWarning', 'Messages will be restored to their original folders.')}</p>
</div>
</div>
) : (
currentEnvelope && <MessageSummary envelope={currentEnvelope} t={t} />
)}
</div>}
confirmText={t('restore_message.confirm', 'Restore')}
handleConfirm={() => restoreMutation.mutate()}
className="sm:max-w-sm"
isLoading={restoreMutation.isPending}
disabled={restoreMutation.isPending}
disabled={restoreMutation.isPending || (!isBulk && !currentEnvelope)}
/>
)
}
@@ -28,7 +28,7 @@ import {
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { useTranslation } from 'react-i18next'
import { MoreVertical, TagIcon, Trash2 } from 'lucide-react'
import { MoreVertical, TagIcon, Trash2, Upload } from 'lucide-react'
import { EmailEnvelope } from '@/api'
import { useSearchContext } from '../context'
@@ -37,7 +37,7 @@ interface DataTableRowActionsProps {
}
export function DataTableRowActions({ row }: DataTableRowActionsProps) {
const { setOpen, setCurrentEnvelope, setToDelete } = useSearchContext()
const { setOpen, setCurrentEnvelope, setSelected, setToDelete } = useSearchContext()
const { t } = useTranslation()
const toggleToDelete = (accountId: number, mailId: number) => {
@@ -93,12 +93,13 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
onClick={(e) => {
e.stopPropagation()
setCurrentEnvelope(row.original)
setSelected(new Map())
setOpen("restore")
}}
>
{t('restore_message.restore_to_imap', 'Restore Mail')}
<DropdownMenuShortcut>
<TagIcon size={16} />
<Upload size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuSeparator />
+12 -7
View File
@@ -1453,14 +1453,19 @@
"confirm": "تسجيل الخروج"
},
"restore_message": {
"title": "استعادة الرسائل",
"desc": "سيقوم هذا الإجراء بإعادة رفع الرسائل المختارة من Bichon واستعادتها إلى صناديق البريد المقابلة لها على خادم IMAP.",
"title": "استعادة رسالة واحدة",
"bulkTitle": "استعادة رسائل متعددة",
"bulkWarning": "ملاحظة: سيتم استعادة الرسائل إلى مجلداتها الأصلية.",
"accountsInvolved": "الحسابات المعنية",
"summary": "تفاصيل الاستعادة",
"messages": "رسائل",
"desc": "سيقوم هذا الإجراء بإعادة رفع الرسائل المحددة من Bichon واستعادتها إلى صناديق البريد المقابلة لها على خادم IMAP.",
"confirm": "تنفيذ الاستعادة",
"restore_to_imap": "استعادة البريد",
"success": "تمت استعادة الرسائل بنجاح",
"successDesc": "تمت استعادة الرسائل المختارة إلى خادم IMAP بنجاح.",
"failed": "فشلت استعادة الرسائل",
"failedTitle": "فشل الاستعادة"
"restore_to_imap": "استعادة الرسالة",
"success": "تمت الاستعادة بنجاح",
"successDesc": "تمت استعادة الرسائل المحددة بنجاح إلى خادم IMAP.",
"failed": "فشلت الاستعادة",
"failedTitle": "فشل في الاستعادة"
},
"time": {
"label": "الوقت",
+13 -8
View File
@@ -1453,14 +1453,19 @@
"confirm": "Log ud"
},
"restore_message": {
"title": "Gendan meddelelser",
"desc": "Denne handling vil uploade de valgte meddelelser fra Bichon og gendanne dem til deres tilsvarende postkasser på IMAP-serveren.",
"confirm": "Gendan",
"restore_to_imap": "Gendan e-mail",
"success": "Meddelelser gendannet",
"successDesc": "De valgte meddelelser er blevet gendannet til IMAP-serveren.",
"failed": "Kunne ikke gendanne meddelelser",
"failedTitle": "Gendannelse mislykkedes"
"title": "Gendan enkelt besked",
"bulkTitle": "Gendan flere beskeder",
"bulkWarning": "Bemærk: Beskeder vil blive gendannet til deres oprindelige mapper.",
"accountsInvolved": "Involverede konti",
"summary": "Gendannelsesdetaljer",
"messages": "beskeder",
"desc": "Denne handling vil gen-uploade valgte beskeder fra Bichon og gendanne dem til deres tilsvarende postkasser på IMAP-serveren.",
"confirm": "Udfør gendannelse",
"restore_to_imap": "Gendan besked",
"success": "Gendannelse gennemført",
"successDesc": "De valgte beskeder er blevet gendannet til IMAP-serveren.",
"failed": "Gendannelse mislykkedes",
"failedTitle": "Fejl ved gendannelse"
},
"time": {
"label": "Tid",
+10 -5
View File
@@ -1453,11 +1453,16 @@
"confirm": "Abmelden"
},
"restore_message": {
"title": "Nachrichten wiederherstellen",
"desc": "Diese Aktion lädt die ausgewählten Nachrichten von Bichon hoch und stellt sie in den entsprechenden Postfächern auf dem IMAP-Server wieder her.",
"confirm": "Wiederherstellen",
"restore_to_imap": "E-Mail wiederherstellen",
"success": "Nachrichten wiederhergestellt",
"title": "Einzelne Nachricht wiederherstellen",
"bulkTitle": "Mehrere Nachrichten wiederherstellen",
"bulkWarning": "Hinweis: Nachrichten werden in ihren ursprünglichen Ordnern wiederhergestellt.",
"accountsInvolved": "Beteiligte Konten",
"summary": "Details zur Wiederherstellung",
"messages": "Nachrichten",
"desc": "Diese Aktion lädt die ausgewählten Nachrichten von Bichon erneut hoch und stellt sie in den entsprechenden Postfächern auf dem IMAP-Server wieder her.",
"confirm": "Wiederherstellung ausführen",
"restore_to_imap": "Nachricht wiederherstellen",
"success": "Wiederherstellung erfolgreich",
"successDesc": "Die ausgewählten Nachrichten wurden erfolgreich auf dem IMAP-Server wiederhergestellt.",
"failed": "Wiederherstellung fehlgeschlagen",
"failedTitle": "Fehler bei der Wiederherstellung"
+11 -6
View File
@@ -1453,14 +1453,19 @@
"confirm": "Sign out"
},
"restore_message": {
"title": "Restore Messages",
"desc": "This action will append the selected messages from Bichon back to their corresponding mailboxes on the IMAP server.",
"confirm": "Restore",
"restore_to_imap": "Restore Mail",
"title": "Restore Single Message",
"bulkTitle": "Bulk Restore Messages",
"bulkWarning": "Note: Messages will be restored to their original storage folders.",
"accountsInvolved": "Accounts involved",
"summary": "Restoration Details",
"messages": "messages",
"desc": "This action will re-upload selected messages from Bichon and restore them to their corresponding mailboxes on the IMAP server.",
"confirm": "Restore Now",
"restore_to_imap": "Restore Message",
"success": "Messages Restored",
"successDesc": "The selected messages have been successfully restored to the IMAP server.",
"failed": "Failed to restore messages",
"failedTitle": "Restore Failed"
"failed": "Restore Failed",
"failedTitle": "Failed to Restore"
},
"time": {
"label": "Time",
+12 -7
View File
@@ -1453,14 +1453,19 @@
"confirm": "Cerrar sesión"
},
"restore_message": {
"title": "Restaurar mensajes",
"desc": "Esta acción volverá a cargar los mensajes seleccionados de Bichon y los restaurará en sus carpetas correspondientes en el servidor IMAP.",
"confirm": "Restaurar",
"restore_to_imap": "Restaurar correo",
"success": "Mensajes restaurados",
"title": "Restaurar mensaje individual",
"bulkTitle": "Restaurar múltiples mensajes",
"bulkWarning": "Nota: Los mensajes se restaurarán en sus carpetas originales.",
"accountsInvolved": "Cuentas involucradas",
"summary": "Detalles de restauración",
"messages": "mensajes",
"desc": "Esta acción volverá a cargar los mensajes seleccionados desde Bichon y los restaurará en sus buzones correspondientes en el servidor IMAP.",
"confirm": "Ejecutar restauración",
"restore_to_imap": "Restaurar mensaje",
"success": "Restauración exitosa",
"successDesc": "Los mensajes seleccionados se han restaurado correctamente en el servidor IMAP.",
"failed": "Error al restaurar los mensajes",
"failedTitle": "Error de restauración"
"failed": "Error al restaurar",
"failedTitle": "Fallo en la restauración"
},
"time": {
"label": "Tiempo",
+12 -7
View File
@@ -1453,14 +1453,19 @@
"confirm": "Kirjaudu ulos"
},
"restore_message": {
"title": "Palauta viestit",
"desc": "Tämä toiminto lataa valitut viestit Bichonista ja palauttaa ne vastaaviin postilaatikoihin IMAP-palvelimella.",
"confirm": "Palauta",
"restore_to_imap": "Palauta sähköposti",
"success": "Viestit palautettu",
"title": "Palauta yksittäinen viesti",
"bulkTitle": "Palauta useita viestejä",
"bulkWarning": "Huomio: Viestit palautetaan niiden alkuperäisiin kansioihin.",
"accountsInvolved": "Osalliset tilit",
"summary": "Palautuksen tiedot",
"messages": "viestiä",
"desc": "Tämä toiminto lataa valitut viestit uudelleen Bichonista ja palauttaa ne vastaaviin postilaatikoihin IMAP-palvelimella.",
"confirm": "Suorita palautus",
"restore_to_imap": "Palauta viesti",
"success": "Palautus onnistui",
"successDesc": "Valitut viestit on palautettu onnistuneesti IMAP-palvelimelle.",
"failed": "Viestien palautus epäonnistui",
"failedTitle": "Palautus epäonnistui"
"failed": "Palautus epäonnistui",
"failedTitle": "Palautusvirhe"
},
"time": {
"label": "Aika",
+12 -7
View File
@@ -1453,14 +1453,19 @@
"confirm": "Déconnexion"
},
"restore_message": {
"title": "Restaurer les messages",
"desc": "Cette action téléchargera les messages sélectionnés depuis Bichon et les restaurera dans leurs boîtes aux lettres correspondantes sur le serveur IMAP.",
"confirm": "Restaurer",
"restore_to_imap": "Restaurer le courrier",
"success": "Messages restaurés",
"title": "Restaurer un message",
"bulkTitle": "Restaurer plusieurs messages",
"bulkWarning": "Remarque : les messages seront restaurés dans leurs dossiers d'origine.",
"accountsInvolved": "Comptes concernés",
"summary": "Détails de la restauration",
"messages": "messages",
"desc": "Cette action va re-télécharger les messages sélectionnés depuis Bichon et les restaurer dans leurs boîtes aux lettres correspondantes sur le serveur IMAP.",
"confirm": "Exécuter la restauration",
"restore_to_imap": "Restaurer le message",
"success": "Restauration réussie",
"successDesc": "Les messages sélectionnés ont été restaurés avec succès sur le serveur IMAP.",
"failed": "Échec de la restauration des messages",
"failedTitle": "Échec de la restauration"
"failed": "Échec de la restauration",
"failedTitle": "Erreur de restauration"
},
"time": {
"label": "Temps",
+12 -7
View File
@@ -1453,14 +1453,19 @@
"confirm": "Disconnetti"
},
"restore_message": {
"title": "Ripristina messaggi",
"desc": "Questa azione caricherà i messaggi selezionati da Bichon e li ripristinerà nelle rispettive caselle di posta sul server IMAP.",
"confirm": "Ripristina",
"restore_to_imap": "Ripristina posta",
"success": "Messaggi ripristinati",
"title": "Ripristina singolo messaggio",
"bulkTitle": "Ripristino multiplo messaggi",
"bulkWarning": "Nota: i messaggi verranno ripristinati nelle loro cartelle originali.",
"accountsInvolved": "Account coinvolti",
"summary": "Dettagli ripristino",
"messages": "messaggi",
"desc": "Questa azione caricherà nuovamente i messaggi selezionati da Bichon e li ripristinerà nelle rispettive caselle di posta sul server IMAP.",
"confirm": "Esegui ripristino",
"restore_to_imap": "Ripristina messaggio",
"success": "Ripristino completato",
"successDesc": "I messaggi selezionati sono stati ripristinati con successo sul server IMAP.",
"failed": "Impossibile ripristinare i messaggi",
"failedTitle": "Ripristino fallito"
"failed": "Ripristino fallito",
"failedTitle": "Errore di ripristino"
},
"time": {
"label": "Tempo",
+11 -6
View File
@@ -1453,14 +1453,19 @@
"confirm": "サインアウト"
},
"restore_message": {
"title": "メッセージを復元",
"desc": "この操作により、選択したメッセージをBichonから再アップロードし、IMAPサーバー上の対応するメールボックスに復元します。",
"title": "単一メールの復元",
"bulkTitle": "複数メールの一括復元",
"bulkWarning": "注意:メールは元の保存先フォルダーに復元されます。",
"accountsInvolved": "対象アカウント",
"summary": "復元の詳細",
"messages": "通のメール",
"desc": "この操作により、選択されたメールがBichonシステムから再アップロードされ、IMAPサーバー上の対応するメールボックスに復元されます。",
"confirm": "復元を実行",
"restore_to_imap": "メールを復元",
"success": "メッセージを復元しました",
"successDesc": "選択したメッセージがIMAPサーバーに正常に復元されました。",
"failed": "メッセージの復元失敗しました",
"failedTitle": "復元失敗"
"success": "復元成功",
"successDesc": "選択されたメールはIMAPサーバーに正常に復元されました。",
"failed": "復元失敗",
"failedTitle": "復元失敗しました"
},
"time": {
"label": "時間",
+10 -5
View File
@@ -1453,13 +1453,18 @@
"confirm": "로그아웃"
},
"restore_message": {
"title": "메시지 복원",
"desc": "이 작업은 선택한 메시지를 Bichon에서 다시 업로드하여 IMAP 서버의 해당 사서함으로 복원합니다.",
"title": "개별 메시지 복원",
"bulkTitle": "여러 메시지 일괄 복원",
"bulkWarning": "참고: 메시지는 원래 저장된 폴더로 복원됩니다.",
"accountsInvolved": "관련 계정",
"summary": "복원 세부 정보",
"messages": "개의 메시지",
"desc": "이 작업은 선택한 메시지를 Bichon 시스템에서 다시 업로드하여 IMAP 서버의 해당 사서함으로 복원합니다.",
"confirm": "복원 실행",
"restore_to_imap": "메 복원",
"success": "메시지 복원 완료",
"restore_to_imap": "메시지 복원",
"success": "복원 성공",
"successDesc": "선택한 메시지가 IMAP 서버로 성공적으로 복원되었습니다.",
"failed": "메시지 복원 실패",
"failed": "복원 실패",
"failedTitle": "복원 실패"
},
"time": {
+12 -7
View File
@@ -1453,14 +1453,19 @@
"confirm": "Uitloggen"
},
"restore_message": {
"title": "Berichten herstellen",
"desc": "Deze actie uploadt de geselecteerde berichten van Bichon en herstelt ze in de bijbehorende mailboxen op de IMAP-server.",
"confirm": "Herstellen",
"restore_to_imap": "E-mail herstellen",
"success": "Berichten hersteld",
"title": "Enkel bericht herstellen",
"bulkTitle": "Meerdere berichten herstellen",
"bulkWarning": "Let op: berichten worden hersteld in hun oorspronkelijke mappen.",
"accountsInvolved": "Betrokken accounts",
"summary": "Hersteldetails",
"messages": "berichten",
"desc": "Deze actie zal de geselecteerde berichten opnieuw uploaden vanuit Bichon en ze herstellen in de bijbehorende mailboxen op de IMAP-server.",
"confirm": "Herstel uitvoeren",
"restore_to_imap": "Bericht herstellen",
"success": "Herstel geslaagd",
"successDesc": "De geselecteerde berichten zijn succesvol hersteld op de IMAP-server.",
"failed": "Herstellen van berichten mislukt",
"failedTitle": "Herstel mislukt"
"failed": "Herstel mislukt",
"failedTitle": "Herstelfout"
},
"time": {
"label": "Tijd",
+13 -8
View File
@@ -1453,14 +1453,19 @@
"confirm": "Logg ut"
},
"restore_message": {
"title": "Gjenopprett meldinger",
"desc": "Denne handlingen vil laste opp de valgte meldingene fra Bichon og gjenopprette dem til deres tilsvarende postbokser på IMAP-serveren.",
"confirm": "Gjenopprett",
"restore_to_imap": "Gjenopprett e-post",
"success": "Meldinger gjenopprettet",
"successDesc": "De valgte meldingene har blitt gjenopprettet til IMAP-serveren.",
"failed": "Kunne ikke gjenopprette meldinger",
"failedTitle": "Gjenoppretting mislyktes"
"title": "Gjenopprett enkeltmelding",
"bulkTitle": "Gjenopprett flere meldinger",
"bulkWarning": "Merk: Meldinger vil bli gjenopprettet til sine opprinnelige mapper.",
"accountsInvolved": "Involverte kontoer",
"summary": "Gjenopprettingsdetaljer",
"messages": "meldinger",
"desc": "Denne handlingen vil laste opp valgte meldinger fra Bichon på nytt og gjenopprette dem til de tilsvarende postkassene på IMAP-serveren.",
"confirm": "Utfør gjenoppretting",
"restore_to_imap": "Gjenopprett melding",
"success": "Gjenoppretting vellykket",
"successDesc": "De valgte meldingene er gjenopprettet til IMAP-serveren.",
"failed": "Gjenoppretting mislykkedes",
"failedTitle": "Feil ved gjenoppretting"
},
"time": {
"label": "Tid",
+12 -7
View File
@@ -1453,14 +1453,19 @@
"confirm": "Wyloguj się"
},
"restore_message": {
"title": "Przywróć wiadomości",
"desc": "Ta operacja prześle wybrane wiadomości z Bichon i przywróci je do odpowiednich skrzynek pocztowych na serwerze IMAP.",
"confirm": "Przywróć",
"restore_to_imap": "Przywróć pocztę",
"success": "Wiadomości przywrócone",
"title": "Przywróć pojedynczą wiadomość",
"bulkTitle": "Masowe przywracanie wiadomości",
"bulkWarning": "Uwaga: Wiadomości zostaną przywrócone do ich oryginalnych folderów.",
"accountsInvolved": "Zaangażowane konta",
"summary": "Szczegóły przywracania",
"messages": "wiadomości",
"desc": "Ta operacja spowoduje ponowne przesłanie wybranych wiadomości z systemu Bichon i przywrócenie ich do odpowiednich skrzynek pocztowych na serwerze IMAP.",
"confirm": "Wykonaj przywracanie",
"restore_to_imap": "Przywróć wiadomość",
"success": "Przywracanie zakończone sukcesem",
"successDesc": "Wybrane wiadomości zostały pomyślnie przywrócone na serwer IMAP.",
"failed": "Nie udało się przywrócić wiadomości",
"failedTitle": "Przywracanie nie powiodło się"
"failed": "Przywracanie nie powiodło się",
"failedTitle": "Błąd przywracania"
},
"time": {
"label": "Czas",
+12 -7
View File
@@ -1453,13 +1453,18 @@
"confirm": "Sair"
},
"restore_message": {
"title": "Restaurar mensagens",
"desc": "Esta ação irá carregar as mensagens selecionadas do Bichon e restaurá-las nas respetivas caixas de correio no servidor IMAP.",
"confirm": "Restaurar",
"restore_to_imap": "Restaurar e-mail",
"success": "Mensagens restauradas",
"successDesc": "As mensagens selecionadas foram restauradas com sucesso para o servidor IMAP.",
"failed": "Falha ao restaurar mensagens",
"title": "Restaurar mensagem individual",
"bulkTitle": "Restaurar múltiplas mensagens",
"bulkWarning": "Nota: As mensagens serão restauradas nas suas pastas originais.",
"accountsInvolved": "Contas envolvidas",
"summary": "Detalhes da restauração",
"messages": "mensagens",
"desc": "Esta ação irá recarregar as mensagens selecionadas do Bichon e restaurá-las nas pastas correspondentes no servidor IMAP.",
"confirm": "Executar restauração",
"restore_to_imap": "Restaurar mensagem",
"success": "Restauração bem-sucedida",
"successDesc": "As mensagens selecionadas foram restauradas com sucesso no servidor IMAP.",
"failed": "Falha ao restaurar",
"failedTitle": "Falha na restauração"
},
"time": {
+13 -8
View File
@@ -1453,14 +1453,19 @@
"confirm": "Выйти"
},
"restore_message": {
"title": "Восстановить сообщения",
"desc": "Это действие загрузит выбранные сообщения из Bichon и восстановит их в соответствующих почтовых ящиках на IMAP-сервере.",
"confirm": "Восстановить",
"restore_to_imap": "Восстановить почту",
"success": "Сообщения восстановлены",
"successDesc": "Выбранные сообщения были успешно восстановлены на IMAP-сервере.",
"failed": "Не удалось восстановить сообщения",
"failedTitle": "Ошибка восстановления"
"title": "Восстановить одно сообщение",
"bulkTitle": "Массовое восстановление сообщений",
"bulkWarning": "Примечание: сообщения будут восстановлены в исходные папки.",
"accountsInvolved": "Задействованные аккаунты",
"summary": "Детали восстановления",
"messages": "сообщений",
"desc": "Это действие повторно загрузит выбранные сообщения из Bichon и восстановит их в соответствующих почтовых ящиках на сервере IMAP.",
"confirm": "Выполнить восстановление",
"restore_to_imap": "Восстановить сообщение",
"success": "Восстановление успешно",
"successDesc": "Выбранные сообщения были успешно восстановлены на сервере IMAP.",
"failed": "Ошибка восстановления",
"failedTitle": "Восстановление не удалось"
},
"time": {
"label": "Время",
+12 -7
View File
@@ -1453,14 +1453,19 @@
"confirm": "Logga ut"
},
"restore_message": {
"title": "Återställ meddelanden",
"desc": "Denna åtgärd kommer att ladda upp de valda meddelandena från Bichon och återställa dem till deras motsvarande brevlådor på IMAP-servern.",
"confirm": "Återställ",
"restore_to_imap": "Återställ e-post",
"success": "Meddelanden återställda",
"title": "Återställ enstaka meddelande",
"bulkTitle": "Återställ flera meddelanden",
"bulkWarning": "Obs: Meddelanden kommer att återställas till sina ursprungliga mappar.",
"accountsInvolved": "Inblandade konton",
"summary": "Återställningsdetaljer",
"messages": "meddelanden",
"desc": "Denna åtgärd kommer att ladda upp de valda meddelandena igen från Bichon och återställa dem till deras motsvarande inkorgar på IMAP-servern.",
"confirm": "Utför återställning",
"restore_to_imap": "Återställ meddelande",
"success": "Återställning lyckades",
"successDesc": "De valda meddelandena har återställts till IMAP-servern.",
"failed": "Misslyckades med att återställa meddelanden",
"failedTitle": "Återställning misslyckades"
"failed": "Återställning misslyckades",
"failedTitle": "Fel vid återställning"
},
"time": {
"label": "Tid",
+8 -3
View File
@@ -1453,12 +1453,17 @@
"confirm": "登出"
},
"restore_message": {
"title": "還原郵件",
"desc": "此操作將把選定的郵件從 Bichon 系統重新上傳並還原到其在 IMAP 伺服器上對應的信箱中。",
"title": "還原單個郵件",
"bulkTitle": "批量還原多個郵件",
"bulkWarning": "請注意:郵件將被還原至其原始存儲的資料夾中。",
"accountsInvolved": "涉及帳戶",
"summary": "待還原詳情",
"messages": "封郵件",
"desc": "此操作將把選定的郵件從 Bichon 系統重新上傳並恢復到其在 IMAP 服務器上對應的郵箱中。",
"confirm": "執行還原",
"restore_to_imap": "還原郵件",
"success": "郵件還原成功",
"successDesc": "選定的郵件已成功還原到 IMAP 服器。",
"successDesc": "選定的郵件已成功恢復到 IMAP 服器。",
"failed": "還原郵件失敗",
"failedTitle": "還原失敗"
},
+6 -1
View File
@@ -1453,7 +1453,12 @@
"confirm": "退出登录"
},
"restore_message": {
"title": "还原邮件",
"title": "还原单个邮件",
"bulkTitle": "批量还原多个邮件",
"bulkWarning": "请注意:邮件将被还原至其原始存储的文件夹中。",
"accountsInvolved": "涉及账户",
"summary": "待还原详情",
"messages": "封邮件",
"desc": "此操作将把选定的邮件从 Bichon 系统重新上传并恢复到其在 IMAP 服务器上对应的邮箱中。",
"confirm": "执行还原",
"restore_to_imap": "还原邮件",