fix: localize special-folder names by JMAP role #404

This commit is contained in:
Linus Rath
2026-06-24 19:32:13 +02:00
parent 7882b254a0
commit f972068143
5 changed files with 104 additions and 5 deletions
+43
View File
@@ -0,0 +1,43 @@
import { describe, it, expect } from "vitest";
import { localizeMailboxName } from "@/lib/mailbox-label";
// Stand-in translator mirroring the `sidebar.mailboxes` namespace.
const RU: Record<string, string> = {
inbox: "Входящие",
sent: "Отправленные",
drafts: "Черновики",
trash: "Корзина",
archive: "Архив",
spam: "Спам",
important: "Важные",
starred: "Помечённые",
all_mail: "Вся почта",
};
const translate = (key: string) => RU[key] ?? `MISSING:${key}`;
describe("localizeMailboxName", () => {
it("localizes special-use folders by JMAP role, ignoring the server name", () => {
expect(localizeMailboxName("inbox", "Inbox", translate)).toBe("Входящие");
expect(localizeMailboxName("sent", "Sent", translate)).toBe("Отправленные");
expect(localizeMailboxName("drafts", "Drafts", translate)).toBe("Черновики");
expect(localizeMailboxName("trash", "Deleted Items", translate)).toBe("Корзина");
expect(localizeMailboxName("archive", "Archive", translate)).toBe("Архив");
expect(localizeMailboxName("important", "Important", translate)).toBe("Важные");
});
it("maps junk/flagged/all onto reused translation keys", () => {
expect(localizeMailboxName("junk", "Junk", translate)).toBe("Спам");
expect(localizeMailboxName("flagged", "Flagged", translate)).toBe("Помечённые");
expect(localizeMailboxName("all", "All Mail", translate)).toBe("Вся почта");
});
it("leaves user-created folders (no role) untouched", () => {
expect(localizeMailboxName(undefined, "Projects", translate)).toBe("Projects");
expect(localizeMailboxName(null, "Работа", translate)).toBe("Работа");
expect(localizeMailboxName("", "Receipts", translate)).toBe("Receipts");
});
it("falls back to the server name for unknown roles", () => {
expect(localizeMailboxName("subscribed", "Subscribed", translate)).toBe("Subscribed");
});
});
+44
View File
@@ -0,0 +1,44 @@
/**
* Localizes the display name of special-use mailboxes.
*
* Mail servers (e.g. Stalwart) always create system folders with English
* names — "Inbox", "Sent", "Junk" — regardless of the account locale. JMAP
* exposes the special-use semantics via the mailbox `role`, so we map that
* role onto a translated label (mirroring Roundcube's behaviour). Folders
* without a recognized role — i.e. user-created folders — keep their server
* name untouched.
*
* The keys live under the `sidebar.mailboxes` namespace; `junk`, `flagged`
* and `all` reuse the existing `spam`/`starred`/`all_mail` keys so every
* locale already has a translation.
*/
const ROLE_TRANSLATION_KEY: Record<string, string> = {
inbox: "inbox",
sent: "sent",
drafts: "drafts",
trash: "trash",
archive: "archive",
junk: "spam",
important: "important",
flagged: "starred",
all: "all_mail",
};
/**
* Returns the localized name for a mailbox, or its raw server name when the
* role is unknown/absent.
*
* @param translate Resolves a `sidebar.mailboxes` leaf key (e.g. `"inbox"`) to
* its localized string. Callers scoped to the `sidebar` namespace pass
* `(k) => t(`mailboxes.${k}`)`; root-scoped callers pass
* `(k) => t(`sidebar.mailboxes.${k}`)`.
*/
export function localizeMailboxName(
role: string | undefined | null,
name: string,
translate: (key: string) => string,
): string {
if (!role) return name;
const key = ROLE_TRANSLATION_KEY[role];
return key ? translate(key) : name;
}