mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-01 00:13:37 +00:00
feat: use Gmail's advanced search form in Mountain View
This commit is contained in:
@@ -82,6 +82,7 @@ import { useSearchHistoryStore } from "@/stores/search-history-store";
|
||||
import { WelcomeBanner } from "@/components/ui/welcome-banner";
|
||||
import { NavigationRail } from "@/components/layout/navigation-rail";
|
||||
import { MvTopBar } from "@/components/layout/mv-top-bar";
|
||||
import { MvSearchForm } from "@/components/search/mv-search-form";
|
||||
import { MvListToolbar } from "@/components/email/mv-list-toolbar";
|
||||
import { SidebarAppsModal } from "@/components/layout/sidebar-apps-modal";
|
||||
import { InlineAppView } from "@/components/layout/inline-app-view";
|
||||
@@ -3831,6 +3832,39 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
</button>
|
||||
);
|
||||
|
||||
// The folder the advanced search runs in. Scopes the search only - it does
|
||||
// not navigate the mail list. `rerun` re-queries straight away when a search
|
||||
// is running; Mountain View's form waits for its Search button instead.
|
||||
const renderSearchFolderSelect = (className: string, rerun: boolean) => (
|
||||
<select
|
||||
value={searchMailboxId}
|
||||
onChange={(e) => {
|
||||
setSearchMailboxId(e.target.value);
|
||||
// Only re-query when a search is actually running;
|
||||
// otherwise just remember the scope for the next one.
|
||||
if (rerun && (searchQuery.trim() || !isFilterEmpty(searchFilters))) handleAdvancedSearch();
|
||||
}}
|
||||
className={className}
|
||||
>
|
||||
<option value="">{t("advanced_search.all_folders_except_spam_trash")}</option>
|
||||
<option value={SEARCH_SCOPE_ALL_FOLDERS}>{t("advanced_search.all_folders")}</option>
|
||||
{searchScopeFolders.own.map((mb) => (
|
||||
<option key={mb.id} value={mb.id}>
|
||||
{"\u00A0".repeat(mb.depth * 3)}{mb.name}
|
||||
</option>
|
||||
))}
|
||||
{searchScopeFolders.shared.map((group) => (
|
||||
<optgroup key={group.ownerId} label={group.label}>
|
||||
{group.mailboxes.map((mb) => (
|
||||
<option key={mb.id} value={mb.id}>
|
||||
{"\u00A0".repeat(mb.depth * 3)}{mb.name}
|
||||
</option>
|
||||
))}
|
||||
</optgroup>
|
||||
))}
|
||||
</select>
|
||||
);
|
||||
|
||||
// The composer, rendered in the reading pane - or, under Mountain View on
|
||||
// desktop, in a window docked over the list (see MvComposeWindow).
|
||||
const composerNode = (
|
||||
@@ -4182,7 +4216,8 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
{mvShell ? (
|
||||
<MvListToolbar
|
||||
loadedCount={activeEmails.length}
|
||||
totalCount={mailboxes.find((mb) => mb.id === selectedMailbox)?.totalEmails}
|
||||
// A search's results are not the folder: count what came back.
|
||||
totalCount={searchQuery || !isFilterEmpty(searchFilters) ? undefined : mailboxes.find((mb) => mb.id === selectedMailbox)?.totalEmails}
|
||||
onRefresh={handleManualRefresh}
|
||||
isRefreshing={isManualRefreshing}
|
||||
onMarkFolderRead={selectedMailbox ? () => handleMarkFolderRead(selectedMailbox) : undefined}
|
||||
@@ -4284,6 +4319,18 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
search field there rather than from the list header. */}
|
||||
{isAdvancedSearchOpen && (
|
||||
<FilterPanelHost anchor={mvShell ? filterAnchor : null}>
|
||||
{mvShell ? (
|
||||
<MvSearchForm
|
||||
filters={searchFilters}
|
||||
onChange={setSearchFilters}
|
||||
onSearch={() => { handleAdvancedSearch(); toggleAdvancedSearch(); }}
|
||||
onClear={() => { clearSearchFilters(); if (client) advancedSearch(client); }}
|
||||
folderSelect={!isUnifiedView ? renderSearchFolderSelect(
|
||||
"w-full h-8 bg-transparent border-0 border-b border-border px-0 text-sm text-foreground focus:outline-none focus:border-b-2 focus:border-primary",
|
||||
false,
|
||||
) : undefined}
|
||||
/>
|
||||
) : (<>
|
||||
{/* Quick toggle filters + clear */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
@@ -4384,33 +4431,10 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
{!isUnifiedView && (
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground mb-1 block">{t("advanced_search.folder")}</label>
|
||||
<select
|
||||
value={searchMailboxId}
|
||||
onChange={(e) => {
|
||||
setSearchMailboxId(e.target.value);
|
||||
// Only re-query when a search is actually running;
|
||||
// otherwise just remember the scope for the next one.
|
||||
if (searchQuery.trim() || !isFilterEmpty(searchFilters)) handleAdvancedSearch();
|
||||
}}
|
||||
className="w-full h-8 text-sm rounded-md border border-input bg-background px-3 text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1"
|
||||
>
|
||||
<option value="">{t("advanced_search.all_folders_except_spam_trash")}</option>
|
||||
<option value={SEARCH_SCOPE_ALL_FOLDERS}>{t("advanced_search.all_folders")}</option>
|
||||
{searchScopeFolders.own.map((mb) => (
|
||||
<option key={mb.id} value={mb.id}>
|
||||
{"\u00A0".repeat(mb.depth * 3)}{mb.name}
|
||||
</option>
|
||||
))}
|
||||
{searchScopeFolders.shared.map((group) => (
|
||||
<optgroup key={group.ownerId} label={group.label}>
|
||||
{group.mailboxes.map((mb) => (
|
||||
<option key={mb.id} value={mb.id}>
|
||||
{"\u00A0".repeat(mb.depth * 3)}{mb.name}
|
||||
</option>
|
||||
))}
|
||||
</optgroup>
|
||||
))}
|
||||
</select>
|
||||
{renderSearchFolderSelect(
|
||||
"w-full h-8 text-sm rounded-md border border-input bg-background px-3 text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1",
|
||||
true,
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -4464,6 +4488,7 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>)}
|
||||
</FilterPanelHost>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { DEFAULT_SEARCH_FILTERS } from '@/lib/jmap/search-utils';
|
||||
import { MvSearchForm } from '../mv-search-form';
|
||||
|
||||
describe('MvSearchForm', () => {
|
||||
it('edits the filters without searching, and searches on submit', () => {
|
||||
const onChange = vi.fn();
|
||||
const onSearch = vi.fn();
|
||||
render(<MvSearchForm filters={DEFAULT_SEARCH_FILTERS} onChange={onChange} onSearch={onSearch} onClear={() => {}} />);
|
||||
|
||||
fireEvent.change(screen.getByLabelText('from'), { target: { value: 'alice' } });
|
||||
expect(onChange).toHaveBeenCalledWith({ from: 'alice' });
|
||||
fireEvent.click(screen.getByLabelText('has_attachment_check'));
|
||||
expect(onChange).toHaveBeenCalledWith({ hasAttachment: true });
|
||||
expect(onSearch).not.toHaveBeenCalled();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'search' }));
|
||||
expect(onSearch).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('unticking a criterion drops it rather than searching for its opposite', () => {
|
||||
const onChange = vi.fn();
|
||||
render(
|
||||
<MvSearchForm filters={{ ...DEFAULT_SEARCH_FILTERS, isUnread: true }} onChange={onChange} onSearch={() => {}} onClear={() => {}} />,
|
||||
);
|
||||
fireEvent.click(screen.getByLabelText('unread'));
|
||||
expect(onChange).toHaveBeenCalledWith({ isUnread: null });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,113 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import type { SearchFilters } from "@/lib/jmap/search-utils";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface MvSearchFormProps {
|
||||
filters: SearchFilters;
|
||||
onChange: (patch: Partial<SearchFilters>) => void;
|
||||
/** Runs the search and closes the panel. */
|
||||
onSearch: () => void;
|
||||
onClear: () => void;
|
||||
/** The folder picker, shared with the default layout's panel. */
|
||||
folderSelect?: ReactNode;
|
||||
}
|
||||
|
||||
const FIELD = "w-full h-8 bg-transparent border-0 border-b border-border px-0 text-sm text-foreground placeholder:text-muted-foreground/70 focus:outline-none focus:border-b-2 focus:border-primary";
|
||||
|
||||
/**
|
||||
* Mountain View's advanced search: Gmail's form under the search field, one
|
||||
* labelled row per criterion with underlined fields, the yes/no criteria as
|
||||
* checkboxes, and a Search button that runs it.
|
||||
*/
|
||||
export function MvSearchForm({ filters, onChange, onSearch, onClear, folderSelect }: MvSearchFormProps) {
|
||||
const t = useTranslations("advanced_search");
|
||||
|
||||
const row = (label: string, field: ReactNode) => (
|
||||
<label className="grid grid-cols-[8rem_1fr] items-end gap-4 py-1">
|
||||
<span className="pb-1.5 text-sm text-muted-foreground">{label}</span>
|
||||
{field}
|
||||
</label>
|
||||
);
|
||||
|
||||
const check = (label: string, value: boolean | null, key: "hasAttachment" | "isStarred" | "isUnread") => (
|
||||
<label className="inline-flex items-center gap-3 text-sm text-foreground cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={value === true}
|
||||
onChange={(e) => onChange({ [key]: e.target.checked ? true : null })}
|
||||
className="h-4 w-4 rounded-sm accent-[var(--color-primary)]"
|
||||
/>
|
||||
{label}
|
||||
</label>
|
||||
);
|
||||
|
||||
return (
|
||||
<form
|
||||
data-mv-search-form=""
|
||||
className="px-3 pb-1 pt-1"
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
onSearch();
|
||||
}}
|
||||
>
|
||||
{row(t("from"), <input className={FIELD} value={filters.from} onChange={(e) => onChange({ from: e.target.value })} />)}
|
||||
{row(t("to"), <input className={FIELD} value={filters.to} onChange={(e) => onChange({ to: e.target.value })} />)}
|
||||
{row(t("subject"), <input className={FIELD} value={filters.subject} onChange={(e) => onChange({ subject: e.target.value })} />)}
|
||||
{row(t("has_words"), <input className={FIELD} value={filters.body} onChange={(e) => onChange({ body: e.target.value })} />)}
|
||||
{row(t("size"), (
|
||||
<span className="grid grid-cols-2 gap-4">
|
||||
<input
|
||||
type="number"
|
||||
min={1}
|
||||
inputMode="numeric"
|
||||
className={FIELD}
|
||||
placeholder={t("size_min")}
|
||||
value={filters.minSizeKb}
|
||||
onChange={(e) => onChange({ minSizeKb: e.target.value })}
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
min={1}
|
||||
inputMode="numeric"
|
||||
className={FIELD}
|
||||
placeholder={t("size_max")}
|
||||
value={filters.maxSizeKb}
|
||||
onChange={(e) => onChange({ maxSizeKb: e.target.value })}
|
||||
/>
|
||||
</span>
|
||||
))}
|
||||
{row(t("date_within"), (
|
||||
<span className="grid grid-cols-2 gap-4">
|
||||
<input type="date" aria-label={t("date_after")} className={FIELD} value={filters.dateAfter} onChange={(e) => onChange({ dateAfter: e.target.value })} />
|
||||
<input type="date" aria-label={t("date_before")} className={FIELD} value={filters.dateBefore} onChange={(e) => onChange({ dateBefore: e.target.value })} />
|
||||
</span>
|
||||
))}
|
||||
{folderSelect && row(t("search_in"), folderSelect)}
|
||||
|
||||
<div className="flex flex-wrap items-center gap-x-6 gap-y-2 py-3">
|
||||
{check(t("has_attachment_check"), filters.hasAttachment, "hasAttachment")}
|
||||
{check(t("starred"), filters.isStarred, "isStarred")}
|
||||
{check(t("unread"), filters.isUnread, "isUnread")}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end gap-2 pb-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClear}
|
||||
className="h-9 rounded-full px-4 text-sm font-medium text-muted-foreground hover:bg-muted transition-colors"
|
||||
>
|
||||
{t("clear")}
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className={cn("h-9 rounded-full px-6 text-sm font-medium bg-primary text-primary-foreground hover:shadow-md transition-shadow")}
|
||||
>
|
||||
{t("search")}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
@@ -3597,7 +3597,13 @@
|
||||
"suggestions_people": "الأشخاص",
|
||||
"suggestions_from": "البحث في البريد من {address}",
|
||||
"suggestions_to": "البحث في البريد إلى {address}",
|
||||
"suggestions_remove_recent": "إزالة من عمليات البحث الأخيرة"
|
||||
"suggestions_remove_recent": "إزالة من عمليات البحث الأخيرة",
|
||||
"has_words": "يحتوي على الكلمات",
|
||||
"size": "الحجم",
|
||||
"date_within": "التاريخ",
|
||||
"search_in": "البحث في",
|
||||
"has_attachment_check": "يحتوي على مرفق",
|
||||
"search": "بحث"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "مرحبًا بك في صندوق بريدك",
|
||||
|
||||
@@ -3597,7 +3597,13 @@
|
||||
"suggestions_people": "Persones",
|
||||
"suggestions_from": "Cerca correu de {address}",
|
||||
"suggestions_to": "Cerca correu per a {address}",
|
||||
"suggestions_remove_recent": "Elimina de les cerques recents"
|
||||
"suggestions_remove_recent": "Elimina de les cerques recents",
|
||||
"has_words": "Conté les paraules",
|
||||
"size": "Mida",
|
||||
"date_within": "Data",
|
||||
"search_in": "Cerca a",
|
||||
"has_attachment_check": "Té fitxers adjunts",
|
||||
"search": "Cerca"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Us donem la benvinguda a la bústia",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "Lidé",
|
||||
"suggestions_from": "Hledat e-maily od {address}",
|
||||
"suggestions_to": "Hledat e-maily pro {address}",
|
||||
"suggestions_remove_recent": "Odebrat z nedávných hledání"
|
||||
"suggestions_remove_recent": "Odebrat z nedávných hledání",
|
||||
"has_words": "Obsahuje slova",
|
||||
"size": "Velikost",
|
||||
"date_within": "Datum",
|
||||
"search_in": "Hledat v",
|
||||
"has_attachment_check": "Má přílohu",
|
||||
"search": "Hledat"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Vítejte ve své poštovní schránce",
|
||||
|
||||
@@ -3597,7 +3597,13 @@
|
||||
"suggestions_people": "Personer",
|
||||
"suggestions_from": "Søg efter mails fra {address}",
|
||||
"suggestions_to": "Søg efter mails til {address}",
|
||||
"suggestions_remove_recent": "Fjern fra seneste søgninger"
|
||||
"suggestions_remove_recent": "Fjern fra seneste søgninger",
|
||||
"has_words": "Indeholder ordene",
|
||||
"size": "Størrelse",
|
||||
"date_within": "Dato",
|
||||
"search_in": "Søg i",
|
||||
"has_attachment_check": "Har vedhæftet fil",
|
||||
"search": "Søg"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Velkommen til din postkasse",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "Personen",
|
||||
"suggestions_from": "E-Mails von {address} suchen",
|
||||
"suggestions_to": "E-Mails an {address} suchen",
|
||||
"suggestions_remove_recent": "Aus den letzten Suchen entfernen"
|
||||
"suggestions_remove_recent": "Aus den letzten Suchen entfernen",
|
||||
"has_words": "Enthält die Wörter",
|
||||
"size": "Größe",
|
||||
"date_within": "Datum",
|
||||
"search_in": "Suchen in",
|
||||
"has_attachment_check": "Mit Anhang",
|
||||
"search": "Suchen"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Willkommen in Ihrem Postfach",
|
||||
|
||||
@@ -3597,7 +3597,13 @@
|
||||
"suggestions_people": "People",
|
||||
"suggestions_from": "Search mail from {address}",
|
||||
"suggestions_to": "Search mail to {address}",
|
||||
"suggestions_remove_recent": "Remove from recent searches"
|
||||
"suggestions_remove_recent": "Remove from recent searches",
|
||||
"has_words": "Has the words",
|
||||
"size": "Size",
|
||||
"date_within": "Date",
|
||||
"search_in": "Search in",
|
||||
"has_attachment_check": "Has attachment",
|
||||
"search": "Search"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Welcome to your mailbox",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "Personas",
|
||||
"suggestions_from": "Buscar correos de {address}",
|
||||
"suggestions_to": "Buscar correos para {address}",
|
||||
"suggestions_remove_recent": "Quitar de las búsquedas recientes"
|
||||
"suggestions_remove_recent": "Quitar de las búsquedas recientes",
|
||||
"has_words": "Contiene las palabras",
|
||||
"size": "Tamaño",
|
||||
"date_within": "Fecha",
|
||||
"search_in": "Buscar en",
|
||||
"has_attachment_check": "Tiene archivos adjuntos",
|
||||
"search": "Buscar"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Bienvenido a tu buzón",
|
||||
|
||||
@@ -3597,7 +3597,13 @@
|
||||
"suggestions_people": "افراد",
|
||||
"suggestions_from": "جستجوی ایمیلهای از {address}",
|
||||
"suggestions_to": "جستجوی ایمیلهای به {address}",
|
||||
"suggestions_remove_recent": "حذف از جستجوهای اخیر"
|
||||
"suggestions_remove_recent": "حذف از جستجوهای اخیر",
|
||||
"has_words": "شامل کلمات",
|
||||
"size": "اندازه",
|
||||
"date_within": "تاریخ",
|
||||
"search_in": "جستجو در",
|
||||
"has_attachment_check": "دارای پیوست",
|
||||
"search": "جستجو"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "به صندوق پستی خود خوش آمدید",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "Personnes",
|
||||
"suggestions_from": "Rechercher les e-mails de {address}",
|
||||
"suggestions_to": "Rechercher les e-mails à {address}",
|
||||
"suggestions_remove_recent": "Retirer des recherches récentes"
|
||||
"suggestions_remove_recent": "Retirer des recherches récentes",
|
||||
"has_words": "Contient les mots",
|
||||
"size": "Taille",
|
||||
"date_within": "Date",
|
||||
"search_in": "Rechercher dans",
|
||||
"has_attachment_check": "Contient une pièce jointe",
|
||||
"search": "Rechercher"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Bienvenue dans votre boite mail",
|
||||
|
||||
@@ -3479,7 +3479,13 @@
|
||||
"suggestions_people": "אנשים",
|
||||
"suggestions_from": "חיפוש הודעות מאת {address}",
|
||||
"suggestions_to": "חיפוש הודעות אל {address}",
|
||||
"suggestions_remove_recent": "הסרה מהחיפושים האחרונים"
|
||||
"suggestions_remove_recent": "הסרה מהחיפושים האחרונים",
|
||||
"has_words": "מכיל את המילים",
|
||||
"size": "גודל",
|
||||
"date_within": "תאריך",
|
||||
"search_in": "חיפוש ב",
|
||||
"has_attachment_check": "יש קובץ מצורף",
|
||||
"search": "חיפוש"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "ברוך הבא לתיבת הדואר שלך",
|
||||
|
||||
@@ -3597,7 +3597,13 @@
|
||||
"suggestions_people": "Személyek",
|
||||
"suggestions_from": "Levelek keresése tőle: {address}",
|
||||
"suggestions_to": "Levelek keresése neki: {address}",
|
||||
"suggestions_remove_recent": "Eltávolítás a legutóbbi keresésekből"
|
||||
"suggestions_remove_recent": "Eltávolítás a legutóbbi keresésekből",
|
||||
"has_words": "Tartalmazza a szavakat",
|
||||
"size": "Méret",
|
||||
"date_within": "Dátum",
|
||||
"search_in": "Keresés itt",
|
||||
"has_attachment_check": "Van melléklete",
|
||||
"search": "Keresés"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Üdvözlünk a postafiókodban",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "Persone",
|
||||
"suggestions_from": "Cerca email da {address}",
|
||||
"suggestions_to": "Cerca email a {address}",
|
||||
"suggestions_remove_recent": "Rimuovi dalle ricerche recenti"
|
||||
"suggestions_remove_recent": "Rimuovi dalle ricerche recenti",
|
||||
"has_words": "Contiene le parole",
|
||||
"size": "Dimensione",
|
||||
"date_within": "Data",
|
||||
"search_in": "Cerca in",
|
||||
"has_attachment_check": "Con allegati",
|
||||
"search": "Cerca"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Benvenuto nella tua casella di posta",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "連絡先",
|
||||
"suggestions_from": "{address} からのメールを検索",
|
||||
"suggestions_to": "{address} 宛のメールを検索",
|
||||
"suggestions_remove_recent": "最近の検索から削除"
|
||||
"suggestions_remove_recent": "最近の検索から削除",
|
||||
"has_words": "含む",
|
||||
"size": "サイズ",
|
||||
"date_within": "日付",
|
||||
"search_in": "検索対象",
|
||||
"has_attachment_check": "添付ファイルあり",
|
||||
"search": "検索"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "メールボックスへようこそ",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "사람",
|
||||
"suggestions_from": "{address}에서 온 메일 검색",
|
||||
"suggestions_to": "{address}에게 보낸 메일 검색",
|
||||
"suggestions_remove_recent": "최근 검색에서 삭제"
|
||||
"suggestions_remove_recent": "최근 검색에서 삭제",
|
||||
"has_words": "포함하는 단어",
|
||||
"size": "크기",
|
||||
"date_within": "날짜",
|
||||
"search_in": "검색 위치",
|
||||
"has_attachment_check": "첨부파일 있음",
|
||||
"search": "검색"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "웹메일에 오신 것을 환영해요!",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "Personas",
|
||||
"suggestions_from": "Meklēt e-pastus no {address}",
|
||||
"suggestions_to": "Meklēt e-pastus adresātam {address}",
|
||||
"suggestions_remove_recent": "Noņemt no nesenajiem meklējumiem"
|
||||
"suggestions_remove_recent": "Noņemt no nesenajiem meklējumiem",
|
||||
"has_words": "Satur vārdus",
|
||||
"size": "Izmērs",
|
||||
"date_within": "Datums",
|
||||
"search_in": "Meklēt",
|
||||
"has_attachment_check": "Ar pielikumu",
|
||||
"search": "Meklēt"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Laipni lūdzam jūsu pastkastē",
|
||||
|
||||
@@ -3597,7 +3597,13 @@
|
||||
"suggestions_people": "Хүмүүс",
|
||||
"suggestions_from": "{address}-аас ирсэн захидал хайх",
|
||||
"suggestions_to": "{address} руу илгээсэн захидал хайх",
|
||||
"suggestions_remove_recent": "Сүүлийн хайлтуудаас хасах"
|
||||
"suggestions_remove_recent": "Сүүлийн хайлтуудаас хасах",
|
||||
"has_words": "Агуулсан үгс",
|
||||
"size": "Хэмжээ",
|
||||
"date_within": "Огноо",
|
||||
"search_in": "Хайх газар",
|
||||
"has_attachment_check": "Хавсралттай",
|
||||
"search": "Хайх"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Таны шуудангийн хайрцагт тавтай морил",
|
||||
|
||||
@@ -3597,7 +3597,13 @@
|
||||
"suggestions_people": "Personer",
|
||||
"suggestions_from": "Søk etter e-post fra {address}",
|
||||
"suggestions_to": "Søk etter e-post til {address}",
|
||||
"suggestions_remove_recent": "Fjern fra nylige søk"
|
||||
"suggestions_remove_recent": "Fjern fra nylige søk",
|
||||
"has_words": "Inneholder ordene",
|
||||
"size": "Størrelse",
|
||||
"date_within": "Dato",
|
||||
"search_in": "Søk i",
|
||||
"has_attachment_check": "Har vedlegg",
|
||||
"search": "Søk"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Velkommen til postkassen din",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "Personen",
|
||||
"suggestions_from": "E-mails van {address} zoeken",
|
||||
"suggestions_to": "E-mails aan {address} zoeken",
|
||||
"suggestions_remove_recent": "Verwijderen uit recente zoekopdrachten"
|
||||
"suggestions_remove_recent": "Verwijderen uit recente zoekopdrachten",
|
||||
"has_words": "Bevat de woorden",
|
||||
"size": "Grootte",
|
||||
"date_within": "Datum",
|
||||
"search_in": "Zoeken in",
|
||||
"has_attachment_check": "Met bijlage",
|
||||
"search": "Zoeken"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Welkom bij uw mailbox",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "Osoby",
|
||||
"suggestions_from": "Szukaj wiadomości od {address}",
|
||||
"suggestions_to": "Szukaj wiadomości do {address}",
|
||||
"suggestions_remove_recent": "Usuń z ostatnich wyszukiwań"
|
||||
"suggestions_remove_recent": "Usuń z ostatnich wyszukiwań",
|
||||
"has_words": "Zawiera słowa",
|
||||
"size": "Rozmiar",
|
||||
"date_within": "Data",
|
||||
"search_in": "Szukaj w",
|
||||
"has_attachment_check": "Z załącznikiem",
|
||||
"search": "Szukaj"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Witaj w swojej skrzynce pocztowej",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "Pessoas",
|
||||
"suggestions_from": "Pesquisar e-mails de {address}",
|
||||
"suggestions_to": "Pesquisar e-mails para {address}",
|
||||
"suggestions_remove_recent": "Remover das pesquisas recentes"
|
||||
"suggestions_remove_recent": "Remover das pesquisas recentes",
|
||||
"has_words": "Contém as palavras",
|
||||
"size": "Tamanho",
|
||||
"date_within": "Data",
|
||||
"search_in": "Pesquisar em",
|
||||
"has_attachment_check": "Com anexo",
|
||||
"search": "Pesquisar"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Bem-vindo à sua caixa de entrada",
|
||||
|
||||
@@ -3597,7 +3597,13 @@
|
||||
"suggestions_people": "Persoane",
|
||||
"suggestions_from": "Caută e-mailuri de la {address}",
|
||||
"suggestions_to": "Caută e-mailuri către {address}",
|
||||
"suggestions_remove_recent": "Elimină din căutările recente"
|
||||
"suggestions_remove_recent": "Elimină din căutările recente",
|
||||
"has_words": "Conține cuvintele",
|
||||
"size": "Dimensiune",
|
||||
"date_within": "Dată",
|
||||
"search_in": "Caută în",
|
||||
"has_attachment_check": "Are atașament",
|
||||
"search": "Caută"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Bine ați venit în căsuța dvs. poștală",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "Люди",
|
||||
"suggestions_from": "Искать письма от {address}",
|
||||
"suggestions_to": "Искать письма для {address}",
|
||||
"suggestions_remove_recent": "Удалить из недавних запросов"
|
||||
"suggestions_remove_recent": "Удалить из недавних запросов",
|
||||
"has_words": "Содержит слова",
|
||||
"size": "Размер",
|
||||
"date_within": "Дата",
|
||||
"search_in": "Искать в",
|
||||
"has_attachment_check": "Есть вложения",
|
||||
"search": "Найти"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Добро пожаловать в ваш почтовый ящик",
|
||||
|
||||
@@ -3597,7 +3597,13 @@
|
||||
"suggestions_people": "Ľudia",
|
||||
"suggestions_from": "Hľadať e-maily od {address}",
|
||||
"suggestions_to": "Hľadať e-maily pre {address}",
|
||||
"suggestions_remove_recent": "Odstrániť z nedávnych vyhľadávaní"
|
||||
"suggestions_remove_recent": "Odstrániť z nedávnych vyhľadávaní",
|
||||
"has_words": "Obsahuje slová",
|
||||
"size": "Veľkosť",
|
||||
"date_within": "Dátum",
|
||||
"search_in": "Hľadať v",
|
||||
"has_attachment_check": "Má prílohu",
|
||||
"search": "Hľadať"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Vitajte vo svojej poštovej schránke",
|
||||
|
||||
@@ -3597,7 +3597,13 @@
|
||||
"suggestions_people": "Kişiler",
|
||||
"suggestions_from": "{address} adresinden gelen e-postaları ara",
|
||||
"suggestions_to": "{address} adresine gönderilen e-postaları ara",
|
||||
"suggestions_remove_recent": "Son aramalardan kaldır"
|
||||
"suggestions_remove_recent": "Son aramalardan kaldır",
|
||||
"has_words": "Şu kelimeleri içeren",
|
||||
"size": "Boyut",
|
||||
"date_within": "Tarih",
|
||||
"search_in": "Şurada ara",
|
||||
"has_attachment_check": "Eki var",
|
||||
"search": "Ara"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Posta kutunuza hoş geldiniz",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "Люди",
|
||||
"suggestions_from": "Шукати листи від {address}",
|
||||
"suggestions_to": "Шукати листи для {address}",
|
||||
"suggestions_remove_recent": "Видалити з останніх пошуків"
|
||||
"suggestions_remove_recent": "Видалити з останніх пошуків",
|
||||
"has_words": "Містить слова",
|
||||
"size": "Розмір",
|
||||
"date_within": "Дата",
|
||||
"search_in": "Шукати в",
|
||||
"has_attachment_check": "Є вкладення",
|
||||
"search": "Шукати"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Ласкаво просимо до вашої поштової скриньки",
|
||||
|
||||
@@ -3597,7 +3597,13 @@
|
||||
"suggestions_people": "聯絡人",
|
||||
"suggestions_from": "搜尋來自 {address} 的郵件",
|
||||
"suggestions_to": "搜尋寄給 {address} 的郵件",
|
||||
"suggestions_remove_recent": "從最近搜尋中移除"
|
||||
"suggestions_remove_recent": "從最近搜尋中移除",
|
||||
"has_words": "包含字詞",
|
||||
"size": "大小",
|
||||
"date_within": "日期",
|
||||
"search_in": "搜尋範圍",
|
||||
"has_attachment_check": "包含附件",
|
||||
"search": "搜尋"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "歡迎使用您的信件匣",
|
||||
|
||||
@@ -3555,7 +3555,13 @@
|
||||
"suggestions_people": "联系人",
|
||||
"suggestions_from": "搜索来自 {address} 的邮件",
|
||||
"suggestions_to": "搜索发给 {address} 的邮件",
|
||||
"suggestions_remove_recent": "从最近搜索中移除"
|
||||
"suggestions_remove_recent": "从最近搜索中移除",
|
||||
"has_words": "包含字词",
|
||||
"size": "大小",
|
||||
"date_within": "日期",
|
||||
"search_in": "搜索范围",
|
||||
"has_attachment_check": "包含附件",
|
||||
"search": "搜索"
|
||||
},
|
||||
"welcome": {
|
||||
"title": "欢迎使用邮箱",
|
||||
|
||||
Reference in New Issue
Block a user