mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-01 08:12:43 +00:00
fix: show folder names in the phone folder settings and move the row actions into a menu
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import { fireEvent, render, screen, within } from '@testing-library/react';
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { FolderSettings } from '../folder-settings';
|
||||
import { useEmailStore } from '@/stores/email-store';
|
||||
import { useAuthStore } from '@/stores/auth-store';
|
||||
import { useSettingsStore } from '@/stores/settings-store';
|
||||
import type { Mailbox } from '@/lib/jmap/types';
|
||||
|
||||
// On the phone the counter select and the row's icon buttons left no room
|
||||
// for the folder name. They sit behind a ⋮ there, which right-click opens
|
||||
// too, and the name keeps its full text in a tooltip.
|
||||
|
||||
vi.mock('../settings-section', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import('../settings-section')>()),
|
||||
SettingsSection: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
|
||||
}));
|
||||
|
||||
const rights = {
|
||||
mayReadItems: true, mayAddItems: true, mayRemoveItems: true, maySetSeen: true, maySetKeywords: true,
|
||||
mayCreateChild: true, mayRename: true, mayDelete: true, maySubmit: true,
|
||||
};
|
||||
|
||||
function makeMailbox(overrides: Partial<Mailbox>): Mailbox {
|
||||
return {
|
||||
id: 'mb', name: 'Folder', sortOrder: 0, totalEmails: 0, unreadEmails: 0, totalThreads: 0, unreadThreads: 0,
|
||||
myRights: rights, isSubscribed: true, isShared: false, ...overrides,
|
||||
} as Mailbox;
|
||||
}
|
||||
|
||||
describe('FolderSettings row actions menu', () => {
|
||||
beforeEach(() => {
|
||||
useAuthStore.setState({ client: null } as never);
|
||||
useSettingsStore.setState({ folderCountModes: {} } as never);
|
||||
useEmailStore.setState({
|
||||
mailboxes: [makeMailbox({ id: 'projects', name: 'Projects with a long name' })],
|
||||
fetchMailboxes: vi.fn(),
|
||||
} as never);
|
||||
});
|
||||
|
||||
it('opens the row actions from a named ⋮ and sets the counter from it', () => {
|
||||
render(<FolderSettings />);
|
||||
expect(screen.getByTitle('Projects with a long name')).toBeTruthy();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'actions' }));
|
||||
const menu = screen.getByRole('menu');
|
||||
expect(within(menu).getByRole('menuitem', { name: 'create_subfolder' })).toBeTruthy();
|
||||
expect(within(menu).getByRole('menuitem', { name: 'rename' })).toBeTruthy();
|
||||
expect(within(menu).getByRole('menuitem', { name: 'delete' })).toBeTruthy();
|
||||
|
||||
fireEvent.click(within(menu).getByRole('menuitem', { name: 'counter' }));
|
||||
fireEvent.click(screen.getByRole('menuitem', { name: 'count_mode_none' }));
|
||||
expect(useSettingsStore.getState().folderCountModes).toEqual({ projects: 'none' });
|
||||
});
|
||||
|
||||
it('opens the same menu on right-click and starts renaming from it', () => {
|
||||
render(<FolderSettings />);
|
||||
fireEvent.contextMenu(screen.getByTitle('Projects with a long name'), { clientX: 20, clientY: 20 });
|
||||
fireEvent.click(screen.getByRole('menuitem', { name: 'rename' }));
|
||||
expect((screen.getByDisplayValue('Projects with a long name') as HTMLInputElement).tagName).toBe('INPUT');
|
||||
});
|
||||
|
||||
it('names the expand toggle of a folder with subfolders', () => {
|
||||
useEmailStore.setState({
|
||||
mailboxes: [
|
||||
makeMailbox({ id: 'p', name: 'Parent' }),
|
||||
makeMailbox({ id: 'c', name: 'Child', parentId: 'p' }),
|
||||
],
|
||||
} as never);
|
||||
render(<FolderSettings />);
|
||||
const toggle = screen.getByRole('button', { name: 'expand' });
|
||||
expect(toggle.getAttribute('aria-expanded')).toBe('false');
|
||||
});
|
||||
});
|
||||
@@ -14,8 +14,12 @@ import {
|
||||
Star, Heart, Bookmark, Tag, Flag, Briefcase, Users,
|
||||
Bell, Zap, Globe, Lock, Eye, MessageSquare, Mail,
|
||||
AlertTriangle, NotebookPen, CalendarClock, BellOff, CheckSquare, Square,
|
||||
MoreVertical, Palette, ListOrdered,
|
||||
type AppIcon,
|
||||
} from '@/components/icons';
|
||||
import { IconButton } from '@/components/ui/icon-button';
|
||||
import { ContextMenu, ContextMenuItem, ContextMenuSeparator, ContextMenuSubMenu } from '@/components/ui/context-menu';
|
||||
import { useContextMenu } from '@/hooks/use-context-menu';
|
||||
import { cn, buildMailboxTree, flattenMailboxTree, type MailboxNode } from '@/lib/utils';
|
||||
import { jmapErrorType } from '@/lib/jmap/jmap-error';
|
||||
import {
|
||||
@@ -201,6 +205,9 @@ export function FolderSettings() {
|
||||
const [moveTarget, setMoveTarget] = useState('');
|
||||
const [isMoving, setIsMoving] = useState(false);
|
||||
|
||||
// The row's actions: the ⋮ on the phone and right-click everywhere.
|
||||
const { contextMenu, openContextMenu, openContextMenuFrom, closeContextMenu, menuRef } = useContextMenu<MailboxNode>();
|
||||
|
||||
const ownMailboxes = mailboxes.filter(mb => !mb.isShared);
|
||||
const folderTree = buildMailboxTree(ownMailboxes);
|
||||
|
||||
@@ -502,7 +509,7 @@ export function FolderSettings() {
|
||||
return (
|
||||
<div
|
||||
className="flex items-center gap-2 mt-1 p-2.5 bg-muted/30 rounded-md border border-border"
|
||||
style={{ marginLeft: depth * 16 }}
|
||||
style={{ marginInlineStart: depth * 16 }}
|
||||
>
|
||||
<FolderPlus className="w-4 h-4 text-primary flex-shrink-0" />
|
||||
<div className="flex-1 flex flex-col gap-1">
|
||||
@@ -563,7 +570,7 @@ export function FolderSettings() {
|
||||
if (editingId === mb.id) {
|
||||
return (
|
||||
<div key={mb.id}>
|
||||
<div className="flex items-center gap-2 py-2 px-3" style={{ paddingLeft: 12 + depth * 16 }}>
|
||||
<div className="flex items-center gap-2 py-2 px-3" style={{ paddingInlineStart: 12 + depth * 16 }}>
|
||||
<Icon className="w-4 h-4 text-muted-foreground flex-shrink-0" />
|
||||
<input
|
||||
type="text"
|
||||
@@ -600,7 +607,7 @@ export function FolderSettings() {
|
||||
if (deletingId === mb.id) {
|
||||
return (
|
||||
<div key={mb.id}>
|
||||
<div className="flex items-center gap-3 py-2.5 px-3 bg-destructive/5 rounded-md border border-destructive/20" style={{ marginLeft: depth * 16 }}>
|
||||
<div className="flex items-center gap-3 py-2.5 px-3 bg-destructive/5 rounded-md border border-destructive/20" style={{ marginInlineStart: depth * 16 }}>
|
||||
<Trash2 className="w-4 h-4 text-destructive flex-shrink-0" />
|
||||
<p className="text-sm text-foreground flex-1">
|
||||
{t('confirm_delete', { name: mb.name })}
|
||||
@@ -628,10 +635,14 @@ export function FolderSettings() {
|
||||
<SortableFolderRow id={mb.id} title={t('reorder')}>
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-center justify-between py-2 px-3 rounded-md hover:bg-muted/50",
|
||||
isSelected && "bg-muted",
|
||||
"flex items-center justify-between gap-1 py-2 px-3 rounded-md hover:bg-muted/50",
|
||||
isSelected && "bg-selection",
|
||||
)}
|
||||
style={{ paddingLeft: 12 + depth * 16 }}
|
||||
style={{ paddingInlineStart: 12 + depth * 16 }}
|
||||
onContextMenu={(e) => {
|
||||
if ((e.target as HTMLElement).closest('input, select')) return;
|
||||
openContextMenu(e, mb);
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-2.5 min-w-0">
|
||||
{mb.myRights?.mayRename ? (
|
||||
@@ -659,15 +670,17 @@ export function FolderSettings() {
|
||||
)}
|
||||
{/* Expand/collapse toggle for folders with children */}
|
||||
{hasChildren ? (
|
||||
<button
|
||||
<IconButton
|
||||
label={isExpanded ? t('collapse', { name: mb.name }) : t('expand', { name: mb.name })}
|
||||
aria-expanded={isExpanded}
|
||||
onClick={() => toggleExpanded(mb.id)}
|
||||
className="p-0.5 text-muted-foreground hover:text-foreground rounded transition-colors flex-shrink-0"
|
||||
className="h-5 w-5 text-muted-foreground flex-shrink-0"
|
||||
>
|
||||
{isExpanded
|
||||
? <ChevronDown className="w-3.5 h-3.5" />
|
||||
: <ChevronRight className="w-3.5 h-3.5" />
|
||||
}
|
||||
</button>
|
||||
</IconButton>
|
||||
) : (
|
||||
<span className="w-4.5 flex-shrink-0" />
|
||||
)}
|
||||
@@ -707,7 +720,7 @@ export function FolderSettings() {
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<span className="text-sm text-foreground truncate">{mb.name}</span>
|
||||
<span className="text-sm text-foreground truncate" title={mb.name} dir="auto">{mb.name}</span>
|
||||
{mb.role && (
|
||||
<span className="text-xs px-1.5 py-0.5 rounded-full bg-primary/10 text-primary font-medium flex-shrink-0">
|
||||
{t(`role_${mb.role}`)}
|
||||
@@ -719,48 +732,49 @@ export function FolderSettings() {
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-0.5">
|
||||
{/* Phone: the counter and the row actions don't fit next to the
|
||||
name, so they sit behind a ⋮ (right-click opens it too). */}
|
||||
<IconButton
|
||||
label={t('actions', { name: mb.name })}
|
||||
className="sm:hidden flex-shrink-0 text-muted-foreground"
|
||||
onClick={(e) => openContextMenuFrom(e.currentTarget, mb, 'end')}
|
||||
>
|
||||
<MoreVertical />
|
||||
</IconButton>
|
||||
<div className="hidden sm:flex items-center gap-0.5 flex-shrink-0">
|
||||
<Select
|
||||
value={folderCountModes?.[mb.id] ?? ''}
|
||||
onChange={(value) => {
|
||||
const { [mb.id]: _, ...rest } = folderCountModes ?? {};
|
||||
updateSetting('folderCountModes', isFolderCountMode(value) ? { ...rest, [mb.id]: value } : rest);
|
||||
}}
|
||||
onChange={(value) => setCountMode(mb.id, value)}
|
||||
ariaLabel={t('count_mode', { name: mb.name })}
|
||||
className="px-1.5 py-0.5 text-xs max-w-[9rem]"
|
||||
options={[
|
||||
{ value: '', label: t('count_mode_default') },
|
||||
{ value: 'unread', label: t('count_mode_unread') },
|
||||
{ value: 'all', label: t('count_mode_all') },
|
||||
{ value: 'none', label: t('count_mode_none') },
|
||||
]}
|
||||
options={countModeOptions}
|
||||
/>
|
||||
{mb.myRights?.mayCreateChild && (
|
||||
<button
|
||||
<IconButton
|
||||
label={t('create_subfolder')}
|
||||
onClick={() => startCreateSubfolder(mb.id)}
|
||||
className="p-1.5 text-muted-foreground hover:text-foreground hover:bg-accent rounded-md transition-colors"
|
||||
title={t('create_subfolder')}
|
||||
className="text-muted-foreground"
|
||||
>
|
||||
<FolderPlus className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
<FolderPlus />
|
||||
</IconButton>
|
||||
)}
|
||||
{mb.myRights?.mayRename && (
|
||||
<button
|
||||
<IconButton
|
||||
label={t('rename')}
|
||||
onClick={() => startEdit(mb)}
|
||||
className="p-1.5 text-muted-foreground hover:text-foreground hover:bg-accent rounded-md transition-colors"
|
||||
title={t('rename')}
|
||||
className="text-muted-foreground"
|
||||
>
|
||||
<Pencil className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
<Pencil />
|
||||
</IconButton>
|
||||
)}
|
||||
{mb.myRights?.mayDelete && !mb.role && (
|
||||
<button
|
||||
<IconButton
|
||||
label={t('delete')}
|
||||
onClick={() => setDeletingId(mb.id)}
|
||||
className="p-1.5 text-muted-foreground hover:text-destructive hover:bg-destructive/10 rounded-md transition-colors"
|
||||
title={t('delete')}
|
||||
className="text-muted-foreground hover:text-destructive hover:bg-destructive/10"
|
||||
>
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
<Trash2 />
|
||||
</IconButton>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -771,8 +785,58 @@ export function FolderSettings() {
|
||||
);
|
||||
};
|
||||
|
||||
const countModeOptions = [
|
||||
{ value: '', label: t('count_mode_default') },
|
||||
{ value: 'unread', label: t('count_mode_unread') },
|
||||
{ value: 'all', label: t('count_mode_all') },
|
||||
{ value: 'none', label: t('count_mode_none') },
|
||||
];
|
||||
|
||||
const setCountMode = (id: string, value: string) => {
|
||||
const { [id]: _, ...rest } = folderCountModes ?? {};
|
||||
updateSetting('folderCountModes', isFolderCountMode(value) ? { ...rest, [id]: value } : rest);
|
||||
};
|
||||
|
||||
const renderRowMenu = () => {
|
||||
const mb = contextMenu.data;
|
||||
if (!mb) return null;
|
||||
const current = folderCountModes?.[mb.id] ?? '';
|
||||
const run = (fn: () => void) => () => { closeContextMenu(); fn(); };
|
||||
const canDelete = mb.myRights?.mayDelete && !mb.role;
|
||||
return (
|
||||
<ContextMenu ref={menuRef} isOpen={contextMenu.isOpen} position={contextMenu.position} onClose={closeContextMenu}>
|
||||
{mb.myRights?.mayCreateChild && (
|
||||
<ContextMenuItem icon={FolderPlus} label={t('create_subfolder')} onClick={run(() => startCreateSubfolder(mb.id))} />
|
||||
)}
|
||||
{mb.myRights?.mayRename && (
|
||||
<ContextMenuItem icon={Pencil} label={t('rename')} onClick={run(() => startEdit(mb))} />
|
||||
)}
|
||||
{folderIconsAllowed && (
|
||||
<ContextMenuItem icon={Palette} label={t('change_icon')} onClick={run(() => setIconPickerId(mb.id))} />
|
||||
)}
|
||||
<ContextMenuSubMenu icon={ListOrdered} label={t('counter')}>
|
||||
{countModeOptions.map((option) => (
|
||||
<ContextMenuItem
|
||||
key={option.value}
|
||||
icon={current === option.value ? Check : undefined}
|
||||
label={option.label}
|
||||
onClick={run(() => setCountMode(mb.id, option.value))}
|
||||
/>
|
||||
))}
|
||||
</ContextMenuSubMenu>
|
||||
{canDelete && (
|
||||
<>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem icon={Trash2} label={t('delete')} destructive onClick={run(() => setDeletingId(mb.id))} />
|
||||
</>
|
||||
)}
|
||||
</ContextMenu>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
{renderRowMenu()}
|
||||
{/* Folder List - primary section */}
|
||||
<SettingsSection id="folders" title={t('folder_list')} description={t('folder_list_description')}>
|
||||
{selectedCount > 0 && (
|
||||
|
||||
@@ -2099,6 +2099,10 @@
|
||||
"new_folder_name": "اسم المجلد",
|
||||
"rename": "إعادة تسمية",
|
||||
"change_icon": "تغيير الأيقونة",
|
||||
"actions": "إجراءات {name}",
|
||||
"expand": "توسيع {name}",
|
||||
"collapse": "طي {name}",
|
||||
"counter": "العداد",
|
||||
"count_mode": "العداد لـ {name}",
|
||||
"count_mode_default": "العداد: افتراضي",
|
||||
"count_mode_unread": "غير المقروءة فقط",
|
||||
|
||||
@@ -2099,6 +2099,10 @@
|
||||
"new_folder_name": "Nom de la carpeta",
|
||||
"rename": "Canvia el nom",
|
||||
"change_icon": "Canvia la icona",
|
||||
"actions": "Accions per a {name}",
|
||||
"expand": "Desplega {name}",
|
||||
"collapse": "Plega {name}",
|
||||
"counter": "Comptador",
|
||||
"count_mode": "Comptador per a {name}",
|
||||
"count_mode_default": "Comptador: per defecte",
|
||||
"count_mode_unread": "Només no llegits",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "Název složky",
|
||||
"rename": "Přejmenovat",
|
||||
"change_icon": "Změnit ikonu",
|
||||
"actions": "Akce pro {name}",
|
||||
"expand": "Rozbalit {name}",
|
||||
"collapse": "Sbalit {name}",
|
||||
"counter": "Počítadlo",
|
||||
"count_mode": "Počítadlo pro {name}",
|
||||
"count_mode_default": "Počítadlo: výchozí",
|
||||
"count_mode_unread": "Jen nepřečtené",
|
||||
|
||||
@@ -2095,6 +2095,10 @@
|
||||
"new_folder_name": "Mappenavn",
|
||||
"rename": "Omdøb",
|
||||
"change_icon": "Skift ikon",
|
||||
"actions": "Handlinger for {name}",
|
||||
"expand": "Fold {name} ud",
|
||||
"collapse": "Fold {name} sammen",
|
||||
"counter": "Tæller",
|
||||
"count_mode": "Tæller for {name}",
|
||||
"count_mode_default": "Tæller: standard",
|
||||
"count_mode_unread": "Kun ulæste",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "Ordnername",
|
||||
"rename": "Umbenennen",
|
||||
"change_icon": "Symbol ändern",
|
||||
"actions": "Aktionen für {name}",
|
||||
"expand": "{name} aufklappen",
|
||||
"collapse": "{name} zuklappen",
|
||||
"counter": "Zähler",
|
||||
"count_mode": "Zähler für {name}",
|
||||
"count_mode_default": "Zähler: Standard",
|
||||
"count_mode_unread": "Nur ungelesene",
|
||||
|
||||
@@ -2099,6 +2099,10 @@
|
||||
"new_folder_name": "Folder name",
|
||||
"rename": "Rename",
|
||||
"change_icon": "Change icon",
|
||||
"actions": "Actions for {name}",
|
||||
"expand": "Expand {name}",
|
||||
"collapse": "Collapse {name}",
|
||||
"counter": "Counter",
|
||||
"count_mode": "Counter for {name}",
|
||||
"count_mode_default": "Counter: default",
|
||||
"count_mode_unread": "Unread only",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "Nombre de la carpeta",
|
||||
"rename": "Renombrar",
|
||||
"change_icon": "Cambiar icono",
|
||||
"actions": "Acciones para {name}",
|
||||
"expand": "Expandir {name}",
|
||||
"collapse": "Contraer {name}",
|
||||
"counter": "Contador",
|
||||
"count_mode": "Contador de {name}",
|
||||
"count_mode_default": "Contador: predeterminado",
|
||||
"count_mode_unread": "Solo no leídos",
|
||||
|
||||
@@ -2099,6 +2099,10 @@
|
||||
"new_folder_name": "Kausta nimi",
|
||||
"rename": "Nimeta ümber",
|
||||
"change_icon": "Muuda ikooni",
|
||||
"actions": "Toimingud: {name}",
|
||||
"expand": "Laienda: {name}",
|
||||
"collapse": "Ahenda: {name}",
|
||||
"counter": "Loendur",
|
||||
"count_mode": "Kausta {name} loendur",
|
||||
"count_mode_default": "Loendur: vaikimisi",
|
||||
"count_mode_unread": "Ainult lugemata",
|
||||
|
||||
@@ -2099,6 +2099,10 @@
|
||||
"new_folder_name": "نام پوشه",
|
||||
"rename": "تغییر نام",
|
||||
"change_icon": "تغییر آیکون",
|
||||
"actions": "کارها برای {name}",
|
||||
"expand": "باز کردن {name}",
|
||||
"collapse": "بستن {name}",
|
||||
"counter": "شمارنده",
|
||||
"count_mode": "شمارنده برای {name}",
|
||||
"count_mode_default": "شمارنده: پیشفرض",
|
||||
"count_mode_unread": "فقط خواندهنشده",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "Nom du dossier",
|
||||
"rename": "Renommer",
|
||||
"change_icon": "Changer l'icône",
|
||||
"actions": "Actions pour {name}",
|
||||
"expand": "Développer {name}",
|
||||
"collapse": "Réduire {name}",
|
||||
"counter": "Compteur",
|
||||
"count_mode": "Compteur pour {name}",
|
||||
"count_mode_default": "Compteur : par défaut",
|
||||
"count_mode_unread": "Non lus uniquement",
|
||||
|
||||
@@ -2056,6 +2056,10 @@
|
||||
"new_folder_name": "שם התיקיה",
|
||||
"rename": "שנה שם",
|
||||
"change_icon": "שנה סמל",
|
||||
"actions": "פעולות עבור {name}",
|
||||
"expand": "הרחבת {name}",
|
||||
"collapse": "כיווץ {name}",
|
||||
"counter": "מונה",
|
||||
"count_mode": "מונה עבור {name}",
|
||||
"count_mode_default": "מונה: ברירת מחדל",
|
||||
"count_mode_unread": "רק שלא נקראו",
|
||||
|
||||
@@ -2095,6 +2095,10 @@
|
||||
"new_folder_name": "Mappa neve",
|
||||
"rename": "Átnevezés",
|
||||
"change_icon": "Ikon módosítása",
|
||||
"actions": "{name} – műveletek",
|
||||
"expand": "{name} kibontása",
|
||||
"collapse": "{name} összecsukása",
|
||||
"counter": "Számláló",
|
||||
"count_mode": "Számláló: {name}",
|
||||
"count_mode_default": "Számláló: alapértelmezett",
|
||||
"count_mode_unread": "Csak olvasatlan",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "Nome della cartella",
|
||||
"rename": "Rinomina",
|
||||
"change_icon": "Cambia icona",
|
||||
"actions": "Azioni per {name}",
|
||||
"expand": "Espandi {name}",
|
||||
"collapse": "Comprimi {name}",
|
||||
"counter": "Contatore",
|
||||
"count_mode": "Contatore per {name}",
|
||||
"count_mode_default": "Contatore: predefinito",
|
||||
"count_mode_unread": "Solo non letti",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "フォルダー名",
|
||||
"rename": "名前を変更",
|
||||
"change_icon": "アイコンを変更",
|
||||
"actions": "{name} の操作",
|
||||
"expand": "{name} を展開",
|
||||
"collapse": "{name} を折りたたむ",
|
||||
"counter": "カウンター",
|
||||
"count_mode": "{name} のカウンター",
|
||||
"count_mode_default": "カウンター: 既定",
|
||||
"count_mode_unread": "未読のみ",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "폴더 이름",
|
||||
"rename": "이름 바꾸기",
|
||||
"change_icon": "아이콘 바꾸기",
|
||||
"actions": "{name} 작업",
|
||||
"expand": "{name} 펼치기",
|
||||
"collapse": "{name} 접기",
|
||||
"counter": "카운터",
|
||||
"count_mode": "{name} 카운터",
|
||||
"count_mode_default": "카운터: 기본값",
|
||||
"count_mode_unread": "읽지 않음만",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "Mapes nosaukums",
|
||||
"rename": "Pārdēvēt",
|
||||
"change_icon": "Mainīt ikonu",
|
||||
"actions": "Darbības: {name}",
|
||||
"expand": "Izvērst: {name}",
|
||||
"collapse": "Sakļaut: {name}",
|
||||
"counter": "Skaitītājs",
|
||||
"count_mode": "Skaitītājs mapei {name}",
|
||||
"count_mode_default": "Skaitītājs: noklusējums",
|
||||
"count_mode_unread": "Tikai nelasītie",
|
||||
|
||||
@@ -2099,6 +2099,10 @@
|
||||
"new_folder_name": "Хавтасны нэр",
|
||||
"rename": "Нэрээ өөрчлөх",
|
||||
"change_icon": " Дүрсийг өөрчлөх",
|
||||
"actions": "{name}-ийн үйлдлүүд",
|
||||
"expand": "{name}-ийг дэлгэх",
|
||||
"collapse": "{name}-ийг хураах",
|
||||
"counter": "Тоолуур",
|
||||
"count_mode": "{name}-ийн тоолуур",
|
||||
"count_mode_default": "Тоолуур: үндсэн",
|
||||
"count_mode_unread": "Зөвхөн уншаагүй",
|
||||
|
||||
@@ -2099,6 +2099,10 @@
|
||||
"new_folder_name": "Mappenavn",
|
||||
"rename": "Gi nytt navn",
|
||||
"change_icon": "Endre ikon",
|
||||
"actions": "Handlinger for {name}",
|
||||
"expand": "Vis innholdet i {name}",
|
||||
"collapse": "Skjul innholdet i {name}",
|
||||
"counter": "Teller",
|
||||
"count_mode": "Teller for {name}",
|
||||
"count_mode_default": "Teller: standard",
|
||||
"count_mode_unread": "Bare uleste",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "Mapnaam",
|
||||
"rename": "Hernoemen",
|
||||
"change_icon": "Pictogram wijzigen",
|
||||
"actions": "Acties voor {name}",
|
||||
"expand": "{name} uitvouwen",
|
||||
"collapse": "{name} samenvouwen",
|
||||
"counter": "Teller",
|
||||
"count_mode": "Teller voor {name}",
|
||||
"count_mode_default": "Teller: standaard",
|
||||
"count_mode_unread": "Alleen ongelezen",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "Nazwa folderu",
|
||||
"rename": "Zmień nazwę",
|
||||
"change_icon": "Zmień ikonę",
|
||||
"actions": "Działania dla {name}",
|
||||
"expand": "Rozwiń {name}",
|
||||
"collapse": "Zwiń {name}",
|
||||
"counter": "Licznik",
|
||||
"count_mode": "Licznik dla {name}",
|
||||
"count_mode_default": "Licznik: domyślny",
|
||||
"count_mode_unread": "Tylko nieprzeczytane",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "Nome da pasta",
|
||||
"rename": "Renomear",
|
||||
"change_icon": "Alterar ícone",
|
||||
"actions": "Ações para {name}",
|
||||
"expand": "Expandir {name}",
|
||||
"collapse": "Recolher {name}",
|
||||
"counter": "Contador",
|
||||
"count_mode": "Contador de {name}",
|
||||
"count_mode_default": "Contador: padrão",
|
||||
"count_mode_unread": "Apenas não lidas",
|
||||
|
||||
@@ -2099,6 +2099,10 @@
|
||||
"new_folder_name": "Numele folderului",
|
||||
"rename": "Redenumire",
|
||||
"change_icon": "Schimbă pictograma",
|
||||
"actions": "Acțiuni pentru {name}",
|
||||
"expand": "Extinde {name}",
|
||||
"collapse": "Restrânge {name}",
|
||||
"counter": "Contor",
|
||||
"count_mode": "Contor pentru {name}",
|
||||
"count_mode_default": "Contor: implicit",
|
||||
"count_mode_unread": "Doar necitite",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "Название папки",
|
||||
"rename": "Переименовать",
|
||||
"change_icon": "Изменить значок",
|
||||
"actions": "Действия для «{name}»",
|
||||
"expand": "Развернуть «{name}»",
|
||||
"collapse": "Свернуть «{name}»",
|
||||
"counter": "Счётчик",
|
||||
"count_mode": "Счётчик для {name}",
|
||||
"count_mode_default": "Счётчик: по умолчанию",
|
||||
"count_mode_unread": "Только непрочитанные",
|
||||
|
||||
@@ -2099,6 +2099,10 @@
|
||||
"new_folder_name": "Názov priečinka",
|
||||
"rename": "Premenovať",
|
||||
"change_icon": "Zmeniť ikonu",
|
||||
"actions": "Akcie pre {name}",
|
||||
"expand": "Rozbaliť {name}",
|
||||
"collapse": "Zbaliť {name}",
|
||||
"counter": "Počítadlo",
|
||||
"count_mode": "Počítadlo pre {name}",
|
||||
"count_mode_default": "Počítadlo: predvolené",
|
||||
"count_mode_unread": "Len neprečítané",
|
||||
|
||||
@@ -3957,6 +3957,10 @@
|
||||
"new_folder_name": "ชื่อโฟลเดอร์",
|
||||
"rename": "เปลี่ยนชื่อ",
|
||||
"change_icon": "เปลี่ยนไอคอน",
|
||||
"actions": "การทำงานสำหรับ {name}",
|
||||
"expand": "ขยาย {name}",
|
||||
"collapse": "ยุบ {name}",
|
||||
"counter": "ตัวนับ",
|
||||
"count_mode": "ตัวนับสำหรับ {name}",
|
||||
"count_mode_default": "ตัวนับ: ค่าเริ่มต้น",
|
||||
"count_mode_unread": "เฉพาะที่ยังไม่ได้อ่าน",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "Klasör adı",
|
||||
"rename": "Yeniden Adlandır",
|
||||
"change_icon": "Simgeyi değiştir",
|
||||
"actions": "{name} için işlemler",
|
||||
"expand": "{name} klasörünü genişlet",
|
||||
"collapse": "{name} klasörünü daralt",
|
||||
"counter": "Sayaç",
|
||||
"count_mode": "{name} sayacı",
|
||||
"count_mode_default": "Sayaç: varsayılan",
|
||||
"count_mode_unread": "Yalnızca okunmamış",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "Назва папки",
|
||||
"rename": "Перейменувати",
|
||||
"change_icon": "Змінити значок",
|
||||
"actions": "Дії для «{name}»",
|
||||
"expand": "Розгорнути «{name}»",
|
||||
"collapse": "Згорнути «{name}»",
|
||||
"counter": "Лічильник",
|
||||
"count_mode": "Лічильник для {name}",
|
||||
"count_mode_default": "Лічильник: типово",
|
||||
"count_mode_unread": "Лише непрочитані",
|
||||
|
||||
@@ -2099,6 +2099,10 @@
|
||||
"new_folder_name": "信件匣名稱",
|
||||
"rename": "重新命名",
|
||||
"change_icon": "變更圖示",
|
||||
"actions": "{name} 的動作",
|
||||
"expand": "展開 {name}",
|
||||
"collapse": "摺疊 {name}",
|
||||
"counter": "計數",
|
||||
"count_mode": "{name} 的計數",
|
||||
"count_mode_default": "計數:預設",
|
||||
"count_mode_unread": "僅未讀",
|
||||
|
||||
@@ -2092,6 +2092,10 @@
|
||||
"new_folder_name": "文件夹名称",
|
||||
"rename": "重命名",
|
||||
"change_icon": "更改图标",
|
||||
"actions": "{name} 的操作",
|
||||
"expand": "展开 {name}",
|
||||
"collapse": "折叠 {name}",
|
||||
"counter": "计数",
|
||||
"count_mode": "{name} 的计数",
|
||||
"count_mode_default": "计数:默认",
|
||||
"count_mode_unread": "仅未读",
|
||||
|
||||
Reference in New Issue
Block a user