mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
fix: tell an empty address book from an empty account, offer Import there, and use one empty state in Contacts and Files
This commit is contained in:
@@ -224,4 +224,15 @@ describe('ContactsApp', () => {
|
||||
window.matchMedia = matchMedia;
|
||||
}
|
||||
});
|
||||
|
||||
it('says an empty address book is empty, not that the account has no contacts, and offers Import', () => {
|
||||
renderContacts([alice]);
|
||||
act(() => { useContactStore.setState({ addressBooks: [{ id: 'b2', name: 'Work', isDefault: false } as never] }); });
|
||||
fireEvent.click(screen.getAllByRole('button', { name: 'open_categories' })[0]);
|
||||
fireEvent.click(within(drawer()).getByText('Work'));
|
||||
expect(screen.getByText('empty_view_title')).toBeInTheDocument();
|
||||
expect(screen.queryByText('empty_state_title')).toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: /import.title/ }));
|
||||
expect(screen.getByRole('dialog', { name: 'import.title' })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useTranslations, useLocale } from "next-intl";
|
||||
import { Search, BookUser, Trash2, Users, Download, X, UserPlus, CheckSquare, Square, Filter, Mail, Phone, Image as ImageIcon, RotateCcw, Menu, ArrowDownAZ, Loader2, FolderInput } from "@/components/icons";
|
||||
import { Search, BookUser, Trash2, Users, Download, X, UserPlus, CheckSquare, Square, Filter, Mail, Phone, Image as ImageIcon, RotateCcw, Menu, ArrowDownAZ, Loader2, FolderInput, Upload } from "@/components/icons";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { EmptyState } from "@/components/ui/empty-state";
|
||||
import { IconButton } from "@/components/ui/icon-button";
|
||||
import { ContactListItem } from "./contact-list-item";
|
||||
import { ContactContextMenu } from "./contact-context-menu";
|
||||
@@ -123,6 +124,9 @@ interface ContactListProps {
|
||||
onMoveContacts?: (ids: string[]) => void;
|
||||
/** Show a burger button at the start that opens the (overlay) categories sidebar. */
|
||||
onMenuClick?: () => void;
|
||||
/** The list shows one address book, category or group, not the whole account. */
|
||||
emptyView?: boolean;
|
||||
onImport?: () => void;
|
||||
/** Contacts' own entries in the phone header's ⋮. */
|
||||
phoneMenuItems?: (close: () => void) => React.ReactNode;
|
||||
/** The first fetch is still running: show placeholders, not "No contacts yet". */
|
||||
@@ -153,6 +157,8 @@ export function ContactList({
|
||||
onMoveContacts,
|
||||
onMenuClick,
|
||||
phoneMenuItems,
|
||||
emptyView = false,
|
||||
onImport,
|
||||
isLoading = false,
|
||||
}: ContactListProps) {
|
||||
const t = useTranslations("contacts");
|
||||
@@ -651,21 +657,14 @@ export function ContactList({
|
||||
))}
|
||||
</div>
|
||||
) : sorted.length === 0 ? (
|
||||
<div className="flex flex-col items-center justify-center h-full px-6 text-center">
|
||||
{searchQuery || activeFilters > 0 ? (
|
||||
<>
|
||||
{activeFilters > 0 && !searchQuery ? (
|
||||
<Filter className="w-10 h-10 mb-3 text-muted-foreground/30" />
|
||||
) : (
|
||||
<Search className="w-10 h-10 mb-3 text-muted-foreground/30" />
|
||||
)}
|
||||
<p className="text-sm font-medium text-foreground">
|
||||
{searchQuery ? t("empty_search") : t("empty_filtered")}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
{searchQuery ? t("empty_search_hint") : t("empty_filtered_hint")}
|
||||
</p>
|
||||
<div className="flex gap-2 mt-3">
|
||||
searchQuery || activeFilters > 0 ? (
|
||||
<EmptyState
|
||||
compact
|
||||
icon={activeFilters > 0 && !searchQuery ? Filter : Search}
|
||||
title={searchQuery ? t("empty_search") : t("empty_filtered")}
|
||||
description={searchQuery ? t("empty_search_hint") : t("empty_filtered_hint")}
|
||||
actions={
|
||||
<>
|
||||
{searchQuery && (
|
||||
<Button variant="outline" size="sm" onClick={() => onSearchChange("")}>
|
||||
{t("clear_search")}
|
||||
@@ -677,20 +676,33 @@ export function ContactList({
|
||||
{t("filters.clear")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<BookUser className="w-10 h-10 mb-3 text-muted-foreground/30" />
|
||||
<p className="text-sm font-medium text-foreground">{t("empty_state_title")}</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">{t("empty_state_subtitle")}</p>
|
||||
<Button size="sm" className="mt-3" onClick={onCreateNew}>
|
||||
<UserPlus className="w-4 h-4 me-1.5" />
|
||||
{t("create_new")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
// The whole account is empty, or only the address book, category
|
||||
// or group on screen: each says so, and both offer New and Import.
|
||||
<EmptyState
|
||||
compact
|
||||
icon={BookUser}
|
||||
title={emptyView ? t("empty_view_title") : t("empty_state_title")}
|
||||
description={emptyView ? t("empty_view_hint") : t("empty_state_subtitle")}
|
||||
actions={
|
||||
<>
|
||||
<Button size="sm" onClick={onCreateNew}>
|
||||
<UserPlus className="w-4 h-4 me-1.5" />
|
||||
{t("create_new")}
|
||||
</Button>
|
||||
{onImport && (
|
||||
<Button variant="outline" size="sm" onClick={onImport}>
|
||||
<Upload className="w-4 h-4 me-1.5" />
|
||||
{t("import.title")}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
(() => {
|
||||
const renderItem = (contact: ContactCard) => (
|
||||
|
||||
@@ -1294,6 +1294,8 @@ function ContactsAppContent({ linkSegments: routeSegments }: ContactsAppProps =
|
||||
onDuplicateContact={(contact) => void handleDuplicateContact(contact)}
|
||||
onMoveContacts={canMoveContacts ? handleMoveContacts : undefined}
|
||||
onMenuClick={isNarrow ? () => setNarrowSidebarOpen(true) : undefined}
|
||||
emptyView={activeCategory !== "all"}
|
||||
onImport={() => setShowImportDialog(true)}
|
||||
phoneMenuItems={(close) => (
|
||||
// On the phone these are otherwise only in the drawer's "+".
|
||||
<>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Upload, FolderPlus, FolderOpen, SearchX } from "@/components/icons";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { EmptyState } from "@/components/ui/empty-state";
|
||||
|
||||
interface EmptyFolderProps {
|
||||
isRoot: boolean;
|
||||
@@ -15,39 +16,35 @@ interface EmptyFolderProps {
|
||||
export function EmptyFolder({ isRoot, canCreate, onUpload, onCreateFolder }: EmptyFolderProps) {
|
||||
const t = useTranslations("files");
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full min-h-[18rem] p-8">
|
||||
<div className="flex flex-col items-center text-center max-w-sm">
|
||||
<div className="w-14 h-14 rounded-full bg-muted flex items-center justify-center mb-4">
|
||||
{isRoot ? <Upload className="w-7 h-7 text-muted-foreground" /> : <FolderOpen className="w-7 h-7 text-muted-foreground" />}
|
||||
</div>
|
||||
<h3 className="text-base font-medium">{isRoot ? t("empty_state_title") : t("empty_folder_title")}</h3>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
{canCreate ? t("empty_folder_description") : t("empty_folder_read_only")}
|
||||
</p>
|
||||
{canCreate && (
|
||||
<div className="flex gap-2 flex-wrap justify-center mt-5">
|
||||
<Button size="sm" onClick={onUpload} className="gap-1.5">
|
||||
<Upload className="w-4 h-4" />
|
||||
{t("upload_files")}
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" onClick={onCreateFolder} className="gap-1.5">
|
||||
<FolderPlus className="w-4 h-4" />
|
||||
{t("new_folder")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<EmptyState
|
||||
className="h-full"
|
||||
icon={isRoot ? Upload : FolderOpen}
|
||||
title={isRoot ? t("empty_state_title") : t("empty_folder_title")}
|
||||
description={canCreate ? t("empty_folder_description") : t("empty_folder_read_only")}
|
||||
actions={canCreate ? (
|
||||
<>
|
||||
<Button size="sm" onClick={onUpload} className="gap-1.5">
|
||||
<Upload className="w-4 h-4" />
|
||||
{t("upload_files")}
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" onClick={onCreateFolder} className="gap-1.5">
|
||||
<FolderPlus className="w-4 h-4" />
|
||||
{t("new_folder")}
|
||||
</Button>
|
||||
</>
|
||||
) : undefined}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function NoSearchResults({ query, onClear }: { query: string; onClear: () => void }) {
|
||||
const t = useTranslations("files");
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center text-center h-full min-h-[14rem] p-8">
|
||||
<SearchX className="w-10 h-10 text-muted-foreground/50 mb-3" />
|
||||
<p className="text-sm font-medium">{t("no_results_for", { query })}</p>
|
||||
<Button variant="ghost" size="sm" className="mt-2" onClick={onClear}>{t("clear_search")}</Button>
|
||||
</div>
|
||||
<EmptyState
|
||||
className="h-full"
|
||||
icon={SearchX}
|
||||
title={t("no_results_for", { query })}
|
||||
actions={<Button variant="outline" size="sm" onClick={onClear}>{t("clear_search")}</Button>}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "لا توجد جهات اتصال بعد",
|
||||
"empty_state_title": "لا توجد جهات اتصال بعد",
|
||||
"empty_state_subtitle": "أنشئ أول جهة اتصال أو استوردها من ملف vCard",
|
||||
"empty_view_title": "لا توجد جهات اتصال هنا",
|
||||
"empty_view_hint": "أضف جهة اتصال أو استورد ملف vCard.",
|
||||
"empty_search": "لا توجد جهات اتصال مطابقة لبحثك",
|
||||
"empty_search_hint": "جرّب مصطلح بحث مختلف",
|
||||
"empty_filtered": "لا توجد جهات اتصال مطابقة لمرشحاتك",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Encara no hi ha contactes",
|
||||
"empty_state_title": "Encara no hi ha contactes",
|
||||
"empty_state_subtitle": "Creeu el primer contacte o importeu-lo des d'un fitxer vCard",
|
||||
"empty_view_title": "No hi ha contactes aquí",
|
||||
"empty_view_hint": "Afegiu un contacte o importeu un fitxer vCard.",
|
||||
"empty_search": "Cap contacte coincideix amb la cerca",
|
||||
"empty_search_hint": "Proveu amb un altre terme de cerca",
|
||||
"empty_filtered": "Cap contacte coincideix amb els filtres",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Žádné kontakty",
|
||||
"empty_state_title": "Žádné kontakty",
|
||||
"empty_state_subtitle": "Vytvořte první kontakt nebo importujte ze souboru vCard",
|
||||
"empty_view_title": "Nejsou zde žádné kontakty",
|
||||
"empty_view_hint": "Přidejte kontakt nebo importujte soubor vCard.",
|
||||
"empty_search": "Hledání neodpovídají žádné kontakty",
|
||||
"empty_search_hint": "Zkuste použít jiný hledaný výraz",
|
||||
"empty_filtered": "Žádné kontakty neodpovídají filtrům",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Ingen kontakter endnu",
|
||||
"empty_state_title": "Ingen kontakter endnu",
|
||||
"empty_state_subtitle": "Opret din første kontakt eller importér fra en vCard-fil",
|
||||
"empty_view_title": "Ingen kontakter her",
|
||||
"empty_view_hint": "Tilføj en kontakt, eller importér en vCard-fil.",
|
||||
"empty_search": "Ingen kontakter matcher din søgning",
|
||||
"empty_search_hint": "Prøv en anden søgeterm",
|
||||
"empty_filtered": "Ingen kontakter matcher dine filtre",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Keine Kontakte",
|
||||
"empty_state_title": "Keine Kontakte",
|
||||
"empty_state_subtitle": "Erstellen Sie Ihren ersten Kontakt oder importieren Sie aus einer vCard-Datei",
|
||||
"empty_view_title": "Hier sind keine Kontakte",
|
||||
"empty_view_hint": "Fügen Sie einen Kontakt hinzu oder importieren Sie eine vCard-Datei.",
|
||||
"empty_search": "Keine Kontakte gefunden",
|
||||
"empty_search_hint": "Versuchen Sie einen anderen Suchbegriff",
|
||||
"empty_filtered": "Keine Kontakte entsprechen Ihren Filtern",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "No contacts yet",
|
||||
"empty_state_title": "No contacts yet",
|
||||
"empty_state_subtitle": "Create your first contact or import from a vCard file",
|
||||
"empty_view_title": "No contacts here",
|
||||
"empty_view_hint": "Add a contact or import a vCard file.",
|
||||
"empty_search": "No contacts match your search",
|
||||
"empty_search_hint": "Try a different search term",
|
||||
"empty_filtered": "No contacts match your filters",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "No hay contactos",
|
||||
"empty_state_title": "Sin contactos",
|
||||
"empty_state_subtitle": "Crea tu primer contacto o importa desde un archivo vCard",
|
||||
"empty_view_title": "No hay contactos aquí",
|
||||
"empty_view_hint": "Añade un contacto o importa un archivo vCard.",
|
||||
"empty_search": "Ningún contacto coincide con tu búsqueda",
|
||||
"empty_search_hint": "Prueba con otro término de búsqueda",
|
||||
"empty_filtered": "Ningún contacto coincide con tus filtros",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Kontakte veel pole",
|
||||
"empty_state_title": "Kontakte veel pole",
|
||||
"empty_state_subtitle": "Loo oma esimene kontakt või impordi vCard-failist",
|
||||
"empty_view_title": "Siin pole kontakte",
|
||||
"empty_view_hint": "Lisage kontakt või importige vCard-fail.",
|
||||
"empty_search": "Otsingule ei vastanud ükski kontakt",
|
||||
"empty_search_hint": "Proovi teistsugust otsisõna",
|
||||
"empty_filtered": "Filtritele ei vastanud ükski kontakt",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "هنوز مخاطبی نیست",
|
||||
"empty_state_title": "هنوز مخاطبی نیست",
|
||||
"empty_state_subtitle": "اولین مخاطب خود را ایجاد کنید یا از فایل vCard وارد کنید",
|
||||
"empty_view_title": "مخاطبی اینجا نیست",
|
||||
"empty_view_hint": "مخاطبی اضافه کنید یا فایل vCard را وارد کنید.",
|
||||
"empty_search": "مخاطبی با این جستجو مطابقت ندارد",
|
||||
"empty_search_hint": "عبارت جستجوی دیگری را امتحان کنید",
|
||||
"empty_filtered": "مخاطبی با این فیلترها مطابقت ندارد",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Aucun contact",
|
||||
"empty_state_title": "Aucun contact",
|
||||
"empty_state_subtitle": "Créez votre premier contact ou importez depuis un fichier vCard",
|
||||
"empty_view_title": "Aucun contact ici",
|
||||
"empty_view_hint": "Ajoutez un contact ou importez un fichier vCard.",
|
||||
"empty_search": "Aucun contact ne correspond à votre recherche",
|
||||
"empty_search_hint": "Essayez un autre terme de recherche",
|
||||
"empty_filtered": "Aucun contact ne correspond à vos filtres",
|
||||
|
||||
@@ -2867,6 +2867,8 @@
|
||||
"empty_state": "עדיין אין אנשי קשר",
|
||||
"empty_state_title": "עדיין אין אנשי קשר",
|
||||
"empty_state_subtitle": "צור את איש הקשר הראשון שלך או ייבא מקובץ vCard",
|
||||
"empty_view_title": "אין כאן אנשי קשר",
|
||||
"empty_view_hint": "הוסף איש קשר או ייבא קובץ vCard.",
|
||||
"empty_search": "אין אנשי קשר שתואמים לחיפוש שלך",
|
||||
"empty_search_hint": "נסה מונח חיפוש אחר",
|
||||
"clear_search": "נקה חיפוש",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Még nincsenek névjegyek",
|
||||
"empty_state_title": "Még nincsenek névjegyek",
|
||||
"empty_state_subtitle": "Hozd létre az első névjegyed vagy importálj vCard fájlból",
|
||||
"empty_view_title": "Itt nincsenek névjegyek",
|
||||
"empty_view_hint": "Adjon hozzá egy névjegyet, vagy importáljon egy vCard-fájlt.",
|
||||
"empty_search": "Nincs a keresésnek megfelelő névjegy",
|
||||
"empty_search_hint": "Próbálj meg más keresési kifejezést",
|
||||
"empty_filtered": "Nincs a szűrőknek megfelelő névjegy",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Nessun contatto",
|
||||
"empty_state_title": "Nessun contatto",
|
||||
"empty_state_subtitle": "Crea il tuo primo contatto o importa da un file vCard",
|
||||
"empty_view_title": "Nessun contatto qui",
|
||||
"empty_view_hint": "Aggiungi un contatto o importa un file vCard.",
|
||||
"empty_search": "Nessun contatto corrisponde alla ricerca",
|
||||
"empty_search_hint": "Prova con un altro termine di ricerca",
|
||||
"empty_filtered": "Nessun contatto corrisponde ai filtri",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "連絡先がありません",
|
||||
"empty_state_title": "連絡先がありません",
|
||||
"empty_state_subtitle": "最初の連絡先を作成するか、vCardファイルからインポートしてください",
|
||||
"empty_view_title": "ここに連絡先はありません",
|
||||
"empty_view_hint": "連絡先を追加するか、vCard ファイルを読み込んでください。",
|
||||
"empty_search": "検索に一致する連絡先がありません",
|
||||
"empty_search_hint": "別の検索語をお試しください",
|
||||
"empty_filtered": "フィルターに一致する連絡先がありません",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "아직 연락처가 없어요",
|
||||
"empty_state_title": "아직 연락처가 없어요",
|
||||
"empty_state_subtitle": "새 연락처를 만들거나 vCard 파일에서 가져와 보세요",
|
||||
"empty_view_title": "여기에 연락처가 없습니다",
|
||||
"empty_view_hint": "연락처를 추가하거나 vCard 파일을 가져오세요.",
|
||||
"empty_search": "검색된 연락처가 없어요",
|
||||
"empty_search_hint": "다른 검색어로 다시 시도해 보세요",
|
||||
"empty_filtered": "필터에 일치하는 연락처가 없어요",
|
||||
|
||||
@@ -2941,6 +2941,8 @@
|
||||
"empty_state": "Kontaktu vēl nav",
|
||||
"empty_state_title": "Kontaktu vēl nav",
|
||||
"empty_state_subtitle": "Izveidojiet pirmo kontaktu vai importējiet no vCard faila",
|
||||
"empty_view_title": "Šeit nav kontaktpersonu",
|
||||
"empty_view_hint": "Pievienojiet kontaktpersonu vai importējiet vCard failu.",
|
||||
"empty_search": "Nav kontaktu, kas atbilstu vaicājumam",
|
||||
"empty_search_hint": "Mēģiniet citu meklēšanas vaicājumu",
|
||||
"empty_filtered": "Nav kontaktu, kas atbilstu filtriem",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Харилцагч байхгүй",
|
||||
"empty_state_title": "Хараахан холбоо барих хүн алга",
|
||||
"empty_state_subtitle": "Анхны харилцагчаа үүсгэх эсвэл vCard файлаас импортлох",
|
||||
"empty_view_title": "Энд харилцагч алга",
|
||||
"empty_view_hint": "Харилцагч нэмэх эсвэл vCard файл импортлоно уу.",
|
||||
"empty_search": "Таны хайлтад тохирох харилцагч алга",
|
||||
"empty_search_hint": "Өөр хайлтын үг хэрэглэж үзнэ үү",
|
||||
"empty_filtered": "Таны шүүлтүүрт тохирох харилцагч алга",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Ingen kontakter ennå",
|
||||
"empty_state_title": "Ingen kontakter ennå",
|
||||
"empty_state_subtitle": "Opprett din første kontakt eller importer fra en vCard-fil",
|
||||
"empty_view_title": "Ingen kontakter her",
|
||||
"empty_view_hint": "Legg til en kontakt eller importer en vCard-fil.",
|
||||
"empty_search": "Ingen kontakter passer med søket ditt",
|
||||
"empty_search_hint": "Prøv et annet søkeord",
|
||||
"empty_filtered": "Ingen kontakter passer med filtrene dine",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Geen contacten",
|
||||
"empty_state_title": "Geen contacten",
|
||||
"empty_state_subtitle": "Maak uw eerste contact aan of importeer vanuit een vCard-bestand",
|
||||
"empty_view_title": "Geen contacten hier",
|
||||
"empty_view_hint": "Voeg een contact toe of importeer een vCard-bestand.",
|
||||
"empty_search": "Geen contacten gevonden",
|
||||
"empty_search_hint": "Probeer een andere zoekterm",
|
||||
"empty_filtered": "Geen contacten voldoen aan uw filters",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Brak kontaktów",
|
||||
"empty_state_title": "Brak kontaktów",
|
||||
"empty_state_subtitle": "Utwórz pierwszy kontakt lub zaimportuj z pliku vCard",
|
||||
"empty_view_title": "Brak kontaktów",
|
||||
"empty_view_hint": "Dodaj kontakt lub zaimportuj plik vCard.",
|
||||
"empty_search": "Żadne kontakty nie pasują do wyszukiwania",
|
||||
"empty_search_hint": "Spróbuj użyć innego wyszukiwanego hasła",
|
||||
"empty_filtered": "Żadne kontakty nie pasują do filtrów",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Nenhum contato",
|
||||
"empty_state_title": "Sem contatos",
|
||||
"empty_state_subtitle": "Crie seu primeiro contato ou importe de um arquivo vCard",
|
||||
"empty_view_title": "Nenhum contato aqui",
|
||||
"empty_view_hint": "Adicione um contato ou importe um arquivo vCard.",
|
||||
"empty_search": "Nenhum contato encontrado",
|
||||
"empty_search_hint": "Tente outro termo de pesquisa",
|
||||
"empty_filtered": "Nenhum contato corresponde aos seus filtros",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Nu există încă contacte",
|
||||
"empty_state_title": "Nu există încă contacte",
|
||||
"empty_state_subtitle": "Creați primul dvs. contact sau importați-l dintr-un fișier „vCard”",
|
||||
"empty_view_title": "Nu există contacte aici",
|
||||
"empty_view_hint": "Adăugați un contact sau importați un fișier vCard.",
|
||||
"empty_search": "Nu există contacte care să corespundă căutării dvs.",
|
||||
"empty_search_hint": "Încercați un alt termen de căutare",
|
||||
"empty_filtered": "Nu există contacte care să corespundă filtrelor dvs.",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Контактов пока нет",
|
||||
"empty_state_title": "Контактов пока нет",
|
||||
"empty_state_subtitle": "Создайте первый контакт или импортируйте из файла vCard",
|
||||
"empty_view_title": "Здесь нет контактов",
|
||||
"empty_view_hint": "Добавьте контакт или импортируйте файл vCard.",
|
||||
"empty_search": "Нет контактов, соответствующих вашему запросу",
|
||||
"empty_search_hint": "Попробуйте другой поисковый запрос",
|
||||
"empty_filtered": "Нет контактов, соответствующих фильтрам",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Žiadne kontakty",
|
||||
"empty_state_title": "Žiadne kontakty",
|
||||
"empty_state_subtitle": "Vytvorte prvý kontakt alebo importujte zo súboru vCard",
|
||||
"empty_view_title": "Nie sú tu žiadne kontakty",
|
||||
"empty_view_hint": "Pridajte kontakt alebo importujte súbor vCard.",
|
||||
"empty_search": "Hľadaniu nezodpovedajú žiadne kontakty",
|
||||
"empty_search_hint": "Skúste iný hľadaný výraz",
|
||||
"empty_filtered": "Žiadne kontakty nezodpovedajú filtrom",
|
||||
|
||||
@@ -2318,6 +2318,8 @@
|
||||
"empty_state": "ยังไม่มีผู้ติดต่อ",
|
||||
"empty_state_title": "ยังไม่มีผู้ติดต่อ",
|
||||
"empty_state_subtitle": "สร้างผู้ติดต่อแรกของคุณ หรือนำเข้าจากไฟล์ vCard",
|
||||
"empty_view_title": "ไม่มีผู้ติดต่อที่นี่",
|
||||
"empty_view_hint": "เพิ่มผู้ติดต่อหรือนำเข้าไฟล์ vCard",
|
||||
"empty_search": "ไม่พบผู้ติดต่อที่ตรงกับการค้นหา",
|
||||
"empty_search_hint": "ลองค้นหาด้วยคำอื่น",
|
||||
"empty_filtered": "ไม่พบผู้ติดต่อที่ตรงกับตัวกรอง",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Henüz kişi yok",
|
||||
"empty_state_title": "Henüz kişi yok",
|
||||
"empty_state_subtitle": "İlk kişinizi oluşturun veya vCard dosyasından içe aktarın",
|
||||
"empty_view_title": "Burada kişi yok",
|
||||
"empty_view_hint": "Bir kişi ekleyin veya bir vCard dosyası içe aktarın.",
|
||||
"empty_search": "Aramanızla eşleşen kişi yok",
|
||||
"empty_search_hint": "Farklı bir arama terimi deneyin",
|
||||
"empty_filtered": "Filtrelerinizle eşleşen kişi yok",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "Контактів ще немає",
|
||||
"empty_state_title": "Контактів ще немає",
|
||||
"empty_state_subtitle": "Створіть свій перший контакт або імпортуйте його з файлу vCard",
|
||||
"empty_view_title": "Тут немає контактів",
|
||||
"empty_view_hint": "Додайте контакт або імпортуйте файл vCard.",
|
||||
"empty_search": "Жоден контакт не відповідає вашому пошуку",
|
||||
"empty_search_hint": "Спробуйте інший термін пошуку",
|
||||
"empty_filtered": "Жоден контакт не відповідає фільтрам",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "尚無聯絡人",
|
||||
"empty_state_title": "尚無聯絡人",
|
||||
"empty_state_subtitle": "建立第一位聯絡人,或從 vCard 檔案匯入",
|
||||
"empty_view_title": "這裡沒有聯絡人",
|
||||
"empty_view_hint": "新增聯絡人或匯入 vCard 檔案。",
|
||||
"empty_search": "沒有符合您搜尋條件的聯絡人",
|
||||
"empty_search_hint": "嘗試其他搜尋字詞",
|
||||
"empty_filtered": "沒有符合您篩選條件的聯絡人",
|
||||
|
||||
@@ -2949,6 +2949,8 @@
|
||||
"empty_state": "还没有联系人",
|
||||
"empty_state_title": "还没有联系人",
|
||||
"empty_state_subtitle": "创建您的第一个联系人或从 vCard 文件导入",
|
||||
"empty_view_title": "此处没有联系人",
|
||||
"empty_view_hint": "添加联系人或导入 vCard 文件。",
|
||||
"empty_search": "没有符合您搜索条件的联系人",
|
||||
"empty_search_hint": "尝试不同的搜索词",
|
||||
"empty_filtered": "没有符合您筛选条件的联系人",
|
||||
|
||||
Reference in New Issue
Block a user