mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-05 00:14:18 +00:00
feat: add New event, New task, New contact, Import mail and the composer's Send, Save draft and Attach files to the desktop menus
This commit is contained in:
@@ -125,6 +125,8 @@ import { calendarShortcutAction } from "@/lib/calendar-shortcuts";
|
||||
import { isAppShortcutBlocked, isArrowKeyWidgetTarget } from "@/lib/keyboard";
|
||||
import { isContextMenuOpen } from "@/components/ui/context-menu";
|
||||
import { useRegisterCommands } from "@/lib/command-registry";
|
||||
import { useAppCommands } from "@/lib/app-commands";
|
||||
import { useDesktopCommands } from "@/lib/desktop/commands";
|
||||
import { useConfig } from "@/hooks/use-config";
|
||||
import { CalendarPrint, type CalendarPrintContent } from "@/components/calendar/calendar-print";
|
||||
import { usePrintListener, usePrinting } from "@/components/print/print-root";
|
||||
@@ -1666,6 +1668,28 @@ export function CalendarApp({ linkSegments: routeSegments }: CalendarAppProps =
|
||||
{ mode: "agenda", key: "a" },
|
||||
{ mode: "tasks", key: "k" },
|
||||
];
|
||||
// File > New event and New task in the desktop app's menus, from any app.
|
||||
useAppCommands({
|
||||
"new-event": () => openCreateModal(),
|
||||
"new-task": () => { if (enableCalendarTasks) openCreateTaskModal(); },
|
||||
}, true);
|
||||
// Its View menu's Day, Week, Month and Agenda, and Edit > Search events.
|
||||
const viewFromMenu = (mode: CalendarViewMode) => () => { setMobileReturnToMonth(false); leaveSearch(); setViewMode(mode); };
|
||||
useDesktopCommands({
|
||||
"view.calendar.day": viewFromMenu("day"),
|
||||
"view.calendar.week": viewFromMenu("week"),
|
||||
"view.calendar.month": viewFromMenu("month"),
|
||||
"view.calendar.agenda": viewFromMenu("agenda"),
|
||||
"edit.search": openSearch,
|
||||
}, {
|
||||
"view.calendar.day": { enabled: true, checked: normalizedViewMode === "day" },
|
||||
"view.calendar.week": { enabled: true, checked: normalizedViewMode === "week" },
|
||||
"view.calendar.month": { enabled: true, checked: normalizedViewMode === "month" },
|
||||
"view.calendar.agenda": { enabled: true, checked: normalizedViewMode === "agenda" },
|
||||
"edit.search": normalizedViewMode !== "tasks",
|
||||
"file.newTask": enableCalendarTasks,
|
||||
});
|
||||
|
||||
useRegisterCommands(tSidebar("calendar"), [
|
||||
{ id: "new-event", label: t("events.new_event"), icon: Plus, shortcut: "n", run: () => openCreateModal() },
|
||||
{ id: "new-task", label: t("events.new_task"), icon: ListTodo, run: openCreateTaskModal, when: () => enableCalendarTasks },
|
||||
|
||||
@@ -60,6 +60,7 @@ import { useDocumentTitle } from "@/hooks/use-document-title";
|
||||
import { ContactsSkeleton, ContactsSkeletonBody } from "@/components/boot-skeleton/contacts-skeleton";
|
||||
import { useSkeletonLabels } from "@/components/boot-skeleton/use-skeleton-labels";
|
||||
import { useRegisterCommands } from "@/lib/command-registry";
|
||||
import { useAppCommands } from "@/lib/app-commands";
|
||||
import { useCloseOnBack } from "@/hooks/use-close-on-back";
|
||||
import { useLeaveGuard } from "@/lib/leave-guard";
|
||||
import { useDeleteCategory } from "@/hooks/use-delete-category";
|
||||
@@ -968,6 +969,9 @@ function ContactsAppContent({ linkSegments: routeSegments }: ContactsAppProps =
|
||||
}
|
||||
};
|
||||
|
||||
// File > New contact in the desktop app's menus, from any app.
|
||||
useAppCommands({ "new-contact": () => guard(handleCreateNew)() }, contactsEnabled);
|
||||
|
||||
// The command palette's Contacts group (Ctrl/⌘+K).
|
||||
useRegisterCommands(tSidebar("contacts"), [
|
||||
{ id: "new-contact", label: t("create_new"), icon: UserPlus, run: () => guard(handleCreateNew)() },
|
||||
|
||||
@@ -12,7 +12,8 @@ import { useOfflineStore } from '@/lib/offline/state';
|
||||
import { offerReturnedComposer, takeReturnedComposer } from '@/lib/popout/return-to-main';
|
||||
|
||||
const push = vi.fn();
|
||||
vi.mock('@/i18n/navigation', () => ({ useRouter: () => ({ push }) }));
|
||||
const route = vi.hoisted(() => ({ pathname: '/' }));
|
||||
vi.mock('@/i18n/navigation', () => ({ useRouter: () => ({ push }), usePathname: () => route.pathname }));
|
||||
|
||||
// The catalog on screen: its language, and text that says which one it came from.
|
||||
const intl = vi.hoisted(() => ({ locale: 'en', prefix: '', messages: {} as object }));
|
||||
@@ -76,6 +77,7 @@ function fakeBridge() {
|
||||
const original = useAuthStore.getState();
|
||||
|
||||
beforeEach(() => {
|
||||
route.pathname = '/';
|
||||
Object.assign(intl, { locale: 'en', prefix: '', messages: {} });
|
||||
push.mockClear();
|
||||
resolveExternalLink.mockClear();
|
||||
@@ -106,6 +108,33 @@ describe('DesktopHost', () => {
|
||||
expect(() => render(<DesktopHost />)).not.toThrow();
|
||||
});
|
||||
|
||||
it('File > New event, task and contact open that app with its editor; Settings opens in this window', async () => {
|
||||
const { peekParkedAppCommand } = await import('@/lib/app-commands');
|
||||
const shell = fakeBridge();
|
||||
render(<DesktopHost />);
|
||||
shell.run('file.newEvent');
|
||||
expect(push).toHaveBeenLastCalledWith('/calendar');
|
||||
expect(peekParkedAppCommand()).toBe('new-event');
|
||||
shell.run('file.newTask');
|
||||
expect(push).toHaveBeenLastCalledWith('/calendar');
|
||||
expect(peekParkedAppCommand()).toBe('new-task');
|
||||
shell.run('file.newContact');
|
||||
expect(push).toHaveBeenLastCalledWith('/contacts');
|
||||
expect(peekParkedAppCommand()).toBe('new-contact');
|
||||
shell.run('file.settings');
|
||||
expect(push).toHaveBeenLastCalledWith('/settings');
|
||||
});
|
||||
|
||||
it('tells the menus which part of the app is on screen, and offers the New lines once signed in', async () => {
|
||||
route.pathname = '/calendar';
|
||||
const shell = fakeBridge();
|
||||
render(<DesktopHost />);
|
||||
await waitFor(() => expect(shell.setState).toHaveBeenCalled());
|
||||
const state = shell.setState.mock.lastCall![0];
|
||||
expect(state).toMatchObject({ 'section.calendar': true, 'file.newEvent': true, 'file.newContact': true, 'file.settings': true, 'file.import': true });
|
||||
expect(state['section.mail']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('runs a command from what\'s on the page first', () => {
|
||||
const shell = fakeBridge();
|
||||
render(<DesktopHost />);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useLocale, useMessages, useTranslations } from "next-intl";
|
||||
import { useStrictestDevices } from "@/hooks/use-device-policy";
|
||||
import { useRouter } from "@/i18n/navigation";
|
||||
import { usePathname, useRouter } from "@/i18n/navigation";
|
||||
import { openKeyboardShortcuts, parkAppCommand, requestAppCommand, type AppCommand } from "@/lib/app-commands";
|
||||
import { onComposerOpened, composerIsOpen } from "@/lib/compose-flush-registry";
|
||||
import { getDesktopBridge } from "@/lib/desktop/bridge";
|
||||
@@ -26,6 +26,14 @@ import { useLocaleStore } from "@/stores/locale-store";
|
||||
import { useSettingsStore } from "@/stores/settings-store";
|
||||
import { useThemeStore } from "@/stores/theme-store";
|
||||
import { toast } from "@/stores/toast-store";
|
||||
import { openMailImport } from "@/stores/mail-transfer-store";
|
||||
|
||||
/** The part of the app a path shows, for the menus: Calendar has its own View lines, and no Message menu. */
|
||||
export function desktopSectionOf(pathname: string): "mail" | "calendar" | "contacts" | "files" | "settings" {
|
||||
const first = pathname.split("/").filter(Boolean)[0] ?? "";
|
||||
if (first === "calendar" || first === "contacts" || first === "files" || first === "settings") return first;
|
||||
return "mail";
|
||||
}
|
||||
|
||||
/**
|
||||
* The webmail's side of what every desktop window needs: runs menu commands nothing
|
||||
@@ -35,6 +43,7 @@ import { toast } from "@/stores/toast-store";
|
||||
*/
|
||||
export function DesktopHost() {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const routerRef = useRef(router);
|
||||
routerRef.current = router;
|
||||
const t = useTranslations();
|
||||
@@ -68,6 +77,25 @@ export function DesktopHost() {
|
||||
else toMail("compose");
|
||||
},
|
||||
"edit.search": () => toMail("search"),
|
||||
// The other apps' New items, run once that app is on screen.
|
||||
"file.newEvent": () => {
|
||||
if (requestAppCommand("new-event")) return;
|
||||
parkAppCommand("new-event");
|
||||
routerRef.current.push("/calendar");
|
||||
},
|
||||
"file.newTask": () => {
|
||||
if (requestAppCommand("new-task")) return;
|
||||
parkAppCommand("new-task");
|
||||
routerRef.current.push("/calendar");
|
||||
},
|
||||
"file.newContact": () => {
|
||||
if (requestAppCommand("new-contact")) return;
|
||||
parkAppCommand("new-contact");
|
||||
routerRef.current.push("/contacts");
|
||||
},
|
||||
"file.import": () => openMailImport(),
|
||||
// One way to Settings: in the main window, as the rail's button opens them.
|
||||
"file.settings": () => routerRef.current.push("/settings"),
|
||||
"go.inbox": () => routerRef.current.push("/"),
|
||||
"go.mail": () => routerRef.current.push("/"),
|
||||
"go.calendar": () => routerRef.current.push("/calendar"),
|
||||
@@ -101,6 +129,7 @@ export function DesktopHost() {
|
||||
const canPrint = canPrintAnywhere();
|
||||
const signedIn = isAuthenticated;
|
||||
const popout = isPopoutWindow();
|
||||
const section = desktopSectionOf(pathname ?? "/");
|
||||
setDesktopBaseState({
|
||||
"link.check": true,
|
||||
"shortcuts.singleKeys": singleKeys,
|
||||
@@ -108,6 +137,12 @@ export function DesktopHost() {
|
||||
"file.print": canPrint,
|
||||
"file.savePdf": canPrint,
|
||||
"file.newMessage": signedIn,
|
||||
"file.newEvent": signedIn,
|
||||
"file.newTask": signedIn,
|
||||
"file.newContact": signedIn,
|
||||
"file.import": signedIn && !popout,
|
||||
"file.settings": signedIn,
|
||||
[`section.${section}`]: true,
|
||||
"edit.search": signedIn && !popout,
|
||||
"go.inbox": signedIn,
|
||||
"go.mail": signedIn,
|
||||
@@ -116,7 +151,7 @@ export function DesktopHost() {
|
||||
"go.files": signedIn,
|
||||
"help.shortcuts": true,
|
||||
});
|
||||
}, [isAuthenticated, singleKeys, strictest]);
|
||||
}, [isAuthenticated, singleKeys, strictest, pathname]);
|
||||
|
||||
// Menus, the tray and spellcheck follow the interface: the language its text is in now,
|
||||
// with that text. The stored choice isn't it: on the first render the catalog can still
|
||||
|
||||
@@ -175,6 +175,7 @@ import { usePolicyStore } from "@/stores/policy-store";
|
||||
import { isAppLockedNow } from "@/lib/app-lock/state";
|
||||
import { registerComposeFlush, registerComposeSnapshot } from "@/lib/compose-flush-registry";
|
||||
import { getDesktopBridge } from "@/lib/desktop/bridge";
|
||||
import { useDesktopCommands } from "@/lib/desktop/commands";
|
||||
import { noteComposerLanguage } from "@/lib/desktop/languages";
|
||||
import { noteOpenDraft } from "@/lib/desktop/window-restore";
|
||||
import type { RescuedDraft } from "@/lib/popout/channel";
|
||||
@@ -4694,6 +4695,18 @@ export function EmailComposer({
|
||||
}
|
||||
};
|
||||
|
||||
// The desktop app's Message menu while this composer is open: the same handlers as
|
||||
// its buttons and keys (lib/desktop/commands.ts). Nothing in a browser.
|
||||
useDesktopCommands({
|
||||
'compose.send': () => { if (!isSavingAndClosing) void handleSend(); },
|
||||
'compose.saveDraft': () => { void saveDraft({ announce: true }); },
|
||||
'compose.attach': () => fileInputRef.current?.click(),
|
||||
}, {
|
||||
'compose.send': !!canSend && !isSending && !isSavingAndClosing,
|
||||
'compose.saveDraft': !isSavingAndClosing,
|
||||
'compose.attach': !isSavingAndClosing,
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={setComposerRootEl}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
export type AppCommand = 'compose' | 'search' | 'all-inboxes' | 'show-list' | 'tour-end';
|
||||
export type AppCommand = 'compose' | 'search' | 'all-inboxes' | 'show-list' | 'tour-end' | 'new-event' | 'new-task' | 'new-contact';
|
||||
|
||||
export const COMMAND_PALETTE_OPEN_EVENT = 'bulwark:command-palette';
|
||||
|
||||
|
||||
@@ -120,6 +120,18 @@ export function shellLabels(t: (key: string, values?: Record<string, string>) =>
|
||||
menuGoCalendar: t('sidebar.calendar'),
|
||||
menuGoContacts: t('sidebar.contacts'),
|
||||
menuGoFiles: t('desktopUi.menu.files'),
|
||||
menuNewEvent: t('calendar.events.new_event'),
|
||||
menuNewTask: t('calendar.events.new_task'),
|
||||
menuNewContact: t('contacts.create_new'),
|
||||
menuImport: t('mail_import.menu_import'),
|
||||
menuSearchEvents: t('calendar.search.title'),
|
||||
menuDay: t('calendar.views.day'),
|
||||
menuWeek: t('calendar.views.week'),
|
||||
menuMonth: t('calendar.views.month'),
|
||||
menuAgenda: t('calendar.views.agenda'),
|
||||
menuSend: t('email_composer.send'),
|
||||
menuSaveDraft: t('desktopMenus.save_draft'),
|
||||
menuAttach: t('desktopMenus.attach_files'),
|
||||
menuGoBack: t('desktopUi.menu.back'),
|
||||
menuGoForward: t('desktopUi.menu.forward'),
|
||||
menuMinimize: t('desktopUi.menu.minimize'),
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "إنهاء Bulwark",
|
||||
"tray_exit": "الخروج من Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "حفظ المسودة",
|
||||
"attach_files": "إرفاق ملفات…",
|
||||
"shortcut_apps": "الانتقال إلى البريد أو التقويم أو جهات الاتصال أو الملفات"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "قفل التطبيق",
|
||||
"section_desc": "يطلب رمز PIN بعد فترة دون استخدام، في كل نافذة وعلامة تبويب. أثناء القفل يبقى البريد على هذا الجهاز مشفرًا ولا يملك التطبيق مفتاحه.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Surt de Bulwark",
|
||||
"tray_exit": "Surt de Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Desa l'esborrany",
|
||||
"attach_files": "Adjunta fitxers…",
|
||||
"shortcut_apps": "Ves a Correu, Calendari, Contactes o Fitxers"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Bloqueig de l'app",
|
||||
"section_desc": "Demana un PIN després d'un temps sense ús, a cada finestra i pestanya. Mentre està bloquejada, el correu d'aquest dispositiu continua xifrat i l'app no en té la clau.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Ukončit Bulwark",
|
||||
"tray_exit": "Ukončit Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Uložit koncept",
|
||||
"attach_files": "Přiložit soubory…",
|
||||
"shortcut_apps": "Přejít na Poštu, Kalendář, Kontakty nebo Soubory"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Zámek aplikace",
|
||||
"section_desc": "Po čase bez použití žádá o PIN, v každém okně a na každé kartě. Dokud je zamčeno, zůstává pošta na tomto zařízení zašifrovaná a aplikace k ní nemá klíč.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Afslut Bulwark",
|
||||
"tray_exit": "Afslut Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Gem kladde",
|
||||
"attach_files": "Vedhæft filer…",
|
||||
"shortcut_apps": "Gå til Mail, Kalender, Kontakter eller Filer"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Applås",
|
||||
"section_desc": "Beder om en pinkode efter en tid uden brug, i alle vinduer og faner. Mens den er låst, forbliver mail på denne enhed krypteret, og appen har ingen nøgle til den.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Bulwark beenden",
|
||||
"tray_exit": "Bulwark beenden"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Entwurf speichern",
|
||||
"attach_files": "Dateien anhängen…",
|
||||
"shortcut_apps": "Zu E-Mail, Kalender, Kontakten oder Dateien wechseln"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "App-Sperre",
|
||||
"section_desc": "Fragt nach einer Zeit ohne Nutzung in jedem Fenster und Tab nach einer PIN. Solange gesperrt ist, bleiben E-Mails auf diesem Gerät verschlüsselt und die App hat keinen Schlüssel dafür.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Quit Bulwark",
|
||||
"tray_exit": "Exit Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Save draft",
|
||||
"attach_files": "Attach files…",
|
||||
"shortcut_apps": "Go to Mail, Calendar, Contacts or Files"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "App lock",
|
||||
"section_desc": "Asks for a PIN after a time without use, in every window and tab. While it's locked, mail on this device stays encrypted and the app has no key for it.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Salir de Bulwark",
|
||||
"tray_exit": "Salir de Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Guardar borrador",
|
||||
"attach_files": "Adjuntar archivos…",
|
||||
"shortcut_apps": "Ir a Correo, Calendario, Contactos o Archivos"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Bloqueo de la app",
|
||||
"section_desc": "Pide un PIN tras un tiempo sin uso, en cada ventana y pestaña. Mientras está bloqueada, el correo de este dispositivo sigue cifrado y la app no tiene la clave.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Sulge Bulwark",
|
||||
"tray_exit": "Välju Bulwarkist"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Salvesta mustand",
|
||||
"attach_files": "Lisa failid…",
|
||||
"shortcut_apps": "Mine e-posti, kalendrisse, kontaktidesse või failidesse"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Rakenduse lukk",
|
||||
"section_desc": "Küsib pärast kasutamata aega PIN-koodi, igas aknas ja vahekaardil. Lukus olles jääb selle seadme e-post krüpteerituks ja rakendusel pole selle võtit.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "بستن Bulwark",
|
||||
"tray_exit": "خروج از Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "ذخیره پیشنویس",
|
||||
"attach_files": "پیوست فایلها…",
|
||||
"shortcut_apps": "رفتن به ایمیل، تقویم، مخاطبان یا فایلها"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "قفل برنامه",
|
||||
"section_desc": "پس از مدتی بیاستفاده، در هر پنجره و زبانه پین میخواهد. تا وقتی قفل است، ایمیلهای این دستگاه رمزگذاریشده میمانند و برنامه کلید آنها را ندارد.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Quitter Bulwark",
|
||||
"tray_exit": "Quitter Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Enregistrer le brouillon",
|
||||
"attach_files": "Joindre des fichiers…",
|
||||
"shortcut_apps": "Aller à Mail, Calendrier, Contacts ou Fichiers"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Verrouillage de l'app",
|
||||
"section_desc": "Demande un code PIN après un temps sans utilisation, dans chaque fenêtre et onglet. Tant que l'app est verrouillée, les e-mails sur cet appareil restent chiffrés et l'app n'a pas de clé pour les lire.",
|
||||
|
||||
@@ -6843,6 +6843,11 @@
|
||||
"tray_quit": "סגירת Bulwark",
|
||||
"tray_exit": "יציאה מ-Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "שמירת טיוטה",
|
||||
"attach_files": "צירוף קבצים…",
|
||||
"shortcut_apps": "מעבר לדואר, ליומן, לאנשי הקשר או לקבצים"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "נעילת אפליקציה",
|
||||
"section_desc": "מבקשת קוד PIN אחרי זמן ללא שימוש, בכל חלון וכרטיסייה. בזמן הנעילה הדואר במכשיר הזה נשאר מוצפן ולאפליקציה אין מפתח אליו.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Kilépés a Bulwarkból",
|
||||
"tray_exit": "Kilépés a Bulwarkból"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Piszkozat mentése",
|
||||
"attach_files": "Fájlok csatolása…",
|
||||
"shortcut_apps": "Ugrás a Levelekre, a Naptárra, a Névjegyekre vagy a Fájlokra"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Alkalmazászár",
|
||||
"section_desc": "Használat nélküli idő után PIN-kódot kér, minden ablakban és lapon. Amíg zárolva van, az eszközön lévő levelek titkosítva maradnak, és az alkalmazásnak nincs hozzájuk kulcsa.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Esci da Bulwark",
|
||||
"tray_exit": "Esci da Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Salva bozza",
|
||||
"attach_files": "Allega file…",
|
||||
"shortcut_apps": "Vai a Posta, Calendario, Contatti o File"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Blocco dell'app",
|
||||
"section_desc": "Chiede un PIN dopo un periodo senza utilizzo, in ogni finestra e scheda. Finché è bloccata, la posta su questo dispositivo resta cifrata e l'app non ha la chiave.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Bulwark を終了",
|
||||
"tray_exit": "Bulwark を終了"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "下書きを保存",
|
||||
"attach_files": "ファイルを添付…",
|
||||
"shortcut_apps": "メール、カレンダー、連絡先、ファイルに移動"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "アプリのロック",
|
||||
"section_desc": "一定時間使わないと、すべてのウィンドウとタブで PIN を求めます。ロック中、このデバイスのメールは暗号化されたままで、アプリには鍵がありません。",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Bulwark 종료",
|
||||
"tray_exit": "Bulwark 종료"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "임시 저장",
|
||||
"attach_files": "파일 첨부…",
|
||||
"shortcut_apps": "메일, 캘린더, 연락처, 파일로 이동"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "앱 잠금",
|
||||
"section_desc": "일정 시간 사용하지 않으면 모든 창과 탭에서 PIN을 요청합니다. 잠겨 있는 동안 이 기기의 메일은 암호화된 상태로 유지되며 앱에는 키가 없습니다.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Aizvērt Bulwark",
|
||||
"tray_exit": "Iziet no Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Saglabāt melnrakstu",
|
||||
"attach_files": "Pievienot failus…",
|
||||
"shortcut_apps": "Pāriet uz pastu, kalendāru, kontaktiem vai failiem"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Lietotnes bloķēšana",
|
||||
"section_desc": "Pēc laika bez lietošanas prasa PIN kodu katrā logā un cilnē. Kamēr lietotne ir bloķēta, e-pasts šajā ierīcē paliek šifrēts, un lietotnei nav tā atslēgas.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Bulwark-г хаах",
|
||||
"tray_exit": "Bulwark-аас гарах"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Ноорог хадгалах",
|
||||
"attach_files": "Файл хавсаргах…",
|
||||
"shortcut_apps": "Шуудан, Хуанли, Харилцагчид эсвэл Файлууд руу очих"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Аппын түгжээ",
|
||||
"section_desc": "Хэсэг хугацаанд ашиглаагүй бол цонх, таб бүрт ПИН код асууна. Түгжээтэй үед энэ төхөөрөмжийн имэйл шифрлэгдсэн хэвээр байх бөгөөд аппад түлхүүр нь байхгүй.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Avslutt Bulwark",
|
||||
"tray_exit": "Avslutt Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Lagre utkast",
|
||||
"attach_files": "Legg ved filer…",
|
||||
"shortcut_apps": "Gå til E-post, Kalender, Kontakter eller Filer"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Applås",
|
||||
"section_desc": "Ber om en PIN-kode etter en tid uten bruk, i alle vinduer og faner. Mens den er låst, forblir e-post på denne enheten kryptert, og appen har ingen nøkkel til den.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Bulwark afsluiten",
|
||||
"tray_exit": "Bulwark afsluiten"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Concept opslaan",
|
||||
"attach_files": "Bestanden bijvoegen…",
|
||||
"shortcut_apps": "Naar E-mail, Agenda, Contacten of Bestanden"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "App-vergrendeling",
|
||||
"section_desc": "Vraagt na een tijd zonder gebruik om een pincode, in elk venster en tabblad. Zolang de app vergrendeld is, blijft de mail op dit apparaat versleuteld en heeft de app er geen sleutel voor.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Zakończ Bulwark",
|
||||
"tray_exit": "Zakończ Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Zapisz wersję roboczą",
|
||||
"attach_files": "Załącz pliki…",
|
||||
"shortcut_apps": "Przejdź do Poczty, Kalendarza, Kontaktów lub Plików"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Blokada aplikacji",
|
||||
"section_desc": "Prosi o PIN po czasie bezczynności, w każdym oknie i na każdej karcie. Gdy aplikacja jest zablokowana, poczta na tym urządzeniu pozostaje zaszyfrowana, a aplikacja nie ma do niej klucza.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Sair do Bulwark",
|
||||
"tray_exit": "Sair do Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Salvar rascunho",
|
||||
"attach_files": "Anexar arquivos…",
|
||||
"shortcut_apps": "Ir para E-mail, Calendário, Contatos ou Arquivos"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Bloqueio da app",
|
||||
"section_desc": "Pede um PIN após um tempo sem uso, em todas as janelas e separadores. Enquanto está bloqueada, o correio neste dispositivo fica cifrado e a app não tem a chave.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Închide Bulwark",
|
||||
"tray_exit": "Ieșire din Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Salvează ciorna",
|
||||
"attach_files": "Atașează fișiere…",
|
||||
"shortcut_apps": "Mergi la E-mail, Calendar, Contacte sau Fișiere"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Blocarea aplicației",
|
||||
"section_desc": "Cere un PIN după un timp fără utilizare, în fiecare fereastră și filă. Cât timp e blocată, e-mailurile de pe acest dispozitiv rămân criptate și aplicația nu are cheia lor.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Закрыть Bulwark",
|
||||
"tray_exit": "Выйти из Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Сохранить черновик",
|
||||
"attach_files": "Прикрепить файлы…",
|
||||
"shortcut_apps": "Перейти в Почту, Календарь, Контакты или Файлы"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Блокировка приложения",
|
||||
"section_desc": "Запрашивает PIN-код после периода бездействия, в каждом окне и вкладке. Пока приложение заблокировано, почта на этом устройстве остаётся зашифрованной, и у приложения нет ключа к ней.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Ukončiť Bulwark",
|
||||
"tray_exit": "Ukončiť Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Uložiť koncept",
|
||||
"attach_files": "Priložiť súbory…",
|
||||
"shortcut_apps": "Prejsť na Poštu, Kalendár, Kontakty alebo Súbory"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Zámok aplikácie",
|
||||
"section_desc": "Po čase bez používania žiada o PIN, v každom okne a na každej karte. Kým je zamknuté, pošta na tomto zariadení zostáva šifrovaná a aplikácia k nej nemá kľúč.",
|
||||
|
||||
@@ -6850,6 +6850,11 @@
|
||||
"tray_quit": "ปิด Bulwark",
|
||||
"tray_exit": "ออกจาก Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "บันทึกฉบับร่าง",
|
||||
"attach_files": "แนบไฟล์…",
|
||||
"shortcut_apps": "ไปที่อีเมล ปฏิทิน รายชื่อติดต่อ หรือไฟล์"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "ล็อกแอป",
|
||||
"section_desc": "ขอ PIN หลังจากไม่ได้ใช้งานระยะหนึ่ง ในทุกหน้าต่างและแท็บ ระหว่างล็อก อีเมลบนอุปกรณ์นี้ยังคงเข้ารหัสอยู่และแอปไม่มีกุญแจ",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Bulwark'tan çık",
|
||||
"tray_exit": "Bulwark'tan çık"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Taslağı kaydet",
|
||||
"attach_files": "Dosya ekle…",
|
||||
"shortcut_apps": "Posta, Takvim, Kişiler veya Dosyalar'a git"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Uygulama kilidi",
|
||||
"section_desc": "Bir süre kullanılmadığında her pencerede ve sekmede PIN ister. Kilitliyken bu cihazdaki e-postalar şifreli kalır ve uygulamada anahtarı olmaz.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "Закрити Bulwark",
|
||||
"tray_exit": "Вийти з Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Зберегти чернетку",
|
||||
"attach_files": "Прикріпити файли…",
|
||||
"shortcut_apps": "Перейти до Пошти, Календаря, Контактів або Файлів"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Блокування застосунку",
|
||||
"section_desc": "Запитує PIN-код після часу без використання, у кожному вікні й вкладці. Поки застосунок заблоковано, пошта на цьому пристрої залишається зашифрованою, і застосунок не має ключа до неї.",
|
||||
|
||||
@@ -6854,6 +6854,11 @@
|
||||
"tray_quit": "Thoát Bulwark",
|
||||
"tray_exit": "Thoát Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "Lưu bản nháp",
|
||||
"attach_files": "Đính kèm tệp…",
|
||||
"shortcut_apps": "Đi tới Thư, Lịch, Danh bạ hoặc Tệp"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "Khóa ứng dụng",
|
||||
"section_desc": "Yêu cầu mã PIN sau một thời gian không dùng, trong mọi cửa sổ và thẻ. Khi đang khóa, thư trên thiết bị này vẫn được mã hóa và ứng dụng không có khóa của chúng.",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "結束 Bulwark",
|
||||
"tray_exit": "結束 Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "儲存草稿",
|
||||
"attach_files": "附加檔案…",
|
||||
"shortcut_apps": "前往郵件、行事曆、聯絡人或檔案"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "應用程式鎖定",
|
||||
"section_desc": "一段時間未使用後,在每個視窗和分頁中要求輸入 PIN。鎖定期間,此裝置上的郵件保持加密,應用程式沒有金鑰。",
|
||||
|
||||
@@ -6842,6 +6842,11 @@
|
||||
"tray_quit": "退出 Bulwark",
|
||||
"tray_exit": "退出 Bulwark"
|
||||
},
|
||||
"desktopMenus": {
|
||||
"save_draft": "保存草稿",
|
||||
"attach_files": "附加文件…",
|
||||
"shortcut_apps": "转到邮件、日历、联系人或文件"
|
||||
},
|
||||
"appLock": {
|
||||
"section_title": "应用锁",
|
||||
"section_desc": "一段时间未使用后,在每个窗口和标签页中要求输入 PIN。锁定期间,此设备上的邮件保持加密,应用没有密钥。",
|
||||
|
||||
Reference in New Issue
Block a user