mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 08:13:50 +00:00
feat: add a Sort menu to the mail list header
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { useSettingsStore } from '@/stores/settings-store';
|
||||
import { useAuthStore } from '@/stores/auth-store';
|
||||
import { useEmailStore } from '@/stores/email-store';
|
||||
import { MailSortMenu, sortChoiceFor } from '../mail-list-menus';
|
||||
|
||||
// The mail list's Sort menu writes the "Message list order" setting, like the
|
||||
// Files header's sort menu writes its own.
|
||||
|
||||
const fetchEmails = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
beforeEach(() => {
|
||||
fetchEmails.mockClear();
|
||||
useSettingsStore.setState({ messageListOrder: [], messageListOrderScope: 'inbox' } as never);
|
||||
useAuthStore.setState({ client: { getEmailQuerySortOptions: () => null } } as never);
|
||||
useEmailStore.setState({ selectedMailbox: 'sent', fetchEmails } as never);
|
||||
});
|
||||
|
||||
describe('mail list Sort menu', () => {
|
||||
it('checks the current order', () => {
|
||||
render(<MailSortMenu folderRole="inbox" />);
|
||||
fireEvent.click(screen.getByTestId('mail-sort'));
|
||||
expect(screen.getByTestId('mail-sort-newest').getAttribute('aria-checked')).toBe('true');
|
||||
expect(screen.getByTestId('mail-sort-oldest').getAttribute('aria-checked')).toBe('false');
|
||||
});
|
||||
|
||||
it('writes the setting, makes it reach this folder, and reloads the list', () => {
|
||||
render(<MailSortMenu folderRole="sent" />);
|
||||
fireEvent.click(screen.getByTestId('mail-sort'));
|
||||
fireEvent.click(screen.getByTestId('mail-sort-oldest'));
|
||||
const { messageListOrder, messageListOrderScope } = useSettingsStore.getState();
|
||||
expect(messageListOrder).toEqual([{ criterion: 'receivedAt', direction: 'asc' }]);
|
||||
// The order applied to the Inbox only, so in Sent the pick did nothing.
|
||||
expect(messageListOrderScope).toBe('all');
|
||||
expect(fetchEmails).toHaveBeenCalledWith(expect.anything(), 'sent', { background: true });
|
||||
});
|
||||
|
||||
it('leaves out read state and stars when the server cannot order by them', () => {
|
||||
useAuthStore.setState({ client: { getEmailQuerySortOptions: () => ['receivedAt', 'from'] } } as never);
|
||||
render(<MailSortMenu folderRole="inbox" />);
|
||||
fireEvent.click(screen.getByTestId('mail-sort'));
|
||||
expect(screen.queryByTestId('mail-sort-unread')).toBeNull();
|
||||
expect(screen.getByTestId('mail-sort-sender')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('recognises the orders Settings can make', () => {
|
||||
expect(sortChoiceFor([{ criterion: 'unread', direction: 'desc' }, { criterion: 'receivedAt', direction: 'desc' }])).toBe('unread');
|
||||
expect(sortChoiceFor([{ criterion: 'unread', direction: 'desc' }, { criterion: 'from', direction: 'asc' }])).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,138 @@
|
||||
"use client";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import { ArrowUpDown, Check } from "@/components/icons";
|
||||
import { IconButton } from "@/components/ui/icon-button";
|
||||
import { ContextMenu, ContextMenuSeparator } from "@/components/ui/context-menu";
|
||||
import { useContextMenu } from "@/hooks/use-context-menu";
|
||||
import { useSettingsStore, getMessageListOrderFor } from "@/stores/settings-store";
|
||||
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 { cn } from "@/lib/utils";
|
||||
|
||||
/** The orders the list header offers; Settings has the full editor. */
|
||||
export const SORT_CHOICES = [
|
||||
{ key: "newest", levels: [] },
|
||||
{ key: "oldest", levels: [{ criterion: "receivedAt", direction: "asc" }] },
|
||||
{ key: "unread", levels: [{ criterion: "unread", direction: "desc" }], keyword: true },
|
||||
{ key: "starred", levels: [{ criterion: "starred", direction: "desc" }], keyword: true },
|
||||
{ key: "sender", levels: [{ criterion: "from", direction: "asc" }] },
|
||||
{ key: "subject", levels: [{ criterion: "subject", direction: "asc" }] },
|
||||
{ key: "largest", levels: [{ criterion: "size", direction: "desc" }] },
|
||||
] as const satisfies ReadonlyArray<{ key: string; levels: readonly SortLevel[]; keyword?: boolean }>;
|
||||
|
||||
export type SortChoiceKey = (typeof SORT_CHOICES)[number]["key"];
|
||||
|
||||
/** The choice `levels` is, or null for an order only Settings can make. */
|
||||
export function sortChoiceFor(levels: SortLevel[]): SortChoiceKey | null {
|
||||
// A trailing newest-first level is implicit (see detectPreset).
|
||||
const last = levels[levels.length - 1];
|
||||
const core = levels.length > 1 && last.criterion === "receivedAt" && last.direction === "desc"
|
||||
? levels.slice(0, -1)
|
||||
: levels;
|
||||
if (isDefaultOrder(core)) return "newest";
|
||||
if (core.length !== 1) return null;
|
||||
const match = SORT_CHOICES.find((choice) =>
|
||||
choice.levels.length === 1
|
||||
&& choice.levels[0].criterion === core[0].criterion
|
||||
&& choice.levels[0].direction === core[0].direction);
|
||||
return match?.key ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks an order for the list. It writes the "Message list order" setting, so
|
||||
* Settings and every device agree. That setting applies to the Inbox only
|
||||
* unless "Apply to all folders" is on; picked in another folder, it turns
|
||||
* that on, or the pick would do nothing there.
|
||||
*/
|
||||
export function applySortChoice(key: SortChoiceKey, folderRole: string | null | undefined): void {
|
||||
const choice = SORT_CHOICES.find((c) => c.key === key);
|
||||
if (!choice) return;
|
||||
const { updateSetting, messageListOrderScope } = useSettingsStore.getState();
|
||||
updateSetting("messageListOrder", sanitizeSortLevels(choice.levels.map((level) => ({ ...level }))));
|
||||
if (messageListOrderScope === "inbox" && folderRole !== "inbox" && choice.levels.length > 0) {
|
||||
updateSetting("messageListOrderScope", "all");
|
||||
}
|
||||
const client = useAuthStore.getState().client;
|
||||
const store = useEmailStore.getState();
|
||||
if (client && store.selectedMailbox) void store.fetchEmails(client, store.selectedMailbox, { background: true });
|
||||
}
|
||||
|
||||
/** The list header's Sort button (MAIL-30), like the one in Files. */
|
||||
export function MailSortMenu({ folderRole, disabled, className }: { folderRole: string | null | undefined; disabled?: boolean; className?: string }) {
|
||||
const t = useTranslations("email_list.sort");
|
||||
const menu = useContextMenu<null>();
|
||||
const hidden = usePolicyStore((s) => s.isSettingHidden("messageListOrder"));
|
||||
const locked = usePolicyStore((s) => s.isSettingLocked("messageListOrder"));
|
||||
// Re-render when the order changes elsewhere (Settings, another device).
|
||||
useSettingsStore((s) => s.messageListOrder);
|
||||
useSettingsStore((s) => s.messageListOrderScope);
|
||||
const client = useAuthStore((s) => s.client);
|
||||
if (hidden) return null;
|
||||
|
||||
const current = sortChoiceFor(getMessageListOrderFor(folderRole));
|
||||
// A server without hasKeyword can't order by read state or stars.
|
||||
const sortOptions = client?.getEmailQuerySortOptions?.() ?? null;
|
||||
const keywordSort = sortOptions === null || sortOptions.includes("hasKeyword");
|
||||
|
||||
return (
|
||||
<>
|
||||
<IconButton
|
||||
label={t("title")}
|
||||
aria-haspopup="menu"
|
||||
aria-expanded={menu.contextMenu.isOpen}
|
||||
disabled={disabled || locked}
|
||||
className={cn(menu.contextMenu.isOpen && "bg-accent", className)}
|
||||
data-testid="mail-sort"
|
||||
onMouseDown={(e) => { if (menu.contextMenu.isOpen) e.stopPropagation(); }}
|
||||
onClick={(e) => {
|
||||
if (menu.contextMenu.isOpen) menu.closeContextMenu();
|
||||
else menu.openContextMenuFrom(e.currentTarget, null, "end");
|
||||
}}
|
||||
>
|
||||
<ArrowUpDown />
|
||||
</IconButton>
|
||||
<ContextMenu ref={menu.menuRef} isOpen={menu.contextMenu.isOpen} position={menu.contextMenu.position} onClose={menu.closeContextMenu}>
|
||||
{SORT_CHOICES.filter((choice) => keywordSort || !("keyword" in choice)).map((choice) => (
|
||||
<SortItem
|
||||
key={choice.key}
|
||||
label={t(choice.key)}
|
||||
checked={current === choice.key}
|
||||
testId={`mail-sort-${choice.key}`}
|
||||
onClick={() => {
|
||||
menu.closeContextMenu();
|
||||
applySortChoice(choice.key, folderRole);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{current === null && (
|
||||
<>
|
||||
<ContextMenuSeparator />
|
||||
<SortItem label={t("custom")} checked onClick={menu.closeContextMenu} />
|
||||
</>
|
||||
)}
|
||||
</ContextMenu>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
/** A checkable entry of the Sort menu, as in Files'. */
|
||||
function SortItem({ label, checked, onClick, testId }: { label: string; checked: boolean; onClick: () => void; testId?: string }) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
role="menuitemradio"
|
||||
aria-checked={checked}
|
||||
data-testid={testId}
|
||||
onClick={onClick}
|
||||
className="w-full px-3 py-1.5 max-md:min-h-11 text-sm text-start flex items-center gap-2 hover:bg-muted focus:outline-none focus-visible:bg-muted"
|
||||
>
|
||||
<span className="w-4 h-4 shrink-0 flex items-center justify-center">
|
||||
{checked && <Check className="w-4 h-4" />}
|
||||
</span>
|
||||
<span className="flex-1">{label}</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
@@ -81,6 +81,7 @@ import {
|
||||
} from "@/components/error";
|
||||
import { ConfirmDialog } from "@/components/ui/confirm-dialog";
|
||||
import { ScheduleSendDialog } from "@/components/email/schedule-send-dialog";
|
||||
import { MailSortMenu } from "@/components/email/mail-list-menus";
|
||||
import { PromptDialog } from "@/components/ui/prompt-dialog";
|
||||
import { TotpReauthDialog } from "@/components/totp-reauth-dialog";
|
||||
import { DragDropProvider } from "@/contexts/drag-drop-context";
|
||||
@@ -4939,6 +4940,7 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
<MailSortMenu folderRole={conversationRole} disabled={isScheduledView} className="flex-shrink-0 text-muted-foreground" />
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleManualRefresh}
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "مزيد من الإجراءات للمحدد"
|
||||
},
|
||||
"skip_to_list": "الانتقال إلى قائمة الرسائل",
|
||||
"sort": {
|
||||
"title": "ترتيب",
|
||||
"newest": "الأحدث أولًا",
|
||||
"oldest": "الأقدم أولًا",
|
||||
"unread": "غير المقروءة أولًا",
|
||||
"starred": "المميّزة بنجمة أولًا",
|
||||
"sender": "المرسل (أ–ي)",
|
||||
"subject": "الموضوع (أ–ي)",
|
||||
"largest": "الأكبر أولًا",
|
||||
"custom": "ترتيب مخصص (في الإعدادات)"
|
||||
},
|
||||
"permanent_delete": "حذف نهائي",
|
||||
"permanent_delete_confirm_title": "حذف نهائي",
|
||||
"permanent_delete_confirm_message": "سيتم حذف هذه الرسالة نهائيًا. لا يمكن التراجع عن هذا الإجراء.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Més accions per a la selecció"
|
||||
},
|
||||
"skip_to_list": "Salta a la llista de missatges",
|
||||
"sort": {
|
||||
"title": "Ordena",
|
||||
"newest": "Primer els més nous",
|
||||
"oldest": "Primer els més antics",
|
||||
"unread": "Primer els no llegits",
|
||||
"starred": "Primer els destacats",
|
||||
"sender": "Remitent (A–Z)",
|
||||
"subject": "Assumpte (A–Z)",
|
||||
"largest": "Primer els més grans",
|
||||
"custom": "Ordre personalitzat (a la configuració)"
|
||||
},
|
||||
"permanent_delete": "Suprimeix definitivament",
|
||||
"permanent_delete_confirm_title": "Suprimeix definitivament",
|
||||
"permanent_delete_confirm_message": "Aquest correu se suprimirà definitivament. Aquesta acció no es pot desfer.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Další akce pro výběr"
|
||||
},
|
||||
"skip_to_list": "Přeskočit na seznam zpráv",
|
||||
"sort": {
|
||||
"title": "Řazení",
|
||||
"newest": "Nejnovější nahoře",
|
||||
"oldest": "Nejstarší nahoře",
|
||||
"unread": "Nepřečtené nahoře",
|
||||
"starred": "S hvězdičkou nahoře",
|
||||
"sender": "Odesílatel (A–Z)",
|
||||
"subject": "Předmět (A–Z)",
|
||||
"largest": "Největší nahoře",
|
||||
"custom": "Vlastní řazení (v nastavení)"
|
||||
},
|
||||
"permanent_delete": "Trvale odstranit",
|
||||
"permanent_delete_confirm_title": "Trvalé odstranění",
|
||||
"permanent_delete_confirm_message": "Tato zpráva bude trvale odstraněna. Tuto akci nelze vrátit zpět.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Flere handlinger for markeringen"
|
||||
},
|
||||
"skip_to_list": "Spring til meddelelseslisten",
|
||||
"sort": {
|
||||
"title": "Sortér",
|
||||
"newest": "Nyeste først",
|
||||
"oldest": "Ældste først",
|
||||
"unread": "Ulæste først",
|
||||
"starred": "Stjernemarkerede først",
|
||||
"sender": "Afsender (A–Å)",
|
||||
"subject": "Emne (A–Å)",
|
||||
"largest": "Største først",
|
||||
"custom": "Brugerdefineret rækkefølge (i indstillinger)"
|
||||
},
|
||||
"permanent_delete": "Slet permanent",
|
||||
"permanent_delete_confirm_title": "Slet permanent",
|
||||
"permanent_delete_confirm_message": "Denne e-mail vil blive slettet permanent. Denne handling kan ikke fortrydes.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Weitere Aktionen für die Auswahl"
|
||||
},
|
||||
"skip_to_list": "Zur Nachrichtenliste springen",
|
||||
"sort": {
|
||||
"title": "Sortieren",
|
||||
"newest": "Neueste zuerst",
|
||||
"oldest": "Älteste zuerst",
|
||||
"unread": "Ungelesene zuerst",
|
||||
"starred": "Markierte zuerst",
|
||||
"sender": "Absender (A–Z)",
|
||||
"subject": "Betreff (A–Z)",
|
||||
"largest": "Größte zuerst",
|
||||
"custom": "Eigene Reihenfolge (in den Einstellungen)"
|
||||
},
|
||||
"permanent_delete": "Endgültig löschen",
|
||||
"permanent_delete_confirm_title": "Endgültig löschen",
|
||||
"permanent_delete_confirm_message": "Diese E-Mail wird endgültig gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "More actions for the selection"
|
||||
},
|
||||
"skip_to_list": "Skip to message list",
|
||||
"sort": {
|
||||
"title": "Sort",
|
||||
"newest": "Newest first",
|
||||
"oldest": "Oldest first",
|
||||
"unread": "Unread first",
|
||||
"starred": "Starred first",
|
||||
"sender": "Sender (A–Z)",
|
||||
"subject": "Subject (A–Z)",
|
||||
"largest": "Largest first",
|
||||
"custom": "Custom order (in Settings)"
|
||||
},
|
||||
"permanent_delete": "Delete permanently",
|
||||
"permanent_delete_confirm_title": "Permanently delete",
|
||||
"permanent_delete_confirm_message": "This email will be permanently deleted. This action cannot be undone.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Más acciones para la selección"
|
||||
},
|
||||
"skip_to_list": "Saltar a la lista de mensajes",
|
||||
"sort": {
|
||||
"title": "Ordenar",
|
||||
"newest": "Más recientes primero",
|
||||
"oldest": "Más antiguos primero",
|
||||
"unread": "No leídos primero",
|
||||
"starred": "Destacados primero",
|
||||
"sender": "Remitente (A–Z)",
|
||||
"subject": "Asunto (A–Z)",
|
||||
"largest": "Más grandes primero",
|
||||
"custom": "Orden personalizado (en Ajustes)"
|
||||
},
|
||||
"permanent_delete": "Eliminar permanentemente",
|
||||
"permanent_delete_confirm_title": "Eliminar permanentemente",
|
||||
"permanent_delete_confirm_message": "Este correo se eliminará permanentemente. Esta acción no se puede deshacer.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Rohkem toiminguid valiku jaoks"
|
||||
},
|
||||
"skip_to_list": "Mine kirjade loendisse",
|
||||
"sort": {
|
||||
"title": "Sorteeri",
|
||||
"newest": "Uuemad eespool",
|
||||
"oldest": "Vanemad eespool",
|
||||
"unread": "Lugemata eespool",
|
||||
"starred": "Tärniga eespool",
|
||||
"sender": "Saatja (A–Z)",
|
||||
"subject": "Teema (A–Z)",
|
||||
"largest": "Suuremad eespool",
|
||||
"custom": "Kohandatud järjestus (seadetes)"
|
||||
},
|
||||
"permanent_delete": "Kustuta jäädavalt",
|
||||
"permanent_delete_confirm_title": "Jäädav kustutamine",
|
||||
"permanent_delete_confirm_message": "See kiri kustutatakse jäädavalt. Seda toimingut ei saa tagasi võtta.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "اقدامات بیشتر برای موارد انتخابشده"
|
||||
},
|
||||
"skip_to_list": "رفتن به فهرست پیامها",
|
||||
"sort": {
|
||||
"title": "مرتبسازی",
|
||||
"newest": "جدیدترینها اول",
|
||||
"oldest": "قدیمیترینها اول",
|
||||
"unread": "خواندهنشدهها اول",
|
||||
"starred": "ستارهدارها اول",
|
||||
"sender": "فرستنده (الف–ی)",
|
||||
"subject": "موضوع (الف–ی)",
|
||||
"largest": "بزرگترینها اول",
|
||||
"custom": "ترتیب سفارشی (در تنظیمات)"
|
||||
},
|
||||
"permanent_delete": "حذف دائمی",
|
||||
"permanent_delete_confirm_title": "حذف دائمی",
|
||||
"permanent_delete_confirm_message": "این ایمیل برای همیشه حذف خواهد شد. این عملیات قابل بازگشت نیست.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Plus d'actions pour la sélection"
|
||||
},
|
||||
"skip_to_list": "Aller à la liste des messages",
|
||||
"sort": {
|
||||
"title": "Trier",
|
||||
"newest": "Plus récents d'abord",
|
||||
"oldest": "Plus anciens d'abord",
|
||||
"unread": "Non lus d'abord",
|
||||
"starred": "Suivis d'abord",
|
||||
"sender": "Expéditeur (A–Z)",
|
||||
"subject": "Objet (A–Z)",
|
||||
"largest": "Plus volumineux d'abord",
|
||||
"custom": "Ordre personnalisé (dans les paramètres)"
|
||||
},
|
||||
"permanent_delete": "Supprimer définitivement",
|
||||
"permanent_delete_confirm_title": "Supprimer définitivement",
|
||||
"permanent_delete_confirm_message": "Cet e-mail sera définitivement supprimé. Cette action est irréversible.",
|
||||
|
||||
@@ -261,6 +261,17 @@
|
||||
"selected_messages": "{count, plural, one {דוא״ל 1} other {# דוא״ל}} שנבחרו"
|
||||
},
|
||||
"skip_to_list": "דילוג לרשימת ההודעות",
|
||||
"sort": {
|
||||
"title": "מיון",
|
||||
"newest": "החדשות ביותר קודם",
|
||||
"oldest": "הישנות ביותר קודם",
|
||||
"unread": "שלא נקראו קודם",
|
||||
"starred": "מסומנות בכוכב קודם",
|
||||
"sender": "שולח (א–ת)",
|
||||
"subject": "נושא (א–ת)",
|
||||
"largest": "הגדולות ביותר קודם",
|
||||
"custom": "סדר מותאם (בהגדרות)"
|
||||
},
|
||||
"permanent_delete": "מחק לצמיתות",
|
||||
"permanent_delete_confirm_title": "מחק לצמיתות",
|
||||
"permanent_delete_confirm_message": "אימייל זה יימחק לצמיתות. לא ניתן לבטל פעולה זו.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "További műveletek a kijelöléshez"
|
||||
},
|
||||
"skip_to_list": "Ugrás az üzenetlistára",
|
||||
"sort": {
|
||||
"title": "Rendezés",
|
||||
"newest": "Legújabb elöl",
|
||||
"oldest": "Legrégebbi elöl",
|
||||
"unread": "Olvasatlanok elöl",
|
||||
"starred": "Csillagozottak elöl",
|
||||
"sender": "Feladó (A–Z)",
|
||||
"subject": "Tárgy (A–Z)",
|
||||
"largest": "Legnagyobb elöl",
|
||||
"custom": "Egyéni sorrend (a beállításokban)"
|
||||
},
|
||||
"permanent_delete": "Végleges törlés",
|
||||
"permanent_delete_confirm_title": "Végleges törlés",
|
||||
"permanent_delete_confirm_message": "Ez az e-mail véglegesen törlődik. Ez a művelet nem vonható vissza.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Altre azioni per la selezione"
|
||||
},
|
||||
"skip_to_list": "Vai all'elenco dei messaggi",
|
||||
"sort": {
|
||||
"title": "Ordina",
|
||||
"newest": "Più recenti prima",
|
||||
"oldest": "Meno recenti prima",
|
||||
"unread": "Non letti prima",
|
||||
"starred": "Speciali prima",
|
||||
"sender": "Mittente (A–Z)",
|
||||
"subject": "Oggetto (A–Z)",
|
||||
"largest": "Più grandi prima",
|
||||
"custom": "Ordine personalizzato (nelle impostazioni)"
|
||||
},
|
||||
"permanent_delete": "Elimina definitivamente",
|
||||
"permanent_delete_confirm_title": "Elimina definitivamente",
|
||||
"permanent_delete_confirm_message": "Questa e-mail verrà eliminata definitivamente. Questa azione non può essere annullata.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "選択項目のその他の操作"
|
||||
},
|
||||
"skip_to_list": "メッセージ一覧へ移動",
|
||||
"sort": {
|
||||
"title": "並べ替え",
|
||||
"newest": "新しい順",
|
||||
"oldest": "古い順",
|
||||
"unread": "未読を先頭",
|
||||
"starred": "スター付きを先頭",
|
||||
"sender": "差出人(A–Z)",
|
||||
"subject": "件名(A–Z)",
|
||||
"largest": "サイズの大きい順",
|
||||
"custom": "カスタムの並び順(設定)"
|
||||
},
|
||||
"permanent_delete": "完全に削除",
|
||||
"permanent_delete_confirm_title": "完全に削除",
|
||||
"permanent_delete_confirm_message": "このメールは完全に削除されます。この操作は取り消せません。",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "선택 항목에 대한 추가 작업"
|
||||
},
|
||||
"skip_to_list": "메시지 목록으로 건너뛰기",
|
||||
"sort": {
|
||||
"title": "정렬",
|
||||
"newest": "최신순",
|
||||
"oldest": "오래된순",
|
||||
"unread": "읽지 않은 메일 먼저",
|
||||
"starred": "별표 메일 먼저",
|
||||
"sender": "보낸 사람 (가–하)",
|
||||
"subject": "제목 (가–하)",
|
||||
"largest": "큰 메일 먼저",
|
||||
"custom": "사용자 지정 순서 (설정)"
|
||||
},
|
||||
"permanent_delete": "영구 삭제",
|
||||
"permanent_delete_confirm_title": "영구 삭제",
|
||||
"permanent_delete_confirm_message": "이 메일은 영구적으로 삭제되며, 다시 복구할 수 없어요.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Vairāk darbību atlasei"
|
||||
},
|
||||
"skip_to_list": "Pāriet uz vēstuļu sarakstu",
|
||||
"sort": {
|
||||
"title": "Kārtot",
|
||||
"newest": "Jaunākās vispirms",
|
||||
"oldest": "Vecākās vispirms",
|
||||
"unread": "Nelasītās vispirms",
|
||||
"starred": "Ar zvaigznīti vispirms",
|
||||
"sender": "Sūtītājs (A–Z)",
|
||||
"subject": "Temats (A–Z)",
|
||||
"largest": "Lielākās vispirms",
|
||||
"custom": "Pielāgota secība (iestatījumos)"
|
||||
},
|
||||
"permanent_delete": "Dzēst neatgriezeniski",
|
||||
"permanent_delete_confirm_title": "Dzēst neatgriezeniski",
|
||||
"permanent_delete_confirm_message": "Šī vēstule tiks dzēsta neatgriezeniski. Šo darbību nevar atcelt.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Сонгосон зүйлсийн бусад үйлдэл"
|
||||
},
|
||||
"skip_to_list": "Захидлын жагсаалт руу шилжих",
|
||||
"sort": {
|
||||
"title": "Эрэмбэлэх",
|
||||
"newest": "Шинэ нь эхэндээ",
|
||||
"oldest": "Хуучин нь эхэндээ",
|
||||
"unread": "Уншаагүй нь эхэндээ",
|
||||
"starred": "Одтой нь эхэндээ",
|
||||
"sender": "Илгээгч (А–Я)",
|
||||
"subject": "Гарчиг (А–Я)",
|
||||
"largest": "Том нь эхэндээ",
|
||||
"custom": "Тусгай дараалал (тохиргоонд)"
|
||||
},
|
||||
"permanent_delete": "Бүрмөсөн устгах",
|
||||
"permanent_delete_confirm_title": "Бүрмөсөн устгах",
|
||||
"permanent_delete_confirm_message": "Энэ имэйлийг бүрмөсөн устгах болно. Энэ үйлдлийг буцаах боломжгүй.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Flere handlinger for utvalget"
|
||||
},
|
||||
"skip_to_list": "Hopp til meldingslisten",
|
||||
"sort": {
|
||||
"title": "Sorter",
|
||||
"newest": "Nyeste først",
|
||||
"oldest": "Eldste først",
|
||||
"unread": "Uleste først",
|
||||
"starred": "Stjernemerkede først",
|
||||
"sender": "Avsender (A–Å)",
|
||||
"subject": "Emne (A–Å)",
|
||||
"largest": "Største først",
|
||||
"custom": "Egendefinert rekkefølge (i innstillingene)"
|
||||
},
|
||||
"permanent_delete": "Slett permanent",
|
||||
"permanent_delete_confirm_title": "Slett permanent",
|
||||
"permanent_delete_confirm_message": "Denne e-posten slettes permanent. Denne handlingen kan ikke angres.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Meer acties voor de selectie"
|
||||
},
|
||||
"skip_to_list": "Naar de berichtenlijst",
|
||||
"sort": {
|
||||
"title": "Sorteren",
|
||||
"newest": "Nieuwste eerst",
|
||||
"oldest": "Oudste eerst",
|
||||
"unread": "Ongelezen eerst",
|
||||
"starred": "Met ster eerst",
|
||||
"sender": "Afzender (A–Z)",
|
||||
"subject": "Onderwerp (A–Z)",
|
||||
"largest": "Grootste eerst",
|
||||
"custom": "Eigen volgorde (in Instellingen)"
|
||||
},
|
||||
"permanent_delete": "Definitief verwijderen",
|
||||
"permanent_delete_confirm_title": "Definitief verwijderen",
|
||||
"permanent_delete_confirm_message": "Deze e-mail wordt definitief verwijderd. Deze actie kan niet ongedaan worden gemaakt.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Więcej działań dla zaznaczenia"
|
||||
},
|
||||
"skip_to_list": "Przejdź do listy wiadomości",
|
||||
"sort": {
|
||||
"title": "Sortuj",
|
||||
"newest": "Od najnowszych",
|
||||
"oldest": "Od najstarszych",
|
||||
"unread": "Najpierw nieprzeczytane",
|
||||
"starred": "Najpierw oznaczone gwiazdką",
|
||||
"sender": "Nadawca (A–Z)",
|
||||
"subject": "Temat (A–Z)",
|
||||
"largest": "Od największych",
|
||||
"custom": "Własna kolejność (w ustawieniach)"
|
||||
},
|
||||
"permanent_delete": "Usuń trwale",
|
||||
"permanent_delete_confirm_title": "Trwałe usunięcie",
|
||||
"permanent_delete_confirm_message": "Ta wiadomość zostanie trwale usunięta. Tej operacji nie można cofnąć.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Mais ações para a seleção"
|
||||
},
|
||||
"skip_to_list": "Ir para a lista de mensagens",
|
||||
"sort": {
|
||||
"title": "Ordenar",
|
||||
"newest": "Mais recentes primeiro",
|
||||
"oldest": "Mais antigos primeiro",
|
||||
"unread": "Não lidos primeiro",
|
||||
"starred": "Com estrela primeiro",
|
||||
"sender": "Remetente (A–Z)",
|
||||
"subject": "Assunto (A–Z)",
|
||||
"largest": "Maiores primeiro",
|
||||
"custom": "Ordem personalizada (nas Definições)"
|
||||
},
|
||||
"permanent_delete": "Excluir permanentemente",
|
||||
"permanent_delete_confirm_title": "Excluir permanentemente",
|
||||
"permanent_delete_confirm_message": "Este e-mail será permanentemente excluído. Esta ação não pode ser desfeita.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Mai multe acțiuni pentru selecție"
|
||||
},
|
||||
"skip_to_list": "Salt la lista de mesaje",
|
||||
"sort": {
|
||||
"title": "Sortează",
|
||||
"newest": "Cele mai noi primele",
|
||||
"oldest": "Cele mai vechi primele",
|
||||
"unread": "Necitite primele",
|
||||
"starred": "Cu stea primele",
|
||||
"sender": "Expeditor (A–Z)",
|
||||
"subject": "Subiect (A–Z)",
|
||||
"largest": "Cele mai mari primele",
|
||||
"custom": "Ordine personalizată (în Setări)"
|
||||
},
|
||||
"permanent_delete": "Șterge definitiv",
|
||||
"permanent_delete_confirm_title": "Șterge definitiv",
|
||||
"permanent_delete_confirm_message": "Acest e-mail va fi șters definitiv. Această acțiune nu poate fi anulată.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Другие действия с выбранным"
|
||||
},
|
||||
"skip_to_list": "Перейти к списку писем",
|
||||
"sort": {
|
||||
"title": "Сортировка",
|
||||
"newest": "Сначала новые",
|
||||
"oldest": "Сначала старые",
|
||||
"unread": "Сначала непрочитанные",
|
||||
"starred": "Сначала помеченные",
|
||||
"sender": "Отправитель (А–Я)",
|
||||
"subject": "Тема (А–Я)",
|
||||
"largest": "Сначала большие",
|
||||
"custom": "Свой порядок (в настройках)"
|
||||
},
|
||||
"permanent_delete": "Удалить навсегда",
|
||||
"permanent_delete_confirm_title": "Удалить навсегда",
|
||||
"permanent_delete_confirm_message": "Это письмо будет удалено навсегда. Действие нельзя отменить.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Ďalšie akcie pre výber"
|
||||
},
|
||||
"skip_to_list": "Preskočiť na zoznam správ",
|
||||
"sort": {
|
||||
"title": "Zoradiť",
|
||||
"newest": "Najnovšie hore",
|
||||
"oldest": "Najstaršie hore",
|
||||
"unread": "Neprečítané hore",
|
||||
"starred": "S hviezdičkou hore",
|
||||
"sender": "Odosielateľ (A–Z)",
|
||||
"subject": "Predmet (A–Z)",
|
||||
"largest": "Najväčšie hore",
|
||||
"custom": "Vlastné poradie (v nastaveniach)"
|
||||
},
|
||||
"permanent_delete": "Trvalo odstrániť",
|
||||
"permanent_delete_confirm_title": "Trvalo odstrániť",
|
||||
"permanent_delete_confirm_message": "Tento e-mail bude trvalo odstránený. Túto akciu nie je možné vrátiť.",
|
||||
|
||||
@@ -479,6 +479,17 @@
|
||||
"more": "การดำเนินการเพิ่มเติมสำหรับรายการที่เลือก"
|
||||
},
|
||||
"skip_to_list": "ข้ามไปที่รายการข้อความ",
|
||||
"sort": {
|
||||
"title": "จัดเรียง",
|
||||
"newest": "ใหม่สุดก่อน",
|
||||
"oldest": "เก่าสุดก่อน",
|
||||
"unread": "ยังไม่อ่านก่อน",
|
||||
"starred": "ติดดาวก่อน",
|
||||
"sender": "ผู้ส่ง (ก–ฮ)",
|
||||
"subject": "หัวเรื่อง (ก–ฮ)",
|
||||
"largest": "ใหญ่สุดก่อน",
|
||||
"custom": "ลำดับที่กำหนดเอง (ในการตั้งค่า)"
|
||||
},
|
||||
"permanent_delete": "ลบถาวร",
|
||||
"permanent_delete_confirm_title": "ยืนยันการลบถาวร",
|
||||
"permanent_delete_confirm_message": "อีเมลนี้จะถูกลบอย่างถาวรและไม่สามารถกู้คืนได้",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Seçim için diğer işlemler"
|
||||
},
|
||||
"skip_to_list": "İleti listesine atla",
|
||||
"sort": {
|
||||
"title": "Sırala",
|
||||
"newest": "Önce en yeni",
|
||||
"oldest": "Önce en eski",
|
||||
"unread": "Önce okunmamış",
|
||||
"starred": "Önce yıldızlı",
|
||||
"sender": "Gönderen (A–Z)",
|
||||
"subject": "Konu (A–Z)",
|
||||
"largest": "Önce en büyük",
|
||||
"custom": "Özel sıralama (Ayarlar'da)"
|
||||
},
|
||||
"permanent_delete": "Kalıcı olarak sil",
|
||||
"permanent_delete_confirm_title": "Kalıcı olarak sil",
|
||||
"permanent_delete_confirm_message": "Bu e-posta kalıcı olarak silinecek. Bu işlem geri alınamaz.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "Інші дії з вибраним"
|
||||
},
|
||||
"skip_to_list": "Перейти до списку листів",
|
||||
"sort": {
|
||||
"title": "Сортування",
|
||||
"newest": "Спершу нові",
|
||||
"oldest": "Спершу старі",
|
||||
"unread": "Спершу непрочитані",
|
||||
"starred": "Спершу із зірочкою",
|
||||
"sender": "Відправник (А–Я)",
|
||||
"subject": "Тема (А–Я)",
|
||||
"largest": "Спершу великі",
|
||||
"custom": "Власний порядок (у налаштуваннях)"
|
||||
},
|
||||
"permanent_delete": "Видалити остаточно",
|
||||
"permanent_delete_confirm_title": "Видалити назавжди",
|
||||
"permanent_delete_confirm_message": "Цей електронний лист буде видалено назавжди. Цю дію не можна скасувати.",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "所選項目的更多動作"
|
||||
},
|
||||
"skip_to_list": "跳到郵件清單",
|
||||
"sort": {
|
||||
"title": "排序",
|
||||
"newest": "最新優先",
|
||||
"oldest": "最舊優先",
|
||||
"unread": "未讀優先",
|
||||
"starred": "已加星號優先",
|
||||
"sender": "寄件者(A–Z)",
|
||||
"subject": "主旨(A–Z)",
|
||||
"largest": "最大優先",
|
||||
"custom": "自訂順序(在設定中)"
|
||||
},
|
||||
"permanent_delete": "永久刪除",
|
||||
"permanent_delete_confirm_title": "永久刪除",
|
||||
"permanent_delete_confirm_message": "這封郵件將永久刪除。此動作無法復原。",
|
||||
|
||||
@@ -296,6 +296,17 @@
|
||||
"more": "所选项目的更多操作"
|
||||
},
|
||||
"skip_to_list": "跳到邮件列表",
|
||||
"sort": {
|
||||
"title": "排序",
|
||||
"newest": "最新优先",
|
||||
"oldest": "最早优先",
|
||||
"unread": "未读优先",
|
||||
"starred": "星标优先",
|
||||
"sender": "发件人(A–Z)",
|
||||
"subject": "主题(A–Z)",
|
||||
"largest": "最大优先",
|
||||
"custom": "自定义顺序(在设置中)"
|
||||
},
|
||||
"permanent_delete": "永久删除",
|
||||
"permanent_delete_confirm_title": "永久删除",
|
||||
"permanent_delete_confirm_message": "该邮件将被永久删除。此操作无法撤销。",
|
||||
|
||||
Reference in New Issue
Block a user