diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index f7d690f..c891823 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -21,7 +21,7 @@ import { useDeviceDetection } from "@/hooks/use-media-query"; import { useKeyboardShortcuts } from "@/hooks/use-keyboard-shortcuts"; import { debug } from "@/lib/debug"; import { playNotificationSound } from "@/lib/notification-sound"; -import { cn } from "@/lib/utils"; +import { cn, getMailboxDisplayName } from "@/lib/utils"; import { ErrorBoundary, SidebarErrorFallback, @@ -224,7 +224,7 @@ export default function Home() { // Mailbox view const mailbox = mailboxes.find(mb => mb.id === selectedMailbox); if (mailbox) { - const mailboxName = mailbox.name; + const mailboxName = getMailboxDisplayName(mailbox.role, mailbox.name, (key) => t(`sidebar.${key}`)); const unreadCount = mailbox.unreadEmails || 0; title = unreadCount > 0 ? `${mailboxName} (${unreadCount}) - ${tCommon('app_title')}` @@ -666,7 +666,10 @@ export default function Home() { } // Get current mailbox name for mobile header - const currentMailboxName = mailboxes.find(m => m.id === selectedMailbox)?.name || "Inbox"; + const currentMailbox = mailboxes.find(m => m.id === selectedMailbox); + const currentMailboxName = currentMailbox + ? getMailboxDisplayName(currentMailbox.role, currentMailbox.name, (key) => t(`sidebar.${key}`)) + : t('sidebar.mailboxes.inbox'); // Handle email selection with mobile view switching const handleEmailSelect = async (email: { id: string }) => { diff --git a/components/email/email-composer.tsx b/components/email/email-composer.tsx index 4120435..4e91bc9 100644 --- a/components/email/email-composer.tsx +++ b/components/email/email-composer.tsx @@ -3,7 +3,7 @@ import React, { useState, useEffect, useRef, useCallback } from "react"; import { useFocusTrap } from "@/hooks/use-focus-trap"; import { useConfirmDialog } from "@/hooks/use-confirm-dialog"; -import { useTranslations } from "next-intl"; +import { useTranslations, useLocale } from "next-intl"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { ConfirmDialog } from "@/components/ui/confirm-dialog"; @@ -59,6 +59,7 @@ export function EmailComposer({ }: EmailComposerProps) { const t = useTranslations('email_composer'); const tCommon = useTranslations('common'); + const locale = useLocale(); // Initialize with reply/forward data if provided const getInitialTo = () => { @@ -94,7 +95,7 @@ export function EmailComposer({ const prefix = initialDraftText || ""; if (!replyTo?.body) return prefix; - const date = replyTo.receivedAt ? new Date(replyTo.receivedAt).toLocaleString() : ""; + const date = replyTo.receivedAt ? new Date(replyTo.receivedAt).toLocaleString(locale) : ""; const from = replyTo.from?.[0]; const fromStr = from ? `${from.name || from.email}` : tCommon('unknown'); diff --git a/components/email/email-context-menu.tsx b/components/email/email-context-menu.tsx index 39c7853..d5f590d 100644 --- a/components/email/email-context-menu.tsx +++ b/components/email/email-context-menu.tsx @@ -28,7 +28,7 @@ import { ShieldAlert, ShieldCheck, } from "lucide-react"; -import { cn, buildMailboxTree, flattenMailboxTree } from "@/lib/utils"; +import { cn, buildMailboxTree, flattenMailboxTree, getMailboxDisplayName } from "@/lib/utils"; interface Position { x: number; @@ -125,6 +125,7 @@ export function EmailContextMenu({ }: EmailContextMenuProps) { const t = useTranslations("context_menu"); const tColor = useTranslations("email_viewer.color_tag"); + const tSidebar = useTranslations("sidebar"); const isUnread = !email.keywords?.$seen; const isStarred = email.keywords?.$flagged; const currentColor = getCurrentColor(email.keywords); @@ -228,7 +229,7 @@ export function EmailContextMenu({ 0 ? { paddingLeft: `${12 + mailbox.depth * 12}px` } : undefined} onClick={() => handleAction(() => diff --git a/components/email/email-list-item.tsx b/components/email/email-list-item.tsx index c11f996..14a7ec4 100644 --- a/components/email/email-list-item.tsx +++ b/components/email/email-list-item.tsx @@ -1,6 +1,6 @@ "use client"; -import { useTranslations } from "next-intl"; +import { useTranslations, useLocale } from "next-intl"; import { formatDate } from "@/lib/utils"; import { Email } from "@/lib/jmap/types"; import { cn } from "@/lib/utils"; @@ -44,6 +44,9 @@ const getEmailColor = (keywords: Record | undefined) => { export function EmailListItem({ email, selected, onClick, onContextMenu }: EmailListItemProps) { const t = useTranslations('email_viewer'); + const tList = useTranslations('email_list'); + const tDate = useTranslations('date'); + const locale = useLocale(); const { selectedEmailIds, toggleEmailSelection, selectedMailbox } = useEmailStore(); const showPreview = useSettingsStore((state) => state.showPreview); const listDensity = useSettingsStore((state) => state.listDensity); @@ -184,7 +187,7 @@ export function EmailListItem({ email, selected, onClick, onContextMenu }: Email ? "text-foreground font-semibold" : "text-muted-foreground" )}> - {formatDate(email.receivedAt)} + {formatDate(email.receivedAt, tDate, locale)} @@ -206,7 +209,7 @@ export function EmailListItem({ email, selected, onClick, onContextMenu }: Email ? "text-muted-foreground" : "text-muted-foreground/80" )}> - {email.preview || "No preview available"} + {email.preview || tList('no_preview')}

)} diff --git a/components/email/email-viewer.tsx b/components/email/email-viewer.tsx index 6c7c3ea..fb23a3b 100644 --- a/components/email/email-viewer.tsx +++ b/components/email/email-viewer.tsx @@ -50,7 +50,7 @@ import { Sparkles, Keyboard, } from "lucide-react"; -import { useTranslations } from "next-intl"; +import { useTranslations, useLocale } from "next-intl"; import { useSettingsStore } from "@/stores/settings-store"; import { useUIStore } from "@/stores/ui-store"; import { useDeviceDetection } from "@/hooks/use-media-query"; @@ -186,6 +186,7 @@ export function EmailViewer({ className, }: EmailViewerProps) { const t = useTranslations('email_viewer'); + const locale = useLocale(); const tCommon = useTranslations('common'); const externalContentPolicy = useSettingsStore((state) => state.externalContentPolicy); const addTrustedSender = useSettingsStore((state) => state.addTrustedSender); @@ -799,7 +800,7 @@ export function EmailViewer({
- {new Date(email.receivedAt).toLocaleString('en-US', { + {new Date(email.receivedAt).toLocaleString(locale, { weekday: 'short', year: 'numeric', month: 'short', @@ -839,7 +840,7 @@ export function EmailViewer({ title={t('tooltips.reply')} > - Reply + {t('reply')} {/* Reply Options Dropdown - hidden on mobile/tablet */} @@ -858,14 +859,14 @@ export function EmailViewer({ className="w-full px-3 py-2 text-sm text-left hover:bg-muted text-foreground flex items-center gap-2" > - Reply all + {t('reply_all')}
diff --git a/components/email/move-to-popover.tsx b/components/email/move-to-popover.tsx index 0996ad0..0ea02b3 100644 --- a/components/email/move-to-popover.tsx +++ b/components/email/move-to-popover.tsx @@ -3,7 +3,7 @@ import { useState, useRef, useEffect, useMemo } from "react"; import { createPortal } from "react-dom"; import { FolderInput, Search, Inbox, Send, FileText, Archive, Trash2, AlertTriangle, Folder } from "lucide-react"; -import { cn } from "@/lib/utils"; +import { cn, getMailboxDisplayName } from "@/lib/utils"; import { useTranslations } from "next-intl"; import { Mailbox } from "@/lib/jmap/types"; @@ -44,6 +44,7 @@ function getMailboxDepth(mailbox: Mailbox, allMailboxes: Mailbox[]): number { export function MoveToPopover({ mailboxes, currentMailboxId, onMove, disabled }: MoveToPopoverProps) { const t = useTranslations('email_list'); + const tSidebar = useTranslations('sidebar'); const [isOpen, setIsOpen] = useState(false); const [search, setSearch] = useState(""); const buttonRef = useRef(null); @@ -59,14 +60,14 @@ export function MoveToPopover({ mailboxes, currentMailboxId, onMove, disabled }: const systemRoles = ['inbox', 'sent', 'drafts', 'archive', 'trash', 'junk']; const query = search.toLowerCase(); const filtered = availableMailboxes.filter(m => - m.name.toLowerCase().includes(query) + getMailboxDisplayName(m.role, m.name, tSidebar).toLowerCase().includes(query) ); const system = filtered.filter(m => m.role && systemRoles.includes(m.role)); const custom = filtered.filter(m => !m.role || !systemRoles.includes(m.role)); return { system, custom }; - }, [availableMailboxes, search]); + }, [availableMailboxes, search, tSidebar]); const allFiltered = [...filteredMailboxes.system, ...filteredMailboxes.custom]; @@ -214,7 +215,7 @@ export function MoveToPopover({ mailboxes, currentMailboxId, onMove, disabled }: onClick={() => handleMove(mailbox.id)} > - {highlightMatch(mailbox.name)} + {highlightMatch(getMailboxDisplayName(mailbox.role, mailbox.name, tSidebar))} ); })} diff --git a/components/email/thread-conversation-view.tsx b/components/email/thread-conversation-view.tsx index d00ec48..764ab78 100644 --- a/components/email/thread-conversation-view.tsx +++ b/components/email/thread-conversation-view.tsx @@ -28,7 +28,7 @@ import { FileArchive, File, } from "lucide-react"; -import { useTranslations } from "next-intl"; +import { useTranslations, useLocale } from "next-intl"; import { useSettingsStore } from "@/stores/settings-store"; import { useAuthStore } from "@/stores/auth-store"; @@ -221,6 +221,8 @@ function EmailCard({ onMarkAsRead, }: EmailCardProps) { const t = useTranslations(); + const tDate = useTranslations('date'); + const locale = useLocale(); const resolvedTheme = useThemeStore((state) => state.resolvedTheme); const sender = email.from?.[0]; const isUnread = !email.keywords?.$seen; @@ -458,11 +460,11 @@ function EmailCard({ )}
- {formatDate(email.receivedAt)} + {formatDate(email.receivedAt, tDate, locale)}
{!isExpanded && (

- {email.preview || "No preview available"} + {email.preview || t('email_list.no_preview')}

)} diff --git a/components/email/thread-email-item.tsx b/components/email/thread-email-item.tsx index ffe8b34..49aaa1d 100644 --- a/components/email/thread-email-item.tsx +++ b/components/email/thread-email-item.tsx @@ -1,5 +1,6 @@ "use client"; +import { useTranslations, useLocale } from "next-intl"; import { formatDate } from "@/lib/utils"; import { Email } from "@/lib/jmap/types"; import { cn } from "@/lib/utils"; @@ -21,6 +22,9 @@ export function ThreadEmailItem({ onClick, onContextMenu, }: ThreadEmailItemProps) { + const t = useTranslations(); + const tDate = useTranslations('date'); + const locale = useLocale(); const isUnread = !email.keywords?.$seen; const isStarred = email.keywords?.$flagged; const sender = email.from?.[0]; @@ -70,7 +74,7 @@ export function ThreadEmailItem({ ? "font-semibold text-foreground" : "font-medium text-muted-foreground" )}> - {sender?.name || sender?.email?.split('@')[0] || "Unknown"} + {sender?.name || sender?.email?.split('@')[0] || t('email_viewer.unknown_sender')} {/* Indicators */} @@ -90,7 +94,7 @@ export function ThreadEmailItem({ ? "text-muted-foreground" : "text-muted-foreground/70" )}> - {email.preview || "No preview"} + {email.preview || t('email_list.no_preview')} {/* Date */} @@ -100,7 +104,7 @@ export function ThreadEmailItem({ ? "text-foreground font-medium" : "text-muted-foreground" )}> - {formatDate(email.receivedAt)} + {formatDate(email.receivedAt, tDate, locale)} diff --git a/components/email/thread-list-item.tsx b/components/email/thread-list-item.tsx index 69b6574..74ac4c0 100644 --- a/components/email/thread-list-item.tsx +++ b/components/email/thread-list-item.tsx @@ -11,7 +11,7 @@ import { useUIStore } from "@/stores/ui-store"; import { useEmailStore } from "@/stores/email-store"; import { getThreadColorTag } from "@/lib/thread-utils"; import { ThreadEmailItem } from "./thread-email-item"; -import { useTranslations } from "next-intl"; +import { useTranslations, useLocale } from "next-intl"; interface ThreadListItemProps { thread: ThreadGroup; @@ -51,6 +51,9 @@ interface SingleEmailItemProps { const SingleEmailItem = React.forwardRef( function SingleEmailItem({ email, selected, onClick, onContextMenu, showPreview, colorTag, isChecked, onCheckboxClick, folderBadgeName }, ref) { + const t = useTranslations(); + const tDate = useTranslations('date'); + const locale = useLocale(); const isUnread = !email.keywords?.$seen; const isStarred = email.keywords?.$flagged; const sender = email.from?.[0]; @@ -146,7 +149,7 @@ const SingleEmailItem = React.forwardRef( ? "text-foreground font-semibold" : "text-muted-foreground" )}> - {formatDate(email.receivedAt)} + {formatDate(email.receivedAt, tDate, locale)} @@ -156,7 +159,7 @@ const SingleEmailItem = React.forwardRef( ? "font-semibold text-foreground" : "font-normal text-foreground/90" )}> - {email.subject || "(no subject)"} + {email.subject || t('email_viewer.no_subject')} {showPreview && ( @@ -166,7 +169,7 @@ const SingleEmailItem = React.forwardRef( ? "text-muted-foreground" : "text-muted-foreground/80" )}> - {email.preview || "No preview available"} + {email.preview || t('email_list.no_preview')}

)} @@ -191,6 +194,9 @@ export const ThreadListItem = React.forwardRef state.showPreview); const isMobile = useUIStore((state) => state.isMobile); const { currentQuery, mailboxes } = useEmailStore(); @@ -376,7 +382,7 @@ export const ThreadListItem = React.forwardRef - {formatDate(latestEmail.receivedAt)} + {formatDate(latestEmail.receivedAt, tDate, locale)} @@ -386,7 +392,7 @@ export const ThreadListItem = React.forwardRef - {latestEmail.subject || "(no subject)"} + {latestEmail.subject || tRoot('email_viewer.no_subject')} {showPreview && ( @@ -396,7 +402,7 @@ export const ThreadListItem = React.forwardRef - {latestEmail.preview || "No preview available"} + {latestEmail.preview || tRoot('email_list.no_preview')}

)} diff --git a/components/layout/sidebar.tsx b/components/layout/sidebar.tsx index c0efd90..c07a8de 100644 --- a/components/layout/sidebar.tsx +++ b/components/layout/sidebar.tsx @@ -33,7 +33,7 @@ import { Edit3, FolderInput, } from "lucide-react"; -import { cn, buildMailboxTree, flattenMailboxTree, MailboxNode, formatFileSize } from "@/lib/utils"; +import { cn, buildMailboxTree, flattenMailboxTree, MailboxNode, formatFileSize, getMailboxDisplayName } from "@/lib/utils"; import { Mailbox } from "@/lib/jmap/types"; import { useDragDropContext } from "@/contexts/drag-drop-context"; import { useMailboxDrop } from "@/hooks/use-mailbox-drop"; @@ -232,6 +232,7 @@ function MailboxTreeItem({ const tNotifications = useTranslations('notifications'); const hasChildren = node.children.length > 0; const isExpanded = expandedFolders.has(node.id); + const displayName = getMailboxDisplayName(node.role, node.name, t); const Icon = getIconForMailbox(node.role, node.name, hasChildren, isExpanded, node.isShared, node.id); const indentPixels = node.depth * 16; const isVirtualNode = node.id.startsWith('shared-'); @@ -342,7 +343,7 @@ function MailboxTreeItem({ style={{ paddingLeft: hasChildren ? '4px' : `${indentPixels + 24}px` }} - title={isCollapsed ? node.name : undefined} + title={isCollapsed ? displayName : undefined} > - {node.name} + {displayName} )} {!isRenaming && node.unreadEmails > 0 && ( diff --git a/components/providers/intl-provider.tsx b/components/providers/intl-provider.tsx index 0ca596f..387bf32 100644 --- a/components/providers/intl-provider.tsx +++ b/components/providers/intl-provider.tsx @@ -7,6 +7,7 @@ import type { Locale } from '@/i18n/routing'; import enMessages from '@/locales/en/common.json'; import deMessages from '@/locales/de/common.json'; import esMessages from '@/locales/es/common.json'; +import etMessages from '@/locales/et/common.json'; import frMessages from '@/locales/fr/common.json'; import itMessages from '@/locales/it/common.json'; import jaMessages from '@/locales/ja/common.json'; @@ -21,6 +22,7 @@ const ALL_MESSAGES: Record = { en: enMessages, de: deMessages, es: esMessages, + et: etMessages, fr: frMessages, it: itMessages, ja: jaMessages, @@ -42,6 +44,16 @@ export function IntlProvider({ locale: initialLocale, children }: IntlProviderPr const setLocale = useLocaleStore((state) => state.setLocale); const [activeLocale, setActiveLocale] = useState(currentLocale || initialLocale); const [timeZone, setTimeZone] = useState('UTC'); + // zustand's persist middleware rehydrates from localStorage asynchronously + // (even for synchronous storage backends), so on mount `currentLocale` can + // still read as its pre-hydration `null` default for one tick. Track + // hydration explicitly instead of trusting `!currentLocale` at mount time — + // otherwise the effect below fires while hydration is still in flight and + // permanently overwrites a real saved locale with the server default. + // `persist` itself is only present in a browser context — during SSR + // there's no localStorage to hydrate from anyway, so treat that as + // "already hydrated" (i.e. just use the server-rendered initialLocale). + const [hasHydrated, setHasHydrated] = useState(() => useLocaleStore.persist?.hasHydrated() ?? true); // Detect user's timezone on mount useEffect(() => { @@ -54,14 +66,23 @@ export function IntlProvider({ locale: initialLocale, children }: IntlProviderPr } }, []); - // Sync initial locale with store on first mount only useEffect(() => { - if (!currentLocale) { - setLocale(initialLocale); + if (!useLocaleStore.persist || useLocaleStore.persist.hasHydrated()) { + setHasHydrated(true); + return; } - // eslint-disable-next-line react-hooks/exhaustive-deps -- sync initial locale to store once on mount + return useLocaleStore.persist.onFinishHydration(() => setHasHydrated(true)); }, []); + // Sync initial locale with store on first mount only, and only once we + // know for certain (post-hydration) that there really is no saved locale. + useEffect(() => { + if (hasHydrated && !currentLocale) { + setLocale(initialLocale); + } + // eslint-disable-next-line react-hooks/exhaustive-deps -- sync initial locale to store once hydration is known + }, [hasHydrated]); + // Switch locale immediately when store changes useEffect(() => { if (currentLocale) { diff --git a/components/ui/language-switcher.tsx b/components/ui/language-switcher.tsx index f455057..6f072d4 100644 --- a/components/ui/language-switcher.tsx +++ b/components/ui/language-switcher.tsx @@ -9,6 +9,7 @@ const NATIVE_LANGUAGE_LABELS: Record = { en: 'English', de: 'Deutsch', es: 'Español', + et: 'Eesti', fr: 'Français', it: 'Italiano', ja: '日本語', diff --git a/i18n/routing.ts b/i18n/routing.ts index 0a67bf7..c69579d 100644 --- a/i18n/routing.ts +++ b/i18n/routing.ts @@ -1,7 +1,7 @@ import { defineRouting } from 'next-intl/routing'; export const routing = defineRouting({ - locales: ['en', 'de', 'es', 'fr', 'it', 'ja', 'nl', 'pl', 'pt', 'ru', 'uk'], + locales: ['en', 'de', 'es', 'et', 'fr', 'it', 'ja', 'nl', 'pl', 'pt', 'ru', 'uk'], defaultLocale: 'en', localePrefix: 'never' }); diff --git a/lib/__tests__/locale-parity.test.ts b/lib/__tests__/locale-parity.test.ts index bfdf540..91aa04c 100644 --- a/lib/__tests__/locale-parity.test.ts +++ b/lib/__tests__/locale-parity.test.ts @@ -3,6 +3,7 @@ import { routing } from '@/i18n/routing'; import en from '@/locales/en/common.json'; import de from '@/locales/de/common.json'; import es from '@/locales/es/common.json'; +import et from '@/locales/et/common.json'; import fr from '@/locales/fr/common.json'; import itLocale from '@/locales/it/common.json'; import ja from '@/locales/ja/common.json'; @@ -23,12 +24,13 @@ function leafKeys(obj: Json, prefix = ''): string[] { }); } -const BUNDLES: Record = { en, de, es, fr, it: itLocale, ja, nl, pl, pt, ru, uk }; +const BUNDLES: Record = { en, de, es, et, fr, it: itLocale, ja, nl, pl, pt, ru, uk }; describe('locale parity', () => { - it('routing declares 11 locales including pl', () => { + it('routing declares 12 locales including pl and et', () => { expect(routing.locales).toContain('pl'); - expect(routing.locales).toHaveLength(11); + expect(routing.locales).toContain('et'); + expect(routing.locales).toHaveLength(12); }); it('every declared locale has a message bundle', () => { @@ -54,4 +56,12 @@ describe('locale parity', () => { expect(lang.switch_to_polish).toBeTruthy(); }); } + + for (const [code, msgs] of Object.entries(BUNDLES)) { + it(`${code} defines Estonian language labels`, () => { + const lang = msgs.language as Json; + expect(lang.estonian).toBeTruthy(); + expect(lang.switch_to_estonian).toBeTruthy(); + }); + } }); diff --git a/lib/utils.ts b/lib/utils.ts index caf842c..e1c0e36 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -6,7 +6,12 @@ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } -export function formatDate(date: Date | string): string { +// `t` should be a translator scoped to the `date` namespace (e.g. +// useTranslations('date')) and `locale` the app's active locale (useLocale()) +// — both are required so relative timestamps ("2h ago") and the older-date +// fallback actually respect the user's chosen language instead of always +// rendering in English. +export function formatDate(date: Date | string, t: (key: string, values?: Record) => string, locale: string): string { const d = typeof date === "string" ? new Date(date) : date; const now = new Date(); const diff = now.getTime() - d.getTime(); @@ -15,12 +20,12 @@ export function formatDate(date: Date | string): string { const hours = Math.floor(diff / 3600000); const days = Math.floor(diff / 86400000); - if (minutes < 1) return "Just now"; - if (minutes < 60) return `${minutes}m ago`; - if (hours < 24) return `${hours}h ago`; - if (days < 7) return `${days}d ago`; + if (minutes < 1) return t('just_now'); + if (minutes < 60) return t(minutes === 1 ? 'minutes_ago' : 'minutes_ago_plural', { count: minutes }); + if (hours < 24) return t(hours === 1 ? 'hours_ago' : 'hours_ago_plural', { count: hours }); + if (days < 7) return t(days === 1 ? 'days_ago' : 'days_ago_plural', { count: days }); - return d.toLocaleDateString("en-US", { + return d.toLocaleDateString(locale, { month: "short", day: "numeric", year: d.getFullYear() !== now.getFullYear() ? "numeric" : undefined, @@ -48,6 +53,28 @@ export interface MailboxNode extends Mailbox { depth: number; } +// JMAP standard mailbox roles (RFC 8621) to their translated-label keys under +// the `sidebar.mailboxes` namespace. System mailboxes come back from the +// server with their own (English) `name`, which was being rendered verbatim +// everywhere instead of the already-translated labels sitting unused in the +// locale files. Custom/shared folders have no `role` and keep their literal name. +const MAILBOX_ROLE_LABEL_KEYS: Record = { + inbox: 'mailboxes.inbox', + drafts: 'mailboxes.drafts', + sent: 'mailboxes.sent', + trash: 'mailboxes.trash', + archive: 'mailboxes.archive', + junk: 'mailboxes.spam', + flagged: 'mailboxes.starred', + important: 'mailboxes.important', + all: 'mailboxes.all_mail', +}; + +export function getMailboxDisplayName(role: string | undefined, name: string, t: (key: string) => string): string { + const labelKey = role ? MAILBOX_ROLE_LABEL_KEYS[role] : undefined; + return labelKey ? t(labelKey) : name; +} + // Role priority for mailbox ordering (lower number = higher priority) const ROLE_PRIORITY: Record = { inbox: 0, diff --git a/locales/de/common.json b/locales/de/common.json index c3e2789..6ae38fc 100644 --- a/locales/de/common.json +++ b/locales/de/common.json @@ -145,6 +145,7 @@ "email_list": { "no_emails": "Keine E-Mails", "no_emails_description": "Beginnen Sie, indem Sie eine neue E-Mail verfassen", + "no_preview": "Keine Vorschau verfügbar", "loading": "E-Mails werden geladen...", "unread": "ungelesen", "to_me": "An mich", @@ -528,6 +529,7 @@ "russian": "Русский", "ukrainian": "Українська", "polish": "Polski", + "estonian": "Eesti", "select_language": "Sprache auswählen", "switch_to_english": "Zu Englisch wechseln", "switch_to_french": "Zu Französisch wechseln", @@ -540,6 +542,7 @@ "switch_to_russian": "Zu Russisch wechseln", "switch_to_ukrainian": "Zu Ukrainisch wechseln", "switch_to_polish": "Zu Polnisch wechseln", + "switch_to_estonian": "Zu Estnisch wechseln", "switching": "Sprache wird gewechselt..." }, "settings": { diff --git a/locales/en/common.json b/locales/en/common.json index f31dca4..4abd987 100644 --- a/locales/en/common.json +++ b/locales/en/common.json @@ -145,6 +145,7 @@ "email_list": { "no_emails": "No emails", "no_emails_description": "Start by composing a new email", + "no_preview": "No preview available", "loading": "Loading emails...", "unread": "unread", "to_me": "To me", @@ -532,6 +533,7 @@ "russian": "Русский", "ukrainian": "Українська", "polish": "Polski", + "estonian": "Eesti", "select_language": "Select language", "switch_to_english": "Switch to English", "switch_to_french": "Switch to French", @@ -544,6 +546,7 @@ "switch_to_russian": "Switch to Russian", "switch_to_ukrainian": "Switch to Ukrainian", "switch_to_polish": "Switch to Polish", + "switch_to_estonian": "Switch to Estonian", "switching": "Changing language..." }, "settings": { diff --git a/locales/es/common.json b/locales/es/common.json index 669f6d5..83d3655 100644 --- a/locales/es/common.json +++ b/locales/es/common.json @@ -145,6 +145,7 @@ "email_list": { "no_emails": "Sin correos", "no_emails_description": "Comience redactando un nuevo correo", + "no_preview": "Vista previa no disponible", "loading": "Cargando correos...", "unread": "no leído", "to_me": "Para mí", @@ -528,6 +529,7 @@ "russian": "Русский", "ukrainian": "Українська", "polish": "Polski", + "estonian": "Eesti", "select_language": "Seleccionar idioma", "switch_to_english": "Cambiar a inglés", "switch_to_french": "Cambiar a francés", @@ -540,6 +542,7 @@ "switch_to_russian": "Cambiar a ruso", "switch_to_ukrainian": "Cambiar a ucraniano", "switch_to_polish": "Cambiar a polaco", + "switch_to_estonian": "Cambiar a estonio", "switching": "Cambiando idioma..." }, "settings": { diff --git a/locales/et/common.json b/locales/et/common.json new file mode 100644 index 0000000..5f78410 --- /dev/null +++ b/locales/et/common.json @@ -0,0 +1,1494 @@ +{ + "login": { + "title": "Veebipost", + "username_label": "E-post", + "username_placeholder": "kasutaja@naide.com", + "password_label": "Parool", + "password_placeholder": "Sisesta oma parool", + "sign_in": "Logi sisse", + "signing_in": "Sisselogimine...", + "loading": "Laadimine...", + "error": { + "invalid_credentials": "Vale e-post või parool. Kontrolli oma andmeid ja proovi uuesti.", + "connection_failed": "Serverini ei jõua. Kontrolli internetiühendust ja proovi uuesti.", + "cors_blocked": "Server on kättesaadav, aga blokeerib teiste domeenide päringuid. Kontrolli JMAP-serveri CORS-seadeid ja luba see domeen.", + "server_error": "Server on ajutiselt saadaval. Proovi hiljem uuesti.", + "generic": "Tekkis ootamatu viga. Kui see kordub, võta ühendust oma administraatoriga.", + "totp_invalid": "Vale autentimiskood. Kontrolli oma autentimisrakendust ja proovi uuesti.", + "oauth_discovery_failed": "SSO on lubatud, aga identiteediteenusega ei õnnestunud ühendust saada. Kontrolli OAuth-seadistust." + }, + "show_password": "Näita parooli", + "hide_password": "Peida parool", + "totp_toggle": "Mul on 2FA kood", + "remember_me": "Jäta mind meelde", + "config_error": { + "title": "Seadistuse viga", + "fetch_failed": "Rakenduse seadistust ei õnnestunud laadida. Proovi hiljem uuesti.", + "server_not_configured": "Meiliserverit pole seadistatud. Võta ühendust oma administraatoriga." + }, + "remove_from_history": "Eemalda ajaloost", + "totp_label": "Autentimiskood", + "totp_placeholder": "000000", + "session_expired": "Sinu seanss on aegunud. Palun logi uuesti sisse.", + "dismiss": "Sulge", + "or": "või", + "sign_in_sso": "Logi sisse SSO-ga", + "oauth_completing": "Sisselogimine lõpetamisel...", + "oauth_error": { + "title": "Autentimine ebaõnnestus", + "invalid_state": "Turvakontroll ebaõnnestus. Palun proovi uuesti sisse logida.", + "missing_params": "Autoriseerimisandmed puuduvad. Palun proovi uuesti sisse logida.", + "token_exchange_failed": "Autentimist ei õnnestunud lõpetada. Palun proovi uuesti.", + "access_denied": "Ligipääs keelati. Võta ühendust oma administraatoriga.", + "back_to_login": "Tagasi sisselogimisse", + "requires_https": "Ühekordne sisselogimine (SSO) nõuab turvalist ühendust. Palun kasuta seda veebiposti HTTPS-i kaudu (või arenduse ajal localhost-i)." + } + }, + "sidebar": { + "close": "Sulge", + "compose": "Koosta", + "compose_hint": "Koosta (c)", + "search_placeholder": "Otsi kirjadest...", + "search_placeholder_hint": "Otsi kirjadest... (vajuta /)", + "storage": "Talletusruum", + "sign_out": "Logi välja", + "contacts": "Kontaktid", + "calendar": "Kalender", + "settings": "Seaded", + "loading_mailboxes": "Postkastide laadimine...", + "push_connected": "Reaalajas uuendused aktiivsed", + "push_disconnected": "Reaalajas uuendused pole aktiivsed", + "theme": { + "light": "Hele teema", + "dark": "Tume teema", + "system": "Süsteemi teema" + }, + "language": { + "title": "Keel" + }, + "mailboxes": { + "inbox": "Saabunud", + "sent": "Saadetud", + "drafts": "Mustandid", + "trash": "Prügikast", + "archive": "Arhiiv", + "starred": "Tähistatud", + "all_mail": "Kõik kirjad", + "spam": "Rämpspost", + "important": "Oluline" + }, + "expand": "Laienda", + "collapse": "Ahenda", + "expand_tooltip": "Laienda", + "collapse_tooltip": "Ahenda", + "mobile": { + "search": "Otsi", + "compose": "Koosta", + "go_back": "Tagasi" + }, + "clear_search": "Tühjenda otsing", + "vacation_active": "Puhkusevastaja on aktiivne", + "mail": "Kirjad", + "nav_label": "Navigatsioon", + "tags": { + "title": "Sildid", + "no_tags": "Silte pole" + }, + "empty_folder": { + "title": "Tühjenda kaust", + "confirm": "Kas soovid jäädavalt kustutada kõik {count} kirja kaustast {folder}?", + "success": "Kaust tühjendati edukalt", + "progress": "Kustutamine... {deleted}/{total}", + "error": "Kõiki kirju ei õnnestunud kustutada. Eemaldati {deleted} / {total}.", + "cancel": "Loobu" + }, + "folder_management": { + "new_folder": "Uus kaust", + "new_subfolder": "Uus alamkaust", + "rename": "Nimeta ümber", + "move_to": "Liiguta...", + "delete_folder": "Kustuta kaust", + "delete_confirm_title": "Kustutada \"{name}\"?", + "delete_confirm_with_contents": "See kaust sisaldab {emails} kirja ja {subfolders} alamkausta. Kõik kirjad liigutatakse prügikasti.", + "delete_confirm_empty": "See kaust on tühi. See kustutatakse jäädavalt.", + "folder_created": "Kaust \"{name}\" loodud", + "folder_renamed": "Kaust nimetati ümber \"{name}\"", + "folder_moved": "Kaust liigutati kausta \"{destination}\"", + "folder_moved_to_root": "Kaust liigutati ülemisele tasemele", + "folder_deleted": "Kaust \"{name}\" kustutatud", + "folder_name_placeholder": "Kausta nimi...", + "folder_name_empty_error": "Kausta nimi ei tohi olla tühi", + "folder_name_exists_error": "Sellenimeline kaust on juba olemas", + "folder_name_slash_error": "Kausta nimi ei tohi sisaldada märki /", + "folder_name_too_long_error": "Kausta nimi on liiga pikk (max 200 tähemärki)", + "create_error": "Kausta loomine ebaõnnestus", + "rename_error": "Kausta ümbernimetamine ebaõnnestus", + "move_error": "Kausta liigutamine ebaõnnestus", + "delete_error": "Kausta kustutamine ebaõnnestus", + "permission_error": "Sul pole selleks tegevuseks õigust", + "no_permission": "Õigus puudub", + "drop_to_move_inside": "Lohista, et liigutada kausta sisse", + "enter_to_confirm": "Enter kinnitamiseks · Escape loobumiseks", + "enter_to_create": "Enter loomiseks · Escape loobumiseks", + "no_available_targets": "Sobivaid kaustu pole", + "move_to_top_level": "Ülemine tase" + } + }, + "sort": { + "by_date": "Kuupäev", + "by_sender": "Saatja", + "by_subject": "Teema", + "by_size": "Suurus", + "ascending": "Kasvavalt", + "descending": "Kahanevalt" + }, + "email_list": { + "no_emails": "Kirju pole", + "no_emails_description": "Alusta uue kirja koostamisega", + "no_preview": "Eelvaade puudub", + "loading": "Kirjade laadimine...", + "unread": "lugemata", + "to_me": "Minule", + "to_recipients": "{count} saajale", + "and_others": "ja veel {count}", + "draft": "Mustand", + "starred": "Tähistatud", + "conversations_count": "{count} / {total} vestlust", + "conversations_count_plus": "{count}+ vestlust", + "conversations_count_simple": "{count} vestlust", + "no_conversations": "Vestlusi pole", + "loading_more": "Rohkemate kirjade laadimine...", + "no_more_emails": "Rohkem kirju laadida pole", + "batch_actions": { + "mark_read": "Märgi loetuks", + "mark_unread": "Märgi lugemata", + "delete": "Kustuta", + "clear_selection": "Tühista valik", + "delete_confirm_title": "Kustutada kirjad?", + "delete_confirm_message": "Kas soovid kindlasti kustutada {count, plural, one {# kirja} other {# kirja}}?", + "move_to": "Liiguta...", + "move_success": "Liigutati {count} kirja kausta {folder}", + "move_error": "Kirjade liigutamine ebaõnnestus", + "selected_count": "Valitud {count, plural, one {# kiri} other {# kirja}}" + }, + "select_criteria": { + "label": "Valiku kriteerium", + "all": "Kõik", + "none": "Mitte ükski", + "read": "Loetud", + "unread": "Lugemata", + "starred": "Tähistatud", + "unstarred": "Tähistamata" + }, + "move_to": { + "search_placeholder": "Otsi kaustu...", + "no_results": "Kaustu ei leitud", + "no_other_folders": "Teisi kaustu pole saadaval", + "custom_folders": "Kohandatud kaustad" + } + }, + "email_viewer": { + "no_email_selected": "Ühtegi kirja pole valitud", + "no_email_description": "Vali nimekirjast kiri, et see siin avada", + "no_conversation_selected": "Ühtegi vestlust pole valitud", + "no_conversation_description": "Vali nimekirjast vestlus, et see siin lugeda", + "no_subject": "(Teema puudub)", + "loading_email": "Kirja laadimine...", + "loading": "Laadimine...", + "reply": "Vasta", + "reply_all": "Vasta kõigile", + "forward": "Edasta", + "delete": "Kustuta", + "archive": "Arhiveeri", + "send": "Saada", + "star": "Tähista", + "unstar": "Eemalda täht", + "mark_unread": "Märgi lugemata", + "mark_read": "Märgi loetuks", + "print": "Prindi", + "view_source": "Vaata lähtekoodi", + "keyboard_shortcuts": "Kiirklahvid (?)", + "email_source": "Kirja lähtekood", + "copy_source": "Kopeeri lõikelauale", + "source_copied": "Lähtekood kopeeritud lõikelauale", + "attachments": "Manused", + "important": "Oluline", + "download": "Laadi alla", + "from": "Saatja", + "to": "Saaja", + "cc": "Koopia", + "bcc": "Pime koopia", + "date": "Kuupäev", + "subject": "Teema", + "show_details": "Näita üksikasju", + "hide_details": "Peida üksikasjad", + "external_content_warning": "Pildid ja väline sisu on blokeeritud", + "load_external_content": "Laadi pildid", + "trust_sender": "Usalda seda saatjat alati", + "back_to_list": "Tagasi nimekirja", + "message_details": "Kirja üksikasjad", + "more_reply_options": "Rohkem vastamisvõimalusi", + "set_color": "Määra värv", + "more_actions": "Rohkem tegevusi", + "remove_color": "Eemalda värv", + "more_count": "+{count} veel", + "characters_count": "{count} tähemärki", + "quick_reply_placeholder": "Kirjuta kiirvastus...", + "more_options": "Rohkem valikuid", + "sending": "Saatmine...", + "security_authentication": "Turvalisus ja autentimine", + "security": { + "tooltip": { + "spf_pass": "Saatev server on volitatud saatma selle domeeni nimel", + "spf_fail": "Saatev server EI OLE volitatud selle domeeni nimelt saatma — see kiri võib olla võltsitud", + "spf_softfail": "Saatev server tõenäoliselt pole volitatud — ole ettevaatlik", + "spf_neutral": "Domeeni omanik pole öelnud, kas see server on volitatud", + "spf_temperror": "Saatja kontrollimisel tekkis ajutine viga — proovi hiljem uuesti", + "spf_permerror": "Domeeni SPF-kirje on valesti seadistatud", + "spf_none": "Selle domeeni jaoks SPF-kirjet ei leitud", + "dkim_pass": "Selle kirja sisu pole edastamise ajal muudetud", + "dkim_fail": "Selle kirja sisu võib olla edastamise ajal muudetud", + "dkim_policy": "DKIM-allkiri ei vastanud domeeni nõuetele", + "dkim_neutral": "DKIM-kontroll ei andnud selget tulemust", + "dkim_temperror": "Allkirja kontrollimisel tekkis ajutine viga", + "dkim_permerror": "DKIM-allkiri on vigane või võti puudub", + "dmarc_pass": "Saatja domeen on selle kirja ehtsuse kinnitanud", + "dmarc_fail": "Saatja domeen ei suutnud selle kirja ehtsust kinnitada", + "dmarc_none": "Saatja domeenil pole DMARC-poliitikat seadistatud" + } + }, + "technical_details": "Tehnilised üksikasjad", + "message_id_label": "Kirja ID:", + "reply_to_label": "Vastuse aadress:", + "delivery_time_label": "Kohaletoimetamise aeg:", + "conversation_part_label": "Osa vestlusest:", + "previous_messages": "{count} varasem kiri", + "previous_messages_plural": "{count} varasemat kirja", + "time": { + "day": "päev", + "days": "päeva", + "hour": "tund", + "hours": "tundi", + "minute": "minut", + "minutes": "minutit" + }, + "unknown_sender": "Tundmatu", + "recipient_me": "mina", + "recipient_and_others": "{name} ja veel {count}", + "recipient_to_prefix": "Saaja:", + "authentication": { + "title": "Autentimine", + "status": { + "verified": "Kinnitatud", + "warning": "Hoiatus", + "none": "Autentimata" + }, + "spf": { + "pass": "SPF korras", + "fail": "SPF ebaõnnestus", + "none": "SPF puudub" + }, + "dkim": { + "pass": "DKIM kehtiv", + "fail": "DKIM kehtetu", + "none": "DKIM puudub" + }, + "dmarc": { + "pass": "DMARC korras", + "fail": "DMARC ebaõnnestus", + "none": "DMARC puudub" + }, + "spam_score": "Rämpsposti skoor" + }, + "headers": { + "routing": "Marsruutimine", + "received": "Vastu võetud", + "message_id": "Kirja ID", + "list_info": "Loendi teave" + }, + "color_tag": { + "title": "Värviline silt", + "red": "Punane", + "orange": "Oranž", + "yellow": "Kollane", + "green": "Roheline", + "blue": "Sinine", + "purple": "Lilla", + "pink": "Roosa", + "none": "Puudub" + }, + "tooltips": { + "reply": "Vasta (r)", + "reply_all": "Vasta kõigile (a)", + "forward": "Edasta (f)", + "archive": "Arhiveeri (e)", + "delete": "Kustuta (# või Del)", + "star": "Tähista (s)", + "unstar": "Eemalda täht (s)", + "compose": "Koosta (c)" + }, + "spam": { + "button_title": "Teata rämpspostist", + "not_spam_title": "Märgi õigustatuks", + "toast_success": "Liigutati rämpsposti", + "toast_batch": "{count} kirja liigutati rämpsposti", + "toast_undo": "Võta tagasi", + "toast_not_spam_success": "Liigutati Saabunud kausta", + "toast_not_spam_batch": "{count} kirja liigutati Saabunud kausta", + "error": "Rämpspostist teatamine ebaõnnestus", + "error_not_spam": "Kirja taastamine ebaõnnestus" + }, + "unsubscribe_banner": { + "label": "Uudiskiri", + "button": "Loobu tellimusest", + "confirm_title": "Loobuda selle saatja tellimusest?", + "confirm_button": "Kinnita", + "cancel": "Loobu", + "success_http": "Tellimusest loobumise leht avati uues vahekaardis", + "success_mailto": "Tellimusest loobumise päring saadeti sinu meilirakendusele", + "error": "Tellimusest loobumine ebaõnnestus", + "dismiss": "Sulge" + }, + "calendar_invitation": { + "loading": "Sündmuse üksikasjade laadimine…", + "title": "Kalendrikutse", + "cancelled_title": "Sündmus tühistatud", + "organizer": "Korraldaja: {name}", + "attendees": "{count, plural, one {# osaleja} other {# osalejat}}", + "accept": "Nõustu", + "maybe": "Võib-olla", + "decline": "Keeldu", + "add_to_calendar": "Lisa kalendrisse", + "added": "Lisatud kalendrisse", + "rsvp_sent": "Vastus saadetud", + "parse_error": "Kutset ei õnnestunud lugeda", + "no_calendar": "Kalender pole saadaval", + "select_calendar": "Vali kalender", + "already_in_calendar": "Juba sinu kalendris" + }, + "mobile_actions": { + "reply": "Vasta", + "reply_all": "Vasta kõigile", + "archive": "Arhiveeri", + "delete": "Kustuta", + "more": "Rohkem", + "forward": "Edasta", + "move_to": "Liiguta...", + "star": "Tähista", + "mark_unread": "Märgi lugemata", + "spam": "Teata rämpspostist" + }, + "sender_info": { + "add_to_contacts": "Lisa kontaktidesse", + "view_all_emails": "Vaata kõiki selle saatja kirju", + "no_contact": "Sinu kontaktide hulgas pole" + } + }, + "email_composer": { + "new_message": "Uus kiri", + "reply": "Vasta", + "reply_all": "Vasta kõigile", + "forward": "Edasta", + "reply_to": "Vasta", + "reply_all_to": "Vasta kõigile", + "forward_message": "Edasta", + "from": "Saatja", + "to": "Saaja", + "cc": "Koopia", + "bcc": "Pime koopia", + "subject": "Teema", + "body_placeholder": "Kirjuta oma sõnum...", + "send": "Saada", + "cancel": "Loobu", + "attach": "Lisa manus", + "discard": "Viska ära", + "discard_draft_title": "Viskan mustandi ära?", + "discard_draft_confirm": "Sul on salvestamata muudatusi. Kas soovid selle mustandi ära visata?", + "saving": "Salvestamine...", + "draft_saved": "Mustand salvestatud", + "save_failed": "Salvestamine ebaõnnestus", + "to_placeholder": "Saajate e-posti aadressid (komadega eraldatud)", + "cc_placeholder": "Koopia saajad (komadega eraldatud)", + "bcc_placeholder": "Pimekoopia saajad (komadega eraldatud)", + "subject_placeholder": "Teema", + "cc_label": "Koopia:", + "bcc_label": "Pime koopia:", + "subject_label": "Teema:", + "file_size_kb": "KB", + "prefix": { + "forward": "Edasi:", + "reply": "Vs:" + }, + "no_subject": "(Teema puudub)", + "unknown_sender": "Tundmatu", + "quote": { + "reply_header": "{date}, {sender} kirjutas:", + "forward_header": "---------- Edastatud kiri ----------", + "from": "Saatja: {sender}", + "date": "Kuupäev: {date}", + "subject": "Teema: {subject}", + "to": "Saaja: {recipients}" + }, + "remove_sub_address": "Eemalda alamaadress", + "use_template": "Mall", + "save_as_template": "Salvesta mallina", + "validation": { + "recipient_required": "Lisa saatmiseks saaja", + "subject_required": "Lisa teema", + "body_required": "Kirjuta sõnum või lisa fail", + "attachments_pending": "Oota, kuni manuste üleslaadimine lõpeb" + }, + "upload_progress": "Üleslaadimine {uploaded} / {total}", + "upload_cancel": "Katkesta üleslaadimine", + "upload_failed": "Faili {filename} üleslaadimine ebaõnnestus", + "send_failed": "Kirja saatmine ebaõnnestus" + }, + "confirm_dialog": { + "confirm": "Kinnita", + "cancel": "Loobu" + }, + "common": { + "loading": "Laadimine...", + "error": "Viga", + "success": "Õnnestus", + "cancel": "Loobu", + "save": "Salvesta", + "delete": "Kustuta", + "edit": "Muuda", + "close": "Sulge", + "search": "Otsi", + "refresh": "Värskenda", + "settings": "Seaded", + "help": "Abi", + "logout": "Logi välja", + "yes": "Jah", + "no": "Ei", + "unknown": "Tundmatu", + "app_title": "Veebipost" + }, + "notifications": { + "email_sent": "Kiri saadeti edukalt", + "email_deleted": "Kiri kustutatud", + "email_archived": "Kiri arhiveeritud", + "email_starred": "Kiri tähistatud", + "email_unstarred": "Tähis eemaldatud kirjalt", + "email_marked_read": "Kiri märgiti loetuks", + "email_marked_unread": "Kiri märgiti lugemata", + "copied_to_clipboard": "Kopeeritud lõikelauale", + "source_copied": "Lähtekood kopeeritud lõikelauale", + "error_sending": "Kirja saatmine ebaõnnestus", + "error_deleting": "Kirja kustutamine ebaõnnestus", + "error_loading": "Kirjade laadimine ebaõnnestus", + "new_email": "Uus kiri", + "new_email_from": "Saatjalt {sender}", + "click_to_view": "Kliki vaatamiseks", + "email_moved": "Kiri liigutatud", + "emails_moved": "{count} kirja liigutatud", + "moved_to_mailbox": "Liigutatud kausta {mailbox}", + "move_failed": "Liigutamine ebaõnnestus", + "move_error": "Kirju ei õnnestunud valitud kausta liigutada", + "identity_created": "Identiteet loodi edukalt", + "identity_updated": "Identiteet uuendati edukalt", + "identity_deleted": "Identiteet kustutatud", + "identity_create_failed": "Identiteedi loomine ebaõnnestus: {error}", + "identity_update_failed": "Identiteedi uuendamine ebaõnnestus: {error}", + "identity_delete_failed": "Identiteedi kustutamine ebaõnnestus: {error}", + "identity_unauthorized": "Sul pole õigust sellelt aadressilt saata", + "identity_not_found": "Identiteeti ei leitud", + "vacation_saved": "Puhkusevastaja seaded salvestatud", + "vacation_save_failed": "Puhkusevastaja seadete salvestamine ebaõnnestus", + "filters_saved": "Filtrid salvestati edukalt", + "filters_save_failed": "Filtrite salvestamine ebaõnnestus", + "filters_deleted": "Filtrireegel kustutatud", + "templates_exported": "Mallid eksporditi edukalt", + "templates_imported": "Imporditi {count, plural, one {# mall} other {# malli}}", + "templates_import_errors": "Osa malle ei õnnestunud importida", + "templates_import_empty": "Failist ei leitud ühtegi malli" + }, + "date": { + "today": "Täna", + "yesterday": "Eile", + "this_week": "Sel nädalal", + "last_week": "Eelmisel nädalal", + "this_month": "Sel kuul", + "older": "Vanemad", + "just_now": "Just praegu", + "minutes_ago": "{count} minut tagasi", + "minutes_ago_plural": "{count} minutit tagasi", + "hours_ago": "{count} tund tagasi", + "hours_ago_plural": "{count} tundi tagasi", + "days_ago": "{count} päev tagasi", + "days_ago_plural": "{count} päeva tagasi" + }, + "language": { + "title": "Keel", + "english": "English", + "french": "Français", + "japanese": "日本語", + "spanish": "Español", + "italian": "Italiano", + "german": "Deutsch", + "dutch": "Nederlands", + "portuguese": "Português", + "russian": "Русский", + "ukrainian": "Українська", + "polish": "Polski", + "estonian": "Eesti", + "select_language": "Vali keel", + "switch_to_english": "Vaheta inglise keelele", + "switch_to_french": "Vaheta prantsuse keelele", + "switch_to_japanese": "Vaheta jaapani keelele", + "switch_to_spanish": "Vaheta hispaania keelele", + "switch_to_italian": "Vaheta itaalia keelele", + "switch_to_german": "Vaheta saksa keelele", + "switch_to_dutch": "Vaheta hollandi keelele", + "switch_to_portuguese": "Vaheta portugali keelele", + "switch_to_russian": "Vaheta vene keelele", + "switch_to_ukrainian": "Vaheta ukraina keelele", + "switch_to_polish": "Vaheta poola keelele", + "switch_to_estonian": "Vaheta eesti keelele", + "switching": "Keele vahetamine..." + }, + "settings": { + "title": "Seaded", + "back_to_mail": "Tagasi kirjade juurde", + "save_success": "Seaded salvestati edukalt", + "import_success": "Seaded imporditi edukalt", + "import_error": "Seadete importimine ebaõnnestus", + "unsaved_changes": "Sul on salvestamata muudatusi", + "discard_changes": "Loobu salvestamata muudatustest?", + "discard": "Loobu", + "keep_editing": "Jätka muutmist", + "tabs": { + "appearance": "Välimus", + "language": "Keel ja piirkond", + "email": "Kirjade käitumine", + "composer": "Kirja koostamine", + "privacy": "Privaatsus ja turvalisus", + "account": "Konto", + "identities": "Identiteedid", + "vacation": "Puhkusevastaja", + "advanced": "Täpsem", + "calendar": "Kalender", + "filters": "Filtrid", + "templates": "Mallid" + }, + "appearance": { + "title": "Välimus", + "description": "Kohanda oma veebiposti välimust", + "theme": { + "label": "Teema", + "description": "Vali eelistatud värviskeem", + "light": "Hele", + "dark": "Tume", + "system": "Süsteemi järgi" + }, + "language": { + "label": "Keel", + "description": "Vali eelistatud keel" + }, + "font_size": { + "label": "Kirja suurus", + "description": "Kohanda tekstisuurust parema loetavuse jaoks", + "small": "Väike", + "medium": "Keskmine", + "large": "Suur" + }, + "list_density": { + "label": "Nimekirja tihedus", + "description": "Reguleeri kirjade nimekirja vahesid", + "extra_compact": "Väga tihe", + "compact": "Tihe", + "regular": "Tavaline", + "comfortable": "Mugav" + }, + "animations": { + "label": "Luba animatsioonid", + "description": "Näita sujuvaid üleminekuid ja efekte" + } + }, + "email_behavior": { + "title": "Kirjade käitumine", + "description": "Seadista, kuidas kirju käsitletakse", + "mark_read": { + "label": "Loetuks märkimine", + "description": "Millal märkida kirjad avamisel loetuks", + "instant": "Kohe", + "delay_3s": "3 sekundi pärast", + "delay_5s": "5 sekundi pärast", + "never": "Mitte kunagi" + }, + "delete_action": { + "label": "Kustutamise tegevus", + "description": "Mis juhtub, kui kustutad kirja", + "trash": "Liiguta prügikasti", + "permanent": "Kustuta jäädavalt" + }, + "show_preview": { + "label": "Näita eelvaate teksti", + "description": "Kuva kirja eelvaade nimekirjas" + }, + "emails_per_page": { + "label": "Kirju lehe kohta", + "description": "Korraga laaditavate kirjade arv", + "25": "25 kirja", + "50": "50 kirja", + "100": "100 kirja" + }, + "external_content": { + "label": "Väline sisu", + "description": "Kuidas käsitleda pilte ja välist sisu", + "ask": "Küsi alati", + "block": "Blokeeri alati", + "allow": "Luba alati" + }, + "trusted_senders": { + "label": "Usaldusväärsed saatjad", + "description": "Halda saatjaid, kelle pildid laaditakse automaatselt", + "count_zero": "Puuduvad", + "count_one": "1 saatja", + "count_other": "{count} saatjat", + "modal_title": "Usaldusväärsed saatjad", + "empty_title": "Usaldusväärseid saatjaid pole veel", + "empty_description": "Blokeeritud piltidega kirja vaadates kliki \"Usalda seda saatjat alati\", et lisada saatja siia.", + "add_manually": "Lisa saatja käsitsi", + "add_button": "Lisa", + "add_placeholder": "Sisesta e-posti aadress", + "search_placeholder": "Otsi saatjaid...", + "no_results": "Ükski saatja ei vasta otsingule", + "remove": "Eemalda", + "close": "Sulge", + "invalid_email": "Palun sisesta kehtiv e-posti aadress", + "already_added": "See saatja on juba usaldatud" + }, + "domain_favicon_avatars": { + "label": "Domeeni avatarid", + "description": "Kui kontaktil pole pilti, näita algustähtede asemel saatja domeeni favicon'it. Laaditakse avalikust favicon-teenusest ainult domeeninime põhjal (ilma e-posti aadressi või räsimiseta). Vaikimisi väljas." + } + }, + "composer": { + "title": "Kirja koostamine", + "description": "Seadista kirja koostamise sätteid", + "autosave": { + "label": "Automaatsalvestuse intervall", + "description": "Kui tihti mustandid automaatselt salvestatakse", + "30s": "Iga 30 sekundi järel", + "1m": "Iga minuti järel", + "2m": "Iga 2 minuti järel", + "5m": "Iga 5 minuti järel" + }, + "send_confirmation": { + "label": "Saatmise kinnitus", + "description": "Küsi enne kirja saatmist kinnitust" + }, + "default_reply": { + "label": "Vastuse vaiketegevus", + "description": "Vaiketegevus vastamise klõpsamisel", + "reply": "Vasta", + "reply_all": "Vasta kõigile" + } + }, + "privacy": { + "title": "Privaatsus ja turvalisus", + "description": "Halda oma privaatsus- ja turvaseadeid", + "external_images": { + "label": "Blokeeri välised pildid", + "description": "Väldi jälgimist väliste piltide kaudu" + }, + "session_timeout": { + "label": "Seansi aegumine", + "description": "Logi tegevusetuse korral automaatselt välja", + "never": "Mitte kunagi", + "30m": "30 minutit", + "1h": "1 tund", + "4h": "4 tundi" + }, + "clear_cache": { + "label": "Tühjenda vahemälu", + "description": "Eemalda vahemällu salvestatud andmed ja ajutised failid", + "button": "Tühjenda vahemälu", + "confirm": "Kas soovid kindlasti vahemälu tühjendada?", + "success": "Vahemälu tühjendati edukalt" + } + }, + "account": { + "title": "Konto", + "description": "Vaata oma konto teavet", + "email": { + "label": "E-posti aadress", + "value": "{email}" + }, + "server": { + "label": "JMAP-server", + "value": "{server}" + }, + "storage": { + "label": "Talletusruumi kasutus", + "used": "kasutatud {used} / {total}", + "percentage": "{percent}% kasutatud" + }, + "last_sync": { + "label": "Viimane sünkroonimine", + "value": "{time}" + } + }, + "identities": { + "title": "Saatmisidentiteedid", + "description": "Halda e-posti aadresse, millelt saad saata", + "identities_count": { + "label": "Sinu identiteedid", + "description": "Saatmiseks seadistatud e-posti aadressid", + "count_zero": "Identiteete pole", + "count_one": "1 identiteet", + "count_other": "{count} identiteeti" + }, + "manage": "Halda identiteete", + "sub_addressing": { + "label": "Alamaadressimine", + "description": "Kasuta silte nagu kasutaja+silt@domeen.ee, et korraldada saabuvaid kirju", + "learn_more": "Loe lähemalt" + } + }, + "vacation": { + "title": "Puhkusevastaja", + "description": "Vasta saabuvatele kirjadele automaatselt, kui oled ära", + "loading": "Puhkuseseadete laadimine...", + "not_supported": "Sinu meiliserver ei toeta puhkusevastaja funktsiooni.", + "fetch_error": "Puhkuseseadete laadimine ebaõnnestus. Palun proovi uuesti.", + "status": { + "label": "Puhkusevastaja", + "description": "Saada automaatvastus sulle kirjutavatele inimestele", + "active": "Aktiivne", + "inactive": "Passiivne" + }, + "date_range": { + "title": "Ajavahemik", + "description": "Soovi korral piira automaatvastus kindla perioodiga", + "start": "Algkuupäev", + "start_description": "Jäta tühjaks, kui algust ei piirata", + "end": "Lõppkuupäev", + "end_description": "Jäta tühjaks, kui lõppu ei piirata" + }, + "message": { + "title": "Automaatvastuse sõnum", + "description": "Sõnum, mis saadetakse vastusena", + "subject_label": "Teema", + "subject_description": "Automaatvastuse teemarida", + "subject_placeholder": "Puhkusel", + "body_label": "Sõnumi sisu", + "body_description": "Lihttekstina esitatav sõnumi sisu", + "body_placeholder": "Täname kirja eest. Olen hetkel kontorist ära ja vastan tagasi tulles." + }, + "preview": { + "title": "Eelvaade", + "show": "Näita eelvaadet", + "hide": "Peida eelvaade" + }, + "save": "Salvesta muudatused", + "saving": "Salvestamine...", + "warnings": { + "end_before_start": "Lõppkuupäev peab olema pärast algkuupäeva", + "start_in_past": "Algkuupäev on minevikus", + "empty_body": "Sõnumi sisu on tühi — saajad saavad tühja vastuse" + } + }, + "advanced": { + "title": "Täpsem", + "description": "Täpsemad valikud ja arendajaseaded", + "debug_mode": { + "label": "Silumisrežiim", + "description": "Luba üksikasjalik logimine tõrkeotsinguks" + }, + "keyboard_shortcuts": { + "label": "Kiirklahvid", + "description": "Vaata saadaolevaid kiirklahve", + "button": "Vaata kiirklahve" + }, + "reset_settings": { + "label": "Lähtesta seaded", + "description": "Taasta kõik seaded vaikeväärtustele", + "button": "Lähtesta vaikeväärtustele" + }, + "export_settings": { + "label": "Ekspordi seaded", + "description": "Laadi oma seaded alla JSON-failina", + "button": "Ekspordi" + }, + "import_settings": { + "label": "Impordi seaded", + "description": "Laadi seaded üles JSON-failist", + "button": "Impordi" + } + }, + "filters": { + "title": "Kirjade filtrid", + "description": "Loo reegleid, mis sordivad, sildistavad ja korraldavad saabuvaid kirju automaatselt", + "add_rule": "Lisa reegel", + "no_rules": "Filtrireegleid pole", + "no_rules_description": "Loo reegleid, et korraldada saabuvaid kirju automaatselt", + "edit_rule": "Muuda reeglit", + "new_rule": "Uus reegel", + "delete_rule": "Kustuta reegel", + "delete_confirm": "Kas soovid kindlasti selle reegli kustutada?", + "enable": "Luba", + "disable": "Keela", + "raw_editor": "Töötlemata Sieve-redaktor", + "raw_editor_warning": "Töötlemata Sieve-skripti muutmine võib rikkuda visuaalse reeglite redigeerimise. Siin tehtud muudatused tühistavad visuaalse redaktori.", + "validate": "Kontrolli", + "validation_success": "Skript on kehtiv", + "validation_error": "Skriptis on vigu", + "save": "Salvesta reeglid", + "saving": "Salvestamine...", + "saved": "Filtrid salvestati edukalt", + "save_failed": "Filtrite salvestamine ebaõnnestus", + "loading": "Filtrite laadimine...", + "not_supported": "Sinu meiliserver ei toeta kirjafiltreid.", + "rule_name": "Reegli nimi", + "rule_name_placeholder": "nt Sordi uudiskirjad", + "match_all": "Vasta KÕIGILE tingimustele", + "match_any": "Vasta ÜKSKÕIK MILLISELE tingimusele", + "conditions": "Tingimused", + "add_condition": "Lisa tingimus", + "actions": "Tegevused", + "add_action": "Lisa tegevus", + "stop_processing": "Peata järgnevate reeglite töötlemine", + "condition_fields": { + "from": "Saatja", + "to": "Saaja", + "cc": "Koopia", + "subject": "Teema", + "header": "Kohandatud päis", + "size": "Suurus", + "body": "Sisu" + }, + "comparators": { + "contains": "sisaldab", + "not_contains": "ei sisalda", + "is": "on täpselt", + "not_is": "ei ole", + "starts_with": "algab järgnevaga", + "ends_with": "lõpeb järgnevaga", + "matches": "vastab mustrile", + "greater_than": "on suurem kui", + "less_than": "on väiksem kui" + }, + "action_types": { + "move": "Liiguta kausta", + "copy": "Kopeeri kausta", + "forward": "Edasta aadressile", + "mark_read": "Märgi loetuks", + "star": "Tähista kiri", + "add_label": "Lisa silt", + "discard": "Viska ära (kustuta vaikselt)", + "reject": "Lükka tagasi koos sõnumiga", + "keep": "Jäta Saabunud kausta", + "stop": "Peata töötlemine" + }, + "move_to_folder": "Vali kaust", + "copy_to_folder": "Vali kaust", + "forward_to": "Edasta e-posti aadressile", + "forward_placeholder": "email@naide.com", + "reject_message": "Tagasilükkamise sõnum", + "reject_placeholder": "Sinu kiri lükati tagasi", + "label_name": "Sildi nimi", + "label_placeholder": "nt oluline", + "header_name": "Päise nimi", + "header_placeholder": "nt X-Mailing-List", + "size_bytes": "Suurus baitides", + "size_placeholder": "nt 1000000", + "system_managed": "Süsteemi hallatav reegel", + "opaque_warning": "See skript on muudetud väljaspool visuaalset redaktorit. Saadaval on ainult töötlemata Sieve-redigeerimine.", + "open_sieve_editor": "Ava töötlemata Sieve-redaktor", + "fetch_error": "Filtrite laadimine ebaõnnestus", + "and": "ja", + "or": "või", + "cancel": "Loobu", + "confirm_delete": "Kustuta", + "rule_list": "Filtrireeglid", + "drag_to_reorder": "Lohista ümberjärjestamiseks", + "match_type": "Vastavuse tüüp", + "reset_to_visual": "Lähtesta visuaalsele redaktorile", + "reset_warning": "See tühistab praeguse skripti ja alustab uuesti.", + "confirm_reset": "Lähtesta", + "validation_empty_name": "Reegli nimi on kohustuslik", + "validation_empty_conditions": "Vajalik on vähemalt üks tingimus koos väärtusega", + "validation_empty_actions": "Vajalik on vähemalt üks tegevus", + "templates_section": "Alusta mallist", + "template_newsletters": "Liiguta uudiskirjad kausta", + "template_receipts": "Arhiveeri kviitungid automaatselt", + "template_important": "Märgi olulised kirjad", + "template_notifications": "Filtreeri teavitused", + "sieve_editor": { + "title": "Sieve-skripti redaktor", + "warning": "Töötlemata Sieve-skripti muutmine võib rikkuda visuaalse reeglite redigeerimise. Siin tehtud muudatused tühistavad visuaalse redaktori.", + "script_content": "Sieve-skript", + "valid": "Skript on kehtiv", + "invalid": "Skriptis on vigu", + "save_warning": "Salvestamine kirjutab üle kõik visuaalsed reeglid. Seda ei saa tagasi võtta. Kinnitamiseks kliki uuesti Salvesta.", + "validating": "Kontrollimine...", + "validate": "Kontrolli", + "cancel": "Loobu", + "save": "Salvesta", + "confirm_save": "Kinnita salvestamine", + "validation_failed": "Kontrollpäring ebaõnnestus" + }, + "rule_summary": { + "conditions_count": "{count, plural, one {# tingimus} other {# tingimust}}", + "actions_count": "{count, plural, one {# tegevus} other {# tegevust}}" + } + }, + "templates": { + "title": "E-posti mallid", + "description": "Loo taaskasutatavaid kirjamalle koos kohatäite muutujatega", + "add": "Uus mall", + "edit": "Muuda malli", + "name": "Malli nimi", + "name_placeholder": "nt Järelkiri", + "category": "Kategooria", + "category_placeholder": "nt Töö, Isiklik", + "subject": "Teema", + "subject_placeholder": "Kirja teemarida", + "body": "Sisu", + "body_placeholder": "Kirja sisu...", + "recipients_placeholder": "email@naide.com", + "identity": "Saada kui", + "default_identity": "Vaikeidentiteet", + "favorite": "Lemmik", + "cancel": "Loobu", + "create": "Loo", + "update": "Uuenda", + "confirm_delete": "Kustuta", + "no_templates": "Malle pole veel", + "manage": "Halda malle", + "count": "{count, plural, one {# mall} other {# malli}}", + "export_import": "Eksport ja import", + "export_import_description": "Varunda oma mallid või kanna need üle teise seadmesse", + "export": "Ekspordi", + "import": "Impordi", + "validation": { + "empty": "Malli nimi on kohustuslik", + "too_long": "Malli nimi tohib olla kuni 200 tähemärki" + } + } + }, + "errors": { + "page_error_title": "Midagi läks valesti", + "page_error_description": "Tekkis ootamatu viga. Palun proovi uuesti või mine tagasi avalehele.", + "sidebar_error": "Postkaste ei õnnestunud laadida", + "email_list_error": "Kirju ei õnnestunud laadida", + "viewer_error_title": "Kirja ei õnnestu kuvada", + "viewer_error_description": "Selle kirja kuvamisel tekkis probleem. See võib sisaldada toetamata sisu.", + "composer_error": "Kirja koostamist ei õnnestu laadida", + "settings_error_title": "Seaded pole saadaval", + "settings_error_description": "Seadeid ei õnnestunud laadida. Sinu eelistusi ei pruugita salvestada.", + "try_again": "Proovi uuesti", + "reload": "Laadi uuesti", + "reload_emails": "Laadi kirjad uuesti", + "reload_settings": "Laadi seaded uuesti", + "retry": "Proovi uuesti", + "go_home": "Mine Saabunud kausta" + }, + "context_menu": { + "reply": "Vasta", + "reply_all": "Vasta kõigile", + "forward": "Edasta", + "mark_read": "Märgi loetuks", + "mark_unread": "Märgi lugemata", + "star": "Tähista", + "unstar": "Eemalda täht", + "move_to": "Liiguta...", + "archive": "Arhiveeri", + "delete": "Kustuta", + "mark_as_spam": "Teata rämpspostist", + "not_spam": "Pole rämpspost", + "color_tag": "Värviline silt", + "remove_color": "Eemalda värv", + "items_selected": "{count} kirja valitud" + }, + "shortcuts": { + "title": "Kiirklahvid", + "tip": "Vajuta ? igal ajal, et näha seda abi", + "sections": { + "navigation": "Navigatsioon", + "actions": "Kirjatoimingud", + "global": "Üldine", + "threads": "Vestlused", + "composer": "Kirja koostamine" + }, + "navigation": { + "next_email": "Järgmine kiri", + "previous_email": "Eelmine kiri", + "open_email": "Ava kiri", + "close_email": "Sulge / tühista valik" + }, + "actions": { + "reply": "Vasta", + "reply_all": "Vasta kõigile", + "forward": "Edasta", + "star": "Lülita täht sisse/välja", + "archive": "Arhiveeri", + "delete": "Kustuta", + "mark_unread": "Märgi lugemata", + "mark_read": "Märgi loetuks", + "toggle_spam": "Teata rämpspostist / Pole rämpspost" + }, + "global": { + "compose": "Koosta uus kiri", + "search": "Fookus otsingusse", + "help": "Näita kiirklahve", + "refresh": "Värskenda kirju", + "select_all": "Vali kõik" + }, + "threads": { + "expand_collapse": "Laienda/ahenda vestlus" + }, + "composer": { + "template_picker": "Ava mallivalija" + } + }, + "threads": { + "messages_one": "{count} kiri", + "messages_other": "{count} kirja", + "messages_tooltip": "{count, plural, one {# kiri selles vestluses} other {# kirja selles vestluses}}", + "expand": "Laienda vestlus", + "collapse": "Ahenda vestlus", + "loading": "Vestluse laadimine...", + "mark_read": "Märgi vestlus loetuks", + "mark_unread": "Märgi vestlus lugemata", + "archive": "Arhiveeri vestlus", + "delete": "Kustuta vestlus", + "star": "Tähista vestlus", + "unstar": "Eemalda täht vestluselt", + "toggle_thread": "Lülita vestlus sisse/välja" + }, + "identities": { + "modal_title": "Halda saatmisidentiteete", + "create_new": "Loo uus identiteet", + "edit_identity": "Muuda identiteeti", + "delete_confirm": "Kustutada see identiteet? Seda ei saa tagasi võtta.", + "cannot_delete": "Seda identiteeti ei saa kustutada", + "primary_identity": "Peamine", + "no_identities": "Identiteete ei leitud", + "display": { + "reply_to": "Vastuse aadress:", + "bcc": "Pime koopia:", + "signature": "Allkiri:", + "preview": "Eelvaade:" + }, + "validation_errors": { + "invalid_emails": "Kehtetud e-posti aadressid: {emails}", + "unknown_error": "Tundmatu viga" + }, + "form": { + "name_label": "Kuvatav nimi", + "name_placeholder": "nt Töö e-post, Isiklik", + "name_required": "Nimi on kohustuslik", + "email_label": "E-posti aadress", + "email_placeholder": "sinu.e-post@naide.com", + "email_required": "E-posti aadress on kohustuslik", + "email_invalid": "Palun sisesta kehtiv e-posti aadress", + "email_immutable": "E-posti aadressi ei saa pärast loomist muuta", + "reply_to_label": "Vastuse aadress (valikuline)", + "reply_to_placeholder": "teine@epost.ee", + "bcc_label": "Automaatne pime koopia (valikuline)", + "bcc_placeholder": "arhiiv@epost.ee", + "text_signature_label": "Tekstiallkiri", + "html_signature_label": "HTML-allkiri", + "save": "Salvesta identiteet", + "cancel": "Loobu", + "creating": "Loomine...", + "updating": "Uuendamine..." + }, + "sub_address": { + "button_tooltip": "Kasuta alamaadressi", + "popover_title": "Lisa alamaadressi silt", + "tag_input_placeholder": "Sisesta silt (nt ostlemine)", + "preview_label": "Eelvaade:", + "recent_tags": "Hiljutised sildid", + "suggested_tags": "Soovitatud", + "use_address": "Kasuta seda aadressi", + "invalid_tag": "Silt tohib sisaldada ainult tähti, numbreid ja sidekriipse", + "tag_too_long": "Silt tohib olla kuni 30 tähemärki", + "help_text": "Aadressile kasutaja+silt@domeen.ee saadetud kirjad jõuavad sinu Saabunud kausta", + "validation": { + "empty": "Silt ei tohi olla tühi", + "too_long": "Silt tohib olla kuni {max} tähemärki", + "invalid_chars": "Silt tohib sisaldada ainult tähti, numbreid ja sidekriipse" + } + }, + "badge": { + "sent_via": "kaudu", + "sub_address_tag": "Saadetud alamaadressiga: {tag}", + "identity_name": "Saadetud identiteediga: {name}", + "identity_short": "identiteediga {name}", + "subaddress_tag": "+{tag}" + } + }, + "templates": { + "picker_title": "Vali mall", + "search_placeholder": "Otsi malle...", + "section_favorites": "Lemmikud", + "section_recent": "Hiljutised", + "section_uncategorized": "Muu", + "no_templates": "Malle pole veel", + "no_results": "Malle ei leitud", + "fill_placeholders": "Täida kohatäite väärtused", + "enter_value": "Sisesta väärtus...", + "preview": "Eelvaade", + "insert_with_values": "Lisa koos väärtustega", + "insert_raw": "Lisa töötlemata kujul", + "copy_suffix": "(koopia)", + "placeholder": "Muutuja", + "placeholders": { + "recipient_name": "Saaja nimi", + "company": "Ettevõtte nimi", + "date": "Praegune kuupäev", + "day_of_week": "Nädalapäev", + "sender_name": "Sinu nimi" + } + }, + "contacts": { + "title": "Kontaktid", + "search_placeholder": "Otsi kontaktidest...", + "create_new": "Uus kontakt", + "empty_state": "Kontakte pole veel", + "empty_state_title": "Kontakte pole veel", + "empty_state_subtitle": "Loo oma esimene kontakt või impordi vCard-failist", + "empty_search": "Ükski kontakt ei vasta otsingule", + "empty_search_hint": "Proovi teistsugust otsingusõna", + "clear_search": "Tühjenda otsing", + "import_vcard": "Impordi vCard", + "delete_confirm": "Kas soovid kindlasti selle kontakti kustutada?", + "local_mode": "Kontaktid salvestatakse kohalikult (server ei toeta JMAP Contacts-i)", + "back_to_mail": "Tagasi kirjade juurde", + "tabs": { + "all": "Kõik", + "groups": "Grupid" + }, + "detail": { + "emails": "E-posti aadressid", + "phones": "Telefoninumbrid", + "organizations": "Organisatsioonid", + "addresses": "Aadressid", + "notes": "Märkmed", + "no_contact_selected": "Vali üksikasjade vaatamiseks kontakt", + "compose_email": "Koosta kiri", + "copy_email": "Kopeeri e-post", + "copy_phone": "Kopeeri telefoninumber", + "copied": "Kopeeritud lõikelauale", + "copy_failed": "Lõikelauale kopeerimine ebaõnnestus", + "created": "Loodud", + "updated": "Viimati uuendatud" + }, + "form": { + "create_title": "Uus kontakt", + "edit_title": "Muuda kontakti", + "given_name": "Eesnimi", + "surname": "Perekonnanimi", + "email": "E-post", + "email_placeholder": "email@naide.com", + "phone": "Telefon", + "phone_placeholder": "+372 5123 4567", + "organization": "Organisatsioon", + "organization_placeholder": "Ettevõtte nimi", + "note": "Märkmed", + "note_placeholder": "Lisa märkus...", + "context_work": "Töö", + "context_private": "Isiklik", + "add_email": "Lisa e-post", + "add_phone": "Lisa telefon", + "save": "Salvesta", + "cancel": "Loobu", + "creating": "Loomine...", + "updating": "Uuendamine...", + "name_required": "Vajalik on vähemalt eesnimi või perekonnanimi", + "email_invalid": "Palun sisesta kehtiv e-posti aadress", + "email_error_inline": "Vale e-posti vorming", + "save_failed": "Kontakti salvestamine ebaõnnestus", + "delete": "Kustuta" + }, + "groups": { + "create": "Uus grupp", + "edit": "Muuda gruppi", + "empty": "Gruppe pole veel", + "delete_confirm": "Kas soovid kindlasti selle grupi kustutada?", + "name_label": "Grupi nimi", + "name_placeholder": "nt Meeskond, Perekond", + "name_required": "Grupi nimi on kohustuslik", + "save_failed": "Grupi salvestamine ebaõnnestus", + "members_label": "Liikmed", + "search_members": "Otsi lisatavaid kontakte...", + "no_members": "Selles grupis pole liikmeid", + "member_count": "{count, plural, =0 {Liikmeid pole} one {1 liige} other {# liiget}}" + }, + "import": { + "title": "Impordi kontaktid", + "drop_hint": "Kliki vCard-faili valimiseks", + "file_types": ".vcf või .vcard failid", + "no_contacts": "Failist ei leitud ühtegi kontakti", + "parse_error": "vCard-faili lugemine ebaõnnestus", + "found": "{count, plural, one {1 kontakt leitud} other {# kontakti leitud}}", + "duplicate": "Duplikaat", + "select_all": "Vali kõik", + "deselect_all": "Tühista kõik valikud", + "selected": "{count, plural, one {1 valitud} other {# valitud}}", + "import_button": "Impordi", + "importing": "Importimine...", + "success": "{count, plural, one {1 kontakt imporditud} other {# kontakti imporditud}}", + "failed": "Importimine ebaõnnestus", + "close": "Sulge", + "file_too_large": "Fail on liiga suur (max 5 MB)" + }, + "export": { + "title": "Ekspordi kontaktid", + "success": "{count, plural, one {1 kontakt eksporditud} other {# kontakti eksporditud}}" + }, + "bulk": { + "selected": "{count, plural, one {1 valitud} other {# valitud}}", + "actions": "Mass-toimingud", + "select_all": "Vali kõik", + "delete": "Kustuta", + "delete_confirm": "Kustutada {count, plural, one {1 kontakt} other {# kontakti}}?", + "deleted": "{count, plural, one {1 kontakt kustutatud} other {# kontakti kustutatud}}", + "add_to_group": "Lisa gruppi", + "choose_group": "Vali grupp", + "adding_contacts": "Lisamine: {count, plural, one {1 kontakt} other {# kontakti}}", + "added_to_group": "Kontaktid lisati gruppi", + "export": "Ekspordi", + "clear": "Tühista valik" + }, + "toast": { + "created": "Kontakt loodud", + "updated": "Kontakt uuendatud", + "deleted": "Kontakt kustutatud", + "error_create": "Kontakti loomine ebaõnnestus", + "error_update": "Kontakti uuendamine ebaõnnestus", + "error_delete": "Kontakti kustutamine ebaõnnestus" + }, + "delete_confirm_title": "Kustutada kontakt?" + }, + "calendar": { + "title": "Kalender", + "back_to_email": "Tagasi kirjade juurde", + "my_calendars": "Kalendrid", + "mini_calendar_change": "Kliki kuu vahetamiseks", + "views": { + "month": "Kuu", + "week": "Nädal", + "day": "Päev", + "agenda": "Päevakord", + "today": "Täna", + "month_hint": "Kuu (m)", + "week_hint": "Nädal (w)", + "day_hint": "Päev (d)", + "agenda_hint": "Päevakord (a)" + }, + "events": { + "create": "Loo sündmus", + "edit": "Muuda sündmust", + "delete": "Kustuta sündmus", + "details": "Sündmuse üksikasjad", + "no_events": "Sündmusi pole", + "all_day": "Kogu päev", + "more": "+{count} veel", + "no_title": "(Pealkiri puudub)", + "resize": "Muuda sündmuse suurust", + "duplicate": "Dubleeri", + "today_header": "Täna", + "tomorrow_header": "Homme" + }, + "detail": { + "add_note": "Lisa märkus...", + "save_note": "Salvesta", + "note_saved": "Märkus lisatud", + "open_link": "Ava link", + "meeting_link": "Kohtumise link", + "tentative": "Esialgne", + "cancelled": "Tühistatud", + "delete_confirm": "Kustutada see sündmus?" + }, + "form": { + "title": "Pealkiri", + "description": "Kirjeldus", + "location": "Asukoht", + "start_date": "Alguskuupäev", + "end_date": "Lõppkuupäev", + "start_time": "Algusaeg", + "end_time": "Lõppaeg", + "all_day_event": "Kogu päeva sündmus", + "calendar_select": "Kalender", + "save": "Salvesta", + "cancel": "Loobu", + "delete_confirm": "Kas soovid kindlasti selle sündmuse kustutada?", + "color": "Värv" + }, + "participants": { + "title": "Osalejad", + "add": "Lisa osaleja", + "organizer": "Korraldaja", + "attendee": "Osaleja", + "accepted": "Nõustunud", + "declined": "Keeldunud", + "tentative": "Esialgne", + "needs_action": "Vajab vastust", + "remove": "Eemalda", + "email_placeholder": "Lisa e-posti aadress või otsi kontakte", + "send_invitations": "Saada osalejatele kutsed", + "status_summary": "{accepted} nõustus, {pending} ootel", + "invited_by": "Kutse saatjalt {name}", + "respond_below": "Vasta alloleva nuppudega", + "rsvp_label": "Sinu vastus", + "cancel_notification": "Osalejaid teavitatakse tühistamisest", + "you_organizer": "Sina oled korraldaja", + "you_attendee": "Sina oled osaleja", + "no_participants": "Osalejaid pole", + "count": "{count, plural, one {# osaleja} other {# osalejat}}" + }, + "recurrence": { + "title": "Kordumine", + "none": "Ei kordu", + "daily": "Iga päev", + "weekly": "Iga nädal", + "monthly": "Iga kuu", + "yearly": "Igal aastal", + "every_n_days": "Iga {count} päeva järel", + "every_n_weeks": "Iga {count} nädala järel", + "every_n_months": "Iga {count} kuu järel", + "until": "Kuni", + "occurrences": "{count} korda" + }, + "recurrence_scope": { + "edit_title": "Muuda korduvat sündmust", + "delete_title": "Kustuta korduv sündmus", + "description": "See on korduv sündmus. Milliseid sündmusi soovid muuta?", + "this_event": "Ainult see sündmus", + "this_and_future": "See ja järgnevad sündmused", + "all_events": "Kõik sündmused", + "cancel": "Loobu", + "save": "Salvesta", + "delete": "Kustuta" + }, + "alerts": { + "title": "Meeldetuletus", + "none": "Meeldetuletus puudub", + "at_time": "Sündmuse ajal", + "minutes_before": "{count, plural, one {# minut enne} other {# minutit enne}}", + "hours_before": "{count, plural, one {# tund enne} other {# tundi enne}}", + "days_before": "{count, plural, one {# päev enne} other {# päeva enne}}" + }, + "settings": { + "title": "Kalendri seaded", + "default_view": "Vaikevaade", + "week_starts_on": "Nädal algab", + "time_format": "Ajavorming", + "default_calendar": "Vaikekalender", + "default_reminder": "Vaikemeeldetuletus", + "time_format_12h": "12-tunnine", + "time_format_24h": "24-tunnine", + "notifications_enabled": "Sündmuste teavitused", + "notifications_enabled_desc": "Näita hoiatusi eesootavate kalendrisündmuste kohta", + "notification_sound": "Teavituse heli", + "notification_sound_desc": "Esita kalendriteavituste jaoks heli" + }, + "days": { + "monday": "Esmaspäev", + "tuesday": "Teisipäev", + "wednesday": "Kolmapäev", + "thursday": "Neljapäev", + "friday": "Reede", + "saturday": "Laupäev", + "sunday": "Pühapäev", + "mon": "E", + "tue": "T", + "wed": "K", + "thu": "N", + "fri": "R", + "sat": "L", + "sun": "P" + }, + "notifications": { + "event_created": "Sündmus loodud", + "event_updated": "Sündmus uuendatud", + "event_deleted": "Sündmus kustutatud", + "calendar_created": "Kalender loodud", + "calendar_deleted": "Kalender kustutatud", + "event_move_error": "Sündmuse liigutamine ebaõnnestus", + "event_resize_error": "Sündmuse suuruse muutmine ebaõnnestus", + "alert_title": "Eesootav sündmus", + "alert_now": "Algab kohe", + "alert_in_minutes": "{count} min pärast", + "invitation_sent": "Kutsed saadetud", + "rsvp_updated": "Vastus uuendatud", + "rsvp_error": "Vastuse uuendamine ebaõnnestus", + "event_duplicated": "Sündmus dubleeriti", + "event_error": "Sündmuse salvestamine ebaõnnestus" + }, + "status": { + "loading_calendars": "Kalendrite laadimine...", + "loading_events": "Sündmuste laadimine..." + }, + "quick_create": { + "placeholder": "Uue sündmuse pealkiri", + "aria_label": "Kiirloo sündmus" + }, + "nav_prev": "Eelmine", + "nav_next": "Järgmine", + "import": { + "title": "Impordi kalender", + "select_file": "Vali .ics fail", + "drop_file": "või lohista fail siia", + "supported_formats": "Toetab iCalendar (.ics) faile", + "parsing": "Kalendrifaili lugemine...", + "parsed_events": "Leiti {count} sündmust", + "no_events": "Failist ei leitud ühtegi sündmust", + "select_all": "Vali kõik", + "deselect_all": "Tühista kõik valikud", + "target_calendar": "Impordi kalendrisse", + "import_button": "Impordi valitud", + "importing": "Sündmuste importimine...", + "success": "{count} sündmust imporditi edukalt", + "error": "Kalendri importimine ebaõnnestus", + "file_too_large": "Fail ületab 5MB piirangut", + "invalid_format": "Vale kalendrifaili vorming" + } + }, + "advanced_search": { + "title": "Täpsem otsing", + "from": "Saatja", + "from_placeholder": "Saatja e-post või nimi", + "to": "Saaja", + "to_placeholder": "Saaja e-post või nimi", + "subject": "Teema", + "subject_placeholder": "Teema sisaldab...", + "body": "Sisu", + "has_attachment": "Manused", + "date_after": "Pärast", + "date_before": "Enne", + "starred": "Tähistatud", + "unread": "Lugemata", + "read": "Loetud", + "yes": "Jah", + "no": "Ei", + "clear": "Tühjenda", + "clear_all": "Tühjenda kõik", + "filters_active": "{count} filter", + "filters_active_plural": "{count} filtrit", + "toggle_filters": "Filtrid", + "search_hint": "Kasuta täpseks otsinguks laiendatud filtreid", + "advanced_filters_tooltip": "Täpsema otsingu filtrid" + }, + "welcome": { + "title": "Tere tulemast oma postkasti", + "tip_compose": "Vajuta c, et koostada uus kiri", + "tip_shortcuts": "Vajuta ?, et näha kõiki kiirklahve", + "tip_sidebar": "Kalender, Kontaktid ja Seaded leiad külgriba menüüst", + "tip_settings": "Kohanda oma kogemust Seadete alt", + "got_it": "Selge", + "dismiss": "Sulge" + }, + "search": { + "scope_everywhere": "Kõikjal", + "scope_this_folder": "Selles kaustas", + "include_trash_junk": "+ Prügikast ja rämpspost" + } +} diff --git a/locales/fr/common.json b/locales/fr/common.json index 5ddc0a3..4809197 100644 --- a/locales/fr/common.json +++ b/locales/fr/common.json @@ -145,6 +145,7 @@ "email_list": { "no_emails": "Aucun email", "no_emails_description": "Commencez par composer un nouvel email", + "no_preview": "Aucun aperçu disponible", "loading": "Chargement des emails...", "unread": "non lu", "to_me": "À moi", @@ -528,6 +529,7 @@ "russian": "Русский", "ukrainian": "Українська", "polish": "Polski", + "estonian": "Eesti", "select_language": "Sélectionner la langue", "switch_to_english": "Passer à l'anglais", "switch_to_french": "Passer au français", @@ -540,6 +542,7 @@ "switch_to_russian": "Passer au russe", "switch_to_ukrainian": "Passer à l'ukrainien", "switch_to_polish": "Passer au polonais", + "switch_to_estonian": "Passer à l'estonien", "switching": "Changement de langue..." }, "settings": { diff --git a/locales/it/common.json b/locales/it/common.json index 46f76b6..a7e676e 100644 --- a/locales/it/common.json +++ b/locales/it/common.json @@ -145,6 +145,7 @@ "email_list": { "no_emails": "Nessun messaggio", "no_emails_description": "Inizia scrivendo un nuovo messaggio", + "no_preview": "Nessuna anteprima disponibile", "loading": "Caricamento messaggi...", "unread": "non letto", "to_me": "A me", @@ -528,6 +529,7 @@ "russian": "Русский", "ukrainian": "Українська", "polish": "Polski", + "estonian": "Eesti", "select_language": "Seleziona lingua", "switch_to_english": "Passa all'inglese", "switch_to_french": "Passa al francese", @@ -540,6 +542,7 @@ "switch_to_russian": "Passa al russo", "switch_to_ukrainian": "Passa all'ucraino", "switch_to_polish": "Passa al polacco", + "switch_to_estonian": "Passa all'estone", "switching": "Cambio lingua in corso..." }, "settings": { diff --git a/locales/ja/common.json b/locales/ja/common.json index a5e93fd..08d923b 100644 --- a/locales/ja/common.json +++ b/locales/ja/common.json @@ -145,6 +145,7 @@ "email_list": { "no_emails": "メールがありません", "no_emails_description": "新しいメールを作成してください", + "no_preview": "プレビューはありません", "loading": "メールを読み込み中...", "unread": "未読", "to_me": "宛先: 自分", @@ -528,6 +529,7 @@ "russian": "Русский", "ukrainian": "Українська", "polish": "Polski", + "estonian": "Eesti", "select_language": "言語を選択", "switch_to_english": "英語に切り替え", "switch_to_french": "フランス語に切り替え", @@ -540,6 +542,7 @@ "switch_to_russian": "ロシア語に切り替え", "switch_to_ukrainian": "ウクライナ語に切り替え", "switch_to_polish": "ポーランド語に切り替え", + "switch_to_estonian": "エストニア語に切り替え", "switching": "言語を変更中..." }, "settings": { diff --git a/locales/nl/common.json b/locales/nl/common.json index 4fce775..0f83101 100644 --- a/locales/nl/common.json +++ b/locales/nl/common.json @@ -145,6 +145,7 @@ "email_list": { "no_emails": "Geen e-mails", "no_emails_description": "Begin met het opstellen van een nieuw bericht", + "no_preview": "Geen voorbeeld beschikbaar", "loading": "E-mails laden...", "unread": "ongelezen", "to_me": "Aan mij", @@ -528,6 +529,7 @@ "russian": "Русский", "ukrainian": "Українська", "polish": "Polski", + "estonian": "Eesti", "select_language": "Selecteer taal", "switch_to_english": "Overschakelen naar Engels", "switch_to_french": "Overschakelen naar Frans", @@ -540,6 +542,7 @@ "switch_to_russian": "Overschakelen naar Russisch", "switch_to_ukrainian": "Overschakelen naar Oekraïens", "switch_to_polish": "Overschakelen naar Pools", + "switch_to_estonian": "Overschakelen naar Ests", "switching": "Taal wijzigen..." }, "settings": { diff --git a/locales/pl/common.json b/locales/pl/common.json index 1812cb6..f728ef7 100644 --- a/locales/pl/common.json +++ b/locales/pl/common.json @@ -145,6 +145,7 @@ "email_list": { "no_emails": "Brak wiadomości", "no_emails_description": "Zacznij od napisania nowej wiadomości", + "no_preview": "Brak podglądu", "loading": "Ładowanie wiadomości...", "unread": "nieprzeczytane", "to_me": "Do mnie", @@ -532,6 +533,7 @@ "russian": "Русский", "ukrainian": "Українська", "polish": "Polski", + "estonian": "Eesti", "select_language": "Wybierz język", "switch_to_english": "Przełącz na angielski", "switch_to_french": "Przełącz na francuski", @@ -544,6 +546,7 @@ "switch_to_russian": "Przełącz na rosyjski", "switch_to_ukrainian": "Przełącz na ukraiński", "switch_to_polish": "Przełącz na polski", + "switch_to_estonian": "Przełącz na estoński", "switching": "Zmiana języka..." }, "settings": { diff --git a/locales/pt/common.json b/locales/pt/common.json index c2926ec..a1b4cc6 100644 --- a/locales/pt/common.json +++ b/locales/pt/common.json @@ -145,6 +145,7 @@ "email_list": { "no_emails": "Nenhum e-mail", "no_emails_description": "Comece escrevendo um novo e-mail", + "no_preview": "Nenhuma pré-visualização disponível", "loading": "Carregando e-mails...", "unread": "não lido", "to_me": "Para mim", @@ -528,6 +529,7 @@ "russian": "Русский", "ukrainian": "Українська", "polish": "Polski", + "estonian": "Eesti", "select_language": "Selecionar idioma", "switch_to_english": "Mudar para Inglês", "switch_to_french": "Mudar para Francês", @@ -540,6 +542,7 @@ "switch_to_russian": "Mudar para Russo", "switch_to_ukrainian": "Mudar para Ucraniano", "switch_to_polish": "Mudar para Polonês", + "switch_to_estonian": "Mudar para Estoniano", "switching": "Alterando idioma..." }, "settings": { diff --git a/locales/ru/common.json b/locales/ru/common.json index 965da8f..c4f86bc 100644 --- a/locales/ru/common.json +++ b/locales/ru/common.json @@ -145,6 +145,7 @@ "email_list": { "no_emails": "Нет писем", "no_emails_description": "Начните с создания нового письма", + "no_preview": "Предпросмотр недоступен", "loading": "Загрузка писем…", "unread": "непрочитанные", "to_me": "Мне", @@ -532,6 +533,7 @@ "russian": "Русский", "ukrainian": "Українська", "polish": "Polski", + "estonian": "Eesti", "select_language": "Выберите язык", "switch_to_english": "Сменить язык на английский", "switch_to_french": "Сменить язык на французский", @@ -544,6 +546,7 @@ "switch_to_russian": "Сменить язык на русский", "switch_to_ukrainian": "Сменить язык на украинский", "switch_to_polish": "Сменить язык на польский", + "switch_to_estonian": "Сменить язык на эстонский", "switching": "Меняем язык…" }, "settings": { diff --git a/locales/uk/common.json b/locales/uk/common.json index 932c79a..e7658e1 100644 --- a/locales/uk/common.json +++ b/locales/uk/common.json @@ -145,6 +145,7 @@ "email_list": { "no_emails": "Немає листів", "no_emails_description": "Почніть зі створення нового листа", + "no_preview": "Попередній перегляд недоступний", "loading": "Завантаження листів…", "unread": "непрочитані", "to_me": "Мені", @@ -532,6 +533,7 @@ "russian": "Русский", "ukrainian": "Українська", "polish": "Polski", + "estonian": "Eesti", "select_language": "Виберіть мову", "switch_to_english": "Перейти на англійську", "switch_to_french": "Перейти на французьку", @@ -544,6 +546,7 @@ "switch_to_russian": "Перейти на російську", "switch_to_ukrainian": "Перейти на українську", "switch_to_polish": "Перейти на польську", + "switch_to_estonian": "Перейти на естонську", "switching": "Зміна мови…" }, "settings": { diff --git a/package.json b/package.json index cc25d5f..db673c9 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ "dev": "next dev --turbopack", "build": "next build --turbopack", "start": "next start", - "lint": "next lint", - "lint:fix": "next lint --fix", + "lint": "eslint .", + "lint:fix": "eslint . --fix", "prepare": "husky", "typecheck": "tsc --noEmit" },