diff --git a/components/email/__tests__/mv-list-toolbar.test.tsx b/components/email/__tests__/mv-list-toolbar.test.tsx index 59b486b85..c86e1475b 100644 --- a/components/email/__tests__/mv-list-toolbar.test.tsx +++ b/components/email/__tests__/mv-list-toolbar.test.tsx @@ -282,3 +282,60 @@ describe('MvListToolbar delete prompt', () => { expect(batchDelete).not.toHaveBeenCalled(); }); }); + +// Settings > Accessibility: "Confirm before deleting" and "Confirm before +// archiving" ask before the selection goes, also when the bulk-delete prompt +// is off (WCAG 3.3.4). +describe('MvListToolbar removal confirmations', () => { + const batchDelete = vi.fn().mockResolvedValue(true); + const batchArchive = vi.fn().mockResolvedValue(true); + + beforeEach(() => { + batchDelete.mockClear(); + batchArchive.mockClear(); + useAuthStore.setState({ client: {} as never } as never); + useEmailStore.setState({ + emails: [message('a'), message('b')], + mailboxes, + selectedMailbox: 'inbox', + selectedEmailKeys: new Set(['a', 'b']), + isUnifiedView: false, + unifiedRole: null, + error: null, + batchDelete, + batchArchive, + } as never); + }); + + it('asks before deleting with "Confirm before deleting" on, and deletes after Delete', async () => { + useSettingsStore.setState({ confirmBulkDelete: false, permanentlyDeleteJunk: false, confirmDelete: true } as never); + render( {}} />); + fireEvent.click(screen.getByLabelText('delete')); + + const dialog = await screen.findByRole('alertdialog'); + expect(dialog).toHaveTextContent('delete_title'); + expect(batchDelete).not.toHaveBeenCalled(); + fireEvent.click(screen.getAllByRole('button', { name: 'delete' }).at(-1)!); + await waitFor(() => expect(batchDelete).toHaveBeenCalledTimes(1)); + }); + + it('asks before archiving with "Confirm before archiving" on, and keeps the mail on Cancel', async () => { + useSettingsStore.setState({ confirmArchive: true } as never); + render( {}} />); + fireEvent.click(screen.getByLabelText('archive')); + + const dialog = await screen.findByRole('alertdialog'); + expect(dialog).toHaveTextContent('archive_title'); + fireEvent.click(screen.getByRole('button', { name: 'cancel' })); + await waitFor(() => expect(screen.queryByRole('alertdialog')).toBeNull()); + expect(batchArchive).not.toHaveBeenCalled(); + }); + + it('archives straight away with the setting off', async () => { + useSettingsStore.setState({ confirmArchive: false } as never); + render( {}} />); + fireEvent.click(screen.getByLabelText('archive')); + await waitFor(() => expect(batchArchive).toHaveBeenCalledTimes(1)); + expect(screen.queryByRole('alertdialog')).toBeNull(); + }); +}); diff --git a/components/email/email-list.tsx b/components/email/email-list.tsx index b818c84d0..a446b859d 100644 --- a/components/email/email-list.tsx +++ b/components/email/email-list.tsx @@ -34,6 +34,7 @@ import { useContextMenu } from "@/hooks/use-context-menu"; import { useConfirmDialog } from "@/hooks/use-confirm-dialog"; import { useTranslations } from "next-intl"; import { toast } from "@/stores/toast-store"; +import { confirmMailRemoval } from "@/lib/mail-removal-confirm"; import { markSelectionReadWithUndo, runBatchEmailAction, setSelectionTagWithUndo, toastWithUndo, undoLabels, undoMoveAction } from "@/lib/email-action-toast"; import { useVirtualizer } from "@tanstack/react-virtual"; import { TagDisplayContext, useMeasuredTagDisplay } from "@/hooks/use-tag-display"; @@ -188,6 +189,7 @@ export function EmailList({ const tSidebar = useTranslations('sidebar'); const mountainViewList = useSettingsStore((state) => state.interfaceLayout === 'mountain-view'); const undo = undoLabels(tNotifications); + const tRemove = useTranslations('email_list.confirm_remove'); const { client } = useAuthStore(useShallow((state) => ({ client: state.client }))); const { selectedEmailKeys, @@ -644,6 +646,7 @@ export function EmailList({ const handleBatchArchive = async () => { if (!client || isProcessing) return; + if (!(await confirmMailRemoval('archive', selectedEmailKeys.size, confirmDialog, tRemove))) return; setIsProcessing(true); const count = selectedEmailKeys.size; const restore = restoreBatchesForSelection(client); @@ -700,6 +703,8 @@ export function EmailList({ variant: "destructive", }); if (!confirmed) return; + } else if (!(await confirmMailRemoval('delete', selectedEmailKeys.size, confirmDialog, tRemove))) { + return; } setIsProcessing(true); diff --git a/components/email/mv-list-toolbar.tsx b/components/email/mv-list-toolbar.tsx index d66eb9b71..7bf27916c 100644 --- a/components/email/mv-list-toolbar.tsx +++ b/components/email/mv-list-toolbar.tsx @@ -24,6 +24,7 @@ import { useAuthStore } from "@/stores/auth-store"; import { useShallow } from "zustand/react/shallow"; import { useEmailStore, ArchiveMailboxNotFoundError, resolveSelectedEmails, bulkDeleteIsPermanent, shouldConfirmBulkDelete, removalFolder, canRemoveFromFolder, restoreBatchesForSelection , type CrossAccountMoveReceipt } from "@/stores/email-store"; import { useRemoveFromFolder } from "@/hooks/use-remove-from-folder"; +import { confirmMailRemoval } from "@/lib/mail-removal-confirm"; import { markSelectionReadWithUndo, runBatchEmailAction, setSelectionTagWithUndo, toastWithUndo, undoLabels, undoMoveAction } from "@/lib/email-action-toast"; import { toast } from "@/stores/toast-store"; import { useConfirmDialog } from "@/hooks/use-confirm-dialog"; @@ -119,6 +120,7 @@ export function MvListToolbar({ const tNotifications = useTranslations("notifications"); const tSpam = useTranslations("email_viewer.spam"); const undo = undoLabels(tNotifications); + const tRemove = useTranslations("email_list.confirm_remove"); const client = useAuthStore((s) => s.client); const { @@ -252,6 +254,8 @@ export function MvListToolbar({ variant: "destructive", }); if (!confirmed) return; + } else if (!(await confirmMailRemoval("delete", selectionCount, confirmDialog, tRemove))) { + return; } const restore = permanent ? null : restoreBatchesForSelection(client); await runBatchEmailAction(() => batchDelete(client, permanent), { @@ -478,7 +482,11 @@ export function MvListToolbar({ run(async () => (client ? batchArchive(client) : false), { + onClick={() => run(async () => ( + client && await confirmMailRemoval("archive", selectionCount, confirmDialog, tRemove) + ? batchArchive(client) + : false + ), { success: tNotifications("emails_archived", { count: selectionCount }), error: tNotifications("error_archiving"), describeError: (error) => error instanceof ArchiveMailboxNotFoundError diff --git a/components/mail/mail-app.tsx b/components/mail/mail-app.tsx index b63d2de23..5a15aaff6 100644 --- a/components/mail/mail-app.tsx +++ b/components/mail/mail-app.tsx @@ -63,6 +63,7 @@ import { usePaneSize } from "@/hooks/use-pane-size"; import { usePaneId } from "@/hooks/use-pane-context"; import { useKeyboardShortcuts, type GoToMailboxTarget } from "@/hooks/use-keyboard-shortcuts"; import { useUndoShortcut } from "@/hooks/use-undo-shortcut"; +import { confirmMailRemoval } from "@/lib/mail-removal-confirm"; import { findNextUnreadIndex } from "@/lib/next-unread-email"; import { useRefreshGesture } from "@/hooks/use-refresh-gesture"; import { useConfirmDialog } from "@/hooks/use-confirm-dialog"; @@ -225,6 +226,8 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) { const tNotifications = useTranslations('notifications'); // The toasts' Undo after a delete to Trash, archive, move or spam report. const undo = undoLabels(tNotifications); + // "Confirm before deleting / archiving" (lib/mail-removal-confirm). + const tRemove = useTranslations('email_list.confirm_remove'); const tCommon = useTranslations('common'); const appName = productName(useConfig().appName); const tQuote = useTranslations('quote_header'); @@ -958,6 +961,7 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) { if (isScheduledView) return; if (shortcutsTargetSelection && client) { const count = selectedEmailKeys.size; + if (!(await confirmMailRemoval('archive', count, confirmDialog, tRemove))) return; const restore = restoreBatchesForSelection(client); await runBatchEmailAction(() => batchArchive(client), { success: t('notifications.emails_archived', { count }), @@ -994,6 +998,8 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) { variant: "destructive", }); if (!confirmed) return; + } else if (!(await confirmMailRemoval('delete', selectedEmailKeys.size, confirmDialog, tRemove))) { + return; } const count = selectedEmailKeys.size; const restore = permanent ? null : restoreBatchesForSelection(client); @@ -2955,6 +2961,8 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) { variant: "destructive", }); if (!confirmed) return; + } else if (!(await confirmMailRemoval('delete', 1, confirmDialog, tRemove))) { + return; } // The store's delete reads the "Delete action" setting: move to the @@ -2976,6 +2984,7 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) { const handleArchive = async (emailToArchive: Email | null = selectedEmail) => { if (!client || !emailToArchive || !isArchiveActionEnabled()) return; + if (!(await confirmMailRemoval('archive', 1, confirmDialog, tRemove))) return; // In a list that mixes accounts (the unified views, a tag view) the archive // folder (and any year/month subfolders we create) must live in the email's diff --git a/components/pro/pro-email-tab-body.tsx b/components/pro/pro-email-tab-body.tsx index 8c8288b87..e93db93ad 100644 --- a/components/pro/pro-email-tab-body.tsx +++ b/components/pro/pro-email-tab-body.tsx @@ -24,6 +24,9 @@ import { cn } from "@/lib/utils"; import { getDraftTextBody } from '@/lib/email-body-selection'; import { messagePriorityFromHeaders } from '@/lib/message-priority'; import { useArchiveActionEnabled } from '@/lib/archive-gate'; +import { confirmMailRemoval } from '@/lib/mail-removal-confirm'; +import { useConfirmDialog } from '@/hooks/use-confirm-dialog'; +import { ConfirmDialog } from '@/components/ui/confirm-dialog'; import { saveQuickReplyDraft } from '@/lib/outgoing/quick-reply-envelope'; interface ProEmailTabBodyProps { @@ -91,6 +94,8 @@ function buildReplyContext(email: Email): ProReplyContext { export function ProEmailView({ emailId, client: clientOverride, clientAccountId, accountId, onLoaded, onClose, className }: ProEmailViewProps) { const t = useTranslations(); const tNotifications = useTranslations('notifications'); + const tRemove = useTranslations('email_list.confirm_remove'); + const { dialogProps: confirmDialogProps, confirm: confirmDialog } = useConfirmDialog(); const archiveActionEnabled = useArchiveActionEnabled(); const activeClient = useAuthStore((s) => s.client); @@ -295,6 +300,7 @@ export function ProEmailView({ emailId, client: clientOverride, clientAccountId, const handleDelete = useCallback(async () => { if (!client || !email) return; + if (!(await confirmMailRemoval('delete', 1, confirmDialog, tRemove))) return; try { // false: not deleted (a plugin stopped it), so the tab stays open. if (await deleteEmail(client, email.id)) onClose(); @@ -302,12 +308,13 @@ export function ProEmailView({ emailId, client: clientOverride, clientAccountId, console.error('Delete failed:', err); toast.error(tNotifications('error_deleting')); } - }, [client, email, deleteEmail, onClose, tNotifications]); + }, [client, email, deleteEmail, onClose, tNotifications, confirmDialog, tRemove]); const handleArchive = useCallback(async () => { if (!client || !email) return; const archiveMb = mailboxes.find((m) => m.role === 'archive'); if (!archiveMb) return; + if (!(await confirmMailRemoval('archive', 1, confirmDialog, tRemove))) return; try { if (!(await moveToMailbox(client, email.id, archiveMb.id, emailKeyFor(email)))) return; toast.success(tNotifications('email_archived')); @@ -315,7 +322,7 @@ export function ProEmailView({ emailId, client: clientOverride, clientAccountId, } catch (err) { console.error('Archive failed:', err); } - }, [client, email, mailboxes, moveToMailbox, onClose, tNotifications]); + }, [client, email, mailboxes, moveToMailbox, onClose, tNotifications, confirmDialog, tRemove]); const handleToggleStar = useCallback(async () => { if (!client || !email) return; @@ -490,6 +497,7 @@ export function ProEmailView({ emailId, client: clientOverride, clientAccountId, className="flex-1" /> + ); } diff --git a/lib/mail-removal-confirm.ts b/lib/mail-removal-confirm.ts new file mode 100644 index 000000000..75e2c6619 --- /dev/null +++ b/lib/mail-removal-confirm.ts @@ -0,0 +1,39 @@ +import { useSettingsStore } from '@/stores/settings-store'; + +/** What a confirm dialog hook (useConfirmDialog) takes. */ +export type ConfirmFn = (options: { + title: string; + message: string; + confirmText?: string; + variant?: 'default' | 'destructive'; +}) => Promise; + +/** `t` of the `email_list.confirm_remove` namespace. */ +export type RemovalConfirmT = (key: string, values: { count: number }) => string; + +/** + * Asks before messages are deleted or archived when the user turned on + * "Confirm before deleting" or "Confirm before archiving" (Settings > + * Accessibility; WCAG 3.3.4). Applies to single messages and keyboard + * shortcuts as well as selections. Resolves true when the action may go + * ahead: the setting is off, or the user confirmed. + * + * A permanent delete has its own, stronger question; ask this one only when + * no other confirmation is shown, so nobody is asked twice. + */ +export async function confirmMailRemoval( + kind: 'delete' | 'archive', + count: number, + confirm: ConfirmFn, + t: RemovalConfirmT, +): Promise { + const settings = useSettingsStore.getState(); + if (!(kind === 'delete' ? settings.confirmDelete : settings.confirmArchive)) return true; + if (count <= 0) return true; + return confirm({ + title: t(`${kind}_title`, { count }), + message: t(`${kind}_message`, { count }), + confirmText: t(kind, { count }), + variant: kind === 'delete' ? 'destructive' : 'default', + }); +} diff --git a/locales/ar/common.json b/locales/ar/common.json index 158038972..691c599a2 100644 --- a/locales/ar/common.json +++ b/locales/ar/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "إلغاء الإرسال", "reschedule_send": "إعادة الجدولة", "cancel_and_edit": "إلغاء والتعديل", - "cancel_and_compose_again": "إلغاء وإعادة الكتابة" + "cancel_and_compose_again": "إلغاء وإعادة الكتابة", + "confirm_remove": { + "delete_title": "{count, plural, one {حذف هذه الرسالة؟} other {حذف # رسائل؟}}", + "delete_message": "{count, plural, one {ستُنقل إلى سلة المهملات.} other {ستُنقل إلى سلة المهملات.}}", + "archive_title": "{count, plural, one {أرشفة هذه الرسالة؟} other {أرشفة # رسائل؟}}", + "archive_message": "{count, plural, one {ستُنقل إلى الأرشيف.} other {ستُنقل إلى الأرشيف.}}", + "delete": "حذف", + "archive": "أرشفة" + } }, "shared_tags": { "title": "الوسوم المشتركة", diff --git a/locales/ca/common.json b/locales/ca/common.json index 17b2f59e0..a89a99cf4 100644 --- a/locales/ca/common.json +++ b/locales/ca/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Cancel·la l'enviament", "reschedule_send": "Reprograma", "cancel_and_edit": "Cancel·la i edita", - "cancel_and_compose_again": "Cancel·la i torna a redactar" + "cancel_and_compose_again": "Cancel·la i torna a redactar", + "confirm_remove": { + "delete_title": "{count, plural, one {Vols suprimir aquest correu?} other {Vols suprimir # correus?}}", + "delete_message": "{count, plural, one {Es mourà a la paperera.} other {Es mouran a la paperera.}}", + "archive_title": "{count, plural, one {Vols arxivar aquest correu?} other {Vols arxivar # correus?}}", + "archive_message": "{count, plural, one {Es mourà al teu arxiu.} other {Es mouran al teu arxiu.}}", + "delete": "Suprimeix", + "archive": "Arxiva" + } }, "shared_tags": { "title": "Etiquetes compartides", diff --git a/locales/cs/common.json b/locales/cs/common.json index f2e88c542..5da3e886f 100644 --- a/locales/cs/common.json +++ b/locales/cs/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Zrušit odeslání", "reschedule_send": "Přeplánovat", "cancel_and_edit": "Zrušit a upravit", - "cancel_and_compose_again": "Zrušit a napsat znovu" + "cancel_and_compose_again": "Zrušit a napsat znovu", + "confirm_remove": { + "delete_title": "{count, plural, one {Odstranit tuto zprávu?} few {Odstranit # zprávy?} other {Odstranit # zpráv?}}", + "delete_message": "{count, plural, one {Přesune se do koše.} other {Přesunou se do koše.}}", + "archive_title": "{count, plural, one {Archivovat tuto zprávu?} few {Archivovat # zprávy?} other {Archivovat # zpráv?}}", + "archive_message": "{count, plural, one {Přesune se do archivu.} other {Přesunou se do archivu.}}", + "delete": "Odstranit", + "archive": "Archivovat" + } }, "shared_tags": { "title": "Sdílené štítky", diff --git a/locales/da/common.json b/locales/da/common.json index de32bff1f..a22fba1fb 100644 --- a/locales/da/common.json +++ b/locales/da/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Annuller afsendelse", "reschedule_send": "Planlæg om", "cancel_and_edit": "Annuller og redigér", - "cancel_and_compose_again": "Annuller og skriv igen" + "cancel_and_compose_again": "Annuller og skriv igen", + "confirm_remove": { + "delete_title": "{count, plural, one {Slet denne e-mail?} other {Slet # e-mails?}}", + "delete_message": "{count, plural, one {Den flyttes til papirkurven.} other {De flyttes til papirkurven.}}", + "archive_title": "{count, plural, one {Arkivér denne e-mail?} other {Arkivér # e-mails?}}", + "archive_message": "{count, plural, one {Den flyttes til dit arkiv.} other {De flyttes til dit arkiv.}}", + "delete": "Slet", + "archive": "Arkivér" + } }, "shared_tags": { "title": "Delte tags", diff --git a/locales/de/common.json b/locales/de/common.json index 8e7973cd9..877309c0b 100644 --- a/locales/de/common.json +++ b/locales/de/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Senden abbrechen", "reschedule_send": "Neu planen", "cancel_and_edit": "Abbrechen und bearbeiten", - "cancel_and_compose_again": "Abbrechen und neu verfassen" + "cancel_and_compose_again": "Abbrechen und neu verfassen", + "confirm_remove": { + "delete_title": "{count, plural, one {Diese E-Mail löschen?} other {# E-Mails löschen?}}", + "delete_message": "{count, plural, one {Sie wird in den Papierkorb verschoben.} other {Sie werden in den Papierkorb verschoben.}}", + "archive_title": "{count, plural, one {Diese E-Mail archivieren?} other {# E-Mails archivieren?}}", + "archive_message": "{count, plural, one {Sie wird in Ihr Archiv verschoben.} other {Sie werden in Ihr Archiv verschoben.}}", + "delete": "Löschen", + "archive": "Archivieren" + } }, "shared_tags": { "title": "Geteilte Labels", diff --git a/locales/en/common.json b/locales/en/common.json index 9bbf0113f..9e570d032 100644 --- a/locales/en/common.json +++ b/locales/en/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Cancel send", "reschedule_send": "Reschedule", "cancel_and_edit": "Cancel and edit", - "cancel_and_compose_again": "Cancel and compose again" + "cancel_and_compose_again": "Cancel and compose again", + "confirm_remove": { + "delete_title": "{count, plural, one {Delete this email?} other {Delete # emails?}}", + "delete_message": "{count, plural, one {It moves to the trash.} other {They move to the trash.}}", + "archive_title": "{count, plural, one {Archive this email?} other {Archive # emails?}}", + "archive_message": "{count, plural, one {It moves to your archive.} other {They move to your archive.}}", + "delete": "Delete", + "archive": "Archive" + } }, "shared_tags": { "title": "Shared tags", diff --git a/locales/es/common.json b/locales/es/common.json index a097c0f1d..60e182ac7 100644 --- a/locales/es/common.json +++ b/locales/es/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Cancelar envío", "reschedule_send": "Reprogramar", "cancel_and_edit": "Cancelar y editar", - "cancel_and_compose_again": "Cancelar y redactar de nuevo" + "cancel_and_compose_again": "Cancelar y redactar de nuevo", + "confirm_remove": { + "delete_title": "{count, plural, one {¿Eliminar este correo?} other {¿Eliminar # correos?}}", + "delete_message": "{count, plural, one {Se moverá a la papelera.} other {Se moverán a la papelera.}}", + "archive_title": "{count, plural, one {¿Archivar este correo?} other {¿Archivar # correos?}}", + "archive_message": "{count, plural, one {Se moverá a tu archivo.} other {Se moverán a tu archivo.}}", + "delete": "Eliminar", + "archive": "Archivar" + } }, "shared_tags": { "title": "Etiquetas compartidas", diff --git a/locales/et/common.json b/locales/et/common.json index a8cdfd9fa..51c641869 100644 --- a/locales/et/common.json +++ b/locales/et/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Tühista saatmine", "reschedule_send": "Ajasta uuesti", "cancel_and_edit": "Tühista ja muuda", - "cancel_and_compose_again": "Tühista ja koosta uuesti" + "cancel_and_compose_again": "Tühista ja koosta uuesti", + "confirm_remove": { + "delete_title": "{count, plural, one {Kas kustutada see kiri?} other {Kas kustutada # kirja?}}", + "delete_message": "{count, plural, one {See viiakse prügikasti.} other {Need viiakse prügikasti.}}", + "archive_title": "{count, plural, one {Kas arhiveerida see kiri?} other {Kas arhiveerida # kirja?}}", + "archive_message": "{count, plural, one {See viiakse sinu arhiivi.} other {Need viiakse sinu arhiivi.}}", + "delete": "Kustuta", + "archive": "Arhiveeri" + } }, "shared_tags": { "title": "Jagatud sildid", diff --git a/locales/fa/common.json b/locales/fa/common.json index bc2877c55..6be635575 100644 --- a/locales/fa/common.json +++ b/locales/fa/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "لغو ارسال", "reschedule_send": "باززمان‌بندی", "cancel_and_edit": "لغو و ویرایش", - "cancel_and_compose_again": "لغو و نوشتن مجدد" + "cancel_and_compose_again": "لغو و نوشتن مجدد", + "confirm_remove": { + "delete_title": "{count, plural, one {این ایمیل حذف شود؟} other {# ایمیل حذف شوند؟}}", + "delete_message": "{count, plural, one {به سطل زباله منتقل می‌شود.} other {به سطل زباله منتقل می‌شوند.}}", + "archive_title": "{count, plural, one {این ایمیل بایگانی شود؟} other {# ایمیل بایگانی شوند؟}}", + "archive_message": "{count, plural, one {به بایگانی شما منتقل می‌شود.} other {به بایگانی شما منتقل می‌شوند.}}", + "delete": "حذف", + "archive": "بایگانی" + } }, "shared_tags": { "title": "برچسب‌های مشترک", diff --git a/locales/fr/common.json b/locales/fr/common.json index f32d4eabc..7b2b9f972 100644 --- a/locales/fr/common.json +++ b/locales/fr/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Annuler l’envoi", "reschedule_send": "Replanifier", "cancel_and_edit": "Annuler et modifier", - "cancel_and_compose_again": "Annuler et rédiger à nouveau" + "cancel_and_compose_again": "Annuler et rédiger à nouveau", + "confirm_remove": { + "delete_title": "{count, plural, one {Supprimer cet e-mail ?} other {Supprimer # e-mails ?}}", + "delete_message": "{count, plural, one {Il sera déplacé dans la corbeille.} other {Ils seront déplacés dans la corbeille.}}", + "archive_title": "{count, plural, one {Archiver cet e-mail ?} other {Archiver # e-mails ?}}", + "archive_message": "{count, plural, one {Il sera déplacé dans vos archives.} other {Ils seront déplacés dans vos archives.}}", + "delete": "Supprimer", + "archive": "Archiver" + } }, "shared_tags": { "title": "Étiquettes partagées", diff --git a/locales/he/common.json b/locales/he/common.json index bdc809c13..e024e82ac 100644 --- a/locales/he/common.json +++ b/locales/he/common.json @@ -328,7 +328,15 @@ "cancel_scheduled_send": "ביטול שליחה", "reschedule_send": "תזמן מחדש", "cancel_and_edit": "בטל וערוך", - "cancel_and_compose_again": "בטל והרכיב שוב" + "cancel_and_compose_again": "בטל והרכיב שוב", + "confirm_remove": { + "delete_title": "{count, plural, one {למחוק את ההודעה הזו?} other {למחוק # הודעות?}}", + "delete_message": "{count, plural, one {היא תועבר לאשפה.} other {הן יועברו לאשפה.}}", + "archive_title": "{count, plural, one {להעביר את ההודעה הזו לארכיון?} other {להעביר # הודעות לארכיון?}}", + "archive_message": "{count, plural, one {היא תועבר לארכיון שלך.} other {הן יועברו לארכיון שלך.}}", + "delete": "מחק", + "archive": "העבר לארכיון" + } }, "shared_tags": { "title": "תגים משותפים", diff --git a/locales/hu/common.json b/locales/hu/common.json index 96933fe0a..553cd9d15 100644 --- a/locales/hu/common.json +++ b/locales/hu/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Küldés megszakítása", "reschedule_send": "Átütemezés", "cancel_and_edit": "Mégse és szerkesztés", - "cancel_and_compose_again": "Mégse és újraírás" + "cancel_and_compose_again": "Mégse és újraírás", + "confirm_remove": { + "delete_title": "{count, plural, one {Törlöd ezt az e-mailt?} other {Törölsz # e-mailt?}}", + "delete_message": "{count, plural, one {A kukába kerül.} other {A kukába kerülnek.}}", + "archive_title": "{count, plural, one {Archiválod ezt az e-mailt?} other {Archiválsz # e-mailt?}}", + "archive_message": "{count, plural, one {Az archívumodba kerül.} other {Az archívumodba kerülnek.}}", + "delete": "Törlés", + "archive": "Archiválás" + } }, "shared_tags": { "title": "Megosztott címkék", diff --git a/locales/it/common.json b/locales/it/common.json index fff5d633c..7fa866710 100644 --- a/locales/it/common.json +++ b/locales/it/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Annulla invio", "reschedule_send": "Riprogramma", "cancel_and_edit": "Annulla e modifica", - "cancel_and_compose_again": "Annulla e componi di nuovo" + "cancel_and_compose_again": "Annulla e componi di nuovo", + "confirm_remove": { + "delete_title": "{count, plural, one {Eliminare questa email?} other {Eliminare # email?}}", + "delete_message": "{count, plural, one {Verrà spostata nel cestino.} other {Verranno spostate nel cestino.}}", + "archive_title": "{count, plural, one {Archiviare questa email?} other {Archiviare # email?}}", + "archive_message": "{count, plural, one {Verrà spostata nel tuo archivio.} other {Verranno spostate nel tuo archivio.}}", + "delete": "Elimina", + "archive": "Archivia" + } }, "shared_tags": { "title": "Etichette condivise", diff --git a/locales/ja/common.json b/locales/ja/common.json index f647bee5f..a244e6bbf 100644 --- a/locales/ja/common.json +++ b/locales/ja/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "送信をキャンセル", "reschedule_send": "再予約", "cancel_and_edit": "キャンセルして編集", - "cancel_and_compose_again": "キャンセルして新規作成" + "cancel_and_compose_again": "キャンセルして新規作成", + "confirm_remove": { + "delete_title": "{count, plural, other {#件のメールを削除しますか?}}", + "delete_message": "{count, plural, other {ゴミ箱に移動します。}}", + "archive_title": "{count, plural, other {#件のメールをアーカイブしますか?}}", + "archive_message": "{count, plural, other {アーカイブに移動します。}}", + "delete": "削除", + "archive": "アーカイブ" + } }, "shared_tags": { "title": "共有タグ", diff --git a/locales/ko/common.json b/locales/ko/common.json index 8f68eac76..e626e9868 100644 --- a/locales/ko/common.json +++ b/locales/ko/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "보내기 취소", "reschedule_send": "다시 예약", "cancel_and_edit": "취소하고 편집", - "cancel_and_compose_again": "취소하고 다시 작성" + "cancel_and_compose_again": "취소하고 다시 작성", + "confirm_remove": { + "delete_title": "{count, plural, other {메일 #개를 삭제할까요?}}", + "delete_message": "{count, plural, other {휴지통으로 이동해요.}}", + "archive_title": "{count, plural, other {메일 #개를 보관할까요?}}", + "archive_message": "{count, plural, other {보관함으로 이동해요.}}", + "delete": "삭제", + "archive": "보관" + } }, "shared_tags": { "title": "공유 태그", diff --git a/locales/lv/common.json b/locales/lv/common.json index 1fa1f2e93..25790a5c9 100644 --- a/locales/lv/common.json +++ b/locales/lv/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Atcelt sūtīšanu", "reschedule_send": "Pārplānot", "cancel_and_edit": "Atcelt un rediģēt", - "cancel_and_compose_again": "Atcelt un rakstīt no jauna" + "cancel_and_compose_again": "Atcelt un rakstīt no jauna", + "confirm_remove": { + "delete_title": "{count, plural, zero {Dzēst # vēstules?} one {Dzēst šo vēstuli?} other {Dzēst # vēstules?}}", + "delete_message": "{count, plural, zero {Tās tiks pārvietotas uz atkritni.} one {Tā tiks pārvietota uz atkritni.} other {Tās tiks pārvietotas uz atkritni.}}", + "archive_title": "{count, plural, zero {Arhivēt # vēstules?} one {Arhivēt šo vēstuli?} other {Arhivēt # vēstules?}}", + "archive_message": "{count, plural, zero {Tās tiks pārvietotas uz jūsu arhīvu.} one {Tā tiks pārvietota uz jūsu arhīvu.} other {Tās tiks pārvietotas uz jūsu arhīvu.}}", + "delete": "Dzēst", + "archive": "Arhivēt" + } }, "shared_tags": { "title": "Kopīgotie tagi", diff --git a/locales/mn/common.json b/locales/mn/common.json index c33be2380..340a29f9d 100644 --- a/locales/mn/common.json +++ b/locales/mn/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Илгээхийг цуцлах", "reschedule_send": "Хуваарь солих", "cancel_and_edit": "Цуцлах, засах", - "cancel_and_compose_again": "Цуцлаад дахин бичих" + "cancel_and_compose_again": "Цуцлаад дахин бичих", + "confirm_remove": { + "delete_title": "{count, plural, one {Энэ имэйлийг устгах уу?} other {# имэйлийг устгах уу?}}", + "delete_message": "{count, plural, other {Хогийн сав руу шилжинэ.}}", + "archive_title": "{count, plural, one {Энэ имэйлийг архивлах уу?} other {# имэйлийг архивлах уу?}}", + "archive_message": "{count, plural, other {Таны архив руу шилжинэ.}}", + "delete": "Устгах", + "archive": "Архивлах" + } }, "shared_tags": { "title": "Хуваалцсан тагууд", diff --git a/locales/nb/common.json b/locales/nb/common.json index 98b9533a6..064459686 100644 --- a/locales/nb/common.json +++ b/locales/nb/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Avbryt sending", "reschedule_send": "Planlegg på nytt", "cancel_and_edit": "Avbryt og rediger", - "cancel_and_compose_again": "Avbryt og skriv meldingen på nytt" + "cancel_and_compose_again": "Avbryt og skriv meldingen på nytt", + "confirm_remove": { + "delete_title": "{count, plural, one {Slette denne e-posten?} other {Slette # e-poster?}}", + "delete_message": "{count, plural, one {Den flyttes til papirkurven.} other {De flyttes til papirkurven.}}", + "archive_title": "{count, plural, one {Arkivere denne e-posten?} other {Arkivere # e-poster?}}", + "archive_message": "{count, plural, one {Den flyttes til arkivet ditt.} other {De flyttes til arkivet ditt.}}", + "delete": "Slett", + "archive": "Arkiver" + } }, "shared_tags": { "title": "Delte etiketter", diff --git a/locales/nl/common.json b/locales/nl/common.json index 732e8a0c4..6814a8318 100644 --- a/locales/nl/common.json +++ b/locales/nl/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Verzenden annuleren", "reschedule_send": "Opnieuw plannen", "cancel_and_edit": "Annuleren en bewerken", - "cancel_and_compose_again": "Annuleren en opnieuw opstellen" + "cancel_and_compose_again": "Annuleren en opnieuw opstellen", + "confirm_remove": { + "delete_title": "{count, plural, one {Deze e-mail verwijderen?} other {# e-mails verwijderen?}}", + "delete_message": "{count, plural, one {Hij gaat naar de prullenbak.} other {Ze gaan naar de prullenbak.}}", + "archive_title": "{count, plural, one {Deze e-mail archiveren?} other {# e-mails archiveren?}}", + "archive_message": "{count, plural, one {Hij gaat naar uw archief.} other {Ze gaan naar uw archief.}}", + "delete": "Verwijderen", + "archive": "Archiveren" + } }, "shared_tags": { "title": "Gedeelde labels", diff --git a/locales/pl/common.json b/locales/pl/common.json index 7c6d2eaba..e29750e17 100644 --- a/locales/pl/common.json +++ b/locales/pl/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Anuluj wysyłkę", "reschedule_send": "Przełóż", "cancel_and_edit": "Anuluj i edytuj", - "cancel_and_compose_again": "Anuluj i napisz ponownie" + "cancel_and_compose_again": "Anuluj i napisz ponownie", + "confirm_remove": { + "delete_title": "{count, plural, one {Usunąć tę wiadomość?} few {Usunąć # wiadomości?} many {Usunąć # wiadomości?} other {Usunąć # wiadomości?}}", + "delete_message": "{count, plural, one {Zostanie przeniesiona do kosza.} other {Zostaną przeniesione do kosza.}}", + "archive_title": "{count, plural, one {Zarchiwizować tę wiadomość?} few {Zarchiwizować # wiadomości?} many {Zarchiwizować # wiadomości?} other {Zarchiwizować # wiadomości?}}", + "archive_message": "{count, plural, one {Zostanie przeniesiona do archiwum.} other {Zostaną przeniesione do archiwum.}}", + "delete": "Usuń", + "archive": "Archiwizuj" + } }, "shared_tags": { "title": "Wspólne etykiety", diff --git a/locales/pt/common.json b/locales/pt/common.json index 14b7268e0..43b99f94a 100644 --- a/locales/pt/common.json +++ b/locales/pt/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Cancelar envio", "reschedule_send": "Reagendar", "cancel_and_edit": "Cancelar e editar", - "cancel_and_compose_again": "Cancelar e escrever novamente" + "cancel_and_compose_again": "Cancelar e escrever novamente", + "confirm_remove": { + "delete_title": "{count, plural, one {Excluir este e-mail?} other {Excluir # e-mails?}}", + "delete_message": "{count, plural, one {Ele vai para a lixeira.} other {Eles vão para a lixeira.}}", + "archive_title": "{count, plural, one {Arquivar este e-mail?} other {Arquivar # e-mails?}}", + "archive_message": "{count, plural, one {Ele vai para o seu arquivo.} other {Eles vão para o seu arquivo.}}", + "delete": "Excluir", + "archive": "Arquivar" + } }, "shared_tags": { "title": "Etiquetas compartilhadas", diff --git a/locales/ro/common.json b/locales/ro/common.json index 1f3c47213..836b8775b 100644 --- a/locales/ro/common.json +++ b/locales/ro/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Anulează trimiterea", "reschedule_send": "Reprogramare", "cancel_and_edit": "Anulează și editează", - "cancel_and_compose_again": "Anulează și redactează din nou" + "cancel_and_compose_again": "Anulează și redactează din nou", + "confirm_remove": { + "delete_title": "{count, plural, one {Ștergi acest e-mail?} few {Ștergi # e-mailuri?} other {Ștergi # de e-mailuri?}}", + "delete_message": "{count, plural, one {Va fi mutat în coșul de gunoi.} other {Vor fi mutate în coșul de gunoi.}}", + "archive_title": "{count, plural, one {Arhivezi acest e-mail?} few {Arhivezi # e-mailuri?} other {Arhivezi # de e-mailuri?}}", + "archive_message": "{count, plural, one {Va fi mutat în arhiva ta.} other {Vor fi mutate în arhiva ta.}}", + "delete": "Șterge", + "archive": "Arhivează" + } }, "shared_tags": { "title": "Etichete partajate", diff --git a/locales/ru/common.json b/locales/ru/common.json index 4446a18d9..76ebd56fa 100644 --- a/locales/ru/common.json +++ b/locales/ru/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Отменить отправку", "reschedule_send": "Перенести", "cancel_and_edit": "Отменить и изменить", - "cancel_and_compose_again": "Отменить и написать заново" + "cancel_and_compose_again": "Отменить и написать заново", + "confirm_remove": { + "delete_title": "{count, plural, one {Удалить это письмо?} few {Удалить # письма?} many {Удалить # писем?} other {Удалить # письма?}}", + "delete_message": "{count, plural, one {Оно будет перемещено в корзину.} other {Они будут перемещены в корзину.}}", + "archive_title": "{count, plural, one {Архивировать это письмо?} few {Архивировать # письма?} many {Архивировать # писем?} other {Архивировать # письма?}}", + "archive_message": "{count, plural, one {Оно будет перемещено в архив.} other {Они будут перемещены в архив.}}", + "delete": "Удалить", + "archive": "Архивировать" + } }, "shared_tags": { "title": "Общие теги", diff --git a/locales/sk/common.json b/locales/sk/common.json index 026f1372e..fcf4678a1 100644 --- a/locales/sk/common.json +++ b/locales/sk/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Zrušiť odoslanie", "reschedule_send": "Prenaplánovať", "cancel_and_edit": "Zrušiť a upraviť", - "cancel_and_compose_again": "Zrušiť a napísať znova" + "cancel_and_compose_again": "Zrušiť a napísať znova", + "confirm_remove": { + "delete_title": "{count, plural, one {Odstrániť tento e-mail?} few {Odstrániť # e-maily?} other {Odstrániť # e-mailov?}}", + "delete_message": "{count, plural, one {Presunie sa do koša.} other {Presunú sa do koša.}}", + "archive_title": "{count, plural, one {Archivovať tento e-mail?} few {Archivovať # e-maily?} other {Archivovať # e-mailov?}}", + "archive_message": "{count, plural, one {Presunie sa do archívu.} other {Presunú sa do archívu.}}", + "delete": "Odstrániť", + "archive": "Archivovať" + } }, "shared_tags": { "title": "Zdieľané štítky", diff --git a/locales/th/common.json b/locales/th/common.json index eaa9c26d1..d435bd0f6 100644 --- a/locales/th/common.json +++ b/locales/th/common.json @@ -617,7 +617,15 @@ "cancel_scheduled_send": "ยกเลิกการส่ง", "reschedule_send": "เปลี่ยนเวลาส่งใหม่", "cancel_and_edit": "ยกเลิกและแก้ไข", - "cancel_and_compose_again": "ยกเลิกและเขียนใหม่" + "cancel_and_compose_again": "ยกเลิกและเขียนใหม่", + "confirm_remove": { + "delete_title": "{count, plural, other {ลบอีเมล # ฉบับหรือไม่}}", + "delete_message": "{count, plural, other {อีเมลจะถูกย้ายไปที่ถังขยะ}}", + "archive_title": "{count, plural, other {เก็บอีเมล # ฉบับถาวรหรือไม่}}", + "archive_message": "{count, plural, other {อีเมลจะถูกย้ายไปที่ที่เก็บถาวร}}", + "delete": "ลบ", + "archive": "เก็บถาวร" + } }, "shared_tags": { "title": "ป้ายกำกับที่แชร์", diff --git a/locales/tr/common.json b/locales/tr/common.json index 3b12a6588..dc781390f 100644 --- a/locales/tr/common.json +++ b/locales/tr/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Göndermeyi iptal et", "reschedule_send": "Yeniden zamanla", "cancel_and_edit": "İptal et ve düzenle", - "cancel_and_compose_again": "İptal et ve yeniden yaz" + "cancel_and_compose_again": "İptal et ve yeniden yaz", + "confirm_remove": { + "delete_title": "{count, plural, one {Bu e-posta silinsin mi?} other {# e-posta silinsin mi?}}", + "delete_message": "{count, plural, other {Çöp kutusuna taşınır.}}", + "archive_title": "{count, plural, one {Bu e-posta arşivlensin mi?} other {# e-posta arşivlensin mi?}}", + "archive_message": "{count, plural, other {Arşivinize taşınır.}}", + "delete": "Sil", + "archive": "Arşivle" + } }, "shared_tags": { "title": "Paylaşılan etiketler", diff --git a/locales/uk/common.json b/locales/uk/common.json index 27207d483..51ec4f88a 100644 --- a/locales/uk/common.json +++ b/locales/uk/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "Скасувати надсилання", "reschedule_send": "Перенести", "cancel_and_edit": "Скасувати й редагувати", - "cancel_and_compose_again": "Скасувати й написати знову" + "cancel_and_compose_again": "Скасувати й написати знову", + "confirm_remove": { + "delete_title": "{count, plural, one {Видалити цей лист?} few {Видалити # листи?} many {Видалити # листів?} other {Видалити # листа?}}", + "delete_message": "{count, plural, one {Його буде переміщено в кошик.} other {Їх буде переміщено в кошик.}}", + "archive_title": "{count, plural, one {Архівувати цей лист?} few {Архівувати # листи?} many {Архівувати # листів?} other {Архівувати # листа?}}", + "archive_message": "{count, plural, one {Його буде переміщено в архів.} other {Їх буде переміщено в архів.}}", + "delete": "Видалити", + "archive": "Архівувати" + } }, "shared_tags": { "title": "Спільні теги", diff --git a/locales/zh-TW/common.json b/locales/zh-TW/common.json index 4bc2f2bc2..d9138a6a7 100644 --- a/locales/zh-TW/common.json +++ b/locales/zh-TW/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "取消傳送", "reschedule_send": "重新排程", "cancel_and_edit": "取消並編輯", - "cancel_and_compose_again": "取消並重新撰寫" + "cancel_and_compose_again": "取消並重新撰寫", + "confirm_remove": { + "delete_title": "{count, plural, other {要刪除 # 封郵件嗎?}}", + "delete_message": "{count, plural, other {郵件將移到垃圾桶。}}", + "archive_title": "{count, plural, other {要封存 # 封郵件嗎?}}", + "archive_message": "{count, plural, other {郵件將移到封存。}}", + "delete": "刪除", + "archive": "封存" + } }, "shared_tags": { "title": "共用標籤", diff --git a/locales/zh/common.json b/locales/zh/common.json index af7e6d920..cf514d5bf 100644 --- a/locales/zh/common.json +++ b/locales/zh/common.json @@ -363,7 +363,15 @@ "cancel_scheduled_send": "取消发送", "reschedule_send": "重新计划", "cancel_and_edit": "取消并编辑", - "cancel_and_compose_again": "取消并重新撰写" + "cancel_and_compose_again": "取消并重新撰写", + "confirm_remove": { + "delete_title": "{count, plural, other {要删除 # 封邮件吗?}}", + "delete_message": "{count, plural, other {邮件将移到废纸篓。}}", + "archive_title": "{count, plural, other {要归档 # 封邮件吗?}}", + "archive_message": "{count, plural, other {邮件将移到归档。}}", + "delete": "删除", + "archive": "归档" + } }, "shared_tags": { "title": "共享标签",