mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
feat: announce how much new mail came and flash the tab title slowly with visual alerts
This commit is contained in:
@@ -70,7 +70,7 @@ import { useConfirmDialog } from "@/hooks/use-confirm-dialog";
|
||||
import { usePromptDialog } from "@/hooks/use-prompt-dialog";
|
||||
import { useBrowserNavigation, type NavSnapshot } from "@/hooks/use-browser-navigation";
|
||||
import { debug } from "@/lib/debug";
|
||||
import { playNotificationSound } from "@/lib/notification-sound";
|
||||
import { useNewMailAlerts } from "@/hooks/use-new-mail-alerts";
|
||||
import { cn, formatDateTime, getMailboxPath } from "@/lib/utils";
|
||||
import { localizeMailboxName } from "@/lib/mailbox-label";
|
||||
import { KEYWORD_PREFIX, KEYWORD_PREFIX_LEGACY, emailKeyFor, groupEmailsByThread, threadKeyFor } from "@/lib/thread-utils";
|
||||
@@ -420,7 +420,6 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
selectedMailbox,
|
||||
quota,
|
||||
isPushConnected,
|
||||
newEmailNotification,
|
||||
selectEmail,
|
||||
selectMailbox,
|
||||
selectedEmailKeys,
|
||||
@@ -447,7 +446,6 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
finishOpenEmail,
|
||||
abandonOpenEmail,
|
||||
handleStateChange,
|
||||
clearNewEmailNotification,
|
||||
markAsSpam,
|
||||
undoSpam,
|
||||
searchFilters,
|
||||
@@ -509,7 +507,6 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
selectedMailbox: state.selectedMailbox,
|
||||
quota: state.quota,
|
||||
isPushConnected: state.isPushConnected,
|
||||
newEmailNotification: state.newEmailNotification,
|
||||
selectEmail: state.selectEmail,
|
||||
selectMailbox: state.selectMailbox,
|
||||
selectedEmailKeys: state.selectedEmailKeys,
|
||||
@@ -536,7 +533,6 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
finishOpenEmail: state.finishOpenEmail,
|
||||
abandonOpenEmail: state.abandonOpenEmail,
|
||||
handleStateChange: state.handleStateChange,
|
||||
clearNewEmailNotification: state.clearNewEmailNotification,
|
||||
markAsSpam: state.markAsSpam,
|
||||
undoSpam: state.undoSpam,
|
||||
searchFilters: state.searchFilters,
|
||||
@@ -2068,17 +2064,9 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedEmail?.id, isScheduledView, mvShell, cursorOnly]);
|
||||
|
||||
// Handle new email notifications - play sound
|
||||
useEffect(() => {
|
||||
if (newEmailNotification) {
|
||||
const { emailNotificationsEnabled, emailNotificationSound, notificationSoundChoice } = useSettingsStore.getState();
|
||||
if (emailNotificationsEnabled && emailNotificationSound) {
|
||||
playNotificationSound(notificationSoundChoice);
|
||||
}
|
||||
debug.log('email', 'New email received:', newEmailNotification.subject);
|
||||
clearNewEmailNotification();
|
||||
}
|
||||
}, [newEmailNotification, clearNewEmailNotification]);
|
||||
// New mail: the sound, the screen reader count and the visual alert, all
|
||||
// silenced by Do not disturb.
|
||||
useNewMailAlerts();
|
||||
|
||||
// Lock body scroll when sidebar is open on mobile/tablet
|
||||
useEffect(() => {
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import { useNewMailAlerts, NEW_MAIL_BATCH_MS } from '../use-new-mail-alerts';
|
||||
import { useEmailStore } from '@/stores/email-store';
|
||||
import { useSettingsStore } from '@/stores/settings-store';
|
||||
import { LIVE_REGION_IDS, resetAnnouncerForTests } from '@/lib/announce';
|
||||
import { stopTitleAlert, TITLE_ALERT_INTERVAL_MS, TITLE_ALERT_MAX_SWAPS } from '@/lib/title-alert';
|
||||
import type { Email } from '@/lib/jmap/types';
|
||||
|
||||
// The count must reach the words, so t shows its values.
|
||||
vi.mock('next-intl', () => ({
|
||||
useTranslations: () => (key: string, values?: Record<string, unknown>) =>
|
||||
values ? `${key}:${JSON.stringify(values)}` : key,
|
||||
}));
|
||||
|
||||
const playNotificationSound = vi.hoisted(() => vi.fn());
|
||||
vi.mock('@/lib/notification-sound', () => ({ playNotificationSound }));
|
||||
|
||||
const polite = () => document.getElementById(LIVE_REGION_IDS.polite)?.textContent ?? '';
|
||||
const arrive = (id: string) => act(() => {
|
||||
useEmailStore.getState().handleNewEmailNotification({ id, subject: `Secret ${id}` } as Email);
|
||||
});
|
||||
|
||||
describe('new mail alerts', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
resetAnnouncerForTests();
|
||||
playNotificationSound.mockClear();
|
||||
useEmailStore.setState({ newEmailNotification: null });
|
||||
useSettingsStore.setState({
|
||||
emailNotificationsEnabled: true, emailNotificationSound: true, announceNewMail: true,
|
||||
doNotDisturb: false, visualAlerts: false,
|
||||
});
|
||||
document.title = 'Inbox - Bulwark';
|
||||
});
|
||||
afterEach(() => {
|
||||
stopTitleAlert();
|
||||
vi.restoreAllMocks();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it('tells screen readers once how many messages came, never what they say', () => {
|
||||
renderHook(() => useNewMailAlerts());
|
||||
arrive('a');
|
||||
arrive('b');
|
||||
arrive('c');
|
||||
expect(polite()).toBe('');
|
||||
act(() => { vi.advanceTimersByTime(NEW_MAIL_BATCH_MS + 100); });
|
||||
expect(polite()).toBe('new_mail_count:{"count":3}');
|
||||
expect(polite()).not.toContain('Secret');
|
||||
// One sound for the batch, not three.
|
||||
expect(playNotificationSound).toHaveBeenCalledTimes(1);
|
||||
expect(useEmailStore.getState().newEmailNotification).toBeNull();
|
||||
});
|
||||
|
||||
it('stays quiet for screen readers with "Announce new mail" off', () => {
|
||||
useSettingsStore.setState({ announceNewMail: false });
|
||||
renderHook(() => useNewMailAlerts());
|
||||
arrive('a');
|
||||
act(() => { vi.advanceTimersByTime(NEW_MAIL_BATCH_MS + 100); });
|
||||
expect(polite()).toBe('');
|
||||
expect(playNotificationSound).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('plays no sound, says nothing and leaves the title alone with Do not disturb on', () => {
|
||||
useSettingsStore.setState({ doNotDisturb: true, visualAlerts: true });
|
||||
vi.spyOn(document, 'hasFocus').mockReturnValue(false);
|
||||
renderHook(() => useNewMailAlerts());
|
||||
arrive('a');
|
||||
act(() => { vi.advanceTimersByTime(NEW_MAIL_BATCH_MS + 100); });
|
||||
expect(playNotificationSound).not.toHaveBeenCalled();
|
||||
expect(polite()).toBe('');
|
||||
expect(document.title).toBe('Inbox - Bulwark');
|
||||
});
|
||||
|
||||
it('swaps the tab title slowly with Visual alerts on while the tab is in the background', () => {
|
||||
useSettingsStore.setState({ visualAlerts: true });
|
||||
vi.spyOn(document, 'hasFocus').mockReturnValue(false);
|
||||
renderHook(() => useNewMailAlerts());
|
||||
arrive('a');
|
||||
expect(document.title).toBe('new_mail_count:{"count":1}');
|
||||
arrive('b');
|
||||
expect(document.title).toBe('new_mail_count:{"count":2}');
|
||||
act(() => { vi.advanceTimersByTime(TITLE_ALERT_INTERVAL_MS); });
|
||||
expect(document.title).toBe('Inbox - Bulwark');
|
||||
act(() => { vi.advanceTimersByTime(TITLE_ALERT_INTERVAL_MS * TITLE_ALERT_MAX_SWAPS); });
|
||||
expect(document.title).toBe('Inbox - Bulwark');
|
||||
});
|
||||
});
|
||||
@@ -12,6 +12,7 @@ import { useToastStore } from '@/stores/toast-store';
|
||||
import { getPendingAlerts, getPendingTaskAlerts, getNextAlertFireTime, buildAlertKey } from '@/lib/calendar-alerts';
|
||||
import { playNotificationSound } from '@/lib/notification-sound';
|
||||
import { lastingToastDuration } from '@/lib/toast-duration';
|
||||
import { startTitleAlert } from '@/lib/title-alert';
|
||||
import { getPathPrefix } from '@/lib/browser-navigation';
|
||||
import type { CalendarEvent } from '@/lib/jmap/types';
|
||||
import { calendarHooks } from '@/lib/plugin-hooks';
|
||||
@@ -43,6 +44,15 @@ function reminderSoundOn(soundSetting: boolean): boolean {
|
||||
return soundSetting && !useSettingsStore.getState().doNotDisturb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visual alerts: the tab title swaps slowly to the reminder while the tab
|
||||
* is in the background. Reminders were asked for, so Do not disturb keeps
|
||||
* this too.
|
||||
*/
|
||||
function reminderTitleAlert(text: string): void {
|
||||
if (useSettingsStore.getState().visualAlerts) startTitleAlert(text);
|
||||
}
|
||||
|
||||
export function useCalendarAlerts() {
|
||||
const { isAuthenticated, client } = useAuthStore();
|
||||
const { events, calendars, supportsCalendar } = useCalendarStore();
|
||||
@@ -107,6 +117,7 @@ export function useCalendarAlerts() {
|
||||
? `${timeLabel} · ${alert.calendarName}`
|
||||
: timeLabel;
|
||||
|
||||
reminderTitleAlert(t('title_alert', { title: alert.event.title || t('alert_title') }));
|
||||
addToast({
|
||||
type: 'info',
|
||||
title: alert.event.title || t('alert_title'),
|
||||
@@ -139,6 +150,7 @@ export function useCalendarAlerts() {
|
||||
? `${t('task_due')} · ${taskAlert.calendarName}`
|
||||
: t('task_due');
|
||||
|
||||
reminderTitleAlert(t('title_alert', { title: taskAlert.task.title || t('alert_title') }));
|
||||
addToast({
|
||||
type: 'info',
|
||||
title: taskAlert.task.title || t('alert_title'),
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useConfig } from '@/hooks/use-config';
|
||||
import { useIsFocusedProTab, usePaneId } from '@/hooks/use-pane-context';
|
||||
import { useAccountStore } from '@/stores/account-store';
|
||||
import { formatTabTitle } from '@/lib/tab-title';
|
||||
import { isTitleAlertActive } from '@/lib/title-alert';
|
||||
|
||||
// The surface that set the title last owns it. One that is still mounted
|
||||
// (during a route transition) stops re-applying, so two titles never fight.
|
||||
@@ -45,6 +46,9 @@ export function useDocumentTitle(context?: string | null): void {
|
||||
let readBack: string | null = null;
|
||||
const apply = () => {
|
||||
if (owner !== self) return;
|
||||
// A visual alert swaps the title for now (lib/title-alert); it puts
|
||||
// the title back when it stops, and this runs again then.
|
||||
if (isTitleAlertActive()) return;
|
||||
const current = document.title;
|
||||
if (current === title || current === readBack) return;
|
||||
document.title = title;
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useEmailStore } from "@/stores/email-store";
|
||||
import { useSettingsStore } from "@/stores/settings-store";
|
||||
import { playNotificationSound } from "@/lib/notification-sound";
|
||||
import { announce } from "@/lib/announce";
|
||||
import { startTitleAlert } from "@/lib/title-alert";
|
||||
import { debug } from "@/lib/debug";
|
||||
|
||||
/**
|
||||
* Mail that arrives within this time is told about once ("3 new messages"),
|
||||
* not message by message.
|
||||
*/
|
||||
export const NEW_MAIL_BATCH_MS = 3000;
|
||||
|
||||
/**
|
||||
* What the app does when new mail reaches the Inbox (the store sets
|
||||
* `newEmailNotification` for each message; muted folders never do):
|
||||
*
|
||||
* - plays the new-mail sound once per batch, when mail notifications and
|
||||
* their sound are on;
|
||||
* - tells screen reader users how many messages came, never what they say,
|
||||
* when "Announce new mail" is on;
|
||||
* - with Visual alerts on, swaps the tab title slowly while the tab is in
|
||||
* the background (lib/title-alert).
|
||||
*
|
||||
* Do not disturb silences all of it until it is turned off.
|
||||
*/
|
||||
export function useNewMailAlerts(): void {
|
||||
const t = useTranslations("notifications");
|
||||
|
||||
useEffect(() => {
|
||||
let batch = 0;
|
||||
let batchTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
// Messages the title alert counts: since the tab was last in front.
|
||||
let unseen = 0;
|
||||
|
||||
const flush = () => {
|
||||
batchTimer = null;
|
||||
const count = batch;
|
||||
batch = 0;
|
||||
const s = useSettingsStore.getState();
|
||||
if (count > 0 && s.announceNewMail && !s.doNotDisturb) {
|
||||
announce(t("new_mail_count", { count }), { key: "new-mail" });
|
||||
}
|
||||
};
|
||||
|
||||
const onNewMail = () => {
|
||||
const s = useSettingsStore.getState();
|
||||
if (s.doNotDisturb) return;
|
||||
if (batchTimer === null) {
|
||||
if (s.emailNotificationsEnabled && s.emailNotificationSound) {
|
||||
playNotificationSound(s.notificationSoundChoice);
|
||||
}
|
||||
batchTimer = setTimeout(flush, NEW_MAIL_BATCH_MS);
|
||||
}
|
||||
batch += 1;
|
||||
if (s.visualAlerts) {
|
||||
unseen += 1;
|
||||
startTitleAlert(t("new_mail_count", { count: unseen }));
|
||||
}
|
||||
};
|
||||
|
||||
const resetUnseen = () => { unseen = 0; };
|
||||
window.addEventListener("focus", resetUnseen);
|
||||
|
||||
const unsubscribe = useEmailStore.subscribe((state, prev) => {
|
||||
const email = state.newEmailNotification;
|
||||
if (!email || email === prev.newEmailNotification) return;
|
||||
debug.log("email", "New email received:", email.subject);
|
||||
state.clearNewEmailNotification();
|
||||
onNewMail();
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubscribe();
|
||||
window.removeEventListener("focus", resetUnseen);
|
||||
if (batchTimer) clearTimeout(batchTimer);
|
||||
};
|
||||
}, [t]);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import {
|
||||
isTitleAlertActive, startTitleAlert, stopTitleAlert, TITLE_ALERT_INTERVAL_MS, TITLE_ALERT_MAX_SWAPS,
|
||||
} from '../title-alert';
|
||||
|
||||
describe('title alert', () => {
|
||||
let focused = false;
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
focused = false;
|
||||
vi.spyOn(document, 'hasFocus').mockImplementation(() => focused);
|
||||
document.title = 'Inbox';
|
||||
});
|
||||
afterEach(() => {
|
||||
stopTitleAlert();
|
||||
vi.restoreAllMocks();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it('never swaps faster than once a second', () => {
|
||||
expect(TITLE_ALERT_INTERVAL_MS).toBeGreaterThanOrEqual(1000);
|
||||
startTitleAlert('1 new message');
|
||||
expect(document.title).toBe('1 new message');
|
||||
vi.advanceTimersByTime(999);
|
||||
expect(document.title).toBe('1 new message');
|
||||
vi.advanceTimersByTime(TITLE_ALERT_INTERVAL_MS - 999);
|
||||
expect(document.title).toBe('Inbox');
|
||||
});
|
||||
|
||||
it('stops by itself after a few rounds and puts the title back', () => {
|
||||
startTitleAlert('1 new message');
|
||||
vi.advanceTimersByTime(TITLE_ALERT_INTERVAL_MS * TITLE_ALERT_MAX_SWAPS);
|
||||
expect(isTitleAlertActive()).toBe(false);
|
||||
expect(document.title).toBe('Inbox');
|
||||
vi.advanceTimersByTime(TITLE_ALERT_INTERVAL_MS * 4);
|
||||
expect(document.title).toBe('Inbox');
|
||||
});
|
||||
|
||||
it('stops when the tab gets the focus', () => {
|
||||
startTitleAlert('1 new message');
|
||||
focused = true;
|
||||
window.dispatchEvent(new Event('focus'));
|
||||
expect(isTitleAlertActive()).toBe(false);
|
||||
expect(document.title).toBe('Inbox');
|
||||
});
|
||||
|
||||
it('does nothing while the tab is in front', () => {
|
||||
focused = true;
|
||||
startTitleAlert('1 new message');
|
||||
expect(isTitleAlertActive()).toBe(false);
|
||||
expect(document.title).toBe('Inbox');
|
||||
});
|
||||
});
|
||||
@@ -7,6 +7,7 @@ import { useAuthStore } from '@/stores/auth-store';
|
||||
import { useCalendarStore } from '@/stores/calendar-store';
|
||||
import { useCalendarNotificationStore } from '@/stores/calendar-notification-store';
|
||||
import { useCalendarAlerts } from '@/hooks/use-calendar-alerts';
|
||||
import { stopTitleAlert } from '@/lib/title-alert';
|
||||
import type { CalendarEvent } from '@/lib/jmap/types';
|
||||
|
||||
const playNotificationSound = vi.hoisted(() => vi.fn());
|
||||
@@ -110,6 +111,8 @@ describe('reminder toasts', () => {
|
||||
useCalendarStore.setState({ events: [], calendars: [], supportsCalendar: true });
|
||||
});
|
||||
afterEach(() => {
|
||||
// A reminder with Visual alerts on may have started the title alert.
|
||||
stopTitleAlert();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
@@ -133,6 +136,21 @@ describe('reminder toasts', () => {
|
||||
expect(showReminder('r4').duration).toBe(0);
|
||||
});
|
||||
|
||||
it('swaps the tab title to the reminder with Visual alerts on, in the background', () => {
|
||||
const hasFocus = vi.spyOn(document, 'hasFocus').mockReturnValue(false);
|
||||
document.title = 'Calendar';
|
||||
try {
|
||||
useSettingsStore.setState({ visualAlerts: true, doNotDisturb: true });
|
||||
const shown = showReminder('r7');
|
||||
expect(shown?.title).toBe('Meeting r7');
|
||||
expect(document.title).toBe('title_alert');
|
||||
} finally {
|
||||
stopTitleAlert();
|
||||
hasFocus.mockRestore();
|
||||
}
|
||||
expect(document.title).toBe('Calendar');
|
||||
});
|
||||
|
||||
it('still shows with Do not disturb on, but without a sound', () => {
|
||||
useSettingsStore.setState({ doNotDisturb: true });
|
||||
expect(showReminder('r5')).toBeDefined();
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Visual alerts (Settings > Accessibility): the browser-tab title swaps
|
||||
* slowly between the page's own title and a short alert ("3 new messages")
|
||||
* while the tab is in the background, for people who can't hear the sound.
|
||||
*
|
||||
* It never swaps faster than once a second and never flashes colours
|
||||
* (WCAG 2.3.1), and it stops after a few rounds or as soon as the tab gets
|
||||
* the focus. hooks/use-document-title leaves the title alone while it runs.
|
||||
*/
|
||||
|
||||
/** Time between two swaps. At least a second. */
|
||||
export const TITLE_ALERT_INTERVAL_MS = 1500;
|
||||
/** Swaps before it stops by itself: five rounds of alert and title. */
|
||||
export const TITLE_ALERT_MAX_SWAPS = 10;
|
||||
|
||||
let timer: ReturnType<typeof setInterval> | null = null;
|
||||
let baseTitle = '';
|
||||
let alertText = '';
|
||||
let swaps = 0;
|
||||
let showingAlert = false;
|
||||
|
||||
export function isTitleAlertActive(): boolean {
|
||||
return timer !== null;
|
||||
}
|
||||
|
||||
function tabInView(): boolean {
|
||||
return !document.hidden && document.hasFocus();
|
||||
}
|
||||
|
||||
function onVisibilityChange() {
|
||||
if (tabInView()) stopTitleAlert();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the alert, or changes its text and starts its rounds again when
|
||||
* it is already running. Nothing happens while the tab is in front: the
|
||||
* toast or the list says it there.
|
||||
*/
|
||||
export function startTitleAlert(text: string): void {
|
||||
if (typeof document === 'undefined' || !text) return;
|
||||
if (tabInView()) return;
|
||||
alertText = text;
|
||||
swaps = 0;
|
||||
if (timer !== null) {
|
||||
if (showingAlert) document.title = alertText;
|
||||
return;
|
||||
}
|
||||
baseTitle = document.title;
|
||||
showingAlert = true;
|
||||
document.title = alertText;
|
||||
timer = setInterval(() => {
|
||||
swaps += 1;
|
||||
if (swaps >= TITLE_ALERT_MAX_SWAPS) {
|
||||
stopTitleAlert();
|
||||
return;
|
||||
}
|
||||
showingAlert = !showingAlert;
|
||||
document.title = showingAlert ? alertText : baseTitle;
|
||||
}, TITLE_ALERT_INTERVAL_MS);
|
||||
window.addEventListener('focus', stopTitleAlert);
|
||||
document.addEventListener('visibilitychange', onVisibilityChange);
|
||||
}
|
||||
|
||||
/** Stops the alert and puts the page's title back. */
|
||||
export function stopTitleAlert(): void {
|
||||
if (timer === null) return;
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
showingAlert = false;
|
||||
window.removeEventListener('focus', stopTitleAlert);
|
||||
document.removeEventListener('visibilitychange', onVisibilityChange);
|
||||
// useDocumentTitle sees the change and writes the current title if the
|
||||
// page moved on in the meantime.
|
||||
document.title = baseTitle;
|
||||
}
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {تم تمييز رسالة واحدة كمقروءة} other {تم تمييز # رسائل كمقروءة}}",
|
||||
"emails_marked_unread": "{count, plural, one {تم تمييز رسالة واحدة كغير مقروءة} other {تم تمييز # رسائل كغير مقروءة}}",
|
||||
"tag_removed": "تمت إزالة الوسم",
|
||||
"tag_removed_count": "{count, plural, one {تمت إزالة الوسم من رسالة واحدة} other {تمت إزالة الوسم من # رسائل}}"
|
||||
"tag_removed_count": "{count, plural, one {تمت إزالة الوسم من رسالة واحدة} other {تمت إزالة الوسم من # رسائل}}",
|
||||
"new_mail_count": "{count, plural, one {رسالة جديدة واحدة} other {# رسائل جديدة}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "تحتاج الإشعارات الفورية إلى خادم ترحيل تديره مؤسستك، ولم يُعدّ أي خادم. يستمر ظهور البريد الجديد ما دام التطبيق مفتوحًا.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "موعد استحقاق المهمة",
|
||||
"event_exported": "تم تصدير الحدث",
|
||||
"title_copied": "تم نسخ العنوان",
|
||||
"link_copied": "تم نسخ الرابط"
|
||||
"link_copied": "تم نسخ الرابط",
|
||||
"title_alert": "تذكير: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "جارٍ تحميل التقويمات...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# correu marcat com a llegit} other {# correus marcats com a llegits}}",
|
||||
"emails_marked_unread": "{count, plural, one {# correu marcat com a no llegit} other {# correus marcats com a no llegits}}",
|
||||
"tag_removed": "S'ha tret l'etiqueta",
|
||||
"tag_removed_count": "{count, plural, one {S'ha tret l'etiqueta de # correu} other {S'ha tret l'etiqueta de # correus}}"
|
||||
"tag_removed_count": "{count, plural, one {S'ha tret l'etiqueta de # correu} other {S'ha tret l'etiqueta de # correus}}",
|
||||
"new_mail_count": "{count, plural, one {# missatge nou} other {# missatges nous}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Les notificacions push necessiten un repetidor push gestionat per la vostra organització, i no n'hi ha cap de configurat. El correu nou es continua mostrant mentre l'aplicació està oberta.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "Tasca pendent",
|
||||
"event_exported": "Esdeveniment exportat",
|
||||
"title_copied": "Títol copiat",
|
||||
"link_copied": "Enllaç copiat"
|
||||
"link_copied": "Enllaç copiat",
|
||||
"title_alert": "Recordatori: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Carregant els calendaris...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# zpráva označena jako přečtená} few {# zprávy označeny jako přečtené} other {# zpráv označeno jako přečtené}}",
|
||||
"emails_marked_unread": "{count, plural, one {# zpráva označena jako nepřečtená} few {# zprávy označeny jako nepřečtené} other {# zpráv označeno jako nepřečtené}}",
|
||||
"tag_removed": "Štítek odebrán",
|
||||
"tag_removed_count": "{count, plural, one {Štítek odebrán z # zprávy} few {Štítek odebrán ze # zpráv} other {Štítek odebrán z # zpráv}}"
|
||||
"tag_removed_count": "{count, plural, one {Štítek odebrán z # zprávy} few {Štítek odebrán ze # zpráv} other {Štítek odebrán z # zpráv}}",
|
||||
"new_mail_count": "{count, plural, one {# nová zpráva} few {# nové zprávy} other {# nových zpráv}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Push oznámení potřebují push relay provozovaný vaší organizací a žádný není nastaven. Nová pošta se dál zobrazuje, dokud je aplikace otevřená.",
|
||||
@@ -4451,7 +4452,8 @@
|
||||
"task_due": "Termín úkolu",
|
||||
"event_exported": "Událost exportována",
|
||||
"title_copied": "Název zkopírován",
|
||||
"link_copied": "Odkaz zkopírován"
|
||||
"link_copied": "Odkaz zkopírován",
|
||||
"title_alert": "Připomenutí: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Načítání kalendářů...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# e-mail markeret som læst} other {# e-mails markeret som læst}}",
|
||||
"emails_marked_unread": "{count, plural, one {# e-mail markeret som ulæst} other {# e-mails markeret som ulæst}}",
|
||||
"tag_removed": "Tag fjernet",
|
||||
"tag_removed_count": "{count, plural, one {Tag fjernet fra # e-mail} other {Tag fjernet fra # e-mails}}"
|
||||
"tag_removed_count": "{count, plural, one {Tag fjernet fra # e-mail} other {Tag fjernet fra # e-mails}}",
|
||||
"new_mail_count": "{count, plural, one {# ny besked} other {# nye beskeder}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Push-notifikationer kræver et push-relæ, som din organisation driver, og der er ikke sat noget op. Ny mail vises stadig, mens appen er åben.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "Opgave forfalder",
|
||||
"event_exported": "Begivenhed eksporteret",
|
||||
"title_copied": "Titel kopieret",
|
||||
"link_copied": "Link kopieret"
|
||||
"link_copied": "Link kopieret",
|
||||
"title_alert": "Påmindelse: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Indlæser kalendere...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# E-Mail als gelesen markiert} other {# E-Mails als gelesen markiert}}",
|
||||
"emails_marked_unread": "{count, plural, one {# E-Mail als ungelesen markiert} other {# E-Mails als ungelesen markiert}}",
|
||||
"tag_removed": "Markierung entfernt",
|
||||
"tag_removed_count": "{count, plural, one {Markierung von # E-Mail entfernt} other {Markierung von # E-Mails entfernt}}"
|
||||
"tag_removed_count": "{count, plural, one {Markierung von # E-Mail entfernt} other {Markierung von # E-Mails entfernt}}",
|
||||
"new_mail_count": "{count, plural, one {# neue Nachricht} other {# neue Nachrichten}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Push-Benachrichtigungen brauchen ein Push-Relay Ihrer Organisation, und es ist keines eingerichtet. Neue E-Mails werden weiterhin angezeigt, solange die App geöffnet ist.",
|
||||
@@ -4451,7 +4452,8 @@
|
||||
"task_due": "Aufgabe fällig",
|
||||
"event_exported": "Termin exportiert",
|
||||
"title_copied": "Titel kopiert",
|
||||
"link_copied": "Link kopiert"
|
||||
"link_copied": "Link kopiert",
|
||||
"title_alert": "Erinnerung: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Kalender werden geladen...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# email marked as read} other {# emails marked as read}}",
|
||||
"emails_marked_unread": "{count, plural, one {# email marked as unread} other {# emails marked as unread}}",
|
||||
"tag_removed": "Tag removed",
|
||||
"tag_removed_count": "{count, plural, one {Tag removed from # email} other {Tag removed from # emails}}"
|
||||
"tag_removed_count": "{count, plural, one {Tag removed from # email} other {Tag removed from # emails}}",
|
||||
"new_mail_count": "{count, plural, one {# new message} other {# new messages}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Push notifications need a push relay run by your organisation, and none is set up. New mail still shows while the app is open.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "Task due",
|
||||
"event_exported": "Event exported",
|
||||
"title_copied": "Title copied",
|
||||
"link_copied": "Link copied"
|
||||
"link_copied": "Link copied",
|
||||
"title_alert": "Reminder: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Loading calendars…",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# correo marcado como leído} other {# correos marcados como leídos}}",
|
||||
"emails_marked_unread": "{count, plural, one {# correo marcado como no leído} other {# correos marcados como no leídos}}",
|
||||
"tag_removed": "Etiqueta quitada",
|
||||
"tag_removed_count": "{count, plural, one {Etiqueta quitada de # correo} other {Etiqueta quitada de # correos}}"
|
||||
"tag_removed_count": "{count, plural, one {Etiqueta quitada de # correo} other {Etiqueta quitada de # correos}}",
|
||||
"new_mail_count": "{count, plural, one {# mensaje nuevo} other {# mensajes nuevos}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Las notificaciones push necesitan un relay push gestionado por tu organización, y no hay ninguno configurado. El correo nuevo se sigue mostrando mientras la aplicación está abierta.",
|
||||
@@ -4451,7 +4452,8 @@
|
||||
"task_due": "Tarea vencida",
|
||||
"event_exported": "Evento exportado",
|
||||
"title_copied": "Título copiado",
|
||||
"link_copied": "Enlace copiado"
|
||||
"link_copied": "Enlace copiado",
|
||||
"title_alert": "Recordatorio: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Cargando calendarios...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# kiri märgiti loetuks} other {# kirja märgiti loetuks}}",
|
||||
"emails_marked_unread": "{count, plural, one {# kiri märgiti lugemata} other {# kirja märgiti lugemata}}",
|
||||
"tag_removed": "Silt eemaldati",
|
||||
"tag_removed_count": "{count, plural, one {Silt eemaldati # kirjalt} other {Silt eemaldati # kirjalt}}"
|
||||
"tag_removed_count": "{count, plural, one {Silt eemaldati # kirjalt} other {Silt eemaldati # kirjalt}}",
|
||||
"new_mail_count": "{count, plural, one {# uus kiri} other {# uut kirja}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Tõuketeavitused vajavad sinu organisatsiooni hallatavat push-releed, kuid ühtegi pole seadistatud. Uued kirjad kuvatakse endiselt, kuni rakendus on avatud.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "Ülesande tähtaeg",
|
||||
"event_exported": "Sündmus eksporditud",
|
||||
"title_copied": "Pealkiri kopeeritud",
|
||||
"link_copied": "Link kopeeritud"
|
||||
"link_copied": "Link kopeeritud",
|
||||
"title_alert": "Meeldetuletus: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Kalendrite laadimine...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, other {# ایمیل خوانده شده علامتگذاری شد}}",
|
||||
"emails_marked_unread": "{count, plural, other {# ایمیل خوانده نشده علامتگذاری شد}}",
|
||||
"tag_removed": "برچسب برداشته شد",
|
||||
"tag_removed_count": "{count, plural, other {برچسب از # ایمیل برداشته شد}}"
|
||||
"tag_removed_count": "{count, plural, other {برچسب از # ایمیل برداشته شد}}",
|
||||
"new_mail_count": "{count, plural, other {# پیام جدید}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "اعلانهای push به یک رلهٔ push نیاز دارند که سازمان شما اداره کند، و هیچکدام راهاندازی نشده است. تا وقتی برنامه باز است، ایمیلهای جدید همچنان نمایش داده میشوند.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "موعد وظیفه",
|
||||
"event_exported": "رویداد خروجی گرفته شد",
|
||||
"title_copied": "عنوان کپی شد",
|
||||
"link_copied": "لینک کپی شد"
|
||||
"link_copied": "لینک کپی شد",
|
||||
"title_alert": "یادآوری: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "در حال بارگذاری تقویمها...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# e-mail marqué comme lu} other {# e-mails marqués comme lus}}",
|
||||
"emails_marked_unread": "{count, plural, one {# e-mail marqué comme non lu} other {# e-mails marqués comme non lus}}",
|
||||
"tag_removed": "Étiquette retirée",
|
||||
"tag_removed_count": "{count, plural, one {Étiquette retirée de # e-mail} other {Étiquette retirée de # e-mails}}"
|
||||
"tag_removed_count": "{count, plural, one {Étiquette retirée de # e-mail} other {Étiquette retirée de # e-mails}}",
|
||||
"new_mail_count": "{count, plural, one {# nouveau message} other {# nouveaux messages}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Les notifications push nécessitent un relais push géré par votre organisation, et aucun n'est configuré. Les nouveaux messages s'affichent toujours tant que l'application est ouverte.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "Tâche à échéance",
|
||||
"event_exported": "Événement exporté",
|
||||
"title_copied": "Titre copié",
|
||||
"link_copied": "Lien copié"
|
||||
"link_copied": "Lien copié",
|
||||
"title_alert": "Rappel : {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Chargement des calendriers...",
|
||||
|
||||
@@ -1131,7 +1131,8 @@
|
||||
"emails_marked_read": "{count, plural, one {הודעה אחת סומנה כנקראה} other {# הודעות סומנו כנקראו}}",
|
||||
"emails_marked_unread": "{count, plural, one {הודעה אחת סומנה כלא נקראה} other {# הודעות סומנו כלא נקראו}}",
|
||||
"tag_removed": "התגית הוסרה",
|
||||
"tag_removed_count": "{count, plural, one {התגית הוסרה מהודעה אחת} other {התגית הוסרה מ-# הודעות}}"
|
||||
"tag_removed_count": "{count, plural, one {התגית הוסרה מהודעה אחת} other {התגית הוסרה מ-# הודעות}}",
|
||||
"new_mail_count": "{count, plural, one {הודעה חדשה אחת} other {# הודעות חדשות}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "התראות Push דורשות ממסר Push שהארגון שלך מפעיל, ולא הוגדר אף אחד. דואר חדש עדיין מוצג כל עוד האפליקציה פתוחה.",
|
||||
@@ -4369,7 +4370,8 @@
|
||||
"task_due": "משימה בשל",
|
||||
"event_exported": "אירוע ייצא",
|
||||
"title_copied": "כותרת הועתקה",
|
||||
"link_copied": "קישור הועתק"
|
||||
"link_copied": "קישור הועתק",
|
||||
"title_alert": "תזכורת: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "טוען יומנים...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, other {# e-mail olvasottnak jelölve}}",
|
||||
"emails_marked_unread": "{count, plural, other {# e-mail olvasatlannak jelölve}}",
|
||||
"tag_removed": "Címke eltávolítva",
|
||||
"tag_removed_count": "{count, plural, other {Címke eltávolítva # e-mailről}}"
|
||||
"tag_removed_count": "{count, plural, other {Címke eltávolítva # e-mailről}}",
|
||||
"new_mail_count": "{count, plural, other {# új üzenet}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "A push-értesítésekhez a szervezeted által üzemeltetett push relé kell, és nincs beállítva egy sem. Az új levelek továbbra is megjelennek, amíg az alkalmazás nyitva van.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "Feladat határidős",
|
||||
"event_exported": "Esemény exportálva",
|
||||
"title_copied": "Cím másolva",
|
||||
"link_copied": "Link másolva"
|
||||
"link_copied": "Link másolva",
|
||||
"title_alert": "Emlékeztető: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Naptárak betöltése...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# email segnata come letta} other {# email segnate come lette}}",
|
||||
"emails_marked_unread": "{count, plural, one {# email segnata come non letta} other {# email segnate come non lette}}",
|
||||
"tag_removed": "Etichetta rimossa",
|
||||
"tag_removed_count": "{count, plural, one {Etichetta rimossa da # email} other {Etichetta rimossa da # email}}"
|
||||
"tag_removed_count": "{count, plural, one {Etichetta rimossa da # email} other {Etichetta rimossa da # email}}",
|
||||
"new_mail_count": "{count, plural, one {# nuovo messaggio} other {# nuovi messaggi}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Le notifiche push richiedono un relay push gestito dalla tua organizzazione, e non ne è configurato nessuno. La nuova posta compare comunque finché l'app è aperta.",
|
||||
@@ -4451,7 +4452,8 @@
|
||||
"task_due": "Attività in scadenza",
|
||||
"event_exported": "Evento esportato",
|
||||
"title_copied": "Titolo copiato",
|
||||
"link_copied": "Link copiato"
|
||||
"link_copied": "Link copiato",
|
||||
"title_alert": "Promemoria: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Caricamento calendari...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, other {#件のメールを既読にしました}}",
|
||||
"emails_marked_unread": "{count, plural, other {#件のメールを未読にしました}}",
|
||||
"tag_removed": "タグを外しました",
|
||||
"tag_removed_count": "{count, plural, other {#件のメールからタグを外しました}}"
|
||||
"tag_removed_count": "{count, plural, other {#件のメールからタグを外しました}}",
|
||||
"new_mail_count": "{count, plural, other {新着メッセージ #件}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "プッシュ通知には組織が運用するプッシュリレーが必要ですが、設定されていません。アプリを開いている間は、新着メールが引き続き表示されます。",
|
||||
@@ -4451,7 +4452,8 @@
|
||||
"task_due": "タスクの期限です",
|
||||
"event_exported": "イベントをエクスポートしました",
|
||||
"title_copied": "タイトルをコピーしました",
|
||||
"link_copied": "リンクをコピーしました"
|
||||
"link_copied": "リンクをコピーしました",
|
||||
"title_alert": "リマインダー: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "カレンダーを読み込み中...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, other {메일 #개를 읽음으로 표시했어요}}",
|
||||
"emails_marked_unread": "{count, plural, other {메일 #개를 읽지 않음으로 표시했어요}}",
|
||||
"tag_removed": "태그를 뺐어요",
|
||||
"tag_removed_count": "{count, plural, other {메일 #개에서 태그를 뺐어요}}"
|
||||
"tag_removed_count": "{count, plural, other {메일 #개에서 태그를 뺐어요}}",
|
||||
"new_mail_count": "{count, plural, other {새 메시지 #개}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "푸시 알림을 받으려면 조직에서 운영하는 푸시 릴레이가 필요한데, 설정된 릴레이가 없어요. 앱이 열려 있는 동안에는 새 메일이 계속 표시돼요.",
|
||||
@@ -4451,7 +4452,8 @@
|
||||
"task_due": "할 일 기한이 다가와요",
|
||||
"event_exported": "이벤트 내보내기 완료",
|
||||
"title_copied": "제목이 복사되었습니다",
|
||||
"link_copied": "링크가 복사되었습니다"
|
||||
"link_copied": "링크가 복사되었습니다",
|
||||
"title_alert": "알림: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "캘린더를 불러오는 중...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, zero {# vēstules atzīmētas kā izlasītas} one {# vēstule atzīmēta kā izlasīta} other {# vēstules atzīmētas kā izlasītas}}",
|
||||
"emails_marked_unread": "{count, plural, zero {# vēstules atzīmētas kā neizlasītas} one {# vēstule atzīmēta kā neizlasīta} other {# vēstules atzīmētas kā neizlasītas}}",
|
||||
"tag_removed": "Tags noņemts",
|
||||
"tag_removed_count": "{count, plural, zero {Tags noņemts # vēstulēm} one {Tags noņemts # vēstulei} other {Tags noņemts # vēstulēm}}"
|
||||
"tag_removed_count": "{count, plural, zero {Tags noņemts # vēstulēm} one {Tags noņemts # vēstulei} other {Tags noņemts # vēstulēm}}",
|
||||
"new_mail_count": "{count, plural, zero {# jaunas vēstules} one {# jauna vēstule} other {# jaunas vēstules}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Push paziņojumiem vajadzīgs jūsu organizācijas uzturēts push relejs, un neviens nav iestatīts. Jauns pasts joprojām tiek rādīts, kamēr lietotne ir atvērta.",
|
||||
@@ -4450,7 +4451,8 @@
|
||||
"task_due": "Uzdevuma termiņš",
|
||||
"event_exported": "Notikums eksportēts",
|
||||
"title_copied": "Nosaukums nokopēts",
|
||||
"link_copied": "Saite nokopēta"
|
||||
"link_copied": "Saite nokopēta",
|
||||
"title_alert": "Atgādinājums: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Ielādē kalendārus...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, other {# имэйлийг уншсан гэж тэмдэглэлээ}}",
|
||||
"emails_marked_unread": "{count, plural, other {# имэйлийг уншаагүй гэж тэмдэглэлээ}}",
|
||||
"tag_removed": "Хаяг хасагдлаа",
|
||||
"tag_removed_count": "{count, plural, other {# имэйлээс хаяг хасагдлаа}}"
|
||||
"tag_removed_count": "{count, plural, other {# имэйлээс хаяг хасагдлаа}}",
|
||||
"new_mail_count": "{count, plural, other {# шинэ зурвас}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Push мэдэгдэлд таны байгууллагын ажиллуулдаг push буухиа хэрэгтэй, гэвч нэг ч тохируулагдаагүй байна. Апп нээлттэй байх үед шинэ имэйл харагдсаар байна.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "Даалгавар дуусах хугацаа",
|
||||
"event_exported": "Үйл явдал экспортлогдсон",
|
||||
"title_copied": "Гарчиг хуулсан",
|
||||
"link_copied": "Холбоос хуулсан"
|
||||
"link_copied": "Холбоос хуулсан",
|
||||
"title_alert": "Сануулга: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Хуанли ачаалж байна...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# e-post merket som lest} other {# e-poster merket som lest}}",
|
||||
"emails_marked_unread": "{count, plural, one {# e-post merket som ulest} other {# e-poster merket som ulest}}",
|
||||
"tag_removed": "Etikett fjernet",
|
||||
"tag_removed_count": "{count, plural, one {Etikett fjernet fra # e-post} other {Etikett fjernet fra # e-poster}}"
|
||||
"tag_removed_count": "{count, plural, one {Etikett fjernet fra # e-post} other {Etikett fjernet fra # e-poster}}",
|
||||
"new_mail_count": "{count, plural, one {# ny melding} other {# nye meldinger}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Push-varsler trenger et push-relé som organisasjonen din driver, og det er ikke satt opp noe. Ny e-post vises fortsatt mens appen er åpen.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "Oppgaven forfaller",
|
||||
"event_exported": "Hendelsen er eksportert",
|
||||
"title_copied": "Tittelen er kopiert",
|
||||
"link_copied": "Lenken er kopiert"
|
||||
"link_copied": "Lenken er kopiert",
|
||||
"title_alert": "Påminnelse: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Laster inn kalendere...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# e-mail gemarkeerd als gelezen} other {# e-mails gemarkeerd als gelezen}}",
|
||||
"emails_marked_unread": "{count, plural, one {# e-mail gemarkeerd als ongelezen} other {# e-mails gemarkeerd als ongelezen}}",
|
||||
"tag_removed": "Label verwijderd",
|
||||
"tag_removed_count": "{count, plural, one {Label verwijderd van # e-mail} other {Label verwijderd van # e-mails}}"
|
||||
"tag_removed_count": "{count, plural, one {Label verwijderd van # e-mail} other {Label verwijderd van # e-mails}}",
|
||||
"new_mail_count": "{count, plural, one {# nieuw bericht} other {# nieuwe berichten}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Pushmeldingen hebben een pushrelay van je organisatie nodig, en er is er geen ingesteld. Nieuwe e-mail wordt nog steeds getoond zolang de app open is.",
|
||||
@@ -4451,7 +4452,8 @@
|
||||
"task_due": "Taak vervalt",
|
||||
"event_exported": "Afspraak geëxporteerd",
|
||||
"title_copied": "Titel gekopieerd",
|
||||
"link_copied": "Link gekopieerd"
|
||||
"link_copied": "Link gekopieerd",
|
||||
"title_alert": "Herinnering: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Agenda's laden...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# wiadomość oznaczona jako przeczytana} few {# wiadomości oznaczone jako przeczytane} many {# wiadomości oznaczonych jako przeczytane} other {# wiadomości oznaczonych jako przeczytane}}",
|
||||
"emails_marked_unread": "{count, plural, one {# wiadomość oznaczona jako nieprzeczytana} few {# wiadomości oznaczone jako nieprzeczytane} many {# wiadomości oznaczonych jako nieprzeczytane} other {# wiadomości oznaczonych jako nieprzeczytane}}",
|
||||
"tag_removed": "Etykieta usunięta",
|
||||
"tag_removed_count": "{count, plural, one {Usunięto etykietę z # wiadomości} few {Usunięto etykietę z # wiadomości} many {Usunięto etykietę z # wiadomości} other {Usunięto etykietę z # wiadomości}}"
|
||||
"tag_removed_count": "{count, plural, one {Usunięto etykietę z # wiadomości} few {Usunięto etykietę z # wiadomości} many {Usunięto etykietę z # wiadomości} other {Usunięto etykietę z # wiadomości}}",
|
||||
"new_mail_count": "{count, plural, one {# nowa wiadomość} few {# nowe wiadomości} many {# nowych wiadomości} other {# nowych wiadomości}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Powiadomienia push wymagają przekaźnika push prowadzonego przez Twoją organizację, a żaden nie jest skonfigurowany. Nowe wiadomości nadal pojawiają się, gdy aplikacja jest otwarta.",
|
||||
@@ -4451,7 +4452,8 @@
|
||||
"task_due": "Termin zadania",
|
||||
"event_exported": "Wydarzenie wyeksportowane",
|
||||
"title_copied": "Tytuł skopiowany",
|
||||
"link_copied": "Link skopiowany"
|
||||
"link_copied": "Link skopiowany",
|
||||
"title_alert": "Przypomnienie: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Ładowanie kalendarzy...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# e-mail marcado como lido} other {# e-mails marcados como lidos}}",
|
||||
"emails_marked_unread": "{count, plural, one {# e-mail marcado como não lido} other {# e-mails marcados como não lidos}}",
|
||||
"tag_removed": "Etiqueta removida",
|
||||
"tag_removed_count": "{count, plural, one {Etiqueta removida de # e-mail} other {Etiqueta removida de # e-mails}}"
|
||||
"tag_removed_count": "{count, plural, one {Etiqueta removida de # e-mail} other {Etiqueta removida de # e-mails}}",
|
||||
"new_mail_count": "{count, plural, one {# mensagem nova} other {# mensagens novas}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "As notificações push precisam de um relay push mantido pela sua organização, e nenhum está configurado. Os novos e-mails continuam aparecendo enquanto o app estiver aberto.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "Tarefa vencendo",
|
||||
"event_exported": "Evento exportado",
|
||||
"title_copied": "Título copiado",
|
||||
"link_copied": "Link copiado"
|
||||
"link_copied": "Link copiado",
|
||||
"title_alert": "Lembrete: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Carregando calendários...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# e-mail marcat ca citit} few {# e-mailuri marcate ca citite} other {# de e-mailuri marcate ca citite}}",
|
||||
"emails_marked_unread": "{count, plural, one {# e-mail marcat ca necitit} few {# e-mailuri marcate ca necitite} other {# de e-mailuri marcate ca necitite}}",
|
||||
"tag_removed": "Etichetă eliminată",
|
||||
"tag_removed_count": "{count, plural, one {Eticheta a fost eliminată de pe # e-mail} few {Eticheta a fost eliminată de pe # e-mailuri} other {Eticheta a fost eliminată de pe # de e-mailuri}}"
|
||||
"tag_removed_count": "{count, plural, one {Eticheta a fost eliminată de pe # e-mail} few {Eticheta a fost eliminată de pe # e-mailuri} other {Eticheta a fost eliminată de pe # de e-mailuri}}",
|
||||
"new_mail_count": "{count, plural, one {# mesaj nou} few {# mesaje noi} other {# de mesaje noi}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Notificările push au nevoie de un releu push administrat de organizația dvs., iar niciunul nu este configurat. E-mailurile noi apar în continuare cât timp aplicația este deschisă.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "Termen de finalizare a sarcinii",
|
||||
"event_exported": "Eveniment exportat",
|
||||
"title_copied": "Titlu copiat",
|
||||
"link_copied": "Link copiat"
|
||||
"link_copied": "Link copiat",
|
||||
"title_alert": "Memento: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Se încarcă calendarele...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# письмо отмечено прочитанным} few {# письма отмечены прочитанными} many {# писем отмечено прочитанными} other {# письма отмечено прочитанными}}",
|
||||
"emails_marked_unread": "{count, plural, one {# письмо отмечено непрочитанным} few {# письма отмечены непрочитанными} many {# писем отмечено непрочитанными} other {# письма отмечено непрочитанными}}",
|
||||
"tag_removed": "Тег снят",
|
||||
"tag_removed_count": "{count, plural, one {Тег снят с # письма} few {Тег снят с # писем} many {Тег снят с # писем} other {Тег снят с # письма}}"
|
||||
"tag_removed_count": "{count, plural, one {Тег снят с # письма} few {Тег снят с # писем} many {Тег снят с # писем} other {Тег снят с # письма}}",
|
||||
"new_mail_count": "{count, plural, one {# новое сообщение} few {# новых сообщения} many {# новых сообщений} other {# новых сообщения}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Для push-уведомлений нужен push-релей вашей организации, а он не настроен. Новые письма по-прежнему видны, пока приложение открыто.",
|
||||
@@ -4451,7 +4452,8 @@
|
||||
"task_due": "Срок задачи",
|
||||
"event_exported": "Событие экспортировано",
|
||||
"title_copied": "Название скопировано",
|
||||
"link_copied": "Ссылка скопирована"
|
||||
"link_copied": "Ссылка скопирована",
|
||||
"title_alert": "Напоминание: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Загрузка календарей...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# e-mail označený ako prečítaný} few {# e-maily označené ako prečítané} other {# e-mailov označených ako prečítané}}",
|
||||
"emails_marked_unread": "{count, plural, one {# e-mail označený ako neprečítaný} few {# e-maily označené ako neprečítané} other {# e-mailov označených ako neprečítané}}",
|
||||
"tag_removed": "Štítok odstránený",
|
||||
"tag_removed_count": "{count, plural, one {Štítok odstránený z # e-mailu} few {Štítok odstránený z # e-mailov} other {Štítok odstránený z # e-mailov}}"
|
||||
"tag_removed_count": "{count, plural, one {Štítok odstránený z # e-mailu} few {Štítok odstránený z # e-mailov} other {Štítok odstránený z # e-mailov}}",
|
||||
"new_mail_count": "{count, plural, one {# nová správa} few {# nové správy} other {# nových správ}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Push oznámenia potrebujú push relay prevádzkovaný vašou organizáciou a žiadny nie je nastavený. Nová pošta sa naďalej zobrazuje, kým je aplikácia otvorená.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "Termín úlohy",
|
||||
"event_exported": "Udalosť exportovaná",
|
||||
"title_copied": "Názov skopírovaný",
|
||||
"link_copied": "Odkaz skopírovaný"
|
||||
"link_copied": "Odkaz skopírovaný",
|
||||
"title_alert": "Pripomienka: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Načítavanie kalendárov...",
|
||||
|
||||
@@ -525,7 +525,8 @@
|
||||
"emails_marked_read": "{count, plural, other {ทำเครื่องหมายอีเมล # ฉบับว่าอ่านแล้ว}}",
|
||||
"emails_marked_unread": "{count, plural, other {ทำเครื่องหมายอีเมล # ฉบับว่ายังไม่ได้อ่าน}}",
|
||||
"tag_removed": "นำป้ายกำกับออกแล้ว",
|
||||
"tag_removed_count": "{count, plural, other {นำป้ายกำกับออกจากอีเมล # ฉบับแล้ว}}"
|
||||
"tag_removed_count": "{count, plural, other {นำป้ายกำกับออกจากอีเมล # ฉบับแล้ว}}",
|
||||
"new_mail_count": "{count, plural, other {ข้อความใหม่ # ฉบับ}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "การแจ้งเตือนแบบพุชต้องใช้ push relay ที่องค์กรของคุณดูแล แต่ยังไม่ได้ตั้งค่าไว้ อีเมลใหม่จะยังแสดงขณะที่เปิดแอปอยู่",
|
||||
@@ -3423,7 +3424,8 @@
|
||||
"task_due": "ถึงกำหนดส่งงาน",
|
||||
"event_exported": "ส่งออกกิจกรรมแล้ว",
|
||||
"title_copied": "คัดลอกชื่อเรื่องแล้ว",
|
||||
"link_copied": "คัดลอกลิงก์แล้ว"
|
||||
"link_copied": "คัดลอกลิงก์แล้ว",
|
||||
"title_alert": "การเตือน: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "กำลังโหลดปฏิทิน...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, other {# e-posta okundu olarak işaretlendi}}",
|
||||
"emails_marked_unread": "{count, plural, other {# e-posta okunmadı olarak işaretlendi}}",
|
||||
"tag_removed": "Etiket kaldırıldı",
|
||||
"tag_removed_count": "{count, plural, other {# e-postadan etiket kaldırıldı}}"
|
||||
"tag_removed_count": "{count, plural, other {# e-postadan etiket kaldırıldı}}",
|
||||
"new_mail_count": "{count, plural, other {# yeni ileti}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Anlık bildirimler için kuruluşunuzun işlettiği bir push rölesi gerekir ve hiçbiri ayarlanmamış. Uygulama açıkken yeni postalar yine de görünür.",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "Görev süresi doldu",
|
||||
"event_exported": "Etkinlik dışa aktarıldı",
|
||||
"title_copied": "Başlık kopyalandı",
|
||||
"link_copied": "Bağlantı kopyalandı"
|
||||
"link_copied": "Bağlantı kopyalandı",
|
||||
"title_alert": "Hatırlatma: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Takvimler yükleniyor...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, one {# лист позначено прочитаним} few {# листи позначено прочитаними} many {# листів позначено прочитаними} other {# листа позначено прочитаними}}",
|
||||
"emails_marked_unread": "{count, plural, one {# лист позначено непрочитаним} few {# листи позначено непрочитаними} many {# листів позначено непрочитаними} other {# листа позначено непрочитаними}}",
|
||||
"tag_removed": "Тег знято",
|
||||
"tag_removed_count": "{count, plural, one {Тег знято з # листа} few {Тег знято з # листів} many {Тег знято з # листів} other {Тег знято з # листа}}"
|
||||
"tag_removed_count": "{count, plural, one {Тег знято з # листа} few {Тег знято з # листів} many {Тег знято з # листів} other {Тег знято з # листа}}",
|
||||
"new_mail_count": "{count, plural, one {# нове повідомлення} few {# нові повідомлення} many {# нових повідомлень} other {# нового повідомлення}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "Для push-сповіщень потрібне push-реле вашої організації, а його не налаштовано. Нові листи й далі з'являються, поки застосунок відкритий.",
|
||||
@@ -4451,7 +4452,8 @@
|
||||
"task_due": "Термін виконання завдання",
|
||||
"event_exported": "Подію експортовано",
|
||||
"title_copied": "Назву скопійовано",
|
||||
"link_copied": "Посилання скопійовано"
|
||||
"link_copied": "Посилання скопійовано",
|
||||
"title_alert": "Нагадування: {title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "Завантаження календарів...",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, other {已將 # 封郵件標示為已讀}}",
|
||||
"emails_marked_unread": "{count, plural, other {已將 # 封郵件標示為未讀}}",
|
||||
"tag_removed": "已移除標籤",
|
||||
"tag_removed_count": "{count, plural, other {已從 # 封郵件移除標籤}}"
|
||||
"tag_removed_count": "{count, plural, other {已從 # 封郵件移除標籤}}",
|
||||
"new_mail_count": "{count, plural, other {# 封新郵件}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "推送通知需要由您的組織執行的推送中繼,但尚未設定。應用程式開啟時,新郵件仍會顯示。",
|
||||
@@ -4477,7 +4478,8 @@
|
||||
"task_due": "任務到期",
|
||||
"event_exported": "活動已匯出",
|
||||
"title_copied": "標題已複製",
|
||||
"link_copied": "連結已複製"
|
||||
"link_copied": "連結已複製",
|
||||
"title_alert": "提醒:{title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "正在載入行事曆…",
|
||||
|
||||
@@ -1166,7 +1166,8 @@
|
||||
"emails_marked_read": "{count, plural, other {已将 # 封邮件标记为已读}}",
|
||||
"emails_marked_unread": "{count, plural, other {已将 # 封邮件标记为未读}}",
|
||||
"tag_removed": "已移除标签",
|
||||
"tag_removed_count": "{count, plural, other {已从 # 封邮件移除标签}}"
|
||||
"tag_removed_count": "{count, plural, other {已从 # 封邮件移除标签}}",
|
||||
"new_mail_count": "{count, plural, other {# 封新邮件}}"
|
||||
},
|
||||
"third_party": {
|
||||
"push_needs_relay": "推送通知需要由您的组织运行的推送中继,但尚未设置。应用打开时,新邮件仍会显示。",
|
||||
@@ -4451,7 +4452,8 @@
|
||||
"task_due": "任务到期",
|
||||
"event_exported": "日程已导出",
|
||||
"title_copied": "标题已复制",
|
||||
"link_copied": "链接已复制"
|
||||
"link_copied": "链接已复制",
|
||||
"title_alert": "提醒:{title}"
|
||||
},
|
||||
"status": {
|
||||
"loading_calendars": "正在加载日历...",
|
||||
|
||||
Reference in New Issue
Block a user