fix: offer Empty Trash and Empty Spam only there, with the message count, and drop folder actions that can't apply

The folder menu tests no longer expect "Empty folder" on a folder of
your own: emptying is offered on Trash and Spam only now. The Mountain
View list test expects the entry to read "Empty Trash".
This commit is contained in:
Linus Rath
2026-11-04 11:30:11 +01:00
parent 814945a445
commit 0a09fec123
41 changed files with 421 additions and 38 deletions
@@ -29,6 +29,15 @@ describe('list header ⋮', () => {
fireEvent.click(screen.getByText('mark_folder_read'));
expect(onMarkFolderRead).toHaveBeenCalledTimes(1);
});
// p2-14: "Empty folder" read the same in Trash and Spam.
it('names Empty after Trash or Spam', () => {
const onEmptyFolder = vi.fn();
render(<MailFolderMenu folderRole="junk" onEmptyFolder={onEmptyFolder} />);
fireEvent.click(screen.getByTestId('mail-folder-menu'));
expect(screen.getByTestId('mail-empty-folder').textContent).toContain('empty_spam');
fireEvent.click(screen.getByTestId('mail-empty-folder'));
expect(onEmptyFolder).toHaveBeenCalledTimes(1);
});
it('carries Refresh and Sort, which have no buttons of their own', () => {
const onRefresh = vi.fn();
render(<MailFolderMenu folderRole="inbox" onRefresh={onRefresh} onMarkAllFoldersRead={vi.fn()} />);
@@ -160,10 +160,10 @@ describe('MvListToolbar overflow menu', () => {
render(<MvListToolbar loadedCount={1} onRefresh={() => {}} onEmptyFolder={() => {}} />);
open();
expect(screen.queryByText('empty_folder')).toBeNull();
for (const label of ['empty_folder', 'empty_trash', 'empty_spam']) expect(screen.queryByText(label)).toBeNull();
});
it('offers it in the bin', () => {
it('offers it in the bin, as Empty Trash', () => {
useEmailStore.setState({
mailboxes: [mailbox('trash', 'Trash', 'trash')],
selectedMailbox: 'trash',
@@ -172,7 +172,7 @@ describe('MvListToolbar overflow menu', () => {
render(<MvListToolbar loadedCount={1} onRefresh={() => {}} onEmptyFolder={onEmptyFolder} />);
open();
fireEvent.click(screen.getByText('empty_folder'));
fireEvent.click(screen.getByText('empty_trash'));
expect(onEmptyFolder).toHaveBeenCalledOnce();
});
});
+8 -1
View File
@@ -11,6 +11,7 @@ import { usePolicyStore } from "@/stores/policy-store";
import { useAuthStore } from "@/stores/auth-store";
import { useEmailStore } from "@/stores/email-store";
import { isDefaultOrder, sanitizeSortLevels, type SortLevel } from "@/lib/message-list-order";
import { emptyFolderLabelKey } from "@/lib/empty-folder-text";
/** The orders the list header offers; Settings has the full editor. */
export const SORT_CHOICES = [
@@ -185,6 +186,7 @@ export const MailFolderMenu = memo(function MailFolderMenu({
onMarkFolderRead={onMarkFolderRead}
onMarkAllFoldersRead={onMarkAllFoldersRead}
onEmptyFolder={onEmptyFolder}
folderRole={folderRole}
onPicked={menu.closeContextMenu}
/>
</ContextMenu>
@@ -197,14 +199,18 @@ export function MailFolderMenuItems({
onMarkFolderRead,
onMarkAllFoldersRead,
onEmptyFolder,
folderRole,
onPicked,
}: {
onMarkFolderRead?: () => void;
onMarkAllFoldersRead?: () => void;
onEmptyFolder?: () => void;
/** Names the entry "Empty Trash" or "Empty Spam". */
folderRole?: string | null;
onPicked: () => void;
}) {
const tFolder = useTranslations("mailbox_context_menu");
const tRoot = useTranslations();
return (
<>
<ContextMenuItem
@@ -225,8 +231,9 @@ export function MailFolderMenuItems({
<ContextMenuSeparator />
<ContextMenuItem
icon={FolderX}
label={tFolder("empty_folder")}
label={tRoot(emptyFolderLabelKey(folderRole) ?? "mailbox_context_menu.empty_folder")}
destructive
testId="mail-empty-folder"
onClick={() => { onPicked(); onEmptyFolder(); }}
/>
</>
+2 -1
View File
@@ -116,6 +116,7 @@ export function MvListToolbar({
const tBatch = useTranslations("email_list.batch_actions");
const archiveActionEnabled = useArchiveActionEnabled();
const tFolder = useTranslations("mailbox_context_menu");
const tP2 = useTranslations("mail_p2_folders");
const tMenu = useTranslations("context_menu");
const tSidebar = useTranslations("sidebar");
const tCommon = useTranslations("common");
@@ -430,7 +431,7 @@ export function MvListToolbar({
<ContextMenuSeparator />
<ContextMenuItem
icon={FolderX}
label={tFolder("empty_folder")}
label={isInTrash ? tP2("empty_trash") : tP2("empty_spam")}
destructive
onClick={() => {
closeMenu();
@@ -12,7 +12,7 @@ const { MailboxContextMenu } = await import('../mailbox-context-menu');
const folder = { id: 'p', name: 'Projects', sortOrder: 1, totalEmails: 2, unreadEmails: 0, myRights: {} } as unknown as Mailbox;
describe('MailboxContextMenu', () => {
it('ends with Empty folder and Delete folder', () => {
it('ends with Delete folder', () => {
render(
<MailboxContextMenu
target={{ kind: 'mailbox', mailbox: folder, hasChildren: false }}
@@ -28,7 +28,8 @@ describe('MailboxContextMenu', () => {
/>,
);
const labels = screen.getAllByRole('menuitem').map((item) => item.textContent);
expect(labels.slice(-2)).toEqual(['empty_folder_generic', 'delete_folder']);
// A folder of your own has no Empty: it is offered on Trash and Spam only.
expect(labels.slice(-1)).toEqual(['delete_folder']);
expect(labels).toContain('refresh');
});
});
@@ -63,7 +63,7 @@ describe('folder menu states', () => {
const folder = box('f', 2);
renderMenu(folder, [folder]);
expect(screen.getByText('offline_header')).toBeInTheDocument();
for (const name of ['new_subfolder', 'rename', 'menu_import', 'refresh', 'empty_folder_generic', 'delete_folder']) {
for (const name of ['new_subfolder', 'rename', 'menu_import', 'refresh', 'delete_folder']) {
expect(item(name).disabled).toBe(true);
}
// No mail kept on this device: marking read would fail too.
@@ -0,0 +1,76 @@
import { render, screen } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import type { Mailbox } from '@/lib/jmap/types';
// Usability test 2026-11-04, mail-20 and pass 2 p2-14: Trash and Spam
// showed Rename and Delete folder greyed out, "Empty folder" instead of
// "Empty Trash", and Rules and Mute notifications; every folder, the Inbox
// included, offered "Empty folder".
vi.mock('@/components/email/rules-menu', () => ({ FolderRulesSubMenu: () => <div role="menuitem">rules</div> }));
const { MailboxContextMenu } = await import('../mailbox-context-menu');
const box = (id: string, role: string | null) =>
({ id, name: id, role, parentId: null, sortOrder: 1, totalEmails: 5, unreadEmails: 0, myRights: {} }) as unknown as Mailbox;
function labels(mailbox: Mailbox) {
render(
<MailboxContextMenu
target={{ kind: 'mailbox', mailbox, hasChildren: false }}
position={{ x: 0, y: 0 }}
isOpen
onClose={vi.fn()}
menuRef={{ current: null }}
mailboxes={[mailbox]}
onMarkFolderRead={vi.fn()}
onCreateSubfolder={vi.fn()}
onRenameFolder={vi.fn()}
onDeleteFolder={vi.fn()}
onEmptyFolder={vi.fn()}
onImportEmail={vi.fn()}
onRefresh={vi.fn()}
notifications={{
isMailboxMuted: () => false,
isAccountMuted: () => false,
hasFolderSettings: () => false,
setMailboxMuted: vi.fn(),
setAccountMuted: vi.fn(),
resetFolderSettings: vi.fn(),
}}
/>,
);
return screen.getAllByRole('menuitem').map((item) => item.textContent);
}
describe('folder menu of Trash and Spam', () => {
it('Trash: Empty Trash last, no rename, delete, rules or mute', () => {
const items = labels(box('trash', 'trash'));
expect(items[items.length - 1]).toBe('empty_trash');
for (const gone of ['rename', 'delete_folder', 'rules', 'mute_notifications', 'empty_folder', 'empty_folder_generic']) {
expect(items).not.toContain(gone);
}
});
it('Spam: Empty Spam last, no rename, delete, rules or mute', () => {
const items = labels(box('junk', 'junk'));
expect(items[items.length - 1]).toBe('empty_spam');
for (const gone of ['rename', 'delete_folder', 'rules', 'mute_notifications']) expect(items).not.toContain(gone);
});
it('Inbox: no Empty, no rename or delete, but rules and mute', () => {
const items = labels(box('inbox', 'inbox'));
for (const gone of ['empty_folder', 'empty_folder_generic', 'empty_trash', 'empty_spam', 'rename', 'delete_folder']) {
expect(items).not.toContain(gone);
}
expect(items).toContain('rules');
expect(items).toContain('mute_notifications');
});
it('a folder of your own: rename and delete, no Empty', () => {
const items = labels(box('family', null));
expect(items).toContain('rename');
expect(items[items.length - 1]).toBe('delete_folder');
for (const gone of ['empty_folder', 'empty_folder_generic', 'empty_trash', 'empty_spam']) expect(items).not.toContain(gone);
});
});
+36 -25
View File
@@ -159,6 +159,7 @@ export function MailboxContextMenu({
notifications,
}: MailboxContextMenuProps) {
const t = useTranslations("mailbox_context_menu");
const tP2 = useTranslations("mail_p2_folders");
const tSidebar = useTranslations("sidebar");
const tImport = useTranslations("mail_import");
const tExport = useTranslations("mail_export");
@@ -251,6 +252,8 @@ export function MailboxContextMenu({
}
const mailbox = target.mailbox;
// Emptying is offered where people expect it, as "Empty Trash" and "Empty
// Spam"; rules and notifications mean nothing there (mail-20, pass 2 p2-14).
const isTrashOrJunk = mailbox.role === "trash" || mailbox.role === "junk";
const isSystem =
!!mailbox.role &&
@@ -305,13 +308,16 @@ export function MailboxContextMenu({
disabled={!onCreateSubfolder || !canCreateChild || offline}
testId="mailbox-new-subfolder"
/>
<ContextMenuItem
icon={Pencil}
label={t("rename")}
onClick={() => handleAction(() => onRenameFolder?.(mailbox.id))}
disabled={!onRenameFolder || !canRename || offline}
testId="mailbox-rename"
/>
{/* The server's own folders can't be renamed or deleted: not shown greyed out. */}
{!isSystem && (
<ContextMenuItem
icon={Pencil}
label={t("rename")}
onClick={() => handleAction(() => onRenameFolder?.(mailbox.id))}
disabled={!onRenameFolder || !canRename || offline}
testId="mailbox-rename"
/>
)}
{onShareFolder && (
<ContextMenuItem
icon={Users}
@@ -321,8 +327,8 @@ export function MailboxContextMenu({
testId="mailbox-share"
/>
)}
<FolderRulesSubMenu mailbox={mailbox} onClose={onClose} disabled={offline} />
{notifications && (() => {
{!isTrashOrJunk && <FolderRulesSubMenu mailbox={mailbox} onClose={onClose} disabled={offline} />}
{notifications && !isTrashOrJunk && (() => {
const muted = notifications.isMailboxMuted(mailbox);
return (
<ContextMenuItem
@@ -373,23 +379,28 @@ export function MailboxContextMenu({
/>
{/* Destructive entries last (R6). */}
<ContextMenuSeparator />
{(isTrashOrJunk || !isSystem) && <ContextMenuSeparator />}
<ContextMenuItem
icon={FolderX}
label={isTrashOrJunk ? t("empty_folder") : t("empty_folder_generic")}
onClick={() => handleAction(() => onEmptyFolder?.(mailbox.id))}
disabled={!onEmptyFolder || mailbox.totalEmails === 0 || !canRemoveItems || offline}
destructive
/>
<ContextMenuItem
icon={Trash2}
label={t("delete_folder")}
onClick={() => handleAction(() => onDeleteFolder?.(mailbox.id))}
disabled={!onDeleteFolder || !canDelete || offline}
destructive
testId="mailbox-delete"
/>
{isTrashOrJunk && (
<ContextMenuItem
icon={FolderX}
label={mailbox.role === "trash" ? tP2("empty_trash") : tP2("empty_spam")}
onClick={() => handleAction(() => onEmptyFolder?.(mailbox.id))}
disabled={!onEmptyFolder || mailbox.totalEmails === 0 || !canRemoveItems || offline}
destructive
testId="mailbox-empty"
/>
)}
{!isSystem && (
<ContextMenuItem
icon={Trash2}
label={t("delete_folder")}
onClick={() => handleAction(() => onDeleteFolder?.(mailbox.id))}
disabled={!onDeleteFolder || !canDelete || offline}
destructive
testId="mailbox-delete"
/>
)}
</ContextMenu>
);
}
+7 -5
View File
@@ -96,6 +96,7 @@ import {
import { ConfirmDialog } from "@/components/ui/confirm-dialog";
import { ScheduleSendDialog } from "@/components/email/schedule-send-dialog";
import { MailFolderMenu, MailFolderMenuItems } from "@/components/email/mail-list-menus";
import { emptyFolderPrompt } from "@/lib/empty-folder-text";
import { ContextMenuItem } from "@/components/ui/context-menu";
import { PromptDialog } from "@/components/ui/prompt-dialog";
import { DragDropProvider } from "@/contexts/drag-drop-context";
@@ -4072,12 +4073,12 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
const mailbox = mailboxes.find(mb => mb.id === mailboxId);
if (!mailbox) return;
// "Empty Trash", with how many messages go (p2-14).
const prompt = emptyFolderPrompt(mailbox, emptyFolderMovesToTrash(mailbox));
const confirmed = await confirmDialog({
title: tCtxMenu('email_list.empty_folder.confirm_title'),
message: emptyFolderMovesToTrash(mailbox)
? tCtxMenu('email_list.empty_folder.confirm_message_trash')
: tCtxMenu('email_list.empty_folder.confirm_message'),
confirmText: tCtxMenu('email_list.empty_folder.confirm_button'),
title: tCtxMenu(prompt.title),
message: tCtxMenu(prompt.message, prompt.values),
confirmText: tCtxMenu(prompt.confirm),
variant: "destructive",
});
if (!confirmed) return;
@@ -5605,6 +5606,7 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
onMarkFolderRead={selectedMailbox && selectedFolderHasUnread ? () => handleMarkFolderRead(selectedMailbox) : undefined}
onMarkAllFoldersRead={handleMarkAllFoldersRead}
onEmptyFolder={folderIsEmptyable && selectedMailbox ? () => void handleEmptyFolderFromContextMenu(selectedMailbox) : undefined}
folderRole={conversationRole}
onPicked={close}
/>
</>
+28
View File
@@ -0,0 +1,28 @@
import { describe, expect, it } from 'vitest';
import { emptyFolderLabelKey, emptyFolderPrompt } from '../empty-folder-text';
// p2-14: the confirm said "All emails in this folder will be permanently
// deleted" with no number; it now says how many, and names Trash or Spam.
describe('emptyFolderPrompt', () => {
it('names Trash and counts its messages', () => {
expect(emptyFolderPrompt({ role: 'trash', totalEmails: 146 }, false)).toEqual({
title: 'mail_p2_folders.empty_trash',
message: 'mail_p2_folders.empty_trash_confirm',
values: { count: 146 },
confirm: 'mail_p2_folders.empty_trash',
});
});
it('names Spam and counts its messages', () => {
const prompt = emptyFolderPrompt({ role: 'junk', totalEmails: 3 }, false);
expect(prompt.title).toBe('mail_p2_folders.empty_spam');
expect(prompt.message).toBe('mail_p2_folders.empty_spam_confirm');
expect(prompt.values).toEqual({ count: 3 });
});
it('keeps the old wording for other folders', () => {
expect(emptyFolderPrompt({ role: null, totalEmails: 3 }, true).message).toBe('email_list.empty_folder.confirm_message_trash');
expect(emptyFolderLabelKey('inbox')).toBeNull();
});
});
+38
View File
@@ -0,0 +1,38 @@
/**
* What "Empty Trash" / "Empty Spam" is called and what its confirm says, as
* keys of the root catalogue. The confirm counts the messages that go
* (usability test 2026-11-04, p2-14). Other folders keep the old wording:
* nothing in the app offers to empty them, but a plugin can still ask.
*/
export function emptyFolderLabelKey(role: string | null | undefined): string | null {
if (role === "trash") return "mail_p2_folders.empty_trash";
if (role === "junk") return "mail_p2_folders.empty_spam";
return null;
}
export interface EmptyFolderPrompt {
title: string;
message: string;
values?: Record<string, number>;
confirm: string;
}
export function emptyFolderPrompt(
mailbox: { role?: string | null; totalEmails?: number },
movesToTrash: boolean,
): EmptyFolderPrompt {
const label = emptyFolderLabelKey(mailbox.role);
if (label) {
return {
title: label,
message: mailbox.role === "trash" ? "mail_p2_folders.empty_trash_confirm" : "mail_p2_folders.empty_spam_confirm",
values: { count: mailbox.totalEmails ?? 0 },
confirm: label,
};
}
return {
title: "email_list.empty_folder.confirm_title",
message: movesToTrash ? "email_list.empty_folder.confirm_message_trash" : "email_list.empty_folder.confirm_message",
confirm: "email_list.empty_folder.confirm_button",
};
}
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "لا يزال المجلد \"{name}\" يحتوي على {count, plural, one {رسالة واحدة} other {# رسائل}}. هل تريد حذف المجلد وكل رسائله؟ لا يمكن التراجع عن هذا.",
"delete_with_contents_confirm": "حذف المجلد والرسائل"
},
"mail_p2_folders": {
"all_folders": "كل المجلدات",
"empty_trash": "إفراغ المهملات",
"empty_spam": "إفراغ البريد العشوائي",
"empty_trash_confirm": "حذف {count, plural, zero {الرسائل} one {الرسالة} two {الرسالتين} few {كل الرسائل الـ#} many {كل الرسائل الـ#} other {كل الرسائل الـ#}} في المهملات نهائيًا؟ لا يمكن التراجع عن ذلك.",
"empty_spam_confirm": "حذف {count, plural, zero {الرسائل} one {الرسالة} two {الرسالتين} few {كل الرسائل الـ#} many {كل الرسائل الـ#} other {كل الرسائل الـ#}} في البريد العشوائي نهائيًا؟ لا يمكن التراجع عن ذلك."
},
"uxs_folders": {
"manage_accounts": "إدارة الحسابات…",
"apply_to_existing": "{count, plural, one {تطبيق على رسالة موجودة واحدة في {folder}} other {تطبيق على # رسائل موجودة في {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "La carpeta \"{name}\" encara conté {count, plural, one {1 missatge} other {# missatges}}. Vols suprimir la carpeta i tots els seus missatges? No es pot desfer.",
"delete_with_contents_confirm": "Suprimeix la carpeta i els missatges"
},
"mail_p2_folders": {
"all_folders": "Totes les carpetes",
"empty_trash": "Buida la paperera",
"empty_spam": "Buida el correu brossa",
"empty_trash_confirm": "Vols suprimir per sempre {count, plural, one {el missatge} other {els # missatges}} de la paperera? No es pot desfer.",
"empty_spam_confirm": "Vols suprimir per sempre {count, plural, one {el missatge} other {els # missatges}} del correu brossa? No es pot desfer."
},
"uxs_folders": {
"manage_accounts": "Gestiona els comptes…",
"apply_to_existing": "{count, plural, one {Aplica a # missatge existent de {folder}} other {Aplica a # missatges existents de {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "Složka „{name}“ stále obsahuje {count, plural, one {1 zprávu} few {# zprávy} other {# zpráv}}. Smazat složku i všechny její zprávy? Tuto akci nelze vrátit.",
"delete_with_contents_confirm": "Smazat složku i zprávy"
},
"mail_p2_folders": {
"all_folders": "Všechny složky",
"empty_trash": "Vysypat koš",
"empty_spam": "Vyprázdnit spam",
"empty_trash_confirm": "Trvale smazat {count, plural, one {zprávu} few {všechny # zprávy} many {všech # zprávy} other {všech # zpráv}} v koši? Nelze to vrátit zpět.",
"empty_spam_confirm": "Trvale smazat {count, plural, one {zprávu} few {všechny # zprávy} many {všech # zprávy} other {všech # zpráv}} ve spamu? Nelze to vrátit zpět."
},
"uxs_folders": {
"manage_accounts": "Spravovat účty…",
"apply_to_existing": "{count, plural, one {Použít na # existující zprávu ve složce {folder}} few {Použít na # existující zprávy ve složce {folder}} many {Použít na # existující zprávy ve složce {folder}} other {Použít na # existujících zpráv ve složce {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "Mappen \"{name}\" indeholder stadig {count, plural, one {1 besked} other {# beskeder}}. Slet mappen og alle dens beskeder? Dette kan ikke fortrydes.",
"delete_with_contents_confirm": "Slet mappe og beskeder"
},
"mail_p2_folders": {
"all_folders": "Alle mapper",
"empty_trash": "Tøm papirkurven",
"empty_spam": "Tøm spam",
"empty_trash_confirm": "Slet {count, plural, one {beskeden} other {alle # beskeder}} i papirkurven for altid? Det kan ikke fortrydes.",
"empty_spam_confirm": "Slet {count, plural, one {beskeden} other {alle # beskeder}} i spam for altid? Det kan ikke fortrydes."
},
"uxs_folders": {
"manage_accounts": "Administrer konti…",
"apply_to_existing": "{count, plural, one {Anvend på # eksisterende besked i {folder}} other {Anvend på # eksisterende beskeder i {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "Der Ordner „{name}“ enthält noch {count, plural, one {1 Nachricht} other {# Nachrichten}}. Ordner samt allen Nachrichten löschen? Das kann nicht rückgängig gemacht werden.",
"delete_with_contents_confirm": "Ordner und Nachrichten löschen"
},
"mail_p2_folders": {
"all_folders": "Alle Ordner",
"empty_trash": "Papierkorb leeren",
"empty_spam": "Spam leeren",
"empty_trash_confirm": "{count, plural, one {Die Nachricht} other {Alle # Nachrichten}} im Papierkorb endgültig löschen? Das lässt sich nicht rückgängig machen.",
"empty_spam_confirm": "{count, plural, one {Die Nachricht} other {Alle # Nachrichten}} im Spam endgültig löschen? Das lässt sich nicht rückgängig machen."
},
"uxs_folders": {
"manage_accounts": "Konten verwalten…",
"apply_to_existing": "{count, plural, one {Auf # vorhandene Nachricht in {folder} anwenden} other {Auf # vorhandene Nachrichten in {folder} anwenden}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "The folder \"{name}\" still contains {count, plural, one {1 message} other {# messages}}. Delete the folder and all of its messages? This cannot be undone.",
"delete_with_contents_confirm": "Delete folder and messages"
},
"mail_p2_folders": {
"all_folders": "All folders",
"empty_trash": "Empty Trash",
"empty_spam": "Empty Spam",
"empty_trash_confirm": "Delete {count, plural, one {the message} other {all # messages}} in Trash forever? You can't undo this.",
"empty_spam_confirm": "Delete {count, plural, one {the message} other {all # messages}} in Spam forever? You can't undo this."
},
"uxs_folders": {
"manage_accounts": "Manage accounts…",
"apply_to_existing": "{count, plural, one {Apply to # existing message in {folder}} other {Apply to # existing messages in {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"create": "Crear",
"rename_confirm": "Renombrar"
},
"mail_p2_folders": {
"all_folders": "Todas las carpetas",
"empty_trash": "Vaciar papelera",
"empty_spam": "Vaciar spam",
"empty_trash_confirm": "¿Eliminar para siempre {count, plural, one {el mensaje} other {los # mensajes}} de la papelera? No se puede deshacer.",
"empty_spam_confirm": "¿Eliminar para siempre {count, plural, one {el mensaje} other {los # mensajes}} de spam? No se puede deshacer."
},
"uxs_folders": {
"manage_accounts": "Gestionar cuentas…",
"apply_to_existing": "{count, plural, one {Aplicar a # mensaje existente en {folder}} other {Aplicar a # mensajes existentes en {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "Kaust \"{name}\" sisaldab veel {count, plural, one {1 sõnum} other {# sõnumit}}. Kas kustutada kaust ja kõik selle sõnumid? Seda ei saa tagasi võtta.",
"delete_with_contents_confirm": "Kustuta kaust ja sõnumid"
},
"mail_p2_folders": {
"all_folders": "Kõik kaustad",
"empty_trash": "Tühjenda prügikast",
"empty_spam": "Tühjenda rämpspost",
"empty_trash_confirm": "Kas kustutada prügikastist {count, plural, one {kiri} other {kõik # kirja}} jäädavalt? Seda ei saa tagasi võtta.",
"empty_spam_confirm": "Kas kustutada rämpspostist {count, plural, one {kiri} other {kõik # kirja}} jäädavalt? Seda ei saa tagasi võtta."
},
"uxs_folders": {
"manage_accounts": "Halda kontosid…",
"apply_to_existing": "{count, plural, one {Rakenda # olemasolevale kirjale kaustas {folder}} other {Rakenda # olemasolevale kirjale kaustas {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "پوشه «{name}» هنوز شامل {count, plural, one {۱ پیام} other {# پیام}} است. پوشه و همه پیام‌های آن حذف شود؟ این عمل قابل بازگشت نیست.",
"delete_with_contents_confirm": "حذف پوشه و پیام‌ها"
},
"mail_p2_folders": {
"all_folders": "همه پوشه‌ها",
"empty_trash": "خالی کردن زباله‌دان",
"empty_spam": "خالی کردن هرزنامه",
"empty_trash_confirm": "{count, plural, one {پیام} other {همه # پیام}} زباله‌دان برای همیشه حذف شود؟ این کار برگشت‌پذیر نیست.",
"empty_spam_confirm": "{count, plural, one {پیام} other {همه # پیام}} هرزنامه برای همیشه حذف شود؟ این کار برگشت‌پذیر نیست."
},
"uxs_folders": {
"manage_accounts": "مدیریت حساب‌ها…",
"apply_to_existing": "{count, plural, one {اعمال روی # پیام موجود در {folder}} other {اعمال روی # پیام موجود در {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"create": "Créer",
"rename_confirm": "Renommer"
},
"mail_p2_folders": {
"all_folders": "Tous les dossiers",
"empty_trash": "Vider la corbeille",
"empty_spam": "Vider le spam",
"empty_trash_confirm": "Supprimer définitivement {count, plural, one {le message} other {les # messages}} de la corbeille ? Impossible de revenir en arrière.",
"empty_spam_confirm": "Supprimer définitivement {count, plural, one {le message} other {les # messages}} du spam ? Impossible de revenir en arrière."
},
"uxs_folders": {
"manage_accounts": "Gérer les comptes…",
"apply_to_existing": "{count, plural, one {Appliquer à # message existant dans {folder}} other {Appliquer à # messages existants dans {folder}}}"
+7
View File
@@ -5539,6 +5539,13 @@
"delete_with_contents_message": "התיקייה \"{name}\" עדיין מכילה {count, plural, one {הודעה אחת} other {# הודעות}}. למחוק את התיקייה ואת כל ההודעות שבה? לא ניתן לבטל פעולה זו.",
"delete_with_contents_confirm": "מחיקת התיקייה וההודעות"
},
"mail_p2_folders": {
"all_folders": "כל התיקיות",
"empty_trash": "ריקון האשפה",
"empty_spam": "ריקון הספאם",
"empty_trash_confirm": "למחוק לצמיתות {count, plural, one {את ההודעה} two {את שתי ההודעות} other {את כל # ההודעות}} באשפה? אי אפשר לבטל את זה.",
"empty_spam_confirm": "למחוק לצמיתות {count, plural, one {את ההודעה} two {את שתי ההודעות} other {את כל # ההודעות}} בספאם? אי אפשר לבטל את זה."
},
"uxs_folders": {
"manage_accounts": "ניהול חשבונות…",
"apply_to_existing": "{count, plural, one {החלה על הודעה קיימת אחת בתיקייה {folder}} other {החלה על # הודעות קיימות בתיקייה {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "A(z) „{name}” mappa még {count, plural, one {1 üzenetet} other {# üzenetet}} tartalmaz. Törlöd a mappát az összes üzenetével együtt? Ez nem vonható vissza.",
"delete_with_contents_confirm": "Mappa és üzenetek törlése"
},
"mail_p2_folders": {
"all_folders": "Összes mappa",
"empty_trash": "Kuka ürítése",
"empty_spam": "Spam ürítése",
"empty_trash_confirm": "Véglegesen törli {count, plural, one {az üzenetet} other {mind a # üzenetet}} a kukából? Ez nem vonható vissza.",
"empty_spam_confirm": "Véglegesen törli {count, plural, one {az üzenetet} other {mind a # üzenetet}} a spamből? Ez nem vonható vissza."
},
"uxs_folders": {
"manage_accounts": "Fiókok kezelése…",
"apply_to_existing": "{count, plural, one {Alkalmazás # meglévő üzenetre itt: {folder}} other {Alkalmazás # meglévő üzenetre itt: {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"create": "Crea",
"rename_confirm": "Rinomina"
},
"mail_p2_folders": {
"all_folders": "Tutte le cartelle",
"empty_trash": "Svuota cestino",
"empty_spam": "Svuota spam",
"empty_trash_confirm": "Eliminare per sempre {count, plural, one {il messaggio} other {tutti i # messaggi}} nel cestino? Non si può annullare.",
"empty_spam_confirm": "Eliminare per sempre {count, plural, one {il messaggio} other {tutti i # messaggi}} nello spam? Non si può annullare."
},
"uxs_folders": {
"manage_accounts": "Gestisci account…",
"apply_to_existing": "{count, plural, one {Applica a # messaggio esistente in {folder}} other {Applica a # messaggi esistenti in {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"create": "作成",
"rename_confirm": "名前を変更"
},
"mail_p2_folders": {
"all_folders": "すべてのフォルダー",
"empty_trash": "ゴミ箱を空にする",
"empty_spam": "迷惑メールを空にする",
"empty_trash_confirm": "ゴミ箱の{count, plural, other {# 件のメッセージ}}をすべて完全に削除しますか?元に戻せません。",
"empty_spam_confirm": "迷惑メールの{count, plural, other {# 件のメッセージ}}をすべて完全に削除しますか?元に戻せません。"
},
"uxs_folders": {
"manage_accounts": "アカウントを管理…",
"apply_to_existing": "{count, plural, other {{folder} の既存の # 件に適用}}"
+7
View File
@@ -3833,6 +3833,13 @@
"create": "만들기",
"rename_confirm": "이름 바꾸기"
},
"mail_p2_folders": {
"all_folders": "모든 폴더",
"empty_trash": "휴지통 비우기",
"empty_spam": "스팸 비우기",
"empty_trash_confirm": "휴지통의 {count, plural, other {메시지 #개}}를 모두 영구 삭제할까요? 되돌릴 수 없어요.",
"empty_spam_confirm": "스팸의 {count, plural, other {메시지 #개}}를 모두 영구 삭제할까요? 되돌릴 수 없어요."
},
"uxs_folders": {
"manage_accounts": "계정 관리…",
"apply_to_existing": "{count, plural, other {{folder}의 기존 메일 #개에 적용}}"
+7
View File
@@ -3833,6 +3833,13 @@
"create": "Izveidot",
"rename_confirm": "Pārsaukt"
},
"mail_p2_folders": {
"all_folders": "Visas mapes",
"empty_trash": "Iztukšot miskasti",
"empty_spam": "Iztukšot mēstules",
"empty_trash_confirm": "Neatgriezeniski dzēst {count, plural, =1 {vēstuli} zero {visas # vēstules} one {visas # vēstuli} other {visas # vēstules}} miskastē? To nevar atsaukt.",
"empty_spam_confirm": "Neatgriezeniski dzēst {count, plural, =1 {vēstuli} zero {visas # vēstules} one {visas # vēstuli} other {visas # vēstules}} mēstulēs? To nevar atsaukt."
},
"uxs_folders": {
"manage_accounts": "Pārvaldīt kontus…",
"apply_to_existing": "{count, plural, zero {Piemērot # esošajām vēstulēm mapē {folder}} one {Piemērot # esošajai vēstulei mapē {folder}} other {Piemērot # esošajām vēstulēm mapē {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "\"{name}\" хавтсанд одоо ч {count} зурвас байна. Хавтас болон бүх зурвасыг устгах уу? Үүнийг буцаах боломжгүй.",
"delete_with_contents_confirm": "Хавтас болон зурвасыг устгах"
},
"mail_p2_folders": {
"all_folders": "Бүх хавтас",
"empty_trash": "Хогийн савыг хоослох",
"empty_spam": "Спамыг хоослох",
"empty_trash_confirm": "Хогийн саван дахь {count, plural, one {захидлыг} other {бүх # захидлыг}} бүрмөсөн устгах уу? Буцаах боломжгүй.",
"empty_spam_confirm": "Спам дахь {count, plural, one {захидлыг} other {бүх # захидлыг}} бүрмөсөн устгах уу? Буцаах боломжгүй."
},
"uxs_folders": {
"manage_accounts": "Данснуудыг удирдах…",
"apply_to_existing": "{count, plural, one {{folder} доторх байгаа # захианд хэрэглэх} other {{folder} доторх байгаа # захианд хэрэглэх}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "Mappen «{name}» inneholder fortsatt {count, plural, one {1 melding} other {# meldinger}}. Slette mappen og alle meldingene i den? Dette kan ikke angres.",
"delete_with_contents_confirm": "Slett mappe og meldinger"
},
"mail_p2_folders": {
"all_folders": "Alle mapper",
"empty_trash": "Tøm papirkurven",
"empty_spam": "Tøm søppelpost",
"empty_trash_confirm": "Slette {count, plural, one {meldingen} other {alle # meldingene}} i papirkurven for godt? Dette kan ikke angres.",
"empty_spam_confirm": "Slette {count, plural, one {meldingen} other {alle # meldingene}} i søppelpost for godt? Dette kan ikke angres."
},
"uxs_folders": {
"manage_accounts": "Administrer kontoer…",
"apply_to_existing": "{count, plural, one {Bruk på # eksisterende melding i {folder}} other {Bruk på # eksisterende meldinger i {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"create": "Aanmaken",
"rename_confirm": "Hernoemen"
},
"mail_p2_folders": {
"all_folders": "Alle mappen",
"empty_trash": "Prullenbak legen",
"empty_spam": "Spam legen",
"empty_trash_confirm": "{count, plural, one {Het bericht} other {Alle # berichten}} in de prullenbak definitief verwijderen? Dit kan niet ongedaan worden.",
"empty_spam_confirm": "{count, plural, one {Het bericht} other {Alle # berichten}} in spam definitief verwijderen? Dit kan niet ongedaan worden."
},
"uxs_folders": {
"manage_accounts": "Accounts beheren…",
"apply_to_existing": "{count, plural, one {Toepassen op # bestaand bericht in {folder}} other {Toepassen op # bestaande berichten in {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"create": "Utwórz",
"rename_confirm": "Zmień nazwę"
},
"mail_p2_folders": {
"all_folders": "Wszystkie foldery",
"empty_trash": "Opróżnij kosz",
"empty_spam": "Opróżnij spam",
"empty_trash_confirm": "Trwale usunąć {count, plural, one {wiadomość} few {wszystkie # wiadomości} many {wszystkie # wiadomości} other {wszystkie # wiadomości}} z kosza? Nie można tego cofnąć.",
"empty_spam_confirm": "Trwale usunąć {count, plural, one {wiadomość} few {wszystkie # wiadomości} many {wszystkie # wiadomości} other {wszystkie # wiadomości}} ze spamu? Nie można tego cofnąć."
},
"uxs_folders": {
"manage_accounts": "Zarządzaj kontami…",
"apply_to_existing": "{count, plural, one {Zastosuj do # istniejącej wiadomości w folderze {folder}} few {Zastosuj do # istniejących wiadomości w folderze {folder}} many {Zastosuj do # istniejących wiadomości w folderze {folder}} other {Zastosuj do # istniejącej wiadomości w folderze {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"create": "Criar",
"rename_confirm": "Renomear"
},
"mail_p2_folders": {
"all_folders": "Todas as pastas",
"empty_trash": "Esvaziar lixeira",
"empty_spam": "Esvaziar spam",
"empty_trash_confirm": "Excluir para sempre {count, plural, one {a mensagem} other {as # mensagens}} da lixeira? Não é possível desfazer.",
"empty_spam_confirm": "Excluir para sempre {count, plural, one {a mensagem} other {as # mensagens}} do spam? Não é possível desfazer."
},
"uxs_folders": {
"manage_accounts": "Gerir contas…",
"apply_to_existing": "{count, plural, one {Aplicar a # mensagem existente em {folder}} other {Aplicar a # mensagens existentes em {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "Dosarul „{name}” încă mai conține {count, plural, one {1 mesaj} other {# mesaje}}. Ștergi dosarul și toate mesajele sale? Acțiunea nu poate fi anulată.",
"delete_with_contents_confirm": "Șterge dosarul și mesajele"
},
"mail_p2_folders": {
"all_folders": "Toate dosarele",
"empty_trash": "Golește coșul de gunoi",
"empty_spam": "Golește spamul",
"empty_trash_confirm": "Ștergeți definitiv {count, plural, one {mesajul} few {toate cele # mesaje} other {toate cele # de mesaje}} din coșul de gunoi? Nu se poate anula.",
"empty_spam_confirm": "Ștergeți definitiv {count, plural, one {mesajul} few {toate cele # mesaje} other {toate cele # de mesaje}} din spam? Nu se poate anula."
},
"uxs_folders": {
"manage_accounts": "Gestionați conturile…",
"apply_to_existing": "{count, plural, one {Aplicați la # mesaj existent din {folder}} few {Aplicați la # mesaje existente din {folder}} other {Aplicați la # de mesaje existente din {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"create": "Создать",
"rename_confirm": "Переименовать"
},
"mail_p2_folders": {
"all_folders": "Все папки",
"empty_trash": "Очистить корзину",
"empty_spam": "Очистить спам",
"empty_trash_confirm": "Удалить {count, plural, =1 {письмо} one {все # письмо} few {все # письма} many {все # писем} other {все # письма}} в корзине навсегда? Это нельзя отменить.",
"empty_spam_confirm": "Удалить {count, plural, =1 {письмо} one {все # письмо} few {все # письма} many {все # писем} other {все # письма}} в спаме навсегда? Это нельзя отменить."
},
"uxs_folders": {
"manage_accounts": "Управление аккаунтами…",
"apply_to_existing": "{count, plural, one {Применить к # имеющемуся письму в папке {folder}} few {Применить к # имеющимся письмам в папке {folder}} many {Применить к # имеющимся письмам в папке {folder}} other {Применить к # имеющегося письма в папке {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "Priečinok „{name}“ stále obsahuje {count, plural, one {1 správu} few {# správy} other {# správ}}. Odstrániť priečinok aj všetky jeho správy? Túto akciu nie je možné vrátiť späť.",
"delete_with_contents_confirm": "Odstrániť priečinok a správy"
},
"mail_p2_folders": {
"all_folders": "Všetky priečinky",
"empty_trash": "Vyprázdniť kôš",
"empty_spam": "Vyprázdniť spam",
"empty_trash_confirm": "Natrvalo odstrániť {count, plural, one {správu} few {všetky # správy} many {všetkých # správy} other {všetkých # správ}} v koši? Nedá sa to vrátiť späť.",
"empty_spam_confirm": "Natrvalo odstrániť {count, plural, one {správu} few {všetky # správy} many {všetkých # správy} other {všetkých # správ}} v spame? Nedá sa to vrátiť späť."
},
"uxs_folders": {
"manage_accounts": "Spravovať účty…",
"apply_to_existing": "{count, plural, one {Použiť na # existujúcu správu v priečinku {folder}} few {Použiť na # existujúce správy v priečinku {folder}} many {Použiť na # existujúcej správy v priečinku {folder}} other {Použiť na # existujúcich správ v priečinku {folder}}}"
+7
View File
@@ -1029,6 +1029,13 @@
"delete_with_contents_message": "โฟลเดอร์ “{name}” ยังมีข้อความอยู่ {count, plural, other {# ข้อความ}} ต้องการลบโฟลเดอร์และข้อความทั้งหมดภายในหรือไม่? การดำเนินการนี้ไม่สามารถยกเลิกได้",
"delete_with_contents_confirm": "ลบโฟลเดอร์และข้อความทั้งหมด"
},
"mail_p2_folders": {
"all_folders": "โฟลเดอร์ทั้งหมด",
"empty_trash": "ล้างถังขยะ",
"empty_spam": "ล้างสแปม",
"empty_trash_confirm": "ลบข้อความ {count, plural, other {ทั้ง # ฉบับ}} ในถังขยะอย่างถาวรไหม ย้อนกลับไม่ได้",
"empty_spam_confirm": "ลบข้อความ {count, plural, other {ทั้ง # ฉบับ}} ในสแปมอย่างถาวรไหม ย้อนกลับไม่ได้"
},
"uxs_folders": {
"manage_accounts": "จัดการบัญชี…",
"apply_to_existing": "{count, plural, other {นำไปใช้กับข้อความเดิม # ฉบับใน {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "\"{name}\" klasöründe hâlâ {count} ileti var. Klasör ve tüm iletileri silinsin mi? Bu işlem geri alınamaz.",
"delete_with_contents_confirm": "Klasörü ve iletileri sil"
},
"mail_p2_folders": {
"all_folders": "Tüm klasörler",
"empty_trash": "Çöp Kutusunu boşalt",
"empty_spam": "Spam klasörünü boşalt",
"empty_trash_confirm": "Çöp Kutusundaki {count, plural, one {ileti} other {# iletinin tümü}} kalıcı olarak silinsin mi? Bu geri alınamaz.",
"empty_spam_confirm": "Spam klasöründeki {count, plural, one {ileti} other {# iletinin tümü}} kalıcı olarak silinsin mi? Bu geri alınamaz."
},
"uxs_folders": {
"manage_accounts": "Hesapları yönet…",
"apply_to_existing": "{count, plural, one {{folder} içindeki # mevcut iletiye uygula} other {{folder} içindeki # mevcut iletiye uygula}}"
+7
View File
@@ -3833,6 +3833,13 @@
"create": "Створити",
"rename_confirm": "Перейменувати"
},
"mail_p2_folders": {
"all_folders": "Усі папки",
"empty_trash": "Очистити кошик",
"empty_spam": "Очистити спам",
"empty_trash_confirm": "Видалити {count, plural, =1 {лист} one {усі # лист} few {усі # листи} many {усі # листів} other {усі # листа}} в кошику назавжди? Це не можна скасувати.",
"empty_spam_confirm": "Видалити {count, plural, =1 {лист} one {усі # лист} few {усі # листи} many {усі # листів} other {усі # листа}} у спамі назавжди? Це не можна скасувати."
},
"uxs_folders": {
"manage_accounts": "Керувати обліковими записами…",
"apply_to_existing": "{count, plural, one {Застосувати до # наявного листа в теці {folder}} few {Застосувати до # наявних листів у теці {folder}} many {Застосувати до # наявних листів у теці {folder}} other {Застосувати до # наявного листа в теці {folder}}}"
+7
View File
@@ -3845,6 +3845,13 @@
"delete_with_contents_message": "Thư mục \"{name}\" vẫn chứa {count, plural, one {1 thư} other {# thư}}. Xóa thư mục và tất cả thư của nó? Điều này không thể hoàn tác được.",
"delete_with_contents_confirm": "Xóa thư mục và thư"
},
"mail_p2_folders": {
"all_folders": "Tất cả thư mục",
"empty_trash": "Dọn sạch Thùng rác",
"empty_spam": "Dọn sạch Thư rác",
"empty_trash_confirm": "Xóa vĩnh viễn {count, plural, other {tất cả # thư}} trong Thùng rác? Không thể hoàn tác.",
"empty_spam_confirm": "Xóa vĩnh viễn {count, plural, other {tất cả # thư}} trong Thư rác? Không thể hoàn tác."
},
"uxs_folders": {
"manage_accounts": "Quản lý tài khoản…",
"apply_to_existing": "{count, plural, one {Áp dụng cho # thư hiện có trong {folder}} other {Áp dụng cho # thư hiện có trong {folder}}}"
+7
View File
@@ -3833,6 +3833,13 @@
"delete_with_contents_message": "資料夾「{name}」中仍有 {count} 封郵件。要刪除該資料夾及其所有郵件嗎?此操作無法復原。",
"delete_with_contents_confirm": "刪除資料夾和郵件"
},
"mail_p2_folders": {
"all_folders": "所有信件匣",
"empty_trash": "清空垃圾桶",
"empty_spam": "清空垃圾郵件",
"empty_trash_confirm": "要永久刪除垃圾桶中的{count, plural, other {全部 # 封郵件}}嗎?此動作無法復原。",
"empty_spam_confirm": "要永久刪除垃圾郵件中的{count, plural, other {全部 # 封郵件}}嗎?此動作無法復原。"
},
"uxs_folders": {
"manage_accounts": "管理帳號…",
"apply_to_existing": "{count, plural, other {套用到{folder}中的 # 封既有郵件}}"
+7
View File
@@ -3833,6 +3833,13 @@
"create": "创建",
"rename_confirm": "重命名"
},
"mail_p2_folders": {
"all_folders": "所有文件夹",
"empty_trash": "清空已删除",
"empty_spam": "清空垃圾邮件",
"empty_trash_confirm": "要永久删除已删除中的{count, plural, other {全部 # 封邮件}}吗?此操作无法撤销。",
"empty_spam_confirm": "要永久删除垃圾邮件中的{count, plural, other {全部 # 封邮件}}吗?此操作无法撤销。"
},
"uxs_folders": {
"manage_accounts": "管理账户…",
"apply_to_existing": "{count, plural, other {应用于{folder}中的 # 封已有邮件}}"