feat: lay out Mountain View's navigation like Gmail's, with a Labels section

This commit is contained in:
Linus Rath
2026-10-12 00:46:48 +02:00
parent ae151cec25
commit cf558e7e9f
30 changed files with 212 additions and 56 deletions
+30 -2
View File
@@ -1047,10 +1047,38 @@ optgroup {
border-end-end-radius: var(--mv-nav-radius);
}
/* Compose: a 56px pill, which shrinks to a circle with the rail. */
/* Selected and hovered rows fill the pill; a folder with unread mail reads
bold, the way the message rows do. Icons are 20px with an 18px gap. */
[data-interface-layout="mountain-view"] [data-mv-nav-row] {
font-size: 0.875rem;
color: var(--color-foreground);
}
[data-interface-layout="mountain-view"] [data-mv-nav-row]:hover {
background-color: var(--mv-nav-hover);
}
[data-interface-layout="mountain-view"] [data-mv-nav-row][data-selected="true"] {
background-color: var(--mv-nav-selected);
color: var(--color-foreground);
font-weight: 700;
}
[data-interface-layout="mountain-view"] [data-mv-nav-row][data-has-unread] {
font-weight: 700;
}
[data-interface-layout="mountain-view"] [data-mv-nav-row] > button {
gap: 18px;
}
[data-interface-layout="mountain-view"] [data-mv-nav-row] > button > span:first-child,
[data-interface-layout="mountain-view"] [data-mv-nav-row] > button > span:first-child > svg {
width: 20px;
height: 20px;
}
/* Compose: a 56px button with a 16px corner, which shrinks to a square with
the rail. */
[data-interface-layout="mountain-view"] [data-mv-compose] {
height: var(--mv-compose-h);
border-radius: var(--mv-nav-radius);
border-radius: 16px;
font-weight: 500;
}
/* The account popover: a wide card with a very round corner, rather
@@ -2,10 +2,10 @@ import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import type { Mailbox } from '@/lib/jmap/types';
// Under Mountain View the sidebar is one flat list: inbox, sent and drafts,
// then a single "More" that reveals the folders you made, the shared ones and
// the labels. Outside Mountain View the "Folders" / "Tags" sections stay as they
// are, headings and all.
// Under Mountain View the sidebar is laid out the way Gmail's is: inbox, sent
// and drafts, a "More" that reveals the other system folders, then a
// "Labels" list of the folders you made and your tags. Outside Mountain View
// the "Folders" / "Tags" sections stay as they are, headings and all.
vi.mock('@/components/plugins/plugin-slot', () => ({ PluginSlot: () => null }));
vi.mock('@/components/tour/tour-provider', () => ({
@@ -47,15 +47,27 @@ describe('Sidebar under Mountain View', () => {
} as never);
});
it('drops the Folders heading and holds the rest behind More', () => {
it('drops the Folders heading and holds the system folders behind More', () => {
render(<Sidebar mailboxes={mailboxes} selectedMailbox="inbox" mvShell />);
expect(screen.queryByText('folders')).toBeNull();
expect(screen.getByText('show_more')).toBeInTheDocument();
expect(folderRow('Receipts')).toBeNull();
expect(folderRow('Trash')).toBeNull();
// The labels heading goes with them: it shows only once expanded.
});
it('lists your folders and tags under Labels, outside More', () => {
const onCreateFolder = vi.fn();
const { container } = render(
<Sidebar mailboxes={mailboxes} selectedMailbox="inbox" mvShell onCreateFolder={onCreateFolder} />,
);
expect(screen.getByText('labels')).toBeInTheDocument();
expect(screen.queryByText('tags')).toBeNull();
expect(container.querySelector('[data-mv-labels] [data-folder-name="Receipts"]')).not.toBeNull();
expect(screen.getByText('Work')).toBeInTheDocument();
fireEvent.click(screen.getByLabelText('create_label'));
expect(onCreateFolder).toHaveBeenCalledTimes(1);
});
it('keeps the places mail actually goes in view', () => {
@@ -83,16 +95,14 @@ describe('Sidebar under Mountain View', () => {
expect(container.querySelector('[data-folder-name="mv-starred"]')).toBeNull();
});
it('reveals the folders and the labels together, and takes them back', () => {
it('reveals the system folders under More, and takes them back', () => {
render(<Sidebar mailboxes={mailboxes} selectedMailbox="inbox" mvShell />);
fireEvent.click(screen.getByText('show_more'));
expect(folderRow('Receipts')).not.toBeNull();
expect(folderRow('Trash')).not.toBeNull();
expect(screen.getByText('tags')).toBeInTheDocument();
fireEvent.click(screen.getByText('show_fewer'));
expect(folderRow('Receipts')).toBeNull();
expect(folderRow('Trash')).toBeNull();
});
it('leaves the default layout its sections and every folder', () => {
+80 -16
View File
@@ -32,7 +32,8 @@ import {
Loader2,
AlertTriangle,
NotebookPen,
PenSquare,
Pencil,
Plus,
CalendarClock,
BellOff,
Mails,
@@ -210,14 +211,33 @@ function getIconClass(isSelected: boolean, isVirtual: boolean, colorful: boolean
function SidebarRowCounts({
unread,
total,
role,
onUnreadClick,
}: {
unread?: number;
total?: number;
role?: string | null;
isSelected: boolean;
onUnreadClick?: () => void;
}) {
const showFolderTotalCount = useSettingsStore(s => s.showFolderTotalCount);
const mountainView = useSettingsStore(s => s.interfaceLayout === 'mountain-view');
// Mountain View counts one thing per row: what is unread, or for Drafts,
// how many there are, since a draft is never unread.
if (mountainView) {
const count = role === 'drafts' ? (total ?? 0) : (unread ?? 0);
if (count === 0) return null;
return (
<span
className={cn("ms-2 flex-shrink-0 text-xs tabular-nums", role === 'drafts' ? "text-muted-foreground" : "font-bold text-foreground")}
data-testid="folder-counts"
data-unread={unread ?? 0}
data-total={role === 'drafts' ? count : 0}
>
{count.toLocaleString()}
</span>
);
}
const unreadCount = unread ?? 0;
const totalCount = showFolderTotalCount ? (total ?? 0) : 0;
@@ -336,6 +356,7 @@ function SidebarRow({
data-mailbox-id={testMailboxId ?? undefined}
data-shared={testShared ? 'true' : undefined}
data-selected={isSelected ? 'true' : undefined}
data-has-unread={(unread ?? 0) > 0 && testRole !== 'drafts' ? '' : undefined}
style={{ paddingBlock: 'var(--density-sidebar-py)' }}
className={cn(
"group w-full flex items-center max-lg:min-h-[44px] text-sm transition-colors duration-150",
@@ -396,6 +417,7 @@ function SidebarRow({
<SidebarRowCounts
unread={unread}
total={total}
role={testRole}
isSelected={isSelected}
onUnreadClick={onUnreadClick}
/>
@@ -922,7 +944,8 @@ export function Sidebar({
const hideAccountSwitcher = useSettingsStore(s => s.hideAccountSwitcher) || isEmbedded;
const enableUnifiedMailbox = useSettingsStore(s => s.enableUnifiedMailbox);
const includeGroupInUnified = useSettingsStore(s => s.includeGroupInUnified);
const colorfulSidebarIcons = useSettingsStore(s => s.colorfulSidebarIcons);
// Mountain View draws its navigation icons in the text colour.
const colorfulSidebarIcons = useSettingsStore(s => s.colorfulSidebarIcons) && !mvShell;
const tagCounts = useEmailStore(s => s.tagCounts);
const accounts = useAccountStore(s => s.accounts);
const connectedAccounts = accounts.filter(a => a.isConnected);
@@ -1045,6 +1068,11 @@ export function Sidebar({
node.role === 'inbox' || node.role === 'sent' || node.role === 'drafts';
const primaryTree = mvFlat ? ownTree.filter(isPrimaryFolder) : ownTree;
const secondaryTree = mvFlat ? ownTree.filter((node) => !isPrimaryFolder(node)) : [];
// Of those, the system folders (archive, spam, trash...) go behind "More",
// and the folders the user made are listed with the tags under "Labels",
// which is what they are to someone coming from Gmail.
const moreTree = secondaryTree.filter((node) => !!node.role);
const labelTree = secondaryTree.filter((node) => !node.role);
// Everything under "More" is hidden together, so one flag covers the extra
// folders, the shared accounts and the labels.
const showSecondary = !mvFlat || moreExpanded;
@@ -1107,7 +1135,7 @@ export function Sidebar({
return (
<SidebarRow
key={key}
icon={<CalendarClock className="w-4 h-4 flex-shrink-0 text-sky-600 dark:text-sky-400" />}
icon={<CalendarClock className={cn("w-4 h-4 flex-shrink-0", mvShell ? "text-foreground/80" : "text-sky-600 dark:text-sky-400")} />}
label={t('scheduled')}
depth={account?.depth ?? 0}
isSelected={!selectedKeyword && isScheduledSelected}
@@ -1312,13 +1340,13 @@ export function Sidebar({
data-mv-compose=""
data-tour="compose-button"
className={cn(
"flex items-center bg-primary text-primary-foreground shadow-sm hover:shadow-md transition-shadow",
"flex items-center bg-[var(--mv-compose-bg)] text-[var(--mv-compose-fg)] hover:shadow-md transition-shadow",
isCollapsed ? "w-14 justify-center" : "gap-3 ps-4 pe-6"
)}
title={t("compose_hint")}
aria-label={t("compose")}
>
<PenSquare className="w-5 h-5 flex-shrink-0" />
<Pencil className="w-6 h-6 flex-shrink-0" />
{!isCollapsed && <span className="text-sm font-medium">{t("compose")}</span>}
</button>
</div>
@@ -1513,7 +1541,7 @@ export function Sidebar({
isCollapsed={false}
/>
)}
{mvFlat && moreExpanded && secondaryTree.map((node) => (
{mvFlat && moreExpanded && moreTree.map((node) => (
<MailboxTreeItem
key={node.id}
node={node}
@@ -1534,6 +1562,39 @@ export function Sidebar({
</div>
)}
{mvFlat && !useMultiAccount && (
<div data-mv-labels="">
<div className="flex items-center justify-between ps-[26px] pe-3 pt-4 pb-1">
<span className="text-base font-medium text-foreground">{t("labels")}</span>
{onCreateFolder && (
<button
type="button"
onClick={() => onCreateFolder()}
className="grid place-items-center w-8 h-8 rounded-full text-foreground hover:bg-[var(--mv-nav-hover)] transition-colors"
title={t("create_label")}
aria-label={t("create_label")}
>
<Plus className="w-5 h-5" />
</button>
)}
</div>
{labelTree.map((node) => (
<MailboxTreeItem
key={node.id}
node={node}
selectedMailbox={selectedKeyword ? "" : selectedMailbox}
expandedFolders={expandedFolders}
onMailboxSelect={onMailboxSelect}
onToggleExpand={handleToggleExpand}
isCollapsed={isCollapsed}
onUnreadFilterClick={onUnreadFilterClick}
colorful={colorfulSidebarIcons}
onContextMenu={handleMailboxContextMenu}
/>
))}
</div>
)}
{!useMultiAccount && showSecondary && sharedAccounts.length > 0 && (
<div>
<SidebarSectionHeader
@@ -1593,17 +1654,20 @@ export function Sidebar({
</div>
)}
{showSecondary && emailKeywords.length > 0 && (
{(showSecondary || mvFlat) && emailKeywords.length > 0 && (
<div data-tour="keyword-tags">
<SidebarSectionHeader
label={t("tags")}
expanded={tagsExpanded}
onToggle={toggleTags}
onSettings={openKeywordSettings}
settingsTitle={t('settings')}
isCollapsed={isCollapsed}
/>
{((tagsExpanded && !isCollapsed) || isCollapsed) && (
{/* Under Mountain View the tags continue the "Labels" list. */}
{!mvFlat && (
<SidebarSectionHeader
label={t("tags")}
expanded={tagsExpanded}
onToggle={toggleTags}
onSettings={openKeywordSettings}
settingsTitle={t('settings')}
isCollapsed={isCollapsed}
/>
)}
{((tagsExpanded && !isCollapsed) || isCollapsed || mvFlat) && (
<>
{visibleTagTree.map((node) => (
<TagItem
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "كل المميز بنجمة",
"unified_all_mail": "كل البريد",
"remove_account": "إزالة الحساب",
"remove_account_confirm": "هل تريد إزالة {account} من هذا الجهاز؟ يمكنك إضافته مرة أخرى لاحقًا."
"remove_account_confirm": "هل تريد إزالة {account} من هذا الجهاز؟ يمكنك إضافته مرة أخرى لاحقًا.",
"labels": "التصنيفات",
"create_label": "إنشاء تصنيف جديد"
},
"protocol_handlers": {
"title": "التطبيقات الافتراضية",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Tots els destacats",
"unified_all_mail": "Tot el correu",
"remove_account": "Elimina el compte",
"remove_account_confirm": "Voleu eliminar {account} d'aquest dispositiu? El podreu tornar a afegir més endavant."
"remove_account_confirm": "Voleu eliminar {account} d'aquest dispositiu? El podreu tornar a afegir més endavant.",
"labels": "Etiquetes",
"create_label": "Crea una etiqueta nova"
},
"protocol_handlers": {
"title": "Aplicacions predeterminades",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Vše s hvězdičkou",
"unified_all_mail": "Veškerá pošta",
"remove_account": "Odebrat účet",
"remove_account_confirm": "Odebrat účet {account} z tohoto zařízení? Později ho můžete znovu přidat."
"remove_account_confirm": "Odebrat účet {account} z tohoto zařízení? Později ho můžete znovu přidat.",
"labels": "Štítky",
"create_label": "Vytvořit nový štítek"
},
"protocol_handlers": {
"title": "Výchozí aplikace",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Alle med stjerne",
"unified_all_mail": "Al post",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Etiketter",
"create_label": "Opret ny etiket"
},
"protocol_handlers": {
"title": "Standardapps",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Alle markierten",
"unified_all_mail": "Alle Mails",
"remove_account": "Konto entfernen",
"remove_account_confirm": "{account} von diesem Gerät entfernen? Sie können das Konto später wieder hinzufügen."
"remove_account_confirm": "{account} von diesem Gerät entfernen? Sie können das Konto später wieder hinzufügen.",
"labels": "Labels",
"create_label": "Neues Label erstellen"
},
"protocol_handlers": {
"title": "Standard-Apps",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "All starred",
"unified_all_mail": "All mail",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Labels",
"create_label": "Create new label"
},
"protocol_handlers": {
"title": "Default apps",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Todo destacado",
"unified_all_mail": "Todo el correo",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Etiquetas",
"create_label": "Crear etiqueta"
},
"protocol_handlers": {
"title": "Aplicaciones predeterminadas",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "همه ستاره‌دارها",
"unified_all_unread": "همه خوانده‌نشده‌ها",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "برچسب‌ها",
"create_label": "ایجاد برچسب جدید"
},
"protocol_handlers": {
"title": "برنامه‌های پیش‌فرض",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Tous les favoris",
"unified_all_mail": "Tout le courrier",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Libellés",
"create_label": "Créer un libellé"
},
"protocol_handlers": {
"title": "Applications par défaut",
+3 -1
View File
@@ -152,7 +152,9 @@
"unified_all_starred": "הכל מסומנים",
"unified_all_mail": "הכל דוא״ל",
"remove_account": "הסרת חשבון",
"remove_account_confirm": "להסיר את {account} מהמכשיר הזה? ניתן להוסיף אותו שוב מאוחר יותר."
"remove_account_confirm": "להסיר את {account} מהמכשיר הזה? ניתן להוסיף אותו שוב מאוחר יותר.",
"labels": "תוויות",
"create_label": "יצירת תווית חדשה"
},
"sidebar_apps": {
"modal_title": "אפליקציות בסרגל הצד",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Összes csillagozott",
"unified_all_mail": "Összes levél",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Címkék",
"create_label": "Új címke létrehozása"
},
"protocol_handlers": {
"title": "Alapértelmezett alkalmazások",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Tutti gli speciali",
"unified_all_mail": "Tutta la posta",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Etichette",
"create_label": "Crea nuova etichetta"
},
"protocol_handlers": {
"title": "App predefinite",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "すべてのスター付き",
"unified_all_mail": "すべてのメール",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "ラベル",
"create_label": "新しいラベルを作成"
},
"protocol_handlers": {
"title": "既定のアプリ",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "모든 별표",
"unified_all_mail": "모든 메일",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "라벨",
"create_label": "새 라벨 만들기"
},
"protocol_handlers": {
"title": "기본 앱",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Visi ar zvaigzni",
"unified_all_mail": "Visas vēstules",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Etiķetes",
"create_label": "Izveidot jaunu etiķeti"
},
"protocol_handlers": {
"title": "Noklusējuma lietotnes",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Бүх одтой",
"unified_all_mail": "Бүх шуудан",
"remove_account": "Бүртгэл устгах",
"remove_account_confirm": "Энэ төхөөрөмжөөс {account}-г устгах уу? Та дараа дахин нэмж болно."
"remove_account_confirm": "Энэ төхөөрөмжөөс {account}-г устгах уу? Та дараа дахин нэмж болно.",
"labels": "Шошго",
"create_label": "Шинэ шошго үүсгэх"
},
"protocol_handlers": {
"title": "Өгөгдмөл програмууд",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Alle stjernemerkede",
"unified_all_mail": "All e-post",
"remove_account": "Fjern konto",
"remove_account_confirm": "Vil du fjerne {account} fra denne enheten? Du kan legge den til igjen senere."
"remove_account_confirm": "Vil du fjerne {account} fra denne enheten? Du kan legge den til igjen senere.",
"labels": "Etiketter",
"create_label": "Opprett ny etikett"
},
"protocol_handlers": {
"title": "Standardapper",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Alle met ster",
"unified_all_mail": "Alle e-mail",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Labels",
"create_label": "Nieuw label maken"
},
"protocol_handlers": {
"title": "Standaardapps",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Wszystkie oznaczone gwiazdką",
"unified_all_mail": "Cała poczta",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Etykiety",
"create_label": "Utwórz etykietę"
},
"protocol_handlers": {
"title": "Aplikacje domyślne",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Tudo com estrela",
"unified_all_mail": "Todo o correio",
"remove_account": "Remover conta",
"remove_account_confirm": "Remover {account} desse dispositivo? Você pode adicioná-la de volta depois."
"remove_account_confirm": "Remover {account} desse dispositivo? Você pode adicioná-la de volta depois.",
"labels": "Etiquetas",
"create_label": "Criar etiqueta"
},
"protocol_handlers": {
"title": "Aplicativos padrão",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Toate cu stea",
"unified_all_mail": "Toată poșta",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Etichete",
"create_label": "Creează o etichetă nouă"
},
"protocol_handlers": {
"title": "Aplicații implicite",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Все помеченные",
"unified_all_mail": "Вся почта",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Ярлыки",
"create_label": "Создать ярлык"
},
"protocol_handlers": {
"title": "Приложения по умолчанию",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Všetky s hviezdičkou",
"unified_all_mail": "Všetka pošta",
"remove_account": "Odstrániť účet",
"remove_account_confirm": "Odstrániť {account} z tohto zariadenia? Neskôr ho môžete znova pridať."
"remove_account_confirm": "Odstrániť {account} z tohto zariadenia? Neskôr ho môžete znova pridať.",
"labels": "Štítky",
"create_label": "Vytvoriť nový štítok"
},
"protocol_handlers": {
"title": "Predvolené aplikácie",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Tüm yıldızlılar",
"unified_all_mail": "Tüm postalar",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Etiketler",
"create_label": "Yeni etiket oluştur"
},
"protocol_handlers": {
"title": "Varsayılan uygulamalar",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "Усі позначені",
"unified_all_mail": "Уся пошта",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "Мітки",
"create_label": "Створити мітку"
},
"protocol_handlers": {
"title": "Програми за замовчуванням",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "全部已加星號",
"unified_all_mail": "全部郵件",
"remove_account": "移除帳號",
"remove_account_confirm": "要從這部裝置移除 {account} 嗎?您稍後仍可重新新增。"
"remove_account_confirm": "要從這部裝置移除 {account} 嗎?您稍後仍可重新新增。",
"labels": "標籤",
"create_label": "建立新標籤"
},
"protocol_handlers": {
"title": "預設應用程式",
+3 -1
View File
@@ -153,7 +153,9 @@
"unified_all_starred": "全部加星标",
"unified_all_mail": "全部邮件",
"remove_account": "Remove account",
"remove_account_confirm": "Remove {account} from this device? You can add it back later."
"remove_account_confirm": "Remove {account} from this device? You can add it back later.",
"labels": "标签",
"create_label": "新建标签"
},
"protocol_handlers": {
"title": "默认应用",