feat: use Gmail's advanced search form in Mountain View

This commit is contained in:
Linus Rath
2026-10-12 01:34:02 +02:00
parent 78e68e8886
commit cedac10c29
30 changed files with 385 additions and 55 deletions
+53 -28
View File
@@ -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 });
});
});
+113
View File
@@ -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>
);
}
+7 -1
View File
@@ -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": "مرحبًا بك في صندوق بريدك",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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": "به صندوق پستی خود خوش آمدید",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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": "ברוך הבא לתיבת הדואר שלך",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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": "メールボックスへようこそ",
+7 -1
View File
@@ -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": "웹메일에 오신 것을 환영해요!",
+7 -1
View File
@@ -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ē",
+7 -1
View File
@@ -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": "Таны шуудангийн хайрцагт тавтай морил",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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ă",
+7 -1
View File
@@ -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": "Добро пожаловать в ваш почтовый ящик",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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",
+7 -1
View File
@@ -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": "Ласкаво просимо до вашої поштової скриньки",
+7 -1
View File
@@ -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": "歡迎使用您的信件匣",
+7 -1
View File
@@ -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": "欢迎使用邮箱",