mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-02 00:14:23 +00:00
feat: list your own folders in a separate section of the sidebar #1205
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import type { Mailbox } from '@/lib/jmap/types';
|
||||
|
||||
// #1205: the folders the user made get a "Your folders" section of their own
|
||||
// below the system folders, instead of being mixed in with Inbox, Sent and
|
||||
// Trash. Users with no folders of their own see no change.
|
||||
|
||||
vi.mock('@/components/plugins/plugin-slot', () => ({ PluginSlot: () => null }));
|
||||
vi.mock('@/components/tour/tour-provider', () => ({
|
||||
useTour: () => ({ startTour: vi.fn(), resetTourCompletion: vi.fn(), activeTour: null, endTour: vi.fn(), registerStep: vi.fn() }),
|
||||
}));
|
||||
vi.mock('@/contexts/drag-drop-context', () => ({
|
||||
useDragDropContext: () => ({ isDragging: false }),
|
||||
}));
|
||||
vi.mock('@/hooks/use-mailbox-drop', () => ({
|
||||
useMailboxDrop: () => ({ dropHandlers: {}, isValidDropTarget: false, isInvalidDropTarget: false }),
|
||||
}));
|
||||
vi.mock('@/hooks/use-tag-drop', () => ({
|
||||
useTagDrop: () => ({ dropHandlers: {}, isValidDropTarget: false }),
|
||||
}));
|
||||
vi.mock('../account-switcher', () => ({ AccountSwitcher: () => null }));
|
||||
|
||||
const { Sidebar } = await import('../sidebar');
|
||||
const { useSettingsStore } = await import('@/stores/settings-store');
|
||||
const { useUIStore } = await import('@/stores/ui-store');
|
||||
const { useAccountStore } = await import('@/stores/account-store');
|
||||
const { useAuthStore } = await import('@/stores/auth-store');
|
||||
|
||||
const box = (id: string, name: string, role: string | null, sortOrder: number, parentId: string | null = null) =>
|
||||
({ id, name, role, parentId, totalEmails: 0, unreadEmails: 0, sortOrder, myRights: { mayAddItems: true } });
|
||||
|
||||
const systemOnly = [
|
||||
box('inbox', 'Inbox', 'inbox', 0),
|
||||
box('drafts', 'Drafts', 'drafts', 1),
|
||||
box('sent', 'Sent', 'sent', 2),
|
||||
box('trash', 'Trash', 'trash', 3),
|
||||
];
|
||||
const withCustom = [
|
||||
...systemOnly,
|
||||
box('receipts', 'Receipts', null, 4),
|
||||
box('projects', 'Projects', null, 5),
|
||||
box('inbox-sub', 'Newsletters', null, 6, 'inbox'),
|
||||
] as unknown as Mailbox[];
|
||||
|
||||
const folderRow = (name: string) => document.querySelector(`[data-folder-name="${name}"]`);
|
||||
const inYourFolders = (name: string) =>
|
||||
document.querySelector(`[data-testid="section-your-folders"] [data-folder-name="${name}"]`);
|
||||
|
||||
describe('Sidebar "Your folders" section (#1205)', () => {
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
useUIStore.setState({ sidebarCollapsed: false } as never);
|
||||
useAccountStore.setState({ accounts: [] } as never);
|
||||
useSettingsStore.setState({
|
||||
emailKeywords: [],
|
||||
enableUnifiedMailbox: false,
|
||||
hideAccountSwitcher: true,
|
||||
} as never);
|
||||
});
|
||||
|
||||
it('lists the folders you made under their own heading, apart from the system folders', () => {
|
||||
render(<Sidebar mailboxes={withCustom} selectedMailbox="inbox" />);
|
||||
|
||||
expect(screen.getByText('your_folders')).toBeInTheDocument();
|
||||
expect(inYourFolders('Receipts')).not.toBeNull();
|
||||
expect(inYourFolders('Projects')).not.toBeNull();
|
||||
for (const name of ['Inbox', 'Drafts', 'Sent', 'Trash']) {
|
||||
expect(folderRow(name)).not.toBeNull();
|
||||
expect(inYourFolders(name)).toBeNull();
|
||||
}
|
||||
// The system folders all come before the first folder of your own.
|
||||
const rows = [...document.querySelectorAll('[data-folder-name]')].map((r) => r.getAttribute('data-folder-name'));
|
||||
expect(rows.indexOf('Trash')).toBeLessThan(rows.indexOf('Receipts'));
|
||||
});
|
||||
|
||||
it('keeps a folder nested under a system folder with its parent', () => {
|
||||
localStorage.setItem('expandedMailboxes', JSON.stringify(['inbox']));
|
||||
render(<Sidebar mailboxes={withCustom} selectedMailbox="inbox" />);
|
||||
|
||||
expect(folderRow('Newsletters')).not.toBeNull();
|
||||
expect(inYourFolders('Newsletters')).toBeNull();
|
||||
});
|
||||
|
||||
it('shows no section when there are no folders of your own', () => {
|
||||
render(<Sidebar mailboxes={systemOnly as unknown as Mailbox[]} selectedMailbox="inbox" />);
|
||||
|
||||
expect(screen.queryByText('your_folders')).toBeNull();
|
||||
expect(document.querySelector('[data-testid="section-your-folders"]')).toBeNull();
|
||||
expect(folderRow('Trash')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('collapses on its own and remembers it', () => {
|
||||
render(<Sidebar mailboxes={withCustom} selectedMailbox="inbox" />);
|
||||
|
||||
fireEvent.click(screen.getByText('your_folders'));
|
||||
expect(folderRow('Receipts')).toBeNull();
|
||||
// The system folders are untouched.
|
||||
expect(folderRow('Inbox')).not.toBeNull();
|
||||
|
||||
cleanup();
|
||||
render(<Sidebar mailboxes={withCustom} selectedMailbox="inbox" />);
|
||||
expect(screen.getByText('your_folders')).toBeInTheDocument();
|
||||
expect(folderRow('Receipts')).toBeNull();
|
||||
|
||||
fireEvent.click(screen.getByText('your_folders'));
|
||||
expect(folderRow('Receipts')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('creates a new folder from the heading', () => {
|
||||
const onCreateFolder = vi.fn();
|
||||
render(<Sidebar mailboxes={withCustom} selectedMailbox="inbox" onCreateFolder={onCreateFolder} />);
|
||||
|
||||
fireEvent.click(screen.getByLabelText('create_folder'));
|
||||
expect(onCreateFolder).toHaveBeenCalledTimes(1);
|
||||
// The click does not also fold the section away.
|
||||
expect(folderRow('Receipts')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('leaves Mountain View with its Labels list', () => {
|
||||
render(<Sidebar mailboxes={withCustom} selectedMailbox="inbox" mvShell />);
|
||||
|
||||
expect(screen.queryByText('your_folders')).toBeNull();
|
||||
expect(document.querySelector('[data-mv-labels] [data-folder-name="Receipts"]')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('splits every account group in the Pro layout', () => {
|
||||
const account = (id: string) => ({
|
||||
id, label: `${id}@example.com`, email: `${id}@example.com`, username: `${id}@example.com`,
|
||||
cookieSlot: id === 'a' ? 0 : 1, isConnected: true,
|
||||
});
|
||||
useAccountStore.setState({ accounts: [account('a'), account('b')] } as never);
|
||||
useAuthStore.setState({ activeAccountId: 'a' } as never);
|
||||
const other = [box('b-inbox', 'Inbox', 'inbox', 0), box('b-clients', 'Clients', null, 1)] as unknown as Mailbox[];
|
||||
|
||||
render(
|
||||
<Sidebar mailboxes={withCustom} selectedMailbox="inbox" multiAccountMode accountMailboxes={{ b: other }} />,
|
||||
);
|
||||
|
||||
expect(screen.getAllByText('your_folders')).toHaveLength(2);
|
||||
expect(inYourFolders('Receipts')).not.toBeNull();
|
||||
expect(inYourFolders('Clients')).not.toBeNull();
|
||||
expect(inYourFolders('Inbox')).toBeNull();
|
||||
|
||||
// Each account's section folds on its own.
|
||||
fireEvent.click(screen.getByTestId('section-your-folders-header-b'));
|
||||
expect(folderRow('Clients')).toBeNull();
|
||||
expect(folderRow('Receipts')).not.toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -447,6 +447,11 @@ function SidebarRow({
|
||||
);
|
||||
}
|
||||
|
||||
/** A folder the server gave a role (inbox, sent, trash...), as opposed to one the user made. */
|
||||
const isSystemFolder = (node: MailboxNode) => !!node.role;
|
||||
/** Key of the single-account "Your folders" section in the collapsed set. */
|
||||
const OWN_FOLDERS_KEY = '__own__';
|
||||
|
||||
function SidebarSectionHeader({
|
||||
label,
|
||||
expanded,
|
||||
@@ -460,12 +465,16 @@ function SidebarSectionHeader({
|
||||
testId,
|
||||
onContextMenu,
|
||||
status,
|
||||
onAdd,
|
||||
addTitle,
|
||||
}: {
|
||||
label: string;
|
||||
expanded: boolean;
|
||||
onToggle: () => void;
|
||||
onSettings?: () => void;
|
||||
settingsTitle?: string;
|
||||
onAdd?: () => void;
|
||||
addTitle?: string;
|
||||
isCollapsed: boolean;
|
||||
first?: boolean;
|
||||
icon?: ReactNode;
|
||||
@@ -508,6 +517,28 @@ function SidebarSectionHeader({
|
||||
{label}
|
||||
</span>
|
||||
{status}
|
||||
{onAdd && (
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onAdd();
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onAdd();
|
||||
}
|
||||
}}
|
||||
className="ms-auto p-1 rounded text-muted-foreground/70 hover:text-foreground hover:bg-muted transition-colors cursor-pointer"
|
||||
title={addTitle}
|
||||
aria-label={addTitle}
|
||||
>
|
||||
<Plus className="w-3.5 h-3.5" />
|
||||
</span>
|
||||
)}
|
||||
{onSettings && (
|
||||
<span
|
||||
role="button"
|
||||
@@ -523,7 +554,7 @@ function SidebarSectionHeader({
|
||||
onSettings();
|
||||
}
|
||||
}}
|
||||
className="ms-auto p-1 rounded text-muted-foreground/70 hover:text-foreground hover:bg-muted transition-colors cursor-pointer"
|
||||
className={cn(!onAdd && "ms-auto", "p-1 rounded text-muted-foreground/70 hover:text-foreground hover:bg-muted transition-colors cursor-pointer")}
|
||||
title={settingsTitle}
|
||||
>
|
||||
<Settings className="w-3.5 h-3.5" />
|
||||
@@ -966,6 +997,15 @@ function SidebarImpl({
|
||||
} catch { /* fall through */ }
|
||||
return new Set();
|
||||
});
|
||||
// "Your folders" sections the user has collapsed: OWN_FOLDERS_KEY for the
|
||||
// single-account list, the accountId for each Pro account group.
|
||||
const [collapsedCustomFolders, setCollapsedCustomFolders] = useState<Set<string>>(() => {
|
||||
try {
|
||||
const stored = localStorage.getItem('sidebarCollapsedCustomFolders');
|
||||
if (stored !== null) return new Set(JSON.parse(stored) as string[]);
|
||||
} catch { /* fall through */ }
|
||||
return new Set();
|
||||
});
|
||||
const emailKeywords = useSettingsStore(s => s.emailKeywords);
|
||||
const nestedTags = useSettingsStore(s => s.nestedTags);
|
||||
const isEmbedded = useIsEmbedded();
|
||||
@@ -1102,7 +1142,12 @@ function SidebarImpl({
|
||||
const mvFlat = mvShell && !isCollapsed;
|
||||
const isPrimaryFolder = (node: MailboxNode) =>
|
||||
node.role === 'inbox' || node.role === 'sent' || node.role === 'drafts';
|
||||
const primaryTree = mvFlat ? ownTree.filter(isPrimaryFolder) : ownTree;
|
||||
// Everywhere else the folders the user made sit in a "Your folders" section
|
||||
// of their own below the system folders (#1205). Folders nested under a
|
||||
// system folder stay with their parent. With no folders of your own there is
|
||||
// no section, so the list looks as it always did.
|
||||
const primaryTree = mvFlat ? ownTree.filter(isPrimaryFolder) : ownTree.filter(isSystemFolder);
|
||||
const customTree = mvFlat ? [] : ownTree.filter((node) => !isSystemFolder(node));
|
||||
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",
|
||||
@@ -1185,6 +1230,59 @@ function SidebarImpl({
|
||||
);
|
||||
};
|
||||
|
||||
// The "Your folders" section: the user's own top-level folders, under a
|
||||
// heading of their own that collapses and offers to make a new one.
|
||||
const renderCustomFolders = (
|
||||
key: string,
|
||||
tree: MailboxNode[],
|
||||
{
|
||||
sub = false,
|
||||
selected,
|
||||
onSelect,
|
||||
active = true,
|
||||
dragAccountId,
|
||||
}: {
|
||||
sub?: boolean;
|
||||
selected: string;
|
||||
onSelect?: (mailboxId: string) => void;
|
||||
active?: boolean;
|
||||
dragAccountId?: string | null;
|
||||
},
|
||||
) => {
|
||||
if (tree.length === 0) return null;
|
||||
const expanded = !collapsedCustomFolders.has(key);
|
||||
return (
|
||||
// A Pro account group already carries the folders menu for the whole group.
|
||||
<div data-testid="section-your-folders" onContextMenu={active && !sub ? handleFoldersHeaderContextMenu : undefined}>
|
||||
<SidebarSectionHeader
|
||||
label={t("your_folders")}
|
||||
expanded={expanded}
|
||||
onToggle={() => toggleCustomFolders(key)}
|
||||
onAdd={active && onCreateFolder ? () => onCreateFolder() : undefined}
|
||||
addTitle={t("create_folder")}
|
||||
isCollapsed={isCollapsed}
|
||||
sub={sub}
|
||||
testId={`section-your-folders-header-${key}`}
|
||||
/>
|
||||
{((expanded && !isCollapsed) || isCollapsed) && tree.map((node) => (
|
||||
<MailboxTreeItem
|
||||
key={node.id}
|
||||
node={node}
|
||||
selectedMailbox={selected}
|
||||
expandedFolders={expandedFolders}
|
||||
onMailboxSelect={onSelect}
|
||||
onToggleExpand={handleToggleExpand}
|
||||
isCollapsed={isCollapsed}
|
||||
onUnreadFilterClick={active ? onUnreadFilterClick : undefined}
|
||||
colorful={colorfulSidebarIcons}
|
||||
onContextMenu={active ? handleMailboxContextMenu : undefined}
|
||||
dragAccountId={dragAccountId}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const getUnifiedIcon = (role: UnifiedMailboxRole) => {
|
||||
switch (role) {
|
||||
case 'inbox': return Inbox;
|
||||
@@ -1278,6 +1376,14 @@ function SidebarImpl({
|
||||
return next;
|
||||
});
|
||||
};
|
||||
const toggleCustomFolders = (key: string) => {
|
||||
setCollapsedCustomFolders((prev) => {
|
||||
const next = new Set(prev);
|
||||
if (next.has(key)) next.delete(key); else next.add(key);
|
||||
try { localStorage.setItem('sidebarCollapsedCustomFolders', JSON.stringify(Array.from(next))); } catch { /* */ }
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
// The tab now travels in the URL (#733) rather than through sessionStorage,
|
||||
// so a gear click is a link the user can also bookmark or share. It still
|
||||
@@ -1516,7 +1622,7 @@ function SidebarImpl({
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{tree.map((node) => (
|
||||
{tree.filter(isSystemFolder).map((node) => (
|
||||
<Fragment key={node.id}>
|
||||
<MailboxTreeItem
|
||||
node={node}
|
||||
@@ -1536,6 +1642,13 @@ function SidebarImpl({
|
||||
</Fragment>
|
||||
))}
|
||||
{isActive && !tree.some((node) => node.role === 'drafts') && renderScheduledRow(`scheduled-${account.id}`)}
|
||||
{renderCustomFolders(account.id, tree.filter((node) => !isSystemFolder(node)), {
|
||||
sub: true,
|
||||
selected: selectedKeyword || !isViewing ? "" : selectedMailbox,
|
||||
onSelect: (mailboxId) => onAccountMailboxSelect?.(isActive ? null : account.id, mailboxId),
|
||||
active: isActive,
|
||||
dragAccountId: isActive ? null : account.id,
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
@@ -1628,6 +1741,11 @@ function SidebarImpl({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!useMultiAccount && renderCustomFolders(OWN_FOLDERS_KEY, customTree, {
|
||||
selected: selectedKeyword ? "" : selectedMailbox,
|
||||
onSelect: onMailboxSelect,
|
||||
})}
|
||||
|
||||
{mvFlat && !useMultiAccount && (
|
||||
<div data-mv-labels="">
|
||||
<div className="flex items-center justify-between ps-[26px] pe-3 pt-4 pb-1">
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "إظهار الكل ({count})",
|
||||
"show_fewer_tags": "إظهار أقل",
|
||||
"folders": "المجلدات",
|
||||
"your_folders": "مجلداتك",
|
||||
"create_folder": "إنشاء مجلد",
|
||||
"show_more": "المزيد",
|
||||
"show_fewer": "أقل",
|
||||
"shared": "مشترك",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Mostra-ho tot ({count})",
|
||||
"show_fewer_tags": "Mostra'n menys",
|
||||
"folders": "Carpetes",
|
||||
"your_folders": "Les teves carpetes",
|
||||
"create_folder": "Crea una carpeta",
|
||||
"show_more": "Més",
|
||||
"show_fewer": "Menys",
|
||||
"shared": "Compartit",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Zobrazit vše ({count})",
|
||||
"show_fewer_tags": "Zobrazit méně",
|
||||
"folders": "Složky",
|
||||
"your_folders": "Vaše složky",
|
||||
"create_folder": "Vytvořit složku",
|
||||
"show_more": "Více",
|
||||
"show_fewer": "Méně",
|
||||
"shared": "Sdílené",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Vis alle ({count})",
|
||||
"show_fewer_tags": "Vis færre",
|
||||
"folders": "Mapper",
|
||||
"your_folders": "Dine mapper",
|
||||
"create_folder": "Opret mappe",
|
||||
"show_more": "Mere",
|
||||
"show_fewer": "Mindre",
|
||||
"shared": "Delt",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Alle anzeigen ({count})",
|
||||
"show_fewer_tags": "Weniger anzeigen",
|
||||
"folders": "Ordner",
|
||||
"your_folders": "Eigene Ordner",
|
||||
"create_folder": "Ordner erstellen",
|
||||
"show_more": "Mehr",
|
||||
"show_fewer": "Weniger",
|
||||
"mail": "E-Mail",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Show all ({count})",
|
||||
"show_fewer_tags": "Show less",
|
||||
"folders": "Folders",
|
||||
"your_folders": "Your folders",
|
||||
"create_folder": "Create folder",
|
||||
"show_more": "More",
|
||||
"show_fewer": "Less",
|
||||
"shared": "Shared",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Mostrar todo ({count})",
|
||||
"show_fewer_tags": "Mostrar menos",
|
||||
"folders": "Carpetas",
|
||||
"your_folders": "Tus carpetas",
|
||||
"create_folder": "Crear carpeta",
|
||||
"show_more": "Más",
|
||||
"show_fewer": "Menos",
|
||||
"mail": "Correo",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "نمایش همه ({count})",
|
||||
"show_fewer_tags": "نمایش کمتر",
|
||||
"folders": "پوشهها",
|
||||
"your_folders": "پوشههای شما",
|
||||
"create_folder": "ایجاد پوشه",
|
||||
"show_more": "بیشتر",
|
||||
"show_fewer": "کمتر",
|
||||
"shared": "اشتراکی",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Tout afficher ({count})",
|
||||
"show_fewer_tags": "Afficher moins",
|
||||
"folders": "Dossiers",
|
||||
"your_folders": "Vos dossiers",
|
||||
"create_folder": "Créer un dossier",
|
||||
"show_more": "Plus",
|
||||
"show_fewer": "Moins",
|
||||
"mail": "Messagerie",
|
||||
|
||||
@@ -133,6 +133,8 @@
|
||||
"show_all_tags": "הצג הכל ({count})",
|
||||
"show_fewer_tags": "הצג פחות",
|
||||
"folders": "תיקיות",
|
||||
"your_folders": "התיקיות שלך",
|
||||
"create_folder": "יצירת תיקייה",
|
||||
"show_more": "עוד",
|
||||
"show_fewer": "פחות",
|
||||
"mail": "דוֹאַר",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Összes megjelenítése ({count})",
|
||||
"show_fewer_tags": "Kevesebb megjelenítése",
|
||||
"folders": "Mappák",
|
||||
"your_folders": "Saját mappák",
|
||||
"create_folder": "Mappa létrehozása",
|
||||
"show_more": "Több",
|
||||
"show_fewer": "Kevesebb",
|
||||
"shared": "Megosztott",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Mostra tutto ({count})",
|
||||
"show_fewer_tags": "Mostra meno",
|
||||
"folders": "Cartelle",
|
||||
"your_folders": "Le tue cartelle",
|
||||
"create_folder": "Crea cartella",
|
||||
"show_more": "Altro",
|
||||
"show_fewer": "Riduci",
|
||||
"mail": "Posta",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "すべて表示({count})",
|
||||
"show_fewer_tags": "表示を減らす",
|
||||
"folders": "フォルダ",
|
||||
"your_folders": "マイフォルダ",
|
||||
"create_folder": "フォルダを作成",
|
||||
"show_more": "もっと見る",
|
||||
"show_fewer": "折りたたむ",
|
||||
"mail": "メール",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "전체 보기({count})",
|
||||
"show_fewer_tags": "간략히 보기",
|
||||
"folders": "폴더",
|
||||
"your_folders": "내 폴더",
|
||||
"create_folder": "폴더 만들기",
|
||||
"show_more": "더보기",
|
||||
"show_fewer": "간략히",
|
||||
"mail": "메일",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Rādīt visus ({count})",
|
||||
"show_fewer_tags": "Rādīt mazāk",
|
||||
"folders": "Mapes",
|
||||
"your_folders": "Jūsu mapes",
|
||||
"create_folder": "Izveidot mapi",
|
||||
"show_more": "Vairāk",
|
||||
"show_fewer": "Mazāk",
|
||||
"mail": "Pasts",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Бүгдийг нь харуулах ({count})",
|
||||
"show_fewer_tags": "Бага харуулах",
|
||||
"folders": "Хавтас",
|
||||
"your_folders": "Таны хавтаснууд",
|
||||
"create_folder": "Хавтас үүсгэх",
|
||||
"show_more": "Илүү",
|
||||
"show_fewer": "Бага",
|
||||
"shared": "Хуваалцсан",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Vis alle ({count})",
|
||||
"show_fewer_tags": "Vis færre",
|
||||
"folders": "Mapper",
|
||||
"your_folders": "Dine mapper",
|
||||
"create_folder": "Opprett mappe",
|
||||
"show_more": "Mer",
|
||||
"show_fewer": "Mindre",
|
||||
"shared": "Delt",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Alles tonen ({count})",
|
||||
"show_fewer_tags": "Minder tonen",
|
||||
"folders": "Mappen",
|
||||
"your_folders": "Je mappen",
|
||||
"create_folder": "Map maken",
|
||||
"show_more": "Meer",
|
||||
"show_fewer": "Minder",
|
||||
"mail": "E-mail",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Pokaż wszystkie ({count})",
|
||||
"show_fewer_tags": "Pokaż mniej",
|
||||
"folders": "Foldery",
|
||||
"your_folders": "Twoje foldery",
|
||||
"create_folder": "Utwórz folder",
|
||||
"show_more": "Więcej",
|
||||
"show_fewer": "Mniej",
|
||||
"mail": "Poczta",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Mostrar tudo ({count})",
|
||||
"show_fewer_tags": "Mostrar menos",
|
||||
"folders": "Pastas",
|
||||
"your_folders": "As suas pastas",
|
||||
"create_folder": "Criar pasta",
|
||||
"show_more": "Mais",
|
||||
"show_fewer": "Menos",
|
||||
"mail": "E-mail",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Afișează tot ({count})",
|
||||
"show_fewer_tags": "Afișează mai puține",
|
||||
"folders": "Dosare",
|
||||
"your_folders": "Dosarele tale",
|
||||
"create_folder": "Creează dosar",
|
||||
"show_more": "Mai multe",
|
||||
"show_fewer": "Mai puține",
|
||||
"shared": "Partajat",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Показать все ({count})",
|
||||
"show_fewer_tags": "Показать меньше",
|
||||
"folders": "Папки",
|
||||
"your_folders": "Ваши папки",
|
||||
"create_folder": "Создать папку",
|
||||
"show_more": "Ещё",
|
||||
"show_fewer": "Свернуть",
|
||||
"mail": "Почта",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Zobraziť všetko ({count})",
|
||||
"show_fewer_tags": "Zobraziť menej",
|
||||
"folders": "Priečinky",
|
||||
"your_folders": "Vaše priečinky",
|
||||
"create_folder": "Vytvoriť priečinok",
|
||||
"show_more": "Viac",
|
||||
"show_fewer": "Menej",
|
||||
"shared": "Zdieľané",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Tümünü göster ({count})",
|
||||
"show_fewer_tags": "Daha az göster",
|
||||
"folders": "Klasörler",
|
||||
"your_folders": "Klasörleriniz",
|
||||
"create_folder": "Klasör oluştur",
|
||||
"show_more": "Diğer",
|
||||
"show_fewer": "Daha az",
|
||||
"shared": "Paylaşılan",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "Показати всі ({count})",
|
||||
"show_fewer_tags": "Показати менше",
|
||||
"folders": "Папки",
|
||||
"your_folders": "Ваші теки",
|
||||
"create_folder": "Створити теку",
|
||||
"show_more": "Більше",
|
||||
"show_fewer": "Менше",
|
||||
"mail": "Пошта",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "顯示全部({count})",
|
||||
"show_fewer_tags": "顯示較少",
|
||||
"folders": "信件匣",
|
||||
"your_folders": "我的資料夾",
|
||||
"create_folder": "建立資料夾",
|
||||
"show_more": "更多",
|
||||
"show_fewer": "收合",
|
||||
"shared": "共用",
|
||||
|
||||
@@ -142,6 +142,8 @@
|
||||
"show_all_tags": "显示全部({count})",
|
||||
"show_fewer_tags": "收起",
|
||||
"folders": "文件夹",
|
||||
"your_folders": "我的文件夹",
|
||||
"create_folder": "新建文件夹",
|
||||
"show_more": "更多",
|
||||
"show_fewer": "收起",
|
||||
"mail": "邮件",
|
||||
|
||||
Reference in New Issue
Block a user