mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
refactor: combine sidebar apps and plugins into add-ons, about and debug into backup and reset
This commit is contained in:
@@ -13,6 +13,7 @@ import { cn } from '@/lib/utils';
|
||||
import { getPathPrefix, withBasePath } from '@/lib/browser-navigation';
|
||||
import { clearCachedData } from '@/lib/clear-cached-data';
|
||||
import { SpamSiegeGame } from './spam-siege-game';
|
||||
import { DebugSettings } from './debug-settings';
|
||||
|
||||
const APP_VERSION = process.env.NEXT_PUBLIC_APP_VERSION || "0.0.0";
|
||||
const GIT_COMMIT = process.env.NEXT_PUBLIC_GIT_COMMIT || "unknown";
|
||||
@@ -49,24 +50,20 @@ function VersionUpdateTag() {
|
||||
);
|
||||
}
|
||||
|
||||
export function AboutDataSettings() {
|
||||
/**
|
||||
* The About card, in the settings sidebar's footer: logo, version with the
|
||||
* update tag, and the source link. A modified build must offer its own
|
||||
* source (AGPL-3.0 §13), so a configured URL replaces the upstream link.
|
||||
* Three clicks on the logo open Spam Siege, as before.
|
||||
*/
|
||||
export function AboutFooter() {
|
||||
const t = useTranslations('settings.advanced');
|
||||
const tCommon = useTranslations('common');
|
||||
const tSettings = useTranslations('settings');
|
||||
const { settingsSyncDisabled, updateSetting, resetToDefaults, exportSettings, importSettings } =
|
||||
useSettingsStore();
|
||||
// A modified build must offer its own source (AGPL-3.0 §13), so a
|
||||
// configured URL replaces the upstream repository link.
|
||||
const { settingsSyncEnabled, sourceCodeUrl, appName, appLogoLightUrl, appLogoDarkUrl } = useConfig();
|
||||
const { sourceCodeUrl, appName, appLogoLightUrl, appLogoDarkUrl } = useConfig();
|
||||
// A branded deployment (APP_NAME / APP_LOGO_*) shows its own name and logo
|
||||
// here; without them the card keeps the Bulwark mark and title. (#1160)
|
||||
const branded = appName && appName !== 'Webmail';
|
||||
const logoLight = withBasePath(appLogoLightUrl || appLogoDarkUrl) || `${getPathPrefix()}/branding/Bulwark_Logo_Color.svg`;
|
||||
const logoDark = withBasePath(appLogoDarkUrl || appLogoLightUrl) || `${getPathPrefix()}/branding/Bulwark_Logo_White.svg`;
|
||||
const [showResetConfirm, setShowResetConfirm] = useState(false);
|
||||
const [showRefreshConfirm, setShowRefreshConfirm] = useState(false);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const { isFeatureEnabled } = usePolicyStore();
|
||||
const [showGame, setShowGame] = useState(false);
|
||||
const logoClickCount = useRef(0);
|
||||
const logoClickTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
@@ -82,6 +79,58 @@ export function AboutDataSettings() {
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div data-testid="settings-about" className="px-3 py-2">
|
||||
{showGame && <SpamSiegeGame onClose={() => setShowGame(false)} />}
|
||||
<div className="flex items-center gap-3">
|
||||
<button onClick={handleLogoClick} className="flex items-center gap-3 flex-1 min-w-0 text-start focus:outline-none group/about cursor-pointer" aria-label="About">
|
||||
<img
|
||||
src={logoLight}
|
||||
alt={branded ? appName : 'Bulwark'}
|
||||
className="w-7 h-7 shrink-0 object-contain dark:hidden group-active/about:scale-95 transition-transform"
|
||||
/>
|
||||
<img
|
||||
src={logoDark}
|
||||
alt={branded ? appName : 'Bulwark'}
|
||||
className="w-7 h-7 shrink-0 object-contain hidden dark:block group-active/about:scale-95 transition-transform"
|
||||
/>
|
||||
<div className="min-w-0">
|
||||
<p className="text-xs font-medium text-foreground truncate">{branded ? appName : t('about.title')}</p>
|
||||
<p className="text-[11px] text-muted-foreground truncate">
|
||||
v{APP_VERSION} <span className="text-muted-foreground/60">({GIT_COMMIT})</span>
|
||||
<VersionUpdateTag />
|
||||
</p>
|
||||
</div>
|
||||
</button>
|
||||
<a
|
||||
href={sourceCodeUrl || UPSTREAM_SOURCE_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="shrink-0 inline-flex items-center gap-1 text-[11px] text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
{sourceCodeUrl ? t('about.source_code') : 'GitHub'} <ExternalLink className="w-3 h-3" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Backup & reset page: keep settings (sync, export, import), fix a stale
|
||||
* view, start over, and (Advanced, where the admin allows it) debug logging.
|
||||
* The About card moved to the settings sidebar's footer.
|
||||
*/
|
||||
export function AboutDataSettings() {
|
||||
const t = useTranslations('settings.advanced');
|
||||
const tCommon = useTranslations('common');
|
||||
const tSettings = useTranslations('settings');
|
||||
const { settingsSyncDisabled, updateSetting, resetToDefaults, exportSettings, importSettings } =
|
||||
useSettingsStore();
|
||||
const { settingsSyncEnabled } = useConfig();
|
||||
const [showResetConfirm, setShowResetConfirm] = useState(false);
|
||||
const [showRefreshConfirm, setShowRefreshConfirm] = useState(false);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const { isFeatureEnabled } = usePolicyStore();
|
||||
const handleExport = () => {
|
||||
const settingsJson = exportSettings();
|
||||
const blob = new Blob([settingsJson], { type: 'application/json' });
|
||||
@@ -137,45 +186,8 @@ export function AboutDataSettings() {
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{showGame && <SpamSiegeGame onClose={() => setShowGame(false)} />}
|
||||
<div className="rounded-lg border border-border bg-card p-5 mb-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<button onClick={handleLogoClick} className="flex items-center gap-4 flex-1 text-start focus:outline-none group/about cursor-pointer" aria-label="About">
|
||||
<div className="shrink-0">
|
||||
<img
|
||||
src={logoLight}
|
||||
alt={branded ? appName : 'Bulwark'}
|
||||
className="w-12 h-12 object-contain dark:hidden group-hover/about:scale-105 group-active/about:scale-95 transition-transform"
|
||||
/>
|
||||
<img
|
||||
src={logoDark}
|
||||
alt={branded ? appName : 'Bulwark'}
|
||||
className="w-12 h-12 object-contain hidden dark:block group-hover/about:scale-105 group-active/about:scale-95 transition-transform"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-foreground">
|
||||
{branded ? appName : t('about.title')}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground group-hover/about:translate-x-0.5 group-active/about:translate-y-px transition-transform">
|
||||
v{APP_VERSION} <span className="text-muted-foreground/60">({GIT_COMMIT})</span>
|
||||
<VersionUpdateTag />
|
||||
</p>
|
||||
</div>
|
||||
</button>
|
||||
<a
|
||||
href={sourceCodeUrl || UPSTREAM_SOURCE_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
{sourceCodeUrl ? t('about.source_code') : 'GitHub'} <ExternalLink className="w-3 h-3" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SettingsSection title={t('title')} description={t('description')}>
|
||||
<div className="space-y-8">
|
||||
<SettingsSection id="backup" title={t('sections.backup')} description={t('sections.backup_description')}>
|
||||
{settingsSyncEnabled && (
|
||||
<SettingItem label={t('settings_sync.label')} description={t('settings_sync.description')}>
|
||||
<ToggleSwitch checked={!settingsSyncDisabled} onChange={(checked) => updateSetting('settingsSyncDisabled', !checked)} />
|
||||
@@ -206,7 +218,9 @@ export function AboutDataSettings() {
|
||||
</>
|
||||
</SettingItem>
|
||||
)}
|
||||
</SettingsSection>
|
||||
|
||||
<SettingsSection id="fix" title={t('sections.fix')} description={t('sections.fix_description')}>
|
||||
<SettingItem label={t('refresh_cache.label')} description={t('refresh_cache.description')}>
|
||||
<Button
|
||||
variant={showRefreshConfirm ? 'default' : 'outline'}
|
||||
@@ -227,6 +241,8 @@ export function AboutDataSettings() {
|
||||
</Button>
|
||||
</SettingItem>
|
||||
</SettingsSection>
|
||||
</>
|
||||
|
||||
<DebugSettings />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
"use client";
|
||||
|
||||
import { SidebarAppsSettings } from './sidebar-apps-settings';
|
||||
import { PluginsSettings } from './plugins-settings';
|
||||
import { usePolicyStore } from '@/stores/policy-store';
|
||||
|
||||
/**
|
||||
* The Add-ons page: sidebar apps and plugins, the two ways to add things to
|
||||
* Bulwark. Plugins with a page of their own appear under this entry in the
|
||||
* sidebar instead of forming a group.
|
||||
*/
|
||||
export function AddonsSettings() {
|
||||
const { isFeatureEnabled } = usePolicyStore();
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
{isFeatureEnabled('sidebarAppsEnabled') && <SidebarAppsSettings />}
|
||||
{isFeatureEnabled('pluginsEnabled') && <PluginsSettings />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -10,16 +10,12 @@ export function DebugSettings() {
|
||||
const { debugMode, debugCategories, updateSetting } = useSettingsStore();
|
||||
const { isSettingLocked, isSettingHidden, isFeatureEnabled } = usePolicyStore();
|
||||
|
||||
if (isSettingHidden('debugMode') || !isFeatureEnabled('debugModeEnabled')) {
|
||||
return (
|
||||
<SettingsSection title={t('debug_mode.label')} description={t('debug_mode.description')}>
|
||||
<p className="text-sm text-muted-foreground py-2">{t('debug_mode.description')}</p>
|
||||
</SettingsSection>
|
||||
);
|
||||
}
|
||||
// A section of the Backup & reset page now; nothing to show when the admin
|
||||
// keeps debug logging off.
|
||||
if (isSettingHidden('debugMode') || !isFeatureEnabled('debugModeEnabled')) return null;
|
||||
|
||||
return (
|
||||
<SettingsSection title={t('debug_mode.label')} description={t('debug_mode.description')}>
|
||||
<SettingsSection id="debug" advanced title={t('debug_mode.label')} description={t('debug_mode.description')}>
|
||||
<SettingItem label={t('debug_mode.label')} description={t('debug_mode.description')} locked={isSettingLocked('debugMode')}>
|
||||
<ToggleSwitch checked={debugMode} onChange={(checked) => updateSetting('debugMode', checked)} />
|
||||
</SettingItem>
|
||||
|
||||
@@ -112,6 +112,7 @@ export function PluginsSettings() {
|
||||
|
||||
return (
|
||||
<SettingsSection
|
||||
id="plugins"
|
||||
title={t('title')}
|
||||
description={demoMode ? t('description_demo') : uploadsAllowed ? t('description_uploads') : t('description')}
|
||||
>
|
||||
|
||||
@@ -18,14 +18,12 @@ import {
|
||||
FolderOpen,
|
||||
HardDrive,
|
||||
BookUser,
|
||||
PanelLeftClose,
|
||||
Bell,
|
||||
Puzzle,
|
||||
BookOpen,
|
||||
PenLine,
|
||||
LayoutList,
|
||||
Info,
|
||||
Bug,
|
||||
Database,
|
||||
X,
|
||||
type AppIcon,
|
||||
} from '@/components/icons';
|
||||
@@ -43,15 +41,13 @@ import { CalendarSettings } from '@/components/settings/calendar-settings';
|
||||
import { CalendarManagementSettings } from '@/components/settings/calendar-management-settings';
|
||||
import { AddressBookManagementSettings } from '@/components/settings/address-book-management-settings';
|
||||
import { FilterSettings } from '@/components/settings/filter-settings';
|
||||
import { AboutDataSettings } from '@/components/settings/about-data-settings';
|
||||
import { DebugSettings } from '@/components/settings/debug-settings';
|
||||
import { AboutDataSettings, AboutFooter } from '@/components/settings/about-data-settings';
|
||||
import { OrganizeSettings } from '@/components/settings/organize-settings';
|
||||
import { AccountSecuritySettings } from '@/components/settings/account-security-settings';
|
||||
import { FilesSettingsComponent } from '@/components/settings/files-settings';
|
||||
import { ContactsSettings } from '@/components/settings/contacts-settings';
|
||||
import { SidebarAppsSettings } from '@/components/settings/sidebar-apps-settings';
|
||||
import { AddonsSettings } from '@/components/settings/addons-settings';
|
||||
import { NotificationSettings } from '@/components/settings/notification-settings';
|
||||
import { PluginsSettings } from '@/components/settings/plugins-settings';
|
||||
import { PluginIframeSlot } from '@/components/plugins/plugin-iframe-slot';
|
||||
import { offersForSlot as pluginOffersForSlot, subscribe as pluginRegistrySubscribe, get as getActivePlugin } from '@/lib/plugin-sandbox/registry';
|
||||
import { AdvancedSettingsProvider, AdvancedSettingsSwitch } from '@/components/settings/settings-section';
|
||||
@@ -128,10 +124,8 @@ const tabIcons: Record<Tab, AppIcon> = {
|
||||
calendar: Calendar,
|
||||
contacts: BookUser,
|
||||
files: HardDrive,
|
||||
sidebar_apps: PanelLeftClose,
|
||||
about_data: Info,
|
||||
plugins: Puzzle,
|
||||
debug: Bug,
|
||||
addons: Puzzle,
|
||||
backup: Database,
|
||||
};
|
||||
|
||||
const tabGroupOrder: TabGroup[] = ['general', 'appearance', 'mail', 'privacy', 'apps', 'plugins', 'advanced'];
|
||||
@@ -141,7 +135,7 @@ const tabGroupOrder: TabGroup[] = ['general', 'appearance', 'mail', 'privacy', '
|
||||
// land on the page that now holds the setting.
|
||||
export const LEGACY_TAB_MAP: Record<string, Tab> = {
|
||||
email: 'reading',
|
||||
advanced: 'about_data',
|
||||
advanced: 'backup',
|
||||
layout: 'appearance',
|
||||
themes: 'appearance',
|
||||
content_senders: 'reading',
|
||||
@@ -152,6 +146,10 @@ export const LEGACY_TAB_MAP: Record<string, Tab> = {
|
||||
folders: 'organize',
|
||||
keywords: 'organize',
|
||||
downloads: 'reading',
|
||||
sidebar_apps: 'addons',
|
||||
plugins: 'addons',
|
||||
about_data: 'backup',
|
||||
debug: 'backup',
|
||||
};
|
||||
|
||||
function readPersistedTab(): SettingsTabId {
|
||||
@@ -323,7 +321,7 @@ export function SettingsApp({ linkSegments: routeSegments }: SettingsAppProps =
|
||||
: '';
|
||||
return `${p.name} ${p.description} ${p.author} ${fieldText}`;
|
||||
}).join(' ');
|
||||
haystacks.plugins = `${haystacks.plugins ?? ''} ${haystackText}`.toLowerCase();
|
||||
haystacks.addons = `${haystacks.addons ?? ''} ${haystackText}`.toLowerCase();
|
||||
const pluginSubs: SubResult[] = installedPlugins.flatMap((p) => {
|
||||
const items: SubResult[] = [{ label: p.name, description: p.description }];
|
||||
if (p.settingsSchema) {
|
||||
@@ -337,7 +335,7 @@ export function SettingsApp({ linkSegments: routeSegments }: SettingsAppProps =
|
||||
}
|
||||
return items;
|
||||
});
|
||||
subs.plugins = [...(subs.plugins ?? []), ...pluginSubs];
|
||||
subs.addons = [...(subs.addons ?? []), ...pluginSubs];
|
||||
}
|
||||
// Themes are a section of Appearance now, so installed themes match there.
|
||||
if (installedThemes.length) {
|
||||
@@ -350,9 +348,9 @@ export function SettingsApp({ linkSegments: routeSegments }: SettingsAppProps =
|
||||
}
|
||||
if (sidebarAppsList.length) {
|
||||
const text = sidebarAppsList.map((a) => `${a.name} ${a.url}`).join(' ');
|
||||
haystacks.sidebar_apps = `${haystacks.sidebar_apps ?? ''} ${text}`.toLowerCase();
|
||||
subs.sidebar_apps = [
|
||||
...(subs.sidebar_apps ?? []),
|
||||
haystacks.addons = `${haystacks.addons ?? ''} ${text}`.toLowerCase();
|
||||
subs.addons = [
|
||||
...(subs.addons ?? []),
|
||||
...sidebarAppsList.map((a) => ({ label: a.name, description: a.url })),
|
||||
];
|
||||
}
|
||||
@@ -569,7 +567,7 @@ export function SettingsApp({ linkSegments: routeSegments }: SettingsAppProps =
|
||||
...(supportsCalendar && isFeatureEnabled('calendarEnabled') ? [{ id: 'calendar' as Tab, label: t('tabs.calendar'), icon: tabIcons.calendar, group: 'apps' as TabGroup }] : []),
|
||||
...(isFeatureEnabled('contactsEnabled') ? [{ id: 'contacts' as Tab, label: t('tabs.contacts'), icon: tabIcons.contacts, group: 'apps' as TabGroup }] : []),
|
||||
...(supportsFiles && isFeatureEnabled('filesEnabled') ? [{ id: 'files' as Tab, label: t('tabs.files'), icon: tabIcons.files, group: 'apps' as TabGroup }] : []),
|
||||
...(isFeatureEnabled('sidebarAppsEnabled') ? [{ id: 'sidebar_apps' as Tab, label: t('tabs.sidebar_apps'), icon: tabIcons.sidebar_apps, group: 'apps' as TabGroup }] : []),
|
||||
...(isFeatureEnabled('sidebarAppsEnabled') || isFeatureEnabled('pluginsEnabled') ? [{ id: 'addons' as Tab, label: t('tabs.addons'), icon: tabIcons.addons, group: 'apps' as TabGroup }] : []),
|
||||
// Plugin-contributed settings pages: one entry per active plugin that
|
||||
// offers a `settings-section` slot (e.g. S/MIME key & certificate manager).
|
||||
// A plugin that also has a page of its own gets that entry only, with the
|
||||
@@ -590,9 +588,7 @@ export function SettingsApp({ linkSegments: routeSegments }: SettingsAppProps =
|
||||
})),
|
||||
|
||||
// Advanced
|
||||
{ id: 'about_data', label: t('tabs.about_data'), icon: tabIcons.about_data, group: 'advanced' },
|
||||
...(isFeatureEnabled('pluginsEnabled') ? [{ id: 'plugins' as Tab, label: 'Plugins', icon: tabIcons.plugins, group: 'advanced' as TabGroup }] : []),
|
||||
...(isFeatureEnabled('debugModeEnabled') ? [{ id: 'debug' as Tab, label: t('tabs.debug'), icon: tabIcons.debug, group: 'advanced' as TabGroup }] : []),
|
||||
{ id: 'backup', label: t('tabs.backup'), icon: tabIcons.backup, group: 'advanced' },
|
||||
];
|
||||
|
||||
// In scoped (shared-account) mode, restrict to the account-relevant tabs the
|
||||
@@ -713,10 +709,8 @@ export function SettingsApp({ linkSegments: routeSegments }: SettingsAppProps =
|
||||
: <><ContactsSettings /><div className="mt-8"><AddressBookManagementSettings /></div></>
|
||||
)}
|
||||
{effectiveActiveTab === 'files' && <FilesSettingsComponent />}
|
||||
{effectiveActiveTab === 'sidebar_apps' && <SidebarAppsSettings />}
|
||||
{effectiveActiveTab === 'about_data' && <AboutDataSettings />}
|
||||
{effectiveActiveTab === 'plugins' && <PluginsSettings />}
|
||||
{effectiveActiveTab === 'debug' && <DebugSettings />}
|
||||
{effectiveActiveTab === 'addons' && <AddonsSettings />}
|
||||
{effectiveActiveTab === 'backup' && <AboutDataSettings />}
|
||||
{effectiveActiveTab.startsWith('plugin:') && (
|
||||
<PluginIframeSlot
|
||||
key={effectiveActiveTab}
|
||||
@@ -875,6 +869,7 @@ export function SettingsApp({ linkSegments: routeSegments }: SettingsAppProps =
|
||||
|
||||
<div className="border-t border-border px-2 py-2">
|
||||
<AdvancedSettingsSwitch />
|
||||
<AboutFooter />
|
||||
</div>
|
||||
<div className="border-t border-border px-5 py-3">
|
||||
<button
|
||||
@@ -1033,6 +1028,7 @@ export function SettingsApp({ linkSegments: routeSegments }: SettingsAppProps =
|
||||
</div>
|
||||
<div className="border-t border-border px-1 py-1">
|
||||
<AdvancedSettingsSwitch />
|
||||
<AboutFooter />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ function ManagedAppsSection() {
|
||||
if (managedApps.length === 0) return null;
|
||||
|
||||
return (
|
||||
<SettingsSection title={t("managed_title")} description={t("managed_description")}>
|
||||
<SettingsSection id="managed-apps" title={t("managed_title")} description={t("managed_description")}>
|
||||
<div className="space-y-3">
|
||||
{managedApps.map((app) => {
|
||||
const AppIcon = iconForName(app.icon);
|
||||
@@ -289,18 +289,7 @@ export function SidebarAppsSettings() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsSection title={t("title")} description={t("description")}>
|
||||
<SettingItem label={t("keep_loaded")} description={t("keep_loaded_description")}>
|
||||
<ToggleSwitch
|
||||
checked={keepAppsLoaded}
|
||||
onChange={(v) => updateSetting("keepAppsLoaded", v)}
|
||||
/>
|
||||
</SettingItem>
|
||||
</SettingsSection>
|
||||
|
||||
<ManagedAppsSection />
|
||||
|
||||
<SettingsSection title={t("manage_title")} description={t("manage_description")}>
|
||||
<SettingsSection id="sidebar-apps" title={t("title")} description={t("description")}>
|
||||
<div className="space-y-3">
|
||||
{sidebarApps.length === 0 && !showAddForm && (
|
||||
<p className="text-sm text-muted-foreground py-4 text-center">{tApps("no_apps_hint")}</p>
|
||||
@@ -387,8 +376,17 @@ export function SidebarAppsSettings() {
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<SettingItem advanced label={t("keep_loaded")} description={t("keep_loaded_description")}>
|
||||
<ToggleSwitch
|
||||
checked={keepAppsLoaded}
|
||||
onChange={(v) => updateSetting("keepAppsLoaded", v)}
|
||||
/>
|
||||
</SettingItem>
|
||||
</SettingsSection>
|
||||
|
||||
<ManagedAppsSection />
|
||||
|
||||
<ConfirmDialog {...confirmDialogProps} />
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -38,13 +38,12 @@ import { RELEASE_VERSION } from '@/lib/release-version';
|
||||
* opens the page that holds the setting now (the settings page migrates
|
||||
* the id). Listed so an unknown tab is refused here.
|
||||
*/
|
||||
const LEGACY_SETTINGS_TABS = ['layout', 'themes', 'content_senders', 'identities', 'language', 'protocol_handlers', 'templates', 'folders', 'keywords', 'downloads'] as const;
|
||||
const LEGACY_SETTINGS_TABS = ['layout', 'themes', 'content_senders', 'identities', 'language', 'protocol_handlers', 'templates', 'folders', 'keywords', 'downloads', 'sidebar_apps', 'about_data', 'plugins', 'debug'] as const;
|
||||
const SETTINGS_TABS: readonly (SettingsSearchTab | typeof LEGACY_SETTINGS_TABS[number])[] = [
|
||||
'account', 'general', 'notifications', 'appearance', 'message_list', 'reading',
|
||||
'composing', 'vacation', 'filters',
|
||||
'organize', 'security', 'calendar', 'contacts',
|
||||
'files', 'sidebar_apps', 'about_data',
|
||||
'plugins', 'debug',
|
||||
'files', 'addons', 'backup',
|
||||
...LEGACY_SETTINGS_TABS,
|
||||
];
|
||||
|
||||
|
||||
+6
-12
@@ -17,10 +17,8 @@ export type SettingsSearchTab =
|
||||
| 'calendar'
|
||||
| 'contacts'
|
||||
| 'files'
|
||||
| 'sidebar_apps'
|
||||
| 'about_data'
|
||||
| 'plugins'
|
||||
| 'debug';
|
||||
| 'addons'
|
||||
| 'backup';
|
||||
|
||||
type Tab = SettingsSearchTab;
|
||||
|
||||
@@ -125,10 +123,8 @@ export const tabSearchPaths: Record<Tab, string[]> = {
|
||||
calendar: ['calendar.settings', 'calendar.management'],
|
||||
contacts: ['settings.contacts', 'contacts'],
|
||||
files: ['settings.files'],
|
||||
sidebar_apps: ['settings.sidebar_apps', 'sidebar_apps'],
|
||||
about_data: ['settings.advanced'],
|
||||
plugins: [],
|
||||
debug: ['settings.advanced'],
|
||||
addons: ['settings.sidebar_apps', 'sidebar_apps', 'plugins.settings'],
|
||||
backup: ['settings.advanced'],
|
||||
};
|
||||
|
||||
// Extra English keywords per tab so common search terms hit even when the
|
||||
@@ -151,10 +147,8 @@ export const tabKeywords: Record<Tab, string> = {
|
||||
calendar: 'event schedule appointment meeting timezone invitation ics tasks birthday working hours',
|
||||
contacts: 'address book contact',
|
||||
files: 'attachments cloud drive storage upload',
|
||||
sidebar_apps: 'apps webview iframe',
|
||||
about_data: 'export import storage quota privacy backup',
|
||||
plugins: 'extensions addons',
|
||||
debug: 'logs developer console diagnostic',
|
||||
addons: 'apps webview iframe plugins extensions addons sidebar',
|
||||
backup: 'export import storage quota privacy backup reset sync cache about version debug logs developer console diagnostic',
|
||||
};
|
||||
|
||||
export function flattenStrings(node: unknown, sink: string[]): void {
|
||||
|
||||
@@ -1053,7 +1053,9 @@
|
||||
"debug": "التصحيح",
|
||||
"message_list": "قائمة الرسائل",
|
||||
"general": "عام",
|
||||
"organize": "المجلدات والوسوم"
|
||||
"organize": "المجلدات والوسوم",
|
||||
"addons": "الإضافات",
|
||||
"backup": "النسخ الاحتياطي وإعادة الضبط"
|
||||
},
|
||||
"themes": {
|
||||
"title": "السمات",
|
||||
@@ -2236,6 +2238,12 @@
|
||||
"delivered": "مُسلَّمة",
|
||||
"mistakes": "أخطاء"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "نسخة احتياطية من الإعدادات",
|
||||
"backup_description": "احتفظ بإعداداتك عبر المتصفحات والأجهزة.",
|
||||
"fix": "إصلاح المشكلات",
|
||||
"fix_description": "عندما يبدو العرض قديمًا أو خاطئًا، أو عندما تريد البدء من جديد."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1053,7 +1053,9 @@
|
||||
"debug": "Depuració",
|
||||
"message_list": "Llista de missatges",
|
||||
"general": "General",
|
||||
"organize": "Carpetes i etiquetes"
|
||||
"organize": "Carpetes i etiquetes",
|
||||
"addons": "Complements",
|
||||
"backup": "Còpia de seguretat i restabliment"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Temes",
|
||||
@@ -2236,6 +2238,12 @@
|
||||
"delivered": "Lliurats",
|
||||
"mistakes": "Errors"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Còpia de seguretat de la configuració",
|
||||
"backup_description": "Conserveu la configuració entre navegadors i dispositius.",
|
||||
"fix": "Solucionar problemes",
|
||||
"fix_description": "Quan una vista sembla antiga o incorrecta, o voleu començar de nou."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "Ladění",
|
||||
"message_list": "Seznam zpráv",
|
||||
"general": "Obecné",
|
||||
"organize": "Složky a štítky"
|
||||
"organize": "Složky a štítky",
|
||||
"addons": "Doplňky",
|
||||
"backup": "Záloha a obnovení"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Motivy",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "Doručeno",
|
||||
"mistakes": "Chyby"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Záloha nastavení",
|
||||
"backup_description": "Zachovejte nastavení napříč prohlížeči a zařízeními.",
|
||||
"fix": "Řešení potíží",
|
||||
"fix_description": "Když zobrazení vypadá zastarale nebo chybně, nebo chcete začít znovu."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1053,7 +1053,9 @@
|
||||
"debug": "Debug",
|
||||
"message_list": "Beskedliste",
|
||||
"general": "Generelt",
|
||||
"organize": "Mapper og tags"
|
||||
"organize": "Mapper og tags",
|
||||
"addons": "Tilføjelser",
|
||||
"backup": "Sikkerhedskopi og nulstilling"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Temaer",
|
||||
@@ -2232,6 +2234,12 @@
|
||||
"delivered": "Leveret",
|
||||
"mistakes": "Fejl"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Sikkerhedskopi af indstillinger",
|
||||
"backup_description": "Behold dine indstillinger på tværs af browsere og enheder.",
|
||||
"fix": "Løs problemer",
|
||||
"fix_description": "Når en visning ser forældet eller forkert ud, eller du vil starte forfra."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "Debug",
|
||||
"message_list": "Nachrichtenliste",
|
||||
"general": "Allgemein",
|
||||
"organize": "Ordner & Tags"
|
||||
"organize": "Ordner & Tags",
|
||||
"addons": "Erweiterungen",
|
||||
"backup": "Sicherung & Zurücksetzen"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Designs",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "Zugestellt",
|
||||
"mistakes": "Fehler"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Einstellungen sichern",
|
||||
"backup_description": "Ihre Einstellungen über Browser und Geräte hinweg behalten.",
|
||||
"fix": "Probleme beheben",
|
||||
"fix_description": "Wenn eine Ansicht veraltet oder falsch aussieht oder Sie neu anfangen möchten."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1053,7 +1053,9 @@
|
||||
"debug": "Debug",
|
||||
"message_list": "Message list",
|
||||
"general": "General",
|
||||
"organize": "Folders & tags"
|
||||
"organize": "Folders & tags",
|
||||
"addons": "Add-ons",
|
||||
"backup": "Backup & reset"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Themes",
|
||||
@@ -2236,6 +2238,12 @@
|
||||
"delivered": "Delivered",
|
||||
"mistakes": "Mistakes"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Settings backup",
|
||||
"backup_description": "Keep your settings across browsers and devices.",
|
||||
"fix": "Fix problems",
|
||||
"fix_description": "When a view looks stale or wrong, or you want to start over."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "Depuración",
|
||||
"message_list": "Lista de mensajes",
|
||||
"general": "General",
|
||||
"organize": "Carpetas y etiquetas"
|
||||
"organize": "Carpetas y etiquetas",
|
||||
"addons": "Complementos",
|
||||
"backup": "Copia de seguridad y restablecer"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Temas",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "Entregados",
|
||||
"mistakes": "Errores"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Copia de seguridad de los ajustes",
|
||||
"backup_description": "Conserve sus ajustes entre navegadores y dispositivos.",
|
||||
"fix": "Solucionar problemas",
|
||||
"fix_description": "Cuando una vista parece desactualizada o incorrecta, o quiere empezar de cero."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1053,7 +1053,9 @@
|
||||
"debug": "Silumine",
|
||||
"message_list": "Kirjade loend",
|
||||
"general": "Üldine",
|
||||
"organize": "Kaustad ja sildid"
|
||||
"organize": "Kaustad ja sildid",
|
||||
"addons": "Lisad",
|
||||
"backup": "Varundus ja lähtestamine"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Teemad",
|
||||
@@ -2236,6 +2238,12 @@
|
||||
"delivered": "Kohale jõudnud",
|
||||
"mistakes": "Vead"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Seadete varundus",
|
||||
"backup_description": "Säilita oma seaded brauserite ja seadmete vahel.",
|
||||
"fix": "Probleemide lahendamine",
|
||||
"fix_description": "Kui vaade tundub aegunud või vale või soovid otsast alustada."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1053,7 +1053,9 @@
|
||||
"debug": "اشکالزدایی",
|
||||
"message_list": "فهرست پیامها",
|
||||
"general": "عمومی",
|
||||
"organize": "پوشهها و برچسبها"
|
||||
"organize": "پوشهها و برچسبها",
|
||||
"addons": "افزونهها",
|
||||
"backup": "پشتیبانگیری و بازنشانی"
|
||||
},
|
||||
"themes": {
|
||||
"title": "پوستهها",
|
||||
@@ -2236,6 +2238,12 @@
|
||||
"delivered": "تحویلشده",
|
||||
"mistakes": "اشتباهها"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "پشتیبان تنظیمات",
|
||||
"backup_description": "تنظیمات خود را در مرورگرها و دستگاههای مختلف حفظ کنید.",
|
||||
"fix": "رفع مشکلات",
|
||||
"fix_description": "وقتی نمایی قدیمی یا نادرست به نظر میرسد یا میخواهید از نو شروع کنید."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "Débogage",
|
||||
"message_list": "Liste des messages",
|
||||
"general": "Général",
|
||||
"organize": "Dossiers et étiquettes"
|
||||
"organize": "Dossiers et étiquettes",
|
||||
"addons": "Extensions",
|
||||
"backup": "Sauvegarde et réinitialisation"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Thèmes",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "Distribués",
|
||||
"mistakes": "Erreurs"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Sauvegarde des paramètres",
|
||||
"backup_description": "Conservez vos paramètres d'un navigateur et d'un appareil à l'autre.",
|
||||
"fix": "Résoudre les problèmes",
|
||||
"fix_description": "Quand une vue semble obsolète ou incorrecte, ou pour repartir de zéro."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1015,7 +1015,9 @@
|
||||
"debug": "ניפוי שגיאות",
|
||||
"message_list": "רשימת הודעות",
|
||||
"general": "כללי",
|
||||
"organize": "תיקיות ותגיות"
|
||||
"organize": "תיקיות ותגיות",
|
||||
"addons": "תוספים",
|
||||
"backup": "גיבוי ואיפוס"
|
||||
},
|
||||
"themes": {
|
||||
"title": "ערכות נושא",
|
||||
@@ -2195,6 +2197,12 @@
|
||||
"show_avatars_in_junk": {
|
||||
"label": "הצג אווטרים בתיקייה זבל",
|
||||
"description": "הצג תמונות פרופיל וייקוני אתרים עבור שולחים בתיקייה זבל. מושבת כברירת מחדל כדי להימנע מהענקת לגיטימציה חזותית לניסיונות דיוג."
|
||||
},
|
||||
"sections": {
|
||||
"backup": "גיבוי הגדרות",
|
||||
"backup_description": "שמירת ההגדרות שלך בין דפדפנים ומכשירים.",
|
||||
"fix": "פתרון בעיות",
|
||||
"fix_description": "כשתצוגה נראית מיושנת או שגויה, או כשרוצים להתחיל מחדש."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1053,7 +1053,9 @@
|
||||
"debug": "Hibakeresés",
|
||||
"message_list": "Üzenetlista",
|
||||
"general": "Általános",
|
||||
"organize": "Mappák és címkék"
|
||||
"organize": "Mappák és címkék",
|
||||
"addons": "Bővítmények",
|
||||
"backup": "Biztonsági mentés és visszaállítás"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Témák",
|
||||
@@ -2232,6 +2234,12 @@
|
||||
"delivered": "Kézbesítve",
|
||||
"mistakes": "Hibák"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Beállítások mentése",
|
||||
"backup_description": "Őrizze meg beállításait böngészők és eszközök között.",
|
||||
"fix": "Hibák elhárítása",
|
||||
"fix_description": "Ha egy nézet elavultnak vagy hibásnak tűnik, vagy elölről szeretné kezdeni."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "Debug",
|
||||
"message_list": "Elenco messaggi",
|
||||
"general": "Generale",
|
||||
"organize": "Cartelle ed etichette"
|
||||
"organize": "Cartelle ed etichette",
|
||||
"addons": "Componenti aggiuntivi",
|
||||
"backup": "Backup e ripristino"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Temi",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "Consegnati",
|
||||
"mistakes": "Errori"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Backup delle impostazioni",
|
||||
"backup_description": "Conserva le impostazioni tra browser e dispositivi.",
|
||||
"fix": "Risolvere i problemi",
|
||||
"fix_description": "Quando una vista sembra obsoleta o sbagliata, o vuoi ricominciare da capo."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "デバッグ",
|
||||
"message_list": "メッセージ一覧",
|
||||
"general": "一般",
|
||||
"organize": "フォルダーとタグ"
|
||||
"organize": "フォルダーとタグ",
|
||||
"addons": "アドオン",
|
||||
"backup": "バックアップとリセット"
|
||||
},
|
||||
"themes": {
|
||||
"title": "テーマ",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "配信",
|
||||
"mistakes": "ミス"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "設定のバックアップ",
|
||||
"backup_description": "ブラウザーやデバイスをまたいで設定を保持します。",
|
||||
"fix": "問題の解決",
|
||||
"fix_description": "表示が古い、または正しくないとき、あるいは最初からやり直したいときに。"
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "디버그",
|
||||
"message_list": "메시지 목록",
|
||||
"general": "일반",
|
||||
"organize": "폴더 및 태그"
|
||||
"organize": "폴더 및 태그",
|
||||
"addons": "추가 기능",
|
||||
"backup": "백업 및 초기화"
|
||||
},
|
||||
"themes": {
|
||||
"title": "테마",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "배달",
|
||||
"mistakes": "실수"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "설정 백업",
|
||||
"backup_description": "브라우저와 기기 간에 설정을 유지합니다.",
|
||||
"fix": "문제 해결",
|
||||
"fix_description": "보기가 오래되었거나 잘못되었을 때, 또는 처음부터 다시 시작하고 싶을 때."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "Atkļūdošana",
|
||||
"message_list": "Ziņu saraksts",
|
||||
"general": "Vispārīgi",
|
||||
"organize": "Mapes un tagi"
|
||||
"organize": "Mapes un tagi",
|
||||
"addons": "Papildinājumi",
|
||||
"backup": "Dublēšana un atiestatīšana"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Tēmas",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "Piegādātas",
|
||||
"mistakes": "Kļūdas"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Iestatījumu dublējums",
|
||||
"backup_description": "Saglabājiet iestatījumus dažādās pārlūkprogrammās un ierīcēs.",
|
||||
"fix": "Problēmu novēršana",
|
||||
"fix_description": "Ja skats izskatās novecojis vai nepareizs, vai vēlaties sākt no jauna."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1053,7 +1053,9 @@
|
||||
"debug": "Дабаглах",
|
||||
"message_list": "Мессежийн жагсаалт",
|
||||
"general": "Ерөнхий",
|
||||
"organize": "Хавтас ба шошго"
|
||||
"organize": "Хавтас ба шошго",
|
||||
"addons": "Нэмэлтүүд",
|
||||
"backup": "Нөөцлөлт ба дахин тохируулах"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Сэдэв",
|
||||
@@ -2236,6 +2238,12 @@
|
||||
"delivered": "Хүргэсэн",
|
||||
"mistakes": "Алдаа"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Тохиргооны нөөцлөлт",
|
||||
"backup_description": "Хөтөч болон төхөөрөмж хооронд тохиргоогоо хадгална.",
|
||||
"fix": "Асуудал засах",
|
||||
"fix_description": "Харагдац хуучирсан эсвэл буруу харагдах, эсвэл шинээр эхлэхийг хүсвэл."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1053,7 +1053,9 @@
|
||||
"debug": "Feilsøking",
|
||||
"message_list": "Meldingsliste",
|
||||
"general": "Generelt",
|
||||
"organize": "Mapper og etiketter"
|
||||
"organize": "Mapper og etiketter",
|
||||
"addons": "Tillegg",
|
||||
"backup": "Sikkerhetskopi og tilbakestilling"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Temaer",
|
||||
@@ -2236,6 +2238,12 @@
|
||||
"delivered": "Levert",
|
||||
"mistakes": "Feil"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Sikkerhetskopi av innstillinger",
|
||||
"backup_description": "Behold innstillingene dine på tvers av nettlesere og enheter.",
|
||||
"fix": "Løs problemer",
|
||||
"fix_description": "Når en visning ser utdatert eller feil ut, eller du vil starte på nytt."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "Debuggen",
|
||||
"message_list": "Berichtenlijst",
|
||||
"general": "Algemeen",
|
||||
"organize": "Mappen en tags"
|
||||
"organize": "Mappen en tags",
|
||||
"addons": "Add-ons",
|
||||
"backup": "Back-up en herstel"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Thema's",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "Bezorgd",
|
||||
"mistakes": "Fouten"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Back-up van instellingen",
|
||||
"backup_description": "Bewaar uw instellingen over browsers en apparaten heen.",
|
||||
"fix": "Problemen oplossen",
|
||||
"fix_description": "Als een weergave verouderd of onjuist lijkt, of u opnieuw wilt beginnen."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "Debugowanie",
|
||||
"message_list": "Lista wiadomości",
|
||||
"general": "Ogólne",
|
||||
"organize": "Foldery i tagi"
|
||||
"organize": "Foldery i tagi",
|
||||
"addons": "Dodatki",
|
||||
"backup": "Kopia zapasowa i reset"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Motywy",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "Dostarczone",
|
||||
"mistakes": "Błędy"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Kopia zapasowa ustawień",
|
||||
"backup_description": "Zachowaj ustawienia w różnych przeglądarkach i na różnych urządzeniach.",
|
||||
"fix": "Rozwiązywanie problemów",
|
||||
"fix_description": "Gdy widok wygląda na nieaktualny lub błędny albo chcesz zacząć od nowa."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "Depuração",
|
||||
"message_list": "Lista de mensagens",
|
||||
"general": "Geral",
|
||||
"organize": "Pastas e etiquetas"
|
||||
"organize": "Pastas e etiquetas",
|
||||
"addons": "Extras",
|
||||
"backup": "Cópia de segurança e reposição"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Temas",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "Entregues",
|
||||
"mistakes": "Erros"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Cópia de segurança das definições",
|
||||
"backup_description": "Mantenha as suas definições entre navegadores e dispositivos.",
|
||||
"fix": "Resolver problemas",
|
||||
"fix_description": "Quando uma vista parece desatualizada ou errada, ou quer recomeçar."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1053,7 +1053,9 @@
|
||||
"debug": "Depanare",
|
||||
"message_list": "Lista de mesaje",
|
||||
"general": "General",
|
||||
"organize": "Dosare și etichete"
|
||||
"organize": "Dosare și etichete",
|
||||
"addons": "Suplimente",
|
||||
"backup": "Copie de rezervă și resetare"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Teme",
|
||||
@@ -2236,6 +2238,12 @@
|
||||
"delivered": "Livrate",
|
||||
"mistakes": "Greșeli"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Copie de rezervă a setărilor",
|
||||
"backup_description": "Păstrați-vă setările între browsere și dispozitive.",
|
||||
"fix": "Rezolvarea problemelor",
|
||||
"fix_description": "Când o vizualizare pare învechită sau greșită, sau vreți să o luați de la capăt."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "Отладка",
|
||||
"message_list": "Список писем",
|
||||
"general": "Общие",
|
||||
"organize": "Папки и метки"
|
||||
"organize": "Папки и метки",
|
||||
"addons": "Дополнения",
|
||||
"backup": "Резервная копия и сброс"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Темы",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "Доставлено",
|
||||
"mistakes": "Ошибки"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Резервная копия настроек",
|
||||
"backup_description": "Сохраняйте настройки в разных браузерах и на разных устройствах.",
|
||||
"fix": "Устранение проблем",
|
||||
"fix_description": "Если данные выглядят устаревшими или неверными, или вы хотите начать заново."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1053,7 +1053,9 @@
|
||||
"debug": "Ladenie",
|
||||
"message_list": "Zoznam správ",
|
||||
"general": "Všeobecné",
|
||||
"organize": "Priečinky a štítky"
|
||||
"organize": "Priečinky a štítky",
|
||||
"addons": "Doplnky",
|
||||
"backup": "Záloha a obnovenie"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Motívy",
|
||||
@@ -2236,6 +2238,12 @@
|
||||
"delivered": "Doručené",
|
||||
"mistakes": "Chyby"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Záloha nastavení",
|
||||
"backup_description": "Zachovajte nastavenia naprieč prehliadačmi a zariadeniami.",
|
||||
"fix": "Riešenie problémov",
|
||||
"fix_description": "Keď zobrazenie vyzerá zastarano alebo chybne, alebo chcete začať odznova."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "Hata Ayıklama",
|
||||
"message_list": "İleti listesi",
|
||||
"general": "Genel",
|
||||
"organize": "Klasörler ve etiketler"
|
||||
"organize": "Klasörler ve etiketler",
|
||||
"addons": "Eklentiler",
|
||||
"backup": "Yedekleme ve sıfırlama"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Temalar",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "Teslim edilen",
|
||||
"mistakes": "Hatalar"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Ayar yedeği",
|
||||
"backup_description": "Ayarlarınızı tarayıcılar ve cihazlar arasında koruyun.",
|
||||
"fix": "Sorunları giderme",
|
||||
"fix_description": "Bir görünüm eski ya da yanlış göründüğünde ya da baştan başlamak istediğinizde."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "Налагодження",
|
||||
"message_list": "Список листів",
|
||||
"general": "Загальні",
|
||||
"organize": "Теки та мітки"
|
||||
"organize": "Теки та мітки",
|
||||
"addons": "Додатки",
|
||||
"backup": "Резервна копія та скидання"
|
||||
},
|
||||
"themes": {
|
||||
"title": "Теми",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "Доставлено",
|
||||
"mistakes": "Помилки"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "Резервна копія налаштувань",
|
||||
"backup_description": "Зберігайте налаштування в різних браузерах і на різних пристроях.",
|
||||
"fix": "Усунення проблем",
|
||||
"fix_description": "Якщо дані виглядають застарілими чи неправильними, або ви хочете почати спочатку."
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1053,7 +1053,9 @@
|
||||
"debug": "除錯",
|
||||
"message_list": "郵件清單",
|
||||
"general": "一般",
|
||||
"organize": "資料夾與標籤"
|
||||
"organize": "資料夾與標籤",
|
||||
"addons": "附加元件",
|
||||
"backup": "備份與重設"
|
||||
},
|
||||
"themes": {
|
||||
"title": "主題",
|
||||
@@ -2236,6 +2238,12 @@
|
||||
"delivered": "已送達",
|
||||
"mistakes": "失誤"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "設定備份",
|
||||
"backup_description": "在瀏覽器與裝置之間保留您的設定。",
|
||||
"fix": "修正問題",
|
||||
"fix_description": "當檢視看起來過時或有誤,或者您想重新開始時。"
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
@@ -1050,7 +1050,9 @@
|
||||
"debug": "调试",
|
||||
"message_list": "邮件列表",
|
||||
"general": "常规",
|
||||
"organize": "文件夹与标签"
|
||||
"organize": "文件夹与标签",
|
||||
"addons": "附加组件",
|
||||
"backup": "备份与重置"
|
||||
},
|
||||
"themes": {
|
||||
"title": "主题",
|
||||
@@ -2229,6 +2231,12 @@
|
||||
"delivered": "已送达",
|
||||
"mistakes": "失误"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"backup": "设置备份",
|
||||
"backup_description": "在浏览器和设备之间保留您的设置。",
|
||||
"fix": "修复问题",
|
||||
"fix_description": "当视图看起来过时或有误,或者您想重新开始时。"
|
||||
}
|
||||
},
|
||||
"sidebar_apps": {
|
||||
|
||||
Reference in New Issue
Block a user