mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-20 13:00:39 +00:00
Refactor code structure for improved readability and maintainability
This commit is contained in:
Generated
+8
@@ -26,6 +26,7 @@
|
|||||||
"@preact/preset-vite": "^2.10.3",
|
"@preact/preset-vite": "^2.10.3",
|
||||||
"@types/node": "^25.2.3",
|
"@types/node": "^25.2.3",
|
||||||
"autoprefixer": "^10.4.21",
|
"autoprefixer": "^10.4.21",
|
||||||
|
"opencc-js": "^1.0.5",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"tsx": "^4.21.0",
|
"tsx": "^4.21.0",
|
||||||
@@ -3246,6 +3247,13 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/opencc-js": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/opencc-js/-/opencc-js-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-LD+1SoNnZdlRwtYTjnQdFrSVCAaYpuDqL5CkmOaHOkKoKh7mFxUicLTRVNLU5C+Jmi1vXQ3QL4jWdgSaa4sKjg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/path-parse": {
|
"node_modules/path-parse": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz",
|
"resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz",
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
"dev": "wrangler dev -c wrangler.toml",
|
"dev": "wrangler dev -c wrangler.toml",
|
||||||
"dev:kv": "wrangler dev -c wrangler.kv.toml",
|
"dev:kv": "wrangler dev -c wrangler.kv.toml",
|
||||||
"build": "vite build --config webapp/vite.config.ts",
|
"build": "vite build --config webapp/vite.config.ts",
|
||||||
|
"i18n:generate:zh-tw": "node scripts/i18n-generate-zh-tw.cjs",
|
||||||
|
"i18n:validate": "node scripts/i18n-validate.cjs",
|
||||||
"deploy": "wrangler deploy",
|
"deploy": "wrangler deploy",
|
||||||
"deploy:kv": "wrangler deploy -c wrangler.kv.toml"
|
"deploy:kv": "wrangler deploy -c wrangler.kv.toml"
|
||||||
},
|
},
|
||||||
@@ -41,6 +43,7 @@
|
|||||||
"@preact/preset-vite": "^2.10.3",
|
"@preact/preset-vite": "^2.10.3",
|
||||||
"@types/node": "^25.2.3",
|
"@types/node": "^25.2.3",
|
||||||
"autoprefixer": "^10.4.21",
|
"autoprefixer": "^10.4.21",
|
||||||
|
"opencc-js": "^1.0.5",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"tsx": "^4.21.0",
|
"tsx": "^4.21.0",
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const vm = require('vm');
|
||||||
|
|
||||||
|
const localeDir = path.join(__dirname, '..', 'webapp', 'src', 'lib', 'i18n', 'locales');
|
||||||
|
|
||||||
|
function readLocale(fileName, variableName) {
|
||||||
|
let code = fs.readFileSync(path.join(localeDir, fileName), 'utf8');
|
||||||
|
code = code
|
||||||
|
.replace(/const (\w+): Record<string, string> =/g, 'const $1 =')
|
||||||
|
.replace(/export default \w+;\s*$/m, '');
|
||||||
|
code += `\nresult = ${variableName};`;
|
||||||
|
const sandbox = { result: null };
|
||||||
|
vm.createContext(sandbox);
|
||||||
|
vm.runInContext(code, sandbox, { filename: fileName });
|
||||||
|
return sandbox.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeLocale(fileName, variableName, table, header) {
|
||||||
|
const body = JSON.stringify(table, null, 2);
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(localeDir, fileName),
|
||||||
|
`${header}\nconst ${variableName}: Record<string, string> = ${body};\n\nexport default ${variableName};\n`,
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
localeDir,
|
||||||
|
readLocale,
|
||||||
|
writeLocale,
|
||||||
|
};
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
const { readLocale } = require('./i18n-utils.cjs');
|
||||||
|
|
||||||
|
const localeFiles = [
|
||||||
|
['en', 'en.ts', 'en'],
|
||||||
|
['zh-CN', 'zh-CN.ts', 'zhCN'],
|
||||||
|
['zh-TW', 'zh-TW.ts', 'zhTW'],
|
||||||
|
['ru', 'ru.ts', 'ru'],
|
||||||
|
];
|
||||||
|
|
||||||
|
const locales = Object.fromEntries(
|
||||||
|
localeFiles.map(([locale, fileName, variableName]) => [locale, readLocale(fileName, variableName)])
|
||||||
|
);
|
||||||
|
const base = locales.en;
|
||||||
|
const baseKeys = Object.keys(base).sort();
|
||||||
|
const placeholderRe = /\{\w+\}/g;
|
||||||
|
const errors = [];
|
||||||
|
|
||||||
|
for (const [locale, table] of Object.entries(locales)) {
|
||||||
|
const keys = Object.keys(table).sort();
|
||||||
|
const missing = baseKeys.filter((key) => !(key in table));
|
||||||
|
const extra = keys.filter((key) => !baseKeys.includes(key));
|
||||||
|
if (missing.length || extra.length) {
|
||||||
|
errors.push({ locale, missing, extra });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key of baseKeys) {
|
||||||
|
const basePlaceholders = Array.from(String(base[key]).matchAll(placeholderRe), (match) => match[0]).sort().join('|');
|
||||||
|
const localePlaceholders = Array.from(String(table[key]).matchAll(placeholderRe), (match) => match[0]).sort().join('|');
|
||||||
|
if (basePlaceholders !== localePlaceholders) {
|
||||||
|
errors.push({ locale, key, basePlaceholders, localePlaceholders });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(JSON.stringify({
|
||||||
|
counts: Object.fromEntries(Object.entries(locales).map(([locale, table]) => [locale, Object.keys(table).length])),
|
||||||
|
errors,
|
||||||
|
}, null, 2));
|
||||||
|
|
||||||
|
if (errors.length) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
+22
-5
@@ -13,6 +13,7 @@ import {
|
|||||||
clearProfileSnapshot,
|
clearProfileSnapshot,
|
||||||
getCurrentDeviceIdentifier,
|
getCurrentDeviceIdentifier,
|
||||||
getPasswordHint,
|
getPasswordHint,
|
||||||
|
getProfile,
|
||||||
loadProfileSnapshot,
|
loadProfileSnapshot,
|
||||||
saveProfileSnapshot,
|
saveProfileSnapshot,
|
||||||
revokeCurrentSession,
|
revokeCurrentSession,
|
||||||
@@ -70,6 +71,10 @@ const IMPORT_ROUTE_PATHS = [IMPORT_ROUTE, '/tools/import', '/tools/import-export
|
|||||||
const IMPORT_ROUTE_ALIASES: ReadonlySet<string> = new Set(IMPORT_ROUTE_PATHS.filter((path) => path !== IMPORT_ROUTE));
|
const IMPORT_ROUTE_ALIASES: ReadonlySet<string> = new Set(IMPORT_ROUTE_PATHS.filter((path) => path !== IMPORT_ROUTE));
|
||||||
const SETTINGS_HOME_ROUTE = '/settings';
|
const SETTINGS_HOME_ROUTE = '/settings';
|
||||||
const SETTINGS_ACCOUNT_ROUTE = '/settings/account';
|
const SETTINGS_ACCOUNT_ROUTE = '/settings/account';
|
||||||
|
|
||||||
|
function isAdminProfile(profile: Profile | null): profile is Profile {
|
||||||
|
return String(profile?.role || '').toLowerCase() === 'admin';
|
||||||
|
}
|
||||||
const THEME_STORAGE_KEY = 'nodewarden.theme.preference.v1';
|
const THEME_STORAGE_KEY = 'nodewarden.theme.preference.v1';
|
||||||
const SIGNALR_RECORD_SEPARATOR = String.fromCharCode(0x1e);
|
const SIGNALR_RECORD_SEPARATOR = String.fromCharCode(0x1e);
|
||||||
const SIGNALR_UPDATE_TYPE_SYNC_VAULT = 5;
|
const SIGNALR_UPDATE_TYPE_SYNC_VAULT = 5;
|
||||||
@@ -770,16 +775,28 @@ export default function App() {
|
|||||||
enabled: phase === 'app' && !!session?.symEncKey && !!session?.symMacKey && (vaultInitialDecryptDone || location === '/sends'),
|
enabled: phase === 'app' && !!session?.symEncKey && !!session?.symMacKey && (vaultInitialDecryptDone || location === '/sends'),
|
||||||
staleTime: 30_000,
|
staleTime: 30_000,
|
||||||
});
|
});
|
||||||
|
const profileQuery = useQuery({
|
||||||
|
queryKey: ['profile', vaultCacheKey || session?.email],
|
||||||
|
queryFn: () => getProfile(authedFetch),
|
||||||
|
enabled: phase === 'app' && !!session?.accessToken,
|
||||||
|
staleTime: 30_000,
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
if (!profileQuery.data) return;
|
||||||
|
setProfile(profileQuery.data);
|
||||||
|
}, [profileQuery.data]);
|
||||||
|
|
||||||
|
const isAdmin = isAdminProfile(profile);
|
||||||
const usersQuery = useQuery({
|
const usersQuery = useQuery({
|
||||||
queryKey: ['admin-users', vaultCacheKey],
|
queryKey: ['admin-users', vaultCacheKey],
|
||||||
queryFn: () => listAdminUsers(authedFetch),
|
queryFn: () => listAdminUsers(authedFetch),
|
||||||
enabled: phase === 'app' && profile?.role === 'admin' && vaultInitialDecryptDone,
|
enabled: phase === 'app' && isAdmin && vaultInitialDecryptDone,
|
||||||
staleTime: 30_000,
|
staleTime: 30_000,
|
||||||
});
|
});
|
||||||
const invitesQuery = useQuery({
|
const invitesQuery = useQuery({
|
||||||
queryKey: ['admin-invites', vaultCacheKey],
|
queryKey: ['admin-invites', vaultCacheKey],
|
||||||
queryFn: () => listAdminInvites(authedFetch),
|
queryFn: () => listAdminInvites(authedFetch),
|
||||||
enabled: phase === 'app' && profile?.role === 'admin' && vaultInitialDecryptDone,
|
enabled: phase === 'app' && isAdmin && vaultInitialDecryptDone,
|
||||||
staleTime: 30_000,
|
staleTime: 30_000,
|
||||||
});
|
});
|
||||||
const totpStatusQuery = useQuery({
|
const totpStatusQuery = useQuery({
|
||||||
@@ -798,7 +815,7 @@ export default function App() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (phase !== 'app' || !session?.accessToken || !session?.symEncKey || !session?.symMacKey) return;
|
if (phase !== 'app' || !session?.accessToken || !session?.symEncKey || !session?.symMacKey) return;
|
||||||
if (!vaultInitialDecryptDone) return;
|
if (!vaultInitialDecryptDone) return;
|
||||||
if (!profile?.role || profile.role !== 'admin') return;
|
if (!isAdminProfile(profile)) return;
|
||||||
if (repairAttemptRef.current === session.accessToken) return;
|
if (repairAttemptRef.current === session.accessToken) return;
|
||||||
|
|
||||||
repairAttemptRef.current = session.accessToken;
|
repairAttemptRef.current = session.accessToken;
|
||||||
@@ -1148,10 +1165,10 @@ export default function App() {
|
|||||||
}, [phase, isImportHashRoute, location, navigate]);
|
}, [phase, isImportHashRoute, location, navigate]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (phase === 'app' && profile?.role !== 'admin' && location === '/backup') {
|
if (phase === 'app' && !isAdminProfile(profile) && location === '/backup' && !profileQuery.isFetching) {
|
||||||
navigate('/vault');
|
navigate('/vault');
|
||||||
}
|
}
|
||||||
}, [phase, profile?.role, location, navigate]);
|
}, [phase, profile?.role, profileQuery.isFetching, location, navigate]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (phase === 'app' && !mobileLayout && location === SETTINGS_HOME_ROUTE) {
|
if (phase === 'app' && !mobileLayout && location === SETTINGS_HOME_ROUTE) {
|
||||||
|
|||||||
@@ -25,8 +25,13 @@ interface AppAuthenticatedShellProps {
|
|||||||
mainRoutesProps: AppMainRoutesProps;
|
mainRoutesProps: AppMainRoutesProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isAdminProfile(profile: Profile | null): boolean {
|
||||||
|
return String(profile?.role || '').toLowerCase() === 'admin';
|
||||||
|
}
|
||||||
|
|
||||||
export default function AppAuthenticatedShell(props: AppAuthenticatedShellProps) {
|
export default function AppAuthenticatedShell(props: AppAuthenticatedShellProps) {
|
||||||
const routeAnimationKey = props.isImportRoute ? props.importRoute : props.location;
|
const routeAnimationKey = props.isImportRoute ? props.importRoute : props.location;
|
||||||
|
const isAdmin = isAdminProfile(props.profile);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="app-page">
|
<div className="app-page">
|
||||||
@@ -83,7 +88,7 @@ export default function AppAuthenticatedShell(props: AppAuthenticatedShellProps)
|
|||||||
<SendIcon size={16} />
|
<SendIcon size={16} />
|
||||||
<span>{t('nav_sends')}</span>
|
<span>{t('nav_sends')}</span>
|
||||||
</Link>
|
</Link>
|
||||||
{props.profile?.role === 'admin' && (
|
{isAdmin && (
|
||||||
<Link href="/admin" className={`side-link ${props.location === '/admin' ? 'active' : ''}`}>
|
<Link href="/admin" className={`side-link ${props.location === '/admin' ? 'active' : ''}`}>
|
||||||
<ShieldUser size={16} />
|
<ShieldUser size={16} />
|
||||||
<span>{t('nav_admin_panel')}</span>
|
<span>{t('nav_admin_panel')}</span>
|
||||||
@@ -97,7 +102,7 @@ export default function AppAuthenticatedShell(props: AppAuthenticatedShellProps)
|
|||||||
<Shield size={16} />
|
<Shield size={16} />
|
||||||
<span>{t('nav_device_management')}</span>
|
<span>{t('nav_device_management')}</span>
|
||||||
</Link>
|
</Link>
|
||||||
{props.profile?.role === 'admin' && (
|
{isAdmin && (
|
||||||
<Link href="/backup" className={`side-link ${props.location === '/backup' ? 'active' : ''}`}>
|
<Link href="/backup" className={`side-link ${props.location === '/backup' ? 'active' : ''}`}>
|
||||||
<Cloud size={16} />
|
<Cloud size={16} />
|
||||||
<span>{t('nav_backup_strategy')}</span>
|
<span>{t('nav_backup_strategy')}</span>
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ export interface AppMainRoutesProps {
|
|||||||
|
|
||||||
export default function AppMainRoutes(props: AppMainRoutesProps) {
|
export default function AppMainRoutes(props: AppMainRoutesProps) {
|
||||||
const importRoutePaths = [props.importRoute, '/tools/import', '/tools/import-export', '/tools/import-data', '/import', '/import-export'] as const;
|
const importRoutePaths = [props.importRoute, '/tools/import', '/tools/import-export', '/tools/import-data', '/import', '/import-export'] as const;
|
||||||
|
const isAdmin = String(props.profile?.role || '').toLowerCase() === 'admin';
|
||||||
const importPageContent = (
|
const importPageContent = (
|
||||||
<Suspense fallback={<RouteContentFallback />}>
|
<Suspense fallback={<RouteContentFallback />}>
|
||||||
<ImportPage
|
<ImportPage
|
||||||
@@ -262,13 +263,13 @@ export default function AppMainRoutes(props: AppMainRoutesProps) {
|
|||||||
<ArrowUpDown size={18} />
|
<ArrowUpDown size={18} />
|
||||||
<span>{t('nav_import_export')}</span>
|
<span>{t('nav_import_export')}</span>
|
||||||
</Link>
|
</Link>
|
||||||
{props.profile.role === 'admin' && (
|
{isAdmin && (
|
||||||
<Link href="/admin" className="mobile-settings-link">
|
<Link href="/admin" className="mobile-settings-link">
|
||||||
<ShieldUser size={18} />
|
<ShieldUser size={18} />
|
||||||
<span>{t('nav_admin_panel')}</span>
|
<span>{t('nav_admin_panel')}</span>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
{props.profile.role === 'admin' && (
|
{isAdmin && (
|
||||||
<Link href="/backup" className="mobile-settings-link">
|
<Link href="/backup" className="mobile-settings-link">
|
||||||
<Cloud size={18} />
|
<Cloud size={18} />
|
||||||
<span>{t('nav_backup_strategy')}</span>
|
<span>{t('nav_backup_strategy')}</span>
|
||||||
@@ -340,7 +341,7 @@ export default function AppMainRoutes(props: AppMainRoutesProps) {
|
|||||||
<LegacyBackupRedirect onNavigate={props.onNavigate} />
|
<LegacyBackupRedirect onNavigate={props.onNavigate} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/backup">
|
<Route path="/backup">
|
||||||
{props.profile?.role === 'admin' ? (
|
{isAdmin ? (
|
||||||
<div className="stack">
|
<div className="stack">
|
||||||
{props.mobileLayout && (
|
{props.mobileLayout && (
|
||||||
<div className="mobile-settings-subhead">
|
<div className="mobile-settings-subhead">
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { useEffect, useMemo, useState } from 'preact/hooks';
|
import { useEffect, useMemo, useState } from 'preact/hooks';
|
||||||
import { Clipboard, KeyRound, Lightbulb, RefreshCw, ShieldCheck, ShieldOff } from 'lucide-preact';
|
import { Clipboard, KeyRound, RefreshCw, ShieldCheck, ShieldOff } from 'lucide-preact';
|
||||||
import { copyTextToClipboard } from '@/lib/clipboard';
|
import { copyTextToClipboard } from '@/lib/clipboard';
|
||||||
import qrcode from 'qrcode-generator';
|
import qrcode from 'qrcode-generator';
|
||||||
import type { Profile } from '@/lib/types';
|
import type { Profile } from '@/lib/types';
|
||||||
import { t } from '@/lib/i18n';
|
import { AVAILABLE_LOCALES, getLocale, setLocale, t, type Locale } from '@/lib/i18n';
|
||||||
import ConfirmDialog from '@/components/ConfirmDialog';
|
import ConfirmDialog from '@/components/ConfirmDialog';
|
||||||
|
|
||||||
interface SettingsPageProps {
|
interface SettingsPageProps {
|
||||||
@@ -79,6 +79,7 @@ export default function SettingsPage(props: SettingsPageProps) {
|
|||||||
const [masterPasswordPrompt, setMasterPasswordPrompt] = useState<null | 'recovery' | 'apiKey' | 'rotateApiKey'>(null);
|
const [masterPasswordPrompt, setMasterPasswordPrompt] = useState<null | 'recovery' | 'apiKey' | 'rotateApiKey'>(null);
|
||||||
const [masterPasswordPromptValue, setMasterPasswordPromptValue] = useState('');
|
const [masterPasswordPromptValue, setMasterPasswordPromptValue] = useState('');
|
||||||
const [masterPasswordPromptSubmitting, setMasterPasswordPromptSubmitting] = useState(false);
|
const [masterPasswordPromptSubmitting, setMasterPasswordPromptSubmitting] = useState(false);
|
||||||
|
const [selectedLocale, setSelectedLocale] = useState<Locale>(() => getLocale());
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
clearLegacyTotpSetupSecrets();
|
clearLegacyTotpSetupSecrets();
|
||||||
@@ -167,6 +168,13 @@ export default function SettingsPage(props: SettingsPageProps) {
|
|||||||
return parsed.toLocaleString();
|
return parsed.toLocaleString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function changeLocale(next: Locale): Promise<void> {
|
||||||
|
if (next === getLocale()) return;
|
||||||
|
setSelectedLocale(next);
|
||||||
|
await setLocale(next);
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="settings-modules-grid">
|
<div className="settings-modules-grid">
|
||||||
<section className="card settings-module">
|
<section className="card settings-module">
|
||||||
@@ -200,9 +208,23 @@ export default function SettingsPage(props: SettingsPageProps) {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="card settings-module settings-module-placeholder">
|
<section className="card settings-module">
|
||||||
<Lightbulb size={26} aria-hidden="true" />
|
<h3>{t('txt_language')}</h3>
|
||||||
<span>{t('txt_in_planning')}</span>
|
<label className="field">
|
||||||
|
<span>{t('txt_display_language')}</span>
|
||||||
|
<select
|
||||||
|
className="input"
|
||||||
|
value={selectedLocale}
|
||||||
|
onInput={(e) => void changeLocale((e.currentTarget as HTMLSelectElement).value as Locale)}
|
||||||
|
>
|
||||||
|
{AVAILABLE_LOCALES.map((option) => (
|
||||||
|
<option key={option.value} value={option.value}>
|
||||||
|
{option.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<div className="field-help">{t('txt_language_saved_locally')}</div>
|
||||||
|
</label>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="card settings-module">
|
<section className="card settings-module">
|
||||||
|
|||||||
+50
-25
@@ -1,63 +1,80 @@
|
|||||||
export type Locale = 'en' | 'zh-CN';
|
export type Locale = 'en' | 'zh-CN' | 'zh-TW' | 'ru';
|
||||||
|
|
||||||
const LOCALE_STORAGE_KEY = 'nodewarden.locale';
|
const LOCALE_STORAGE_KEY = 'nodewarden.locale';
|
||||||
|
|
||||||
type MessageTable = Record<string, string>;
|
type MessageTable = Record<string, string>;
|
||||||
|
|
||||||
|
export const AVAILABLE_LOCALES: readonly { value: Locale; label: string }[] = [
|
||||||
|
{ value: 'en', label: 'English' },
|
||||||
|
{ value: 'zh-CN', label: '简体中文' },
|
||||||
|
{ value: 'zh-TW', label: '繁體中文' },
|
||||||
|
{ value: 'ru', label: 'Русский' },
|
||||||
|
];
|
||||||
|
|
||||||
let locale: Locale = resolveInitialLocale();
|
let locale: Locale = resolveInitialLocale();
|
||||||
let activeMessages: MessageTable = {};
|
let activeMessages: MessageTable = {};
|
||||||
let englishMessages: MessageTable | null = null;
|
|
||||||
const loadedMessages = new Map<Locale, MessageTable>();
|
const loadedMessages = new Map<Locale, MessageTable>();
|
||||||
|
|
||||||
|
function isLocale(value: unknown): value is Locale {
|
||||||
|
return AVAILABLE_LOCALES.some((item) => item.value === value);
|
||||||
|
}
|
||||||
|
|
||||||
function resolveInitialLocale(): Locale {
|
function resolveInitialLocale(): Locale {
|
||||||
try {
|
try {
|
||||||
const saved = localStorage.getItem(LOCALE_STORAGE_KEY);
|
const saved = localStorage.getItem(LOCALE_STORAGE_KEY);
|
||||||
if (saved === 'en' || saved === 'zh-CN') return saved;
|
if (isLocale(saved)) return saved;
|
||||||
} catch {
|
} catch {
|
||||||
// ignore storage errors
|
// ignore storage errors
|
||||||
}
|
}
|
||||||
if (typeof navigator !== 'undefined') {
|
if (typeof navigator !== 'undefined') {
|
||||||
const langs = Array.isArray(navigator.languages) ? navigator.languages : [navigator.language];
|
const langs = Array.isArray(navigator.languages) ? navigator.languages : [navigator.language];
|
||||||
for (const lang of langs) {
|
for (const lang of langs) {
|
||||||
if (String(lang || '').toLowerCase().startsWith('zh')) return 'zh-CN';
|
const normalized = String(lang || '').toLowerCase();
|
||||||
|
if (normalized === 'zh-tw' || normalized === 'zh-hk' || normalized === 'zh-mo' || normalized.includes('hant')) return 'zh-TW';
|
||||||
|
if (normalized.startsWith('zh')) return 'zh-CN';
|
||||||
|
if (normalized.startsWith('ru')) return 'ru';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 'en';
|
return 'en';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadEnglishMessages(): Promise<MessageTable> {
|
|
||||||
if (englishMessages) return englishMessages;
|
|
||||||
const mod = await import('./i18n/locales/en');
|
|
||||||
englishMessages = mod.default;
|
|
||||||
loadedMessages.set('en', englishMessages);
|
|
||||||
return englishMessages;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadLocaleMessages(next: Locale): Promise<MessageTable> {
|
async function loadLocaleMessages(next: Locale): Promise<MessageTable> {
|
||||||
const cached = loadedMessages.get(next);
|
const cached = loadedMessages.get(next);
|
||||||
if (cached) return cached;
|
if (cached) return cached;
|
||||||
|
|
||||||
if (next === 'en') {
|
const mod = next === 'zh-CN'
|
||||||
return loadEnglishMessages();
|
? await import('./i18n/locales/zh-CN')
|
||||||
}
|
: next === 'zh-TW'
|
||||||
|
? await import('./i18n/locales/zh-TW')
|
||||||
|
: next === 'ru'
|
||||||
|
? await import('./i18n/locales/ru')
|
||||||
|
: await import('./i18n/locales/en');
|
||||||
|
loadedMessages.set(next, mod.default);
|
||||||
|
return mod.default;
|
||||||
|
}
|
||||||
|
|
||||||
const [base, overridesMod] = await Promise.all([
|
async function loadFallbackMessages(): Promise<MessageTable> {
|
||||||
loadEnglishMessages(),
|
const cached = loadedMessages.get('en');
|
||||||
import('./i18n/locales/zh-CN'),
|
if (cached) return cached;
|
||||||
]);
|
const mod = await import('./i18n/locales/en');
|
||||||
const merged = { ...base, ...overridesMod.default };
|
loadedMessages.set('en', mod.default);
|
||||||
loadedMessages.set(next, merged);
|
return mod.default;
|
||||||
return merged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type I18nParams = Record<string, string | number | null | undefined>;
|
export type I18nParams = Record<string, string | number | null | undefined>;
|
||||||
|
|
||||||
export async function initI18n(): Promise<void> {
|
export async function initI18n(): Promise<void> {
|
||||||
activeMessages = await loadLocaleMessages(locale);
|
try {
|
||||||
|
activeMessages = await loadLocaleMessages(locale);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load locale, falling back to English:', error);
|
||||||
|
locale = 'en';
|
||||||
|
activeMessages = await loadFallbackMessages();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function t(key: string, params?: I18nParams): string {
|
export function t(key: string, params?: I18nParams): string {
|
||||||
const template = activeMessages[key] ?? englishMessages?.[key] ?? key;
|
const template = activeMessages[key] ?? key;
|
||||||
if (!params) return template;
|
if (!params) return template;
|
||||||
return template.replace(/\{(\w+)\}/g, (_, name: string) => String(params[name] ?? ''));
|
return template.replace(/\{(\w+)\}/g, (_, name: string) => String(params[name] ?? ''));
|
||||||
}
|
}
|
||||||
@@ -67,8 +84,16 @@ export function getLocale(): Locale {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function setLocale(next: Locale): Promise<void> {
|
export async function setLocale(next: Locale): Promise<void> {
|
||||||
|
let nextMessages: MessageTable;
|
||||||
|
try {
|
||||||
|
nextMessages = await loadLocaleMessages(next);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load selected locale, falling back to English:', error);
|
||||||
|
next = 'en';
|
||||||
|
nextMessages = await loadFallbackMessages();
|
||||||
|
}
|
||||||
locale = next;
|
locale = next;
|
||||||
activeMessages = await loadLocaleMessages(next);
|
activeMessages = nextMessages;
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(LOCALE_STORAGE_KEY, next);
|
localStorage.setItem(LOCALE_STORAGE_KEY, next);
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
+844
-839
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,848 @@
|
|||||||
|
// Complete Russian locale. Keep keys and placeholders unchanged.
|
||||||
|
const ru: Record<string, string> = {
|
||||||
|
"txt_backup_destination_detail_note": "",
|
||||||
|
"nav_account_settings": "Настройки учетной записи",
|
||||||
|
"nav_admin_panel": "Панель администратора",
|
||||||
|
"nav_device_management": "Управление устройствами",
|
||||||
|
"nav_my_vault": "Мое хранилище",
|
||||||
|
"nav_sends": "Отправляет",
|
||||||
|
"nav_backup_strategy": "Облачное резервное копирование",
|
||||||
|
"nav_import_export": "Импорт и экспорт",
|
||||||
|
"backup_strategy_title": "Облачное резервное копирование",
|
||||||
|
"backup_strategy_under_construction": "В стадии строительства.",
|
||||||
|
"import_export_title": "Импорт и экспорт",
|
||||||
|
"import_export_under_construction": "В стадии строительства.",
|
||||||
|
"txt_backup_export": "Экспортировать резервную копию",
|
||||||
|
"txt_backup_import": "Восстановить",
|
||||||
|
"txt_backup_include_attachments": "Включить вложения",
|
||||||
|
"txt_backup_export_description": "Загрузите полную резервную копию ZIP-файла экземпляра для хранения вручную.",
|
||||||
|
"txt_backup_import_description": "Загрузите ранее экспортированный ZIP-архив резервной копии и восстановите его в этот экземпляр.",
|
||||||
|
"txt_backup_exporting": "Экспорт...",
|
||||||
|
"txt_backup_importing": "Восстановление...",
|
||||||
|
"txt_backup_restoring": "Восстановление...",
|
||||||
|
"txt_backup_export_success": "Резервная копия экспортирована.",
|
||||||
|
"txt_backup_import_success_relogin": "Резервная копия восстановлена. Пожалуйста, войдите снова.",
|
||||||
|
"txt_backup_restore_success_relogin": "Резервная копия восстановлена. Пожалуйста, войдите снова.",
|
||||||
|
"txt_backup_restore_completed_verified": "Проверка целостности файла резервной копии пройдена.",
|
||||||
|
"txt_backup_restore_completed_without_checksum": "Резервная копия восстановлена. Маркер целостности имени файла не был доступен для проверки.",
|
||||||
|
"txt_backup_remote_restore_completed_verified": "Проверка целостности удаленной резервной копии пройдена.",
|
||||||
|
"txt_backup_remote_restore_completed_without_checksum": "Удаленная резервная копия восстановлена. Маркер целостности имени файла не был доступен для проверки.",
|
||||||
|
"txt_backup_restore_skipped_summary": "{reason}. Пропущено вложение(я) {attachments}.",
|
||||||
|
"txt_backup_restore_skipped_reason_default": "Некоторые файлы не удалось восстановить",
|
||||||
|
"txt_backup_export_failed": "Не удалось экспортировать резервную копию",
|
||||||
|
"txt_backup_import_failed": "Восстановление резервной копии не удалось",
|
||||||
|
"txt_backup_restore_failed": "Восстановление резервной копии не удалось",
|
||||||
|
"txt_backup_integrity_check_failed": "Проверка целостности резервной копии не удалась",
|
||||||
|
"txt_backup_center_title": "Резервное копирование экземпляра",
|
||||||
|
"txt_backup_center_description": "Сохраняйте локальный экспорт для ручного восстановления и настройте один ежедневный целевой объект удаленного резервного копирования для автоматической защиты.",
|
||||||
|
"txt_backup_restore_note": "При восстановлении текущий экземпляр будет перезаписан, если вы выберете поток замены.",
|
||||||
|
"txt_backup_manual": "Ручное резервное копирование",
|
||||||
|
"txt_backup_manual_description": "Экспортируйте ZIP-файл прямо сейчас или импортируйте его обратно в этот экземпляр.",
|
||||||
|
"txt_backup_destinations_title": "Назначения резервного копирования",
|
||||||
|
"txt_backup_destinations_description": "Оставьте здесь несколько целей WebDAV и E3. Выберите один слева, чтобы отредактировать или просмотреть его.",
|
||||||
|
"txt_backup_recommend_title": "Рекомендуемое хранилище",
|
||||||
|
"txt_backup_recommend_open_signup": "Открыть регистрацию",
|
||||||
|
"txt_backup_recommend_open_signup_aff": "Открытая регистрация (AFF)",
|
||||||
|
"txt_backup_recommend_open_guide": "Открыть руководство",
|
||||||
|
"txt_backup_recommend_empty": "Пока нет рекомендаций.",
|
||||||
|
"txt_backup_recommend_referral_label": "Реферальный код",
|
||||||
|
"txt_backup_recommend_referral_note": "Используйте его при регистрации, чтобы получить дополнительно 5 ГБ. Автор получает 2 ГБ.",
|
||||||
|
"txt_backup_recommend_infinicloud_summary": "Нужен только адрес электронной почты. 20 ГБ бесплатно, всего 25 ГБ с реферальным кодом.",
|
||||||
|
"txt_backup_recommend_infinicloud_step_1": "Зарегистрируйте учетную запись InfiniCLOUD, используя только свой адрес электронной почты.",
|
||||||
|
"txt_backup_recommend_infinicloud_step_2_prefix": "Открыть",
|
||||||
|
"txt_backup_recommend_infinicloud_step_2_suffix": "и включите подключение приложений.",
|
||||||
|
"txt_backup_recommend_infinicloud_step_3": "Используйте идентификатор подключения в качестве имени пользователя WebDAV и пароль приложения в качестве пароля WebDAV.",
|
||||||
|
"txt_backup_recommend_infinicloud_step_4": "Введите реферальный код 2HC5E в разделе «Реферальный бонус» внизу моей страницы, чтобы получить дополнительно 5 ГБ.",
|
||||||
|
"txt_backup_recommend_open_password": "Настройки пароля",
|
||||||
|
"txt_backup_recommend_open_storage": "Открытое хранилище",
|
||||||
|
"txt_backup_recommend_koofr_summary": "Нужен только адрес электронной почты. 10 ГБ бесплатно, и он может соединить Google Drive, OneDrive и Dropbox через WebDAV.",
|
||||||
|
"txt_backup_recommend_koofr_password_link": "Настройки пароля",
|
||||||
|
"txt_backup_recommend_koofr_storage_link": "Хранение",
|
||||||
|
"txt_backup_recommend_koofr_step_1": "Зарегистрируйте учетную запись Koofr, используя только свой адрес электронной почты.",
|
||||||
|
"txt_backup_recommend_koofr_step_2_prefix": "Открыть",
|
||||||
|
"txt_backup_recommend_koofr_step_2_suffix": ", создайте новый пароль приложения, используйте свой адрес электронной почты в качестве имени пользователя WebDAV и используйте пароль приложения в качестве пароля WebDAV.",
|
||||||
|
"txt_backup_recommend_koofr_step_3": "Собственный адрес Куфра в WebDAV — https://app.koofr.net/dav/Koofr.",
|
||||||
|
"txt_backup_recommend_koofr_step_4": "Куфр также может подключать Google Drive, OneDrive и Dropbox. Бесплатные пользователи могут подключить до двух учетных записей хранения.",
|
||||||
|
"txt_backup_recommend_koofr_step_5_prefix": "Открыть",
|
||||||
|
"txt_backup_recommend_koofr_step_5_suffix": ", нажмите «Подключиться» на левой боковой панели и выберите облачное хранилище, которое хотите подключить.",
|
||||||
|
"txt_backup_recommend_koofr_dav_intro": "После подключения учетной записи хранения сохраните тот же адрес электронной почты и пароль приложения и переключите только адрес WebDAV:",
|
||||||
|
"txt_backup_recommend_koofr_dav_self": "Куфр",
|
||||||
|
"txt_backup_recommend_pcloud_summary": "Нужен только адрес электронной почты. До 10 ГБ бесплатно со стандартным доступом WebDAV.",
|
||||||
|
"txt_backup_recommend_pcloud_step_1": "Зарегистрируйте учетную запись pCloud, используя только свой адрес электронной почты.",
|
||||||
|
"txt_backup_recommend_pcloud_step_2": "Используйте https://webdav.ploud.com/ в качестве URL-адреса сервера WebDAV.",
|
||||||
|
"txt_backup_recommend_pcloud_step_3": "Используйте свой регистрационный адрес электронной почты в качестве имени пользователя WebDAV и пароль своей учетной записи в качестве пароля WebDAV.",
|
||||||
|
"txt_backup_add_destination": "Добавить пункт назначения",
|
||||||
|
"txt_backup_schedule_panel_title": "Автоматическое расписание",
|
||||||
|
"txt_backup_schedule_panel_note": "Каждый пункт назначения может иметь собственный ежедневный график резервного копирования.",
|
||||||
|
"txt_backup_scheduled_target": "Запланированная цель",
|
||||||
|
"txt_backup_destination_active_badge": "Автоматическое включение",
|
||||||
|
"txt_backup_destination_idle_badge": "Автовыключение",
|
||||||
|
"txt_backup_destination_last_success": "Последний успех: {time}",
|
||||||
|
"txt_backup_destination_never_run": "Пока ни одного успешного запуска",
|
||||||
|
"txt_backup_destination_detail_title": "Детали пункта назначения",
|
||||||
|
"txt_backup_destination_name": "Имя места назначения",
|
||||||
|
"txt_backup_set_scheduled_target": "Используйте для ежедневного резервного копирования",
|
||||||
|
"txt_backup_delete_destination": "Удалить",
|
||||||
|
"txt_backup_destination_deleted": "Место назначения резервного копирования удалено.",
|
||||||
|
"txt_backup_delete_destination_confirm_message": "Удалить место назначения резервного копирования «{name}»? Это невозможно отменить.",
|
||||||
|
"txt_backup_select_destination": "Сначала выберите место назначения резервного копирования из списка.",
|
||||||
|
"txt_backup_remote_save_first": "Сначала сохраните это место назначения, прежде чем просматривать файлы удаленных резервных копий.",
|
||||||
|
"txt_backup_automation": "Автоматическое резервное копирование",
|
||||||
|
"txt_backup_automation_description": "Выберите пункт назначения, сохраните учетные данные и позвольте работнику загружать одну резервную копию каждый день.",
|
||||||
|
"txt_backup_settings_saved": "Настройки резервной копии сохранены.",
|
||||||
|
"txt_backup_settings_save_failed": "Не удалось сохранить настройки резервного копирования.",
|
||||||
|
"txt_backup_settings_load_failed": "Не удалось загрузить настройки резервного копирования.",
|
||||||
|
"txt_backup_save_settings": "Сохранить настройки",
|
||||||
|
"txt_backup_saving": "Сохранение...",
|
||||||
|
"txt_backup_enable_action": "Включить",
|
||||||
|
"txt_backup_disable_action": "Отключить",
|
||||||
|
"txt_backup_run_now": "Запустите удаленное резервное копирование сейчас",
|
||||||
|
"txt_backup_run_manual": "Запустить вручную",
|
||||||
|
"txt_backup_running_now": "Бег...",
|
||||||
|
"txt_backup_remote_run_success": "Удаленное резервное копирование завершено",
|
||||||
|
"txt_backup_remote_run_success_verified": "Удаленное резервное копирование завершено, проверка целостности пройдена.",
|
||||||
|
"txt_backup_remote_run_failed": "Удаленное резервное копирование не удалось",
|
||||||
|
"txt_backup_remote_title": "Удаленное резервное копирование",
|
||||||
|
"txt_backup_remote_note": "Просмотрите сохраненное место назначения и выберите резервную копию ZIP для загрузки или восстановления.",
|
||||||
|
"txt_backup_remote_saved_basis": "При удаленном просмотре используются последние сохраненные настройки места назначения, а не несохраненные изменения формы.",
|
||||||
|
"txt_backup_remote_refresh": "Обновить",
|
||||||
|
"txt_backup_remote_root": "Корень",
|
||||||
|
"txt_backup_remote_up": "Вверх",
|
||||||
|
"txt_backup_remote_open": "Открыть",
|
||||||
|
"txt_backup_remote_download": "Скачать",
|
||||||
|
"txt_backup_remote_downloading": "Загрузка...",
|
||||||
|
"txt_backup_remote_restore": "Восстановить",
|
||||||
|
"txt_backup_remote_restore_stage_prepare": "Подготовка удаленного восстановления из резервной копии...",
|
||||||
|
"txt_backup_remote_restore_stage_replace": "Очистка текущих данных и восстановление удаленной резервной копии...",
|
||||||
|
"txt_backup_progress_kicker": "Задача резервного копирования",
|
||||||
|
"txt_backup_progress_subject": "Текущий элемент: {name}",
|
||||||
|
"txt_backup_restore_progress_kicker": "Восстановить прогресс",
|
||||||
|
"txt_backup_restore_progress_local_title": "Восстановление локальной резервной копии",
|
||||||
|
"txt_backup_restore_progress_remote_title": "Восстановление удаленной резервной копии",
|
||||||
|
"txt_backup_export_progress_title": "Экспорт резервной копии",
|
||||||
|
"txt_backup_remote_run_progress_title": "Запуск удаленного резервного копирования",
|
||||||
|
"txt_backup_restore_progress_file": "Текущий файл: {name}",
|
||||||
|
"txt_backup_restore_progress_elapsed": "Прошло {seconds} с.",
|
||||||
|
"txt_backup_archive_progress_collect_title": "Сбор данных хранилища",
|
||||||
|
"txt_backup_archive_progress_collect_detail": "Сервер читает таблицы базы данных и собирает полезные данные для резервного копирования.",
|
||||||
|
"txt_backup_archive_progress_collect_with_attachments_detail": "Сервер читает таблицы базы данных и собирает метаданные вложений для полезной нагрузки резервного копирования.",
|
||||||
|
"txt_backup_archive_progress_package_title": "Упаковка резервного архива",
|
||||||
|
"txt_backup_archive_progress_package_detail": "Сервер генерирует резервный ZIP-файл и вычисляет префикс его контрольной суммы.",
|
||||||
|
"txt_backup_archive_progress_package_with_attachments_detail": "Сервер генерирует резервные метаданные ZIP и вычисляет префикс контрольной суммы для экспорта с учетом вложений.",
|
||||||
|
"txt_backup_archive_progress_ready_title": "Подготовка загрузки",
|
||||||
|
"txt_backup_archive_progress_ready_detail": "Резервный архив готов и возвращается в браузер.",
|
||||||
|
"txt_backup_export_progress_fetch_attachments_title": "Загрузка вложенных файлов",
|
||||||
|
"txt_backup_export_progress_fetch_attachments_detail": "Браузер извлекает объекты вложений и добавляет их в пакет экспорта.",
|
||||||
|
"txt_backup_export_progress_rebuild_title": "Восстановление экспортного архива",
|
||||||
|
"txt_backup_export_progress_rebuild_detail": "Браузер восстанавливает окончательный ZIP-архив и обновляет суффикс контрольной суммы.",
|
||||||
|
"txt_backup_export_progress_save_title": "Сохранение файла экспорта",
|
||||||
|
"txt_backup_export_progress_save_detail": "Браузер подготавливает окончательный файл резервной копии для загрузки.",
|
||||||
|
"txt_backup_export_progress_complete_title": "Экспорт завершен",
|
||||||
|
"txt_backup_export_progress_complete_detail": "Резервный экспорт готов.",
|
||||||
|
"txt_backup_export_progress_failed_title": "Экспорт не удался",
|
||||||
|
"txt_backup_export_progress_failed_detail": "Экспорт резервной копии не удалось завершить.",
|
||||||
|
"txt_backup_remote_run_progress_prepare_title": "Подготовка удаленного резервного копирования",
|
||||||
|
"txt_backup_remote_run_progress_prepare_detail": "Сервер загружает выбранное место назначения и готовит этот запуск резервного копирования.",
|
||||||
|
"txt_backup_remote_run_progress_sync_attachments_title": "Проверка индекса вложений",
|
||||||
|
"txt_backup_remote_run_progress_sync_attachments_detail": "Сервер сравнивает метаданные вложений, поэтому загружаются только отсутствующие объекты вложений.",
|
||||||
|
"txt_backup_remote_run_progress_sync_attachments_skipped_detail": "Эта резервная копия не включает вложения, поэтому синхронизация вложений пропускается.",
|
||||||
|
"txt_backup_remote_run_progress_upload_title": "Загрузка резервного архива",
|
||||||
|
"txt_backup_remote_run_progress_upload_detail": "Сервер загружает резервную копию ZIP в удаленное место назначения.",
|
||||||
|
"txt_backup_remote_run_progress_verify_title": "Проверка загруженного архива",
|
||||||
|
"txt_backup_remote_run_progress_verify_detail": "Сервер загружает загруженный ZIP-архив обратно и проверяет его контрольную сумму и размер.",
|
||||||
|
"txt_backup_remote_run_progress_cleanup_title": "Очистка старых резервных копий",
|
||||||
|
"txt_backup_remote_run_progress_cleanup_detail": "Сервер удаляет старые файлы резервных копий в соответствии с политикой хранения.",
|
||||||
|
"txt_backup_remote_run_progress_complete_title": "Удаленное резервное копирование завершено",
|
||||||
|
"txt_backup_remote_run_progress_complete_detail": "Удаленная резервная копия успешно загружена и проверена.",
|
||||||
|
"txt_backup_remote_run_progress_failed_title": "Удаленное резервное копирование не удалось",
|
||||||
|
"txt_backup_remote_run_progress_failed_detail": "Удаленное резервное копирование не удалось завершить.",
|
||||||
|
"txt_backup_restore_progress_local_upload_title": "Загрузка резервного архива",
|
||||||
|
"txt_backup_restore_progress_local_upload_detail": "Выбранный ZIP-файл отправляется на обработку на сервер.",
|
||||||
|
"txt_backup_restore_progress_local_shadow_title": "Создание теневого рабочего пространства",
|
||||||
|
"txt_backup_restore_progress_local_shadow_detail": "Сервер подготавливает изолированную область восстановления, поэтому текущие данные остаются нетронутыми до прохождения проверки.",
|
||||||
|
"txt_backup_restore_progress_local_data_title": "Запись данных хранилища",
|
||||||
|
"txt_backup_restore_progress_local_data_detail": "Сервер импортирует пользователей, папки, элементы хранилища и связанные метаданные в теневые таблицы.",
|
||||||
|
"txt_backup_restore_progress_local_files_title": "Восстановление вложенных файлов",
|
||||||
|
"txt_backup_restore_progress_local_files_detail": "Сервер записывает объекты вложений обратно в хранилище и удаляет все строки вложений, которые невозможно восстановить.",
|
||||||
|
"txt_backup_restore_progress_local_finalize_title": "Проверка и переключение данных",
|
||||||
|
"txt_backup_restore_progress_local_finalize_detail": "Сервер выполняет окончательную проверку, а затем заменяет проверенные данные восстановления в действующие таблицы.",
|
||||||
|
"txt_backup_restore_progress_remote_fetch_title": "Чтение удаленной резервной копии",
|
||||||
|
"txt_backup_restore_progress_remote_fetch_detail": "Сервер загружает выбранный пакет резервной копии из удаленного места назначения.",
|
||||||
|
"txt_backup_restore_progress_remote_shadow_title": "Создание теневого рабочего пространства",
|
||||||
|
"txt_backup_restore_progress_remote_shadow_detail": "Сервер подготавливает изолированную область восстановления, поэтому текущие данные остаются нетронутыми до прохождения проверки.",
|
||||||
|
"txt_backup_restore_progress_remote_data_title": "Запись данных хранилища",
|
||||||
|
"txt_backup_restore_progress_remote_data_detail": "Сервер импортирует пользователей, папки, элементы хранилища и связанные метаданные в теневые таблицы.",
|
||||||
|
"txt_backup_restore_progress_remote_files_title": "Восстановление удаленных вложений",
|
||||||
|
"txt_backup_restore_progress_remote_files_detail": "Сервер извлекает необходимые объекты вложений из удаленного хранилища и записывает их обратно в локальное хранилище.",
|
||||||
|
"txt_backup_restore_progress_remote_finalize_title": "Проверка и переключение данных",
|
||||||
|
"txt_backup_restore_progress_remote_finalize_detail": "Сервер выполняет окончательную проверку, а затем переключает проверенные данные восстановления в живые таблицы.",
|
||||||
|
"txt_backup_remote_loading": "Загрузка удаленных резервных копий...",
|
||||||
|
"txt_backup_remote_cached_empty": "Нажмите «Обновить», чтобы загрузить это место назначения.",
|
||||||
|
"txt_backup_remote_empty": "В этой папке не найдено файлов резервных копий.",
|
||||||
|
"txt_backup_remote_folder": "Папка",
|
||||||
|
"txt_backup_remote_unknown_time": "Неизвестное время",
|
||||||
|
"txt_backup_remote_current_path": "Текущая папка",
|
||||||
|
"txt_backup_remote_load_failed": "Не удалось загрузить удаленные резервные копии.",
|
||||||
|
"txt_backup_remote_invalid_response": "Неверный ответ удаленного резервного копирования",
|
||||||
|
"txt_backup_remote_download_failed": "Не удалось загрузить удаленную резервную копию.",
|
||||||
|
"txt_backup_remote_delete_success": "Удаленная резервная копия удалена.",
|
||||||
|
"txt_backup_remote_delete_failed": "Не удалось удалить удаленную резервную копию.",
|
||||||
|
"txt_backup_remote_delete_confirm_message": "Удалить файл резервной копии «{name}»? Это невозможно отменить.",
|
||||||
|
"txt_backup_remote_deleting": "Удаление...",
|
||||||
|
"txt_backup_remote_restore_failed": "Не удалось восстановить удаленную резервную копию.",
|
||||||
|
"txt_backup_restore_checksum_warning_title": "Предупреждение о целостности резервной копии",
|
||||||
|
"txt_backup_restore_checksum_warning_message": "Выбранный файл резервной копии «{name}» не прошел проверку целостности имени файла. Ожидаемый префикс {expected}, фактический префикс {actual}. Возможно, файл неполный или поврежден. Продолжение может привести к восстановлению поврежденных данных.",
|
||||||
|
"txt_backup_remote_restore_checksum_warning_message": "Файл удаленной резервной копии «{name}» не прошел проверку целостности имени файла. Ожидаемый префикс {expected}, фактический префикс {actual}. Файл может быть поврежден во время загрузки или хранения. Продолжение может привести к восстановлению поврежденных данных и может привести к серьезной потере данных.",
|
||||||
|
"txt_backup_restore_checksum_warning_message_fallback": "Выбранный файл резервной копии не прошел проверку целостности. Продолжение может привести к восстановлению поврежденных данных.",
|
||||||
|
"txt_backup_restore_checksum_warning_confirm": "Продолжить восстановление",
|
||||||
|
"txt_backup_remote_restore_invalid_response": "Неверный ответ на удаленное восстановление из резервной копии",
|
||||||
|
"txt_backup_remote_run_invalid_response": "Неверный ответ на удаленное резервное копирование.",
|
||||||
|
"txt_backup_settings_invalid_response": "Неверный ответ на настройки резервного копирования",
|
||||||
|
"txt_backup_import_invalid_response": "Неверный ответ на импорт резервной копии",
|
||||||
|
"txt_backup_destination": "Место назначения резервного копирования",
|
||||||
|
"txt_backup_protocol_webdav": "ВебДАВ",
|
||||||
|
"txt_backup_protocol_e3": "Е3",
|
||||||
|
"txt_backup_recommend_group_webdav": "ВебДАВ",
|
||||||
|
"txt_backup_recommend_group_s3": "S3",
|
||||||
|
"txt_backup_destination_name_default_webdav": "ВебДАВ {index}",
|
||||||
|
"txt_backup_destination_name_default_e3": "E3 {index}",
|
||||||
|
"txt_backup_type": "Тип резервной копии",
|
||||||
|
"txt_backup_destination_reserved": "Зарезервированный слот",
|
||||||
|
"txt_backup_time": "Время резервного копирования",
|
||||||
|
"txt_backup_start_time": "Время начала",
|
||||||
|
"txt_backup_timezone": "Часовой пояс",
|
||||||
|
"txt_backup_interval_hours": "Каждый",
|
||||||
|
"txt_backup_interval_hours_suffix": "часы",
|
||||||
|
"txt_backup_interval_hours_presets": "Предварительные настройки быстрых интервалов",
|
||||||
|
"txt_backup_frequency": "Частота",
|
||||||
|
"txt_backup_frequency_daily": "Ежедневно",
|
||||||
|
"txt_backup_frequency_weekly": "Еженедельно",
|
||||||
|
"txt_backup_frequency_monthly": "Ежемесячно",
|
||||||
|
"txt_backup_day_of_week": "День недели",
|
||||||
|
"txt_backup_day_of_month": "День месяца",
|
||||||
|
"txt_backup_weekday_monday": "понедельник",
|
||||||
|
"txt_backup_weekday_tuesday": "вторник",
|
||||||
|
"txt_backup_weekday_wednesday": "среда",
|
||||||
|
"txt_backup_weekday_thursday": "Четверг",
|
||||||
|
"txt_backup_weekday_friday": "пятница",
|
||||||
|
"txt_backup_weekday_saturday": "Суббота",
|
||||||
|
"txt_backup_weekday_sunday": "воскресенье",
|
||||||
|
"txt_backup_retention_count": "Держите",
|
||||||
|
"txt_backup_retention_count_suffix": "предметы",
|
||||||
|
"txt_backup_retention_count_hint": "Оставьте пустым, чтобы сохранить все файлы резервных копий. Новые пункты назначения по умолчанию равны 30.",
|
||||||
|
"txt_backup_destination_include_attachments": "Включить вложения",
|
||||||
|
"txt_backup_include_attachments_help_button": "Помощь по резервному копированию вложений",
|
||||||
|
"txt_backup_include_attachments_help": "Вложения сохраняются постепенно в папке удаленных вложений, поэтому при более поздних резервных копиях обычно загружаются только новые файлы. Локальное удаление вложения не приводит к удалению более ранних удаленных копий. Во время восстановления NodeWarden считывает необходимые файлы из папки вложений и пропускает все вложения, которые больше не доступны.",
|
||||||
|
"txt_backup_enable_schedule": "Включить автоматическое ежедневное резервное копирование",
|
||||||
|
"txt_backup_schedule_note": "Работник проверяет расписание каждые 5 минут. Он начинается в выбранное время в выбранном часовом поясе, затем повторяется с выбранным часовым интервалом и сбрасывается с этого времени каждый день.",
|
||||||
|
"txt_backup_schedule_disabled": "Отключено",
|
||||||
|
"txt_backup_schedule_status": "Расписание",
|
||||||
|
"txt_backup_schedule_summary": "Начало в {time} каждые {interval} часов ({timezone}).",
|
||||||
|
"txt_backup_schedule_empty": "Планы автоматического резервного копирования пока не включены.",
|
||||||
|
"txt_backup_last_success": "Последний успех",
|
||||||
|
"txt_backup_last_target": "Последняя цель",
|
||||||
|
"txt_backup_last_file": "Последний файл",
|
||||||
|
"txt_backup_last_error_prefix": "Последняя ошибка",
|
||||||
|
"txt_backup_none_yet": "Удаленное резервное копирование еще не завершено",
|
||||||
|
"txt_backup_not_configured": "Не настроено",
|
||||||
|
"txt_backup_never": "Никогда",
|
||||||
|
"txt_backup_unknown_size": "Неизвестный размер",
|
||||||
|
"txt_backup_webdav_url": "URL-адрес сервера WebDAV",
|
||||||
|
"txt_backup_webdav_username": "Имя пользователя WebDAV",
|
||||||
|
"txt_backup_webdav_password": "Пароль WebDAV",
|
||||||
|
"txt_backup_webdav_path": "Удаленная папка",
|
||||||
|
"txt_backup_e3_endpoint": "Конечная точка E3",
|
||||||
|
"txt_backup_e3_bucket": "Ведро",
|
||||||
|
"txt_backup_e3_region": "Регион",
|
||||||
|
"txt_backup_e3_access_key": "Ключ доступа",
|
||||||
|
"txt_backup_e3_secret_key": "Секретный ключ",
|
||||||
|
"txt_backup_e3_path": "Удаленный путь",
|
||||||
|
"txt_backup_reserved_name": "Зарезервированное имя поставщика",
|
||||||
|
"txt_backup_reserved_notes": "Зарезервированные заметки",
|
||||||
|
"txt_backup_reserved_notes_placeholder": "Оставьте заметку для следующего типа пункта назначения",
|
||||||
|
"txt_backup_reserved_hint": "Этот слот зарезервирован для будущего пункта назначения. Теперь вы можете сохранять заметки, но автоматическая загрузка остается отключенной.",
|
||||||
|
"txt_backup_file": "Резервный файл",
|
||||||
|
"txt_backup_file_required": "Пожалуйста, выберите файл резервной копии",
|
||||||
|
"txt_backup_no_file_selected": "Файл резервной копии не выбран",
|
||||||
|
"txt_backup_selected_file_name": "Выбранный файл: {name}",
|
||||||
|
"txt_backup_replace_confirm_title": "Заменить текущие данные экземпляра",
|
||||||
|
"txt_backup_replace_confirm_message": "Текущий экземпляр уже содержит данные. Продолжить восстановление и заменить текущие данные экземпляра выбранной резервной копией после успешной проверки?",
|
||||||
|
"txt_backup_clear_and_import": "Заменить и импортировать",
|
||||||
|
"txt_backup_clear_and_restore": "Заменить и восстановить",
|
||||||
|
"txt_access_count": "Количество доступов",
|
||||||
|
"txt_accessed_count_times": "Доступ {count} раз",
|
||||||
|
"txt_actions": "Действия",
|
||||||
|
"txt_add": "Добавить",
|
||||||
|
"txt_add_field": "Добавить поле",
|
||||||
|
"txt_add_website": "Добавить веб-сайт",
|
||||||
|
"txt_added": "Добавлено",
|
||||||
|
"txt_additional_options": "Дополнительные опции",
|
||||||
|
"txt_address": "Адрес",
|
||||||
|
"txt_address_1": "Адрес 1",
|
||||||
|
"txt_address_2": "Адрес 2",
|
||||||
|
"txt_address_3": "Адрес 3",
|
||||||
|
"txt_all_device_authorizations_revoked": "Все доверие к устройствам отозвано",
|
||||||
|
"txt_all_invites_deleted": "Все приглашения удалены",
|
||||||
|
"txt_all_items": "Все предметы",
|
||||||
|
"txt_all_sends": "Все отправки",
|
||||||
|
"txt_android": "Андроид",
|
||||||
|
"txt_are_you_sure_you_want_to_delete_count_selected_items": "Вы уверены, что хотите удалить выбранные элементы {count}?",
|
||||||
|
"txt_are_you_sure_you_want_to_delete_count_selected_items_permanently": "Вы уверены, что хотите навсегда удалить выбранные элементы {count}?",
|
||||||
|
"txt_are_you_sure_you_want_to_delete_this_item": "Вы уверены, что хотите удалить этот элемент?",
|
||||||
|
"txt_are_you_sure_you_want_to_delete_this_passkey": "Вы уверены, что хотите удалить этот ключ доступа?",
|
||||||
|
"txt_are_you_sure_you_want_to_log_out": "Вы уверены, что хотите выйти?",
|
||||||
|
"txt_authenticator_key": "Ключ аутентификации",
|
||||||
|
"txt_authorized_devices": "Авторизованные устройства",
|
||||||
|
"txt_auto_copy_link_after_save": "Автоматическое копирование ссылки после сохранения",
|
||||||
|
"txt_autofill_options": "Параметры автозаполнения",
|
||||||
|
"txt_back_to_login": "Вернуться к входу",
|
||||||
|
"txt_ban": "Запретить",
|
||||||
|
"txt_boolean": "логическое значение",
|
||||||
|
"txt_brand": "Бренд",
|
||||||
|
"txt_bulk_delete_failed": "Массовое удаление не удалось",
|
||||||
|
"txt_bulk_permanent_delete_failed": "Не удалось выполнить массовое окончательное удаление.",
|
||||||
|
"txt_bulk_restore_failed": "Массовое восстановление не удалось",
|
||||||
|
"txt_bulk_delete_sends_failed": "Массовое удаление не удалось отправить",
|
||||||
|
"txt_bulk_move_failed": "Массовое перемещение не удалось",
|
||||||
|
"txt_cancel": "Отмена",
|
||||||
|
"txt_continue": "Продолжить",
|
||||||
|
"txt_card": "Карта",
|
||||||
|
"txt_card_details": "Детали карты",
|
||||||
|
"txt_cardholder_name": "Имя владельца карты",
|
||||||
|
"txt_change_master_password": "Изменить главный пароль",
|
||||||
|
"txt_change_password": "Изменить пароль",
|
||||||
|
"txt_change_password_failed": "Сменить пароль не удалось",
|
||||||
|
"txt_change_password_confirm_and_sign_out_all_devices": "Изменение главного пароля приведет к выходу из системы всех устройств, включая этот веб-сеанс. Продолжать?",
|
||||||
|
"txt_copy_failed": "Не удалось скопировать",
|
||||||
|
"txt_checked": "Проверено",
|
||||||
|
"txt_choose_destination_folder": "Выберите папку назначения.",
|
||||||
|
"txt_chrome_browser": "Браузер Chrome",
|
||||||
|
"txt_chrome_extension": "Расширение Chrome",
|
||||||
|
"txt_city_town": "Город / Город",
|
||||||
|
"txt_code": "Код",
|
||||||
|
"txt_company": "Компания",
|
||||||
|
"txt_configure_custom_field_values": "Настройте значения настраиваемых полей.",
|
||||||
|
"txt_confirm": "Подтвердить",
|
||||||
|
"txt_confirm_master_password": "Подтвердите мастер-пароль",
|
||||||
|
"txt_confirm_password": "Подтвердите пароль",
|
||||||
|
"txt_copy": "Копировать",
|
||||||
|
"txt_code_copied": "Код скопирован.",
|
||||||
|
"txt_copy_code": "Копировать код",
|
||||||
|
"txt_copy_link": "Копировать ссылку",
|
||||||
|
"txt_copy_secret": "Копировать секрет",
|
||||||
|
"txt_country": "Страна",
|
||||||
|
"txt_create": "Создать",
|
||||||
|
"txt_create_account": "Создать учетную запись",
|
||||||
|
"txt_registering": "Создание учетной записи...",
|
||||||
|
"txt_create_folder": "Создать папку",
|
||||||
|
"txt_create_folder_failed": "Создать папку не удалось",
|
||||||
|
"txt_create_item_failed": "Создать элемент не удалось",
|
||||||
|
"txt_create_send_failed": "Создать отправить не удалось",
|
||||||
|
"txt_create_timed_invite": "Создать приглашение на время",
|
||||||
|
"txt_created_value": "Создано: {value}",
|
||||||
|
"txt_current_new_password_is_required": "Требуется текущий/новый пароль",
|
||||||
|
"txt_current_password": "Текущий пароль",
|
||||||
|
"txt_custom_fields": "Пользовательские поля",
|
||||||
|
"txt_decrypt_failed": "(Расшифровать не удалось)",
|
||||||
|
"txt_decrypt_failed_2": "Расшифровать не удалось",
|
||||||
|
"txt_delete": "Удалить",
|
||||||
|
"txt_delete_all": "Удалить все",
|
||||||
|
"txt_delete_all_invite_codes_active_inactive": "Удалить все пригласительные коды (активные/неактивные)?",
|
||||||
|
"txt_delete_all_invites": "Удалить все приглашения",
|
||||||
|
"txt_delete_item": "Удалить элемент",
|
||||||
|
"txt_delete_passkey": "Удалить пароль",
|
||||||
|
"txt_delete_item_failed": "Удалить элемент не удалось",
|
||||||
|
"txt_delete_permanently": "Удалить навсегда",
|
||||||
|
"txt_archive": "Архив",
|
||||||
|
"txt_archive_item": "Архивный элемент",
|
||||||
|
"txt_archive_item_message": "После архивирования этот элемент будет исключен из общих результатов поиска и предложений автозаполнения.",
|
||||||
|
"txt_archive_selected_items": "Архивные элементы",
|
||||||
|
"txt_archive_selected_items_message": "После архивирования выбранные элементы {count} будут исключены из общих результатов поиска и предложений автозаполнения.",
|
||||||
|
"txt_archived": "В архиве",
|
||||||
|
"txt_archive_selected": "Архив",
|
||||||
|
"txt_item_archived": "Объект заархивирован",
|
||||||
|
"txt_item_unarchived": "Объект разархивирован",
|
||||||
|
"txt_archived_selected_items": "Выбранные элементы заархивированы",
|
||||||
|
"txt_unarchived_selected_items": "Разархивированы выбранные элементы",
|
||||||
|
"txt_archive_item_failed": "Архивировать элемент не удалось",
|
||||||
|
"txt_unarchive_item_failed": "Разархивировать элемент не удалось",
|
||||||
|
"txt_bulk_archive_failed": "Массовое архивирование не удалось",
|
||||||
|
"txt_bulk_unarchive_failed": "Массовое разархивирование не удалось",
|
||||||
|
"txt_unarchive": "Разархивировать",
|
||||||
|
"txt_delete_selected": "Удалить",
|
||||||
|
"txt_delete_selected_items": "Удалить выбранные элементы",
|
||||||
|
"txt_delete_selected_items_permanently": "Удалить выбранные элементы навсегда",
|
||||||
|
"txt_delete_send_failed": "Удаление, отправка не удалась",
|
||||||
|
"txt_delete_this_user_and_all_user_data": "Удалить этого пользователя и все пользовательские данные?",
|
||||||
|
"txt_delete_user": "Удалить пользователя",
|
||||||
|
"txt_deleted_selected_items": "Удалены выбранные элементы",
|
||||||
|
"txt_deleted_selected_items_permanently": "Безвозвратно удалены выбранные элементы",
|
||||||
|
"txt_restored_selected_items": "Восстановлены выбранные элементы",
|
||||||
|
"txt_deleted_selected_sends": "Удалены выбранные отправки",
|
||||||
|
"txt_deletion_date": "Дата удаления",
|
||||||
|
"txt_deletion_days": "Дни удаления",
|
||||||
|
"txt_device": "Устройство",
|
||||||
|
"txt_device_authorization_revoked": "Доверие к устройству отозвано",
|
||||||
|
"txt_device_management": "Управление устройствами",
|
||||||
|
"txt_device_note": "Примечание устройства",
|
||||||
|
"txt_device_note_required": "Укажите имя устройства.",
|
||||||
|
"txt_device_note_updated": "Имя устройства обновлено.",
|
||||||
|
"txt_device_removed": "Устройство удалено",
|
||||||
|
"txt_load_devices_failed": "Не удалось загрузить устройства.",
|
||||||
|
"txt_disable_this_send": "Отключить эту отправку",
|
||||||
|
"txt_disable_totp": "Отключить TOTP",
|
||||||
|
"txt_disable_totp_failed": "Отключить TOTP не удалось",
|
||||||
|
"txt_download": "Скачать",
|
||||||
|
"txt_downloading": "Загрузка...",
|
||||||
|
"txt_downloading_percent": "Загрузка {percent}%",
|
||||||
|
"txt_attachment": "Приложение",
|
||||||
|
"txt_uploading_attachment_named": "Загрузка {name}...",
|
||||||
|
"txt_uploading_attachment_named_percent": "Загрузка {name} {percent}%",
|
||||||
|
"txt_uploading_file_named": "Загрузка {name}...",
|
||||||
|
"txt_uploading_file_named_percent": "Загрузка {name} {percent}%",
|
||||||
|
"txt_download_failed": "Загрузка не удалась",
|
||||||
|
"txt_edge_browser": "Крайний браузер",
|
||||||
|
"txt_edge_extension": "Расширение края",
|
||||||
|
"txt_edit": "Редактировать",
|
||||||
|
"txt_edit_send": "Редактировать Отправить",
|
||||||
|
"txt_email": "электронная почта",
|
||||||
|
"txt_email_password_and_recovery_code_are_required": "Требуется адрес электронной почты, пароль и код восстановления.",
|
||||||
|
"txt_enable_totp": "Включить TOTP",
|
||||||
|
"txt_enable_totp_failed": "Включить TOTP не удалось",
|
||||||
|
"txt_enabled": "Включено",
|
||||||
|
"txt_encrypted_file": "Зашифрованный файл",
|
||||||
|
"txt_encrypted_file_2": "Зашифрованный файл",
|
||||||
|
"txt_enter_a_folder_name": "Введите имя папки.",
|
||||||
|
"txt_enter_master_password_to_disable_two_step_verification": "Введите мастер-пароль, чтобы отключить двухэтапную проверку.",
|
||||||
|
"txt_enter_master_password_to_continue": "Введите свой мастер-пароль, чтобы продолжить.",
|
||||||
|
"txt_enter_master_password_to_view_this_item": "Введите мастер-пароль, чтобы просмотреть этот элемент.",
|
||||||
|
"txt_expiration_date": "Срок годности",
|
||||||
|
"txt_expiration_days_0_never": "Дни истечения срока действия (0 = никогда)",
|
||||||
|
"txt_expires_at": "Срок действия истекает в",
|
||||||
|
"txt_expires_at_value": "Срок действия истекает: {value}",
|
||||||
|
"txt_expiry": "Срок действия",
|
||||||
|
"txt_expiry_month": "Месяц истечения срока действия",
|
||||||
|
"txt_expiry_year": "Год истечения срока действия",
|
||||||
|
"txt_failed_to_open_send": "Не удалось открыть отправку",
|
||||||
|
"txt_favorite": "Любимый",
|
||||||
|
"txt_favorites": "Избранное",
|
||||||
|
"txt_duplicates": "Дубликаты",
|
||||||
|
"txt_field": "Поле",
|
||||||
|
"txt_field_label": "Метка поля",
|
||||||
|
"txt_field_label_is_required": "Метка поля обязательна.",
|
||||||
|
"txt_field_type": "Тип поля",
|
||||||
|
"txt_field_value": "Значение поля",
|
||||||
|
"txt_file": "Файл",
|
||||||
|
"txt_file_name": "Имя файла",
|
||||||
|
"txt_file_send": "Отправить файл",
|
||||||
|
"txt_file_size": "Размер файла",
|
||||||
|
"txt_fingerprint": "Отпечаток пальца",
|
||||||
|
"txt_firefox_browser": "Браузер Firefox",
|
||||||
|
"txt_firefox_extension": "Расширение Firefox",
|
||||||
|
"txt_first_name": "Имя",
|
||||||
|
"txt_folder": "Папка",
|
||||||
|
"txt_folder_created": "Папка создана",
|
||||||
|
"txt_folder_name": "Имя папки",
|
||||||
|
"txt_folder_name_is_required": "Укажите название папки.",
|
||||||
|
"txt_folders": "Папки",
|
||||||
|
"txt_hidden": "Скрытый",
|
||||||
|
"txt_hide": "Скрыть",
|
||||||
|
"txt_identity": "идентичность",
|
||||||
|
"txt_identity_details": "Данные личности",
|
||||||
|
"txt_ie_browser": "IE-браузер",
|
||||||
|
"txt_invite_code_optional": "Пригласительный код (не требуется для первой учетной записи; требуется для всех остальных)",
|
||||||
|
"txt_invite_created": "Приглашение создано",
|
||||||
|
"txt_invite_revoked": "Приглашение отозвано",
|
||||||
|
"txt_invite_validity_hours": "Срок действия приглашения (часы)",
|
||||||
|
"txt_invites": "Приглашает",
|
||||||
|
"txt_ios": "iOS",
|
||||||
|
"txt_item": "Товар",
|
||||||
|
"txt_item_created": "Объект создан",
|
||||||
|
"txt_item_deleted": "Объект удален.",
|
||||||
|
"txt_item_history": "История предмета",
|
||||||
|
"txt_password_history": "История паролей",
|
||||||
|
"txt_password_updated_value": "Пароль обновлен: {value}",
|
||||||
|
"txt_item_name_is_required": "Укажите название элемента.",
|
||||||
|
"txt_item_updated": "Товар обновлен",
|
||||||
|
"txt_last_edited_value": "Последнее редактирование: {value}",
|
||||||
|
"txt_last_name": "Фамилия",
|
||||||
|
"txt_last_seen": "Последний визит",
|
||||||
|
"txt_license_number": "Номер лицензии",
|
||||||
|
"txt_link_copied": "Ссылка скопирована",
|
||||||
|
"txt_linked": "Связано",
|
||||||
|
"txt_linux_desktop": "Рабочий стол Linux",
|
||||||
|
"txt_loading": "Загрузка...",
|
||||||
|
"txt_loading_nodewarden": "Загрузка NodeWarden...",
|
||||||
|
"txt_jwt_warning_title": "Предупреждение безопасности сервера",
|
||||||
|
"txt_jwt_warning_subtitle": "Секрет JWT настроен неправильно.",
|
||||||
|
"txt_jwt_title_missing": "JWT_SECRET отсутствует.",
|
||||||
|
"txt_jwt_title_too_short": "JWT_SECRET слишком короткий",
|
||||||
|
"txt_jwt_title_default": "JWT_SECRET использует значение по умолчанию.",
|
||||||
|
"txt_jwt_reason_missing": "Секрет JWT отсутствует.",
|
||||||
|
"txt_jwt_reason_default": "Секрет JWT по-прежнему является значением по умолчанию/образцом.",
|
||||||
|
"txt_jwt_reason_too_short": "Секрет JWT слишком короткий. Минимальная длина — {min}.",
|
||||||
|
"txt_jwt_how_to_fix_add": "Как добавить JWT_SECRET",
|
||||||
|
"txt_jwt_how_to_fix_replace": "Как заменить JWT_SECRET",
|
||||||
|
"txt_jwt_add_step_1": "Используйте 32-значный генератор ниже и скопируйте новый ключ.",
|
||||||
|
"txt_jwt_add_step_2_prefix": "Перейдите на панель управления Cloudflare -> Рабочие и страницы -> Ваш сервис ->.",
|
||||||
|
"txt_jwt_add_step_2_suffix": "-> Переменные и секреты -> Добавить",
|
||||||
|
"txt_jwt_add_step_3": "Сохраните и дождитесь повторного развертывания, затем обновите эту страницу.",
|
||||||
|
"txt_jwt_replace_step_1": "Используйте приведенный ниже 32-символьный генератор и создайте более надежный ключ (минимум {min} символов).",
|
||||||
|
"txt_jwt_replace_step_2_prefix": "Перейдите на панель управления Cloudflare -> Рабочие и страницы -> Ваш сервис ->.",
|
||||||
|
"txt_jwt_replace_step_2_suffix": "-> Переменные и секреты -> Обновить JWT_SECRET",
|
||||||
|
"txt_jwt_replace_step_3": "Сохраните и дождитесь повторного развертывания, затем обновите эту страницу.",
|
||||||
|
"txt_jwt_secret_type_label": "Тип:",
|
||||||
|
"txt_jwt_secret_type_value": "Секрет",
|
||||||
|
"txt_jwt_secret_name_label": "Имя переменной:",
|
||||||
|
"txt_jwt_secret_value_label": "Значение:",
|
||||||
|
"txt_jwt_secret_value_requirement": "Случайная строка, содержащая не менее {min} символов.",
|
||||||
|
"txt_jwt_what_is": "Что такое JWT?",
|
||||||
|
"txt_jwt_what_is_body": "JWT_SECRET — это ключ подписи на стороне сервера, используемый для выдачи и проверки токенов входа. Если он отсутствует, слишком короткий или все еще использует образец значения, обычное использование экземпляра небезопасно.",
|
||||||
|
"txt_how_to_fix": "Как исправить",
|
||||||
|
"txt_jwt_fix_step_1": "Откройте переменные среды развертывания.",
|
||||||
|
"txt_jwt_fix_step_2": "Если ваш текущий ключ недостаточно случайный, используйте 32-значный генератор ниже.",
|
||||||
|
"txt_jwt_fix_step_3": "Панель управления Cloudflare -> Рабочие и страницы -> Ваш сервис -> Настройки -> Переменные и секреты, обновите JWT_SECRET.",
|
||||||
|
"txt_jwt_fix_step_4": "Сохраните и дождитесь повторного развертывания, затем обновите эту страницу для проверки.",
|
||||||
|
"txt_random_secret_generator": "Генератор случайных секретов",
|
||||||
|
"txt_copied": "Скопировано",
|
||||||
|
"txt_log_in": "Войти",
|
||||||
|
"txt_logging_in": "Вход в систему...",
|
||||||
|
"txt_log_out": "Выйти",
|
||||||
|
"txt_lock": "Блокировка",
|
||||||
|
"txt_menu": "Меню",
|
||||||
|
"txt_settings": "Настройки",
|
||||||
|
"txt_back": "Назад",
|
||||||
|
"txt_login": "Войти",
|
||||||
|
"txt_login_credentials": "Учетные данные для входа",
|
||||||
|
"txt_login_failed": "Не удалось войти",
|
||||||
|
"txt_login_success": "Вход успешный",
|
||||||
|
"txt_macos_desktop": "macOS Рабочий стол",
|
||||||
|
"txt_manage_authorized_devices_and_30_day_totp_trusted_sessions": "Управляйте авторизованными устройствами и 30-дневными доверенными сеансами TOTP.",
|
||||||
|
"txt_manage_device_sessions_and_30_day_totp_trusted_sessions": "Управляйте сеансами устройств и 30-дневными доверенными сеансами TOTP.",
|
||||||
|
"txt_master_password": "Мастер-пароль",
|
||||||
|
"txt_master_password_changed_please_login_again": "Мастер-пароль изменен. Пожалуйста, войдите снова.",
|
||||||
|
"txt_master_password_changed_signing_out_everywhere": "Мастер-пароль изменен. Выходим из всех устройств.",
|
||||||
|
"txt_master_password_is_required": "Требуется мастер-пароль",
|
||||||
|
"txt_master_password_is_required_2": "Требуется мастер-пароль.",
|
||||||
|
"txt_master_password_must_be_at_least_12_chars": "Мастер-пароль должен содержать не менее 12 символов.",
|
||||||
|
"txt_master_password_reprompt": "Повторный запрос мастер-пароля",
|
||||||
|
"txt_master_password_reprompt_2": "Повторный запрос мастер-пароля",
|
||||||
|
"txt_max_access_count": "Максимальное количество доступов",
|
||||||
|
"txt_middle_name": "Второе имя",
|
||||||
|
"txt_drag_to_reorder": "Перетащите, чтобы изменить порядок",
|
||||||
|
"txt_move": "Переместить",
|
||||||
|
"txt_move_selected_items": "Переместить выбранные элементы",
|
||||||
|
"txt_moved_selected_items": "Перемещены выбранные элементы",
|
||||||
|
"txt_name": "Имя",
|
||||||
|
"txt_name_is_required": "Требуется имя",
|
||||||
|
"txt_new_password": "Новый пароль",
|
||||||
|
"txt_nothing_to_copy": "Нечего копировать",
|
||||||
|
"txt_new_password_must_be_at_least_12_chars": "Новый пароль должен содержать не менее 12 символов.",
|
||||||
|
"txt_new_passwords_do_not_match": "Новые пароли не совпадают",
|
||||||
|
"txt_new_send": "Новая отправка",
|
||||||
|
"txt_next": "Далее",
|
||||||
|
"txt_no": "Нет",
|
||||||
|
"txt_no_devices_found": "Устройства не найдены.",
|
||||||
|
"txt_no_folder": "Нет папки",
|
||||||
|
"txt_no_items": "Нет товаров",
|
||||||
|
"txt_no_username": "(Нет имени пользователя)",
|
||||||
|
"txt_no_verification_codes": "Нет кодов подтверждения",
|
||||||
|
"txt_no_name": "(Без имени)",
|
||||||
|
"txt_no_sends": "Нет отправок",
|
||||||
|
"txt_nodewarden_send": "NodeWarden Отправить",
|
||||||
|
"txt_not_trusted": "Не доверяю",
|
||||||
|
"txt_note": "Примечание",
|
||||||
|
"txt_notes": "Примечания",
|
||||||
|
"txt_replace_device_name_with_note": "Задайте собственное имя для этого устройства, не меняя тип обнаруженной системы.",
|
||||||
|
"txt_number": "Номер",
|
||||||
|
"txt_open": "Открыть",
|
||||||
|
"txt_opera_browser": "Браузер Опера",
|
||||||
|
"txt_opera_extension": "Расширение Оперы",
|
||||||
|
"txt_or": "или",
|
||||||
|
"txt_options": "Опции",
|
||||||
|
"txt_passport_number": "Номер паспорта",
|
||||||
|
"txt_password": "Пароль",
|
||||||
|
"txt_password_is_already_verified": "Пароль уже подтвержден.",
|
||||||
|
"txt_passwords_do_not_match": "Пароли не совпадают",
|
||||||
|
"txt_password_hint": "Подсказка к паролю",
|
||||||
|
"txt_password_hint_optional": "Подсказка к паролю (необязательно)",
|
||||||
|
"txt_password_hint_placeholder": "Подсказка, которую поймешь только ты",
|
||||||
|
"txt_password_hint_register_placeholder": "Эту подсказку можно отобразить непосредственно на странице входа в Интернет.",
|
||||||
|
"txt_password_hint_register_help": "Эту подсказку можно отобразить непосредственно на странице входа в Интернет. Не указывайте свой главный пароль, код восстановления или что-либо, что может его раскрыть.",
|
||||||
|
"txt_password_hint_login_help": "Забыли мастер-пароль? Покажите подсказку, которую вы сохранили при регистрации.",
|
||||||
|
"txt_password_hint_login_note": "Здесь показана только подсказка. Это должно помочь вам запомнить пароль, а не раскрыть его.",
|
||||||
|
"txt_show_password_hint": "Показать подсказку к паролю",
|
||||||
|
"txt_hide_password_hint": "Скрыть подсказку к паролю",
|
||||||
|
"txt_loading_password_hint": "Загрузка подсказки...",
|
||||||
|
"txt_password_hint_not_set": "Для этого адреса электронной почты подсказка к паролю недоступна.",
|
||||||
|
"txt_password_hint_load_failed": "Не удалось загрузить подсказку к паролю.",
|
||||||
|
"txt_password_hint_too_long": "Подсказка к паролю должна содержать не более 120 символов.",
|
||||||
|
"txt_passkey": "Ключ доступа",
|
||||||
|
"txt_passkeys": "Ключи доступа",
|
||||||
|
"txt_passkey_created_at_value": "Создано {value}",
|
||||||
|
"txt_phone": "Телефон",
|
||||||
|
"txt_please_input_email_and_password": "Пожалуйста, введите адрес электронной почты и пароль",
|
||||||
|
"txt_please_input_master_password": "Пожалуйста, введите мастер-пароль",
|
||||||
|
"txt_please_input_totp_code": "Пожалуйста, введите код TOTP",
|
||||||
|
"txt_please_select_a_file": "Пожалуйста, выберите файл",
|
||||||
|
"txt_postal_code": "Почтовый индекс",
|
||||||
|
"txt_prev": "Предыдущий",
|
||||||
|
"txt_private_key": "Закрытый ключ",
|
||||||
|
"txt_profile": "Профиль",
|
||||||
|
"txt_profile_unavailable": "Профиль недоступен",
|
||||||
|
"txt_profile_updated": "Профиль обновлен",
|
||||||
|
"txt_public_key": "Открытый ключ",
|
||||||
|
"txt_recover_2fa_failed": "Восстановить 2FA не удалось",
|
||||||
|
"txt_recover_two_step_login": "Восстановить двухэтапный вход",
|
||||||
|
"txt_recovered_but_auto_login_failed_please_sign_in": "Восстановлено, но не удалось выполнить автоматический вход. Войдите в систему.",
|
||||||
|
"txt_recovery_code": "Код восстановления",
|
||||||
|
"txt_recovery_code_and_api_key": "Код восстановления и ключ API",
|
||||||
|
"txt_recovery_code_copied": "Код восстановления скопирован.",
|
||||||
|
"txt_recovery_code_is_empty": "Код восстановления пуст",
|
||||||
|
"txt_recovery_code_loaded": "Код восстановления загружен.",
|
||||||
|
"txt_api_key": "API-ключ",
|
||||||
|
"txt_view_api_key": "Посмотреть ключ API",
|
||||||
|
"txt_rotate_api_key": "Поворот API-ключа",
|
||||||
|
"txt_api_key_copied": "Ключ API скопирован.",
|
||||||
|
"txt_api_key_loaded": "Ключ API загружен",
|
||||||
|
"txt_api_key_rotated": "Ключ API поменян",
|
||||||
|
"txt_rotate_api_key_confirm": "Поменять ключ API? Текущий ключ немедленно перестанет работать.",
|
||||||
|
"txt_api_key_is_empty": "Ключ API пуст",
|
||||||
|
"txt_api_key_dialog_intro": "Ваш ключ API можно использовать для аутентификации с помощью Bitwarden CLI.",
|
||||||
|
"txt_api_key_warning_body": "Ваш ключ API — это альтернативный механизм аутентификации. Держите это в секрете.",
|
||||||
|
"txt_oauth_client_credentials": "Учетные данные клиента OAuth 2.0",
|
||||||
|
"txt_client_id": "client_id",
|
||||||
|
"txt_client_secret": "client_secret",
|
||||||
|
"txt_scope": "объем",
|
||||||
|
"txt_grant_type": "тип_гранта",
|
||||||
|
"txt_refresh": "Обновить",
|
||||||
|
"txt_refresh_in_seconds_s": "Обновить через {seconds} с.",
|
||||||
|
"txt_regenerate": "Регенерировать",
|
||||||
|
"txt_registration_succeeded_please_sign_in": "Регистрация прошла успешно. Пожалуйста, войдите в систему.",
|
||||||
|
"txt_remove": "Удалить",
|
||||||
|
"txt_remove_device": "Удалить устройство",
|
||||||
|
"txt_remove_device_2": "Удалить устройство",
|
||||||
|
"txt_remove_all_devices": "Удалить все устройства",
|
||||||
|
"txt_remove_all_devices_and_clear_all_2fa_trust": "Удалить все устройства и очистить все доверие 2FA?",
|
||||||
|
"txt_remove_all_devices_and_sign_out_all_sessions": "Удалить все устройства, отменить все доверительные отношения и выйти из системы на каждом устройстве?",
|
||||||
|
"txt_remove_device_name_and_clear_its_2fa_trust": "Удалить устройство «{name}» и очистить его доверие 2FA?",
|
||||||
|
"txt_remove_device_and_sign_out_name": "Удалить устройство «{name}», очистить его доверие и выйти из системы?",
|
||||||
|
"txt_reveal": "Раскрыть",
|
||||||
|
"txt_restore": "Восстановить",
|
||||||
|
"txt_revoke": "Отозвать",
|
||||||
|
"txt_revoke_30_day_totp_trust_for_name": "Отозвать 30-дневное доверие TOTP для «{name}»?",
|
||||||
|
"txt_revoke_30_day_totp_trust_from_all_devices": "Отозвать 30-дневное доверие TOTP со всех устройств?",
|
||||||
|
"txt_revoke_all_trusted": "Отозвать все доверенные",
|
||||||
|
"txt_revoke_all_trusted_devices": "Отозвать все доверие к устройствам",
|
||||||
|
"txt_revoke_device_authorization": "Отозвать доверие устройства",
|
||||||
|
"txt_revoke_device_trust_failed": "Не удалось отозвать доверие устройства.",
|
||||||
|
"txt_revoke_all_device_trust_failed": "Не удалось отозвать все доверие устройств.",
|
||||||
|
"txt_revoke_trust": "Отозвать доверие",
|
||||||
|
"txt_untrust": "Не доверять",
|
||||||
|
"txt_update_device_note_failed": "Не удалось обновить примечание об устройстве.",
|
||||||
|
"txt_role": "Роль",
|
||||||
|
"txt_save": "Сохранить",
|
||||||
|
"txt_save_profile": "Сохранить профиль",
|
||||||
|
"txt_save_profile_failed": "Сохранить профиль не удалось",
|
||||||
|
"txt_search_sends": "Поиск отправляет...",
|
||||||
|
"txt_search_your_secure_vault": "Найдите свое безопасное хранилище...",
|
||||||
|
"txt_clear_search": "Очистить поиск",
|
||||||
|
"txt_clear_search_esc": "Очистить поиск (Esc)",
|
||||||
|
"txt_sort": "Сортировать",
|
||||||
|
"txt_sort_last_edited": "Модифицированный",
|
||||||
|
"txt_sort_created": "Создано",
|
||||||
|
"txt_sort_name": "А-Я",
|
||||||
|
"txt_secret_and_code_are_required": "Требуется секрет и код",
|
||||||
|
"txt_secret_copied": "Секрет скопирован.",
|
||||||
|
"txt_secure_note": "Безопасная заметка",
|
||||||
|
"txt_security_code": "Код безопасности",
|
||||||
|
"txt_security_code_cvv": "Код безопасности (CVV)",
|
||||||
|
"txt_select_all": "Выбрать все",
|
||||||
|
"txt_select_duplicate_items": "Выберите дубликаты",
|
||||||
|
"txt_select_an_item": "Выберите элемент",
|
||||||
|
"txt_send_created": "Отправить создано",
|
||||||
|
"txt_send_deleted": "Отправить удалено",
|
||||||
|
"txt_send_details": "Отправить детали",
|
||||||
|
"txt_send_file": "отправить файл",
|
||||||
|
"txt_send_unavailable": "Send недоступна.",
|
||||||
|
"txt_send_updated": "Отправить обновленное",
|
||||||
|
"txt_sign_out": "Выйти",
|
||||||
|
"txt_ssh_key": "SSH-ключ",
|
||||||
|
"txt_ssn": "ССН",
|
||||||
|
"txt_state_province": "Штат/Провинция",
|
||||||
|
"txt_status": "Статус",
|
||||||
|
"txt_online": "Онлайн",
|
||||||
|
"txt_offline": "Офлайн",
|
||||||
|
"txt_submit": "Отправить",
|
||||||
|
"txt_sync": "Синхронизировать",
|
||||||
|
"txt_sync_vault": "Синхронизировать хранилище",
|
||||||
|
"txt_switch_to_dark_mode": "Переключиться в темный режим",
|
||||||
|
"txt_switch_to_light_mode": "Переключиться в светлый режим",
|
||||||
|
"txt_dash": "-",
|
||||||
|
"txt_text": "Текст",
|
||||||
|
"txt_text_2fa_recovered": "2FA восстановлена",
|
||||||
|
"txt_text_2fa_recovered_new_recovery_code_code": "2FA восстановлена. Новый код восстановления: {code}.",
|
||||||
|
"txt_text_3": "------",
|
||||||
|
"txt_text_is_required": "Требуется текст",
|
||||||
|
"txt_text_send": "Отправить текст",
|
||||||
|
"txt_this_is_a_one_time_code_after_it_is_used_a_new_code_is_generated_automatically": "Это одноразовый код. После его использования автоматически генерируется новый код.",
|
||||||
|
"txt_this_item_requires_master_password_every_time_before_viewing_details": "Этот элемент требует мастер-пароль каждый раз перед просмотром деталей.",
|
||||||
|
"txt_this_link_is_missing_decryption_key": "В этой ссылке отсутствует ключ дешифрования.",
|
||||||
|
"txt_this_send_is_password_protected": "Эта отправка защищена паролем.",
|
||||||
|
"txt_title": "Название",
|
||||||
|
"txt_totp": "ТОТП",
|
||||||
|
"txt_totp_code": "TOTP-код",
|
||||||
|
"txt_totp_disabled": "TOTP отключен",
|
||||||
|
"txt_totp_enabled": "TOTP включен",
|
||||||
|
"txt_totp_is_enabled_for_this_account": "TOTP включен для этой учетной записи.",
|
||||||
|
"txt_total_items_count": "{count} товаров",
|
||||||
|
"txt_totp_secret": "Секрет TOTP",
|
||||||
|
"txt_totp_verify_failed": "Проверка TOTP не удалась",
|
||||||
|
"txt_attachments": "Вложения",
|
||||||
|
"txt_upload_attachments": "Загрузить вложения",
|
||||||
|
"txt_new_attachments": "Новые вложения",
|
||||||
|
"txt_marked_for_removal_count": "Вложения {count} будут удалены при сохранении.",
|
||||||
|
"txt_trash": "мусор",
|
||||||
|
"txt_trust_this_device_for_30_days": "Доверяйте этому устройству в течение 30 дней.",
|
||||||
|
"txt_trusted_until": "Доверено до тех пор, пока",
|
||||||
|
"txt_two_step_verification": "Двухэтапная проверка",
|
||||||
|
"txt_type": "Тип",
|
||||||
|
"txt_type_type": "Введите {type}",
|
||||||
|
"txt_unban": "Разбанить",
|
||||||
|
"txt_unchecked": "Не отмечено",
|
||||||
|
"txt_unknown_device": "Неизвестное устройство",
|
||||||
|
"txt_unlock": "Разблокировать",
|
||||||
|
"txt_unlocking": "Разблокировка...",
|
||||||
|
"txt_unlock_details": "Разблокировать детали",
|
||||||
|
"txt_unlock_failed": "Разблокировать не удалось",
|
||||||
|
"txt_unlock_failed_master_password_is_incorrect": "Разблокировать не удалось. Мастер-пароль неверен.",
|
||||||
|
"txt_unlock_item": "Разблокировать предмет",
|
||||||
|
"txt_unlock_send": "Разблокировать Отправить",
|
||||||
|
"txt_unlock_vault": "Разблокировать хранилище",
|
||||||
|
"txt_unlocked": "Разблокировано",
|
||||||
|
"txt_all_devices_removed": "Все устройства удалены",
|
||||||
|
"txt_remove_device_failed": "Не удалось удалить устройство.",
|
||||||
|
"txt_remove_all_devices_failed": "Не удалось удалить все устройства.",
|
||||||
|
"txt_update_item_failed": "Обновить элемент не удалось",
|
||||||
|
"txt_update_send_failed": "Send обновления не удалась",
|
||||||
|
"txt_use_recovery_code": "Использовать код восстановления",
|
||||||
|
"txt_use_your_one_time_recovery_code_to_disable_two_step_verification": "Используйте одноразовый код восстановления, чтобы отключить двухэтапную проверку.",
|
||||||
|
"txt_user_deleted": "Пользователь удален",
|
||||||
|
"txt_user_status_updated": "Статус пользователя обновлен",
|
||||||
|
"txt_username": "Имя пользователя",
|
||||||
|
"txt_uri_match_default_base_domain": "По умолчанию (базовый домен)",
|
||||||
|
"txt_uri_match_base_domain": "Базовый домен",
|
||||||
|
"txt_uri_match_host": "Хост",
|
||||||
|
"txt_uri_match_exact": "Точный",
|
||||||
|
"txt_uri_match_never": "Никогда",
|
||||||
|
"txt_uri_match_starts_with": "Начинается с",
|
||||||
|
"txt_uri_match_regular_expression": "Регулярное выражение",
|
||||||
|
"txt_users": "Пользователи",
|
||||||
|
"txt_vault_synced": "Сейф синхронизирован",
|
||||||
|
"txt_verification_code": "Код подтверждения",
|
||||||
|
"txt_verify": "Проверить",
|
||||||
|
"txt_warning": "Предупреждение",
|
||||||
|
"txt_view_recovery_code": "Посмотреть код восстановления",
|
||||||
|
"txt_web": "Интернет",
|
||||||
|
"txt_website": "Веб-сайт",
|
||||||
|
"txt_websites": "Веб-сайты",
|
||||||
|
"txt_windows_desktop": "Рабочий стол Windows",
|
||||||
|
"txt_yes": "Да",
|
||||||
|
"txt_auto_lock": "Автоблокировка",
|
||||||
|
"txt_auto_lock_description": "Блокируется после бездействия. Closing and reopening the page always starts locked.",
|
||||||
|
"txt_auto_lock_updated": "Автоблокировка обновлена",
|
||||||
|
"txt_session_timeout": "Тайм-аут сеанса",
|
||||||
|
"txt_session_timeout_updated": "Тайм-аут сеанса обновлен.",
|
||||||
|
"txt_timeout_time": "Время ожидания",
|
||||||
|
"txt_timeout_action": "Действие по тайм-ауту",
|
||||||
|
"txt_timeout_action_logout": "Выйти",
|
||||||
|
"txt_timeout_action_lock": "Блокировка",
|
||||||
|
"txt_in_planning": "В планировании",
|
||||||
|
"txt_security_preferences": "Настройки безопасности",
|
||||||
|
"txt_timeout_1_minute": "1 минута",
|
||||||
|
"txt_timeout_5_minutes": "5 минут",
|
||||||
|
"txt_timeout_15_minutes": "15 минут",
|
||||||
|
"txt_timeout_30_minutes": "30 минут",
|
||||||
|
"txt_timeout_never": "Никогда",
|
||||||
|
"txt_lock_after_1_minute": "Через 1 минуту",
|
||||||
|
"txt_lock_after_5_minutes": "Через 5 минут",
|
||||||
|
"txt_lock_after_15_minutes": "Через 15 минут",
|
||||||
|
"txt_lock_after_30_minutes": "Через 30 минут",
|
||||||
|
"txt_lock_after_never": "Никогда за бездействие",
|
||||||
|
"txt_import": "Импорт",
|
||||||
|
"txt_export": "Экспорт",
|
||||||
|
"txt_format": "Формат",
|
||||||
|
"txt_source_file": "Исходный файл",
|
||||||
|
"txt_folder_handling": "Обработка папок",
|
||||||
|
"txt_import_folder_mode_original": "Исходный путь из файла импорта",
|
||||||
|
"txt_import_folder_mode_none": "Нет папки",
|
||||||
|
"txt_import_folder_mode_target": "Одна выбранная папка",
|
||||||
|
"txt_target_folder": "Целевая папка",
|
||||||
|
"txt_select_folder_placeholder": "-- Выберите папку --",
|
||||||
|
"txt_import_vault_data_hint": "Импортируйте данные хранилища в свою текущую учетную запись.",
|
||||||
|
"txt_export_vault_data_hint": "Экспортируйте данные хранилища из вашей текущей учетной записи.",
|
||||||
|
"txt_import_export_title": "Импорт и экспорт",
|
||||||
|
"txt_encrypted_mode": "Зашифрованный режим",
|
||||||
|
"txt_account_verification": "Проверка аккаунта",
|
||||||
|
"txt_password_verification": "Проверка пароля",
|
||||||
|
"txt_file_password": "Пароль файла",
|
||||||
|
"txt_zip_password_optional": "ZIP-пароль (необязательно)",
|
||||||
|
"txt_zip_password": "ZIP-пароль",
|
||||||
|
"txt_close": "Закрыть",
|
||||||
|
"txt_total": "Итого",
|
||||||
|
"txt_import_success": "Импорт выполнен успешно.",
|
||||||
|
"txt_import_success_number_of_items": "Всего импортировано {count} элементов.",
|
||||||
|
"txt_import_attachment_summary": "Импортировано {imported} из {total} вложений.",
|
||||||
|
"txt_import_failed_attachments_title": "Вложения {count} не были импортированы:",
|
||||||
|
"txt_import_attachment_target_not_found": "Соответствующий импортированный элемент не найден.",
|
||||||
|
"txt_upload_attachment_failed": "Не удалось загрузить вложение.",
|
||||||
|
"txt_import_file_password_required": "Пожалуйста, введите пароль файла.",
|
||||||
|
"txt_import_invalid_zip_password": "Неверный пароль ZIP.",
|
||||||
|
"txt_export_completed": "Экспорт завершен",
|
||||||
|
"txt_export_failed": "Экспорт не удался",
|
||||||
|
"txt_import_invalid_password_protected_file": "Неверный файл экспорта, защищенный паролем.",
|
||||||
|
"txt_import_decrypt_failed": "Не удалось расшифровать файл импорта.",
|
||||||
|
"txt_import_empty_zip_archive": "Пустой zip-архив.",
|
||||||
|
"txt_import_no_json_found_in_zip": "В zip-архиве не найдены импортируемые данные JSON.",
|
||||||
|
"txt_import_data_json_not_found": "data.json не найден в zip-архиве.",
|
||||||
|
"txt_import_zip_password_required": "Требуется пароль ZIP.",
|
||||||
|
"txt_import_invalid_json_file": "Неверный файл JSON",
|
||||||
|
"txt_import_failed": "Импорт не удался",
|
||||||
|
"txt_import_encrypted_file_title": "Импортировать зашифрованный файл",
|
||||||
|
"txt_import_encrypted_file_message": "Этот экспорт Bitwarden защищен паролем. Введите пароль файла экспорта, чтобы продолжить.",
|
||||||
|
"txt_import_encrypted_zip_title": "Импортировать зашифрованный ZIP-файл",
|
||||||
|
"txt_import_encrypted_zip_message": "Этот ZIP-архив защищен паролем. Введите пароль ZIP, чтобы продолжить.",
|
||||||
|
"txt_new_type_header": "Новый {type}",
|
||||||
|
"txt_edit_type_header": "Изменить {type}",
|
||||||
|
"txt_delete_folder": "Удалить папку",
|
||||||
|
"txt_delete_folder_message": "Удалить папку «{name}»? Элементы внутри переместятся в папку «Без папки».",
|
||||||
|
"txt_delete_all_folders": "Удалить все папки",
|
||||||
|
"txt_delete_all_folders_message": "Удалить все папки? Элементы внутри переместятся в папку «Без папки».",
|
||||||
|
"txt_folder_not_found": "Папка не найдена",
|
||||||
|
"txt_folder_deleted": "Папка удалена",
|
||||||
|
"txt_folder_updated": "Папка обновлена",
|
||||||
|
"txt_folders_deleted": "Папки удалены",
|
||||||
|
"txt_update_folder_failed": "Обновить папку не удалось",
|
||||||
|
"txt_delete_folder_failed": "Удалить папку не удалось",
|
||||||
|
"txt_delete_all_folders_failed": "Удалить все папки не удалось",
|
||||||
|
"txt_other": "Другое",
|
||||||
|
"txt_vault_key_unavailable": "Ключ хранилища недоступен. Пожалуйста, разблокируйте хранилище и повторите попытку.",
|
||||||
|
"txt_vault_not_ready": "Хранилище еще не готово",
|
||||||
|
"txt_unsupported_export_format": "Неподдерживаемый формат экспорта",
|
||||||
|
"txt_invalid_encrypted_export": "Неверный зашифрованный файл экспорта.",
|
||||||
|
"txt_export_belongs_to_another_account": "Этот зашифрованный экспорт принадлежит другому аккаунту.",
|
||||||
|
"txt_invalid_argon2id_params": "Неверные параметры Argon2id в файле экспорта.",
|
||||||
|
"txt_unsupported_kdf_type": "Неподдерживаемый тип kdf: {type}",
|
||||||
|
"txt_invalid_file_password": "Неверный пароль файла.",
|
||||||
|
"txt_failed_to_map_attachments": "Не удалось сопоставить {count} вложений с импортированными элементами.",
|
||||||
|
"txt_role_admin": "Админ",
|
||||||
|
"txt_role_user": "Пользователь",
|
||||||
|
"txt_status_active": "Активный",
|
||||||
|
"txt_status_banned": "Запрещено",
|
||||||
|
"txt_status_inactive": "Неактивный",
|
||||||
|
"txt_language": "Язык",
|
||||||
|
"txt_display_language": "Язык дисплея",
|
||||||
|
"txt_language_saved_locally": "Этот выбор сохраняется в текущем браузере и применяется при следующей загрузке приложения."
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ru;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Generated from English defaults plus Chinese translations so zh-CN can load without the English chunk.
|
// Complete Simplified Chinese locale. Keep keys and placeholders unchanged.
|
||||||
const zhCN: Record<string, string> = {
|
const zhCN: Record<string, string> = {
|
||||||
"nav_account_settings": "账户设置",
|
"nav_account_settings": "账户设置",
|
||||||
"nav_admin_panel": "用户管理",
|
"nav_admin_panel": "用户管理",
|
||||||
@@ -839,7 +839,10 @@ const zhCN: Record<string, string> = {
|
|||||||
"txt_role_user": "用户",
|
"txt_role_user": "用户",
|
||||||
"txt_status_active": "正常",
|
"txt_status_active": "正常",
|
||||||
"txt_status_banned": "已封禁",
|
"txt_status_banned": "已封禁",
|
||||||
"txt_status_inactive": "未激活"
|
"txt_status_inactive": "未激活",
|
||||||
|
"txt_language": "语言",
|
||||||
|
"txt_display_language": "显示语言",
|
||||||
|
"txt_language_saved_locally": "此偏好会保存在当前浏览器中,下次打开应用前就会生效。"
|
||||||
};
|
};
|
||||||
|
|
||||||
export default zhCN;
|
export default zhCN;
|
||||||
|
|||||||
@@ -0,0 +1,848 @@
|
|||||||
|
// Complete Traditional Chinese locale generated from zh-CN with OpenCC. Keep keys and placeholders unchanged.
|
||||||
|
const zhTW: Record<string, string> = {
|
||||||
|
"nav_account_settings": "賬戶設置",
|
||||||
|
"nav_admin_panel": "用戶管理",
|
||||||
|
"nav_device_management": "設備管理",
|
||||||
|
"nav_my_vault": "我的密碼庫",
|
||||||
|
"nav_sends": "Send",
|
||||||
|
"nav_backup_strategy": "雲端備份",
|
||||||
|
"nav_import_export": "導入導出",
|
||||||
|
"backup_strategy_title": "雲端備份",
|
||||||
|
"backup_strategy_under_construction": "正在搭建中",
|
||||||
|
"import_export_title": "導入導出",
|
||||||
|
"import_export_under_construction": "正在搭建中",
|
||||||
|
"txt_backup_export": "導出備份",
|
||||||
|
"txt_backup_import": "還原",
|
||||||
|
"txt_backup_include_attachments": "包含附件",
|
||||||
|
"txt_backup_export_description": "下載一個完整的實例備份 ZIP,手動保管即可。",
|
||||||
|
"txt_backup_import_description": "上傳之前導出的備份 ZIP,並還原到當前實例。",
|
||||||
|
"txt_backup_exporting": "正在導出...",
|
||||||
|
"txt_backup_importing": "正在還原...",
|
||||||
|
"txt_backup_restoring": "正在還原...",
|
||||||
|
"txt_backup_export_success": "備份已導出",
|
||||||
|
"txt_backup_import_success_relogin": "備份已還原,請重新登錄",
|
||||||
|
"txt_backup_restore_success_relogin": "備份已還原,請重新登錄",
|
||||||
|
"txt_backup_restore_completed_verified": "備份文件完整性校驗已通過。",
|
||||||
|
"txt_backup_restore_completed_without_checksum": "備份已還原,但文件名中未提供可校驗的完整性標記。",
|
||||||
|
"txt_backup_remote_restore_completed_verified": "遠程備份完整性校驗已通過。",
|
||||||
|
"txt_backup_remote_restore_completed_without_checksum": "遠程備份已還原,但文件名中未提供可校驗的完整性標記。",
|
||||||
|
"txt_backup_restore_skipped_summary": "{reason},已跳過 {attachments} 個附件",
|
||||||
|
"txt_backup_restore_skipped_reason_default": "部分文件無法還原",
|
||||||
|
"txt_backup_export_failed": "備份導出失敗",
|
||||||
|
"txt_backup_import_failed": "備份還原失敗",
|
||||||
|
"txt_backup_restore_failed": "備份還原失敗",
|
||||||
|
"txt_backup_integrity_check_failed": "備份完整性校驗失敗",
|
||||||
|
"txt_backup_center_title": "實例備份",
|
||||||
|
"txt_backup_center_description": "把本地導出和遠程自動備份放在一起管理,既方便手動恢復,也能每天自動留一份。",
|
||||||
|
"txt_backup_restore_note": "還原會覆蓋當前實例;如果當前已有數據,系統會要求你確認“清空後還原”。",
|
||||||
|
"txt_backup_manual": "手動備份",
|
||||||
|
"txt_backup_manual_description": "現在就導出 ZIP,或者把之前導出的 ZIP 恢復到當前實例。",
|
||||||
|
"txt_backup_destinations_title": "備份地點",
|
||||||
|
"txt_backup_destinations_description": "把多個 WebDAV、E3 地點統一放在這裡。左側選一個,右側編輯和瀏覽它。",
|
||||||
|
"txt_backup_recommend_title": "推薦儲存庫",
|
||||||
|
"txt_backup_recommend_open_signup": "前往註冊",
|
||||||
|
"txt_backup_recommend_open_signup_aff": "前往註冊(含 AFF)",
|
||||||
|
"txt_backup_recommend_open_guide": "查看教程",
|
||||||
|
"txt_backup_recommend_empty": "暫時沒有推薦",
|
||||||
|
"txt_backup_recommend_referral_label": "推薦碼",
|
||||||
|
"txt_backup_recommend_referral_note": "註冊時填寫可額外獲得 5 GB,作者會收到 2 GB。",
|
||||||
|
"txt_backup_recommend_infinicloud_summary": "只需郵箱即可註冊。免費 20 GB;填寫推薦碼後總計 25 GB。",
|
||||||
|
"txt_backup_recommend_infinicloud_step_1": "先用郵箱註冊一個 InfiniCLOUD 賬號。",
|
||||||
|
"txt_backup_recommend_infinicloud_step_2_prefix": "進入",
|
||||||
|
"txt_backup_recommend_infinicloud_step_2_suffix": ",然後開啟 Turn on Apps Connection。",
|
||||||
|
"txt_backup_recommend_infinicloud_step_3": "Connection ID 用作 WebDAV 用戶名,Apps Password 用作 WebDAV 密碼。",
|
||||||
|
"txt_backup_recommend_infinicloud_step_4": "在 My Page 最下面的 Referral Bonus 填入推薦碼 2HC5E,可額外獲得 5 GB。",
|
||||||
|
"txt_backup_recommend_open_password": "密碼設置",
|
||||||
|
"txt_backup_recommend_open_storage": "打開儲存連接",
|
||||||
|
"txt_backup_recommend_koofr_summary": "只需郵箱即可註冊使用。免費 10 GB,並且可以通過 WebDAV 接到 Google Drive、OneDrive、Dropbox。",
|
||||||
|
"txt_backup_recommend_koofr_password_link": "密碼設置",
|
||||||
|
"txt_backup_recommend_koofr_storage_link": "Storage",
|
||||||
|
"txt_backup_recommend_koofr_step_1": "先用郵箱註冊一個 Koofr 賬號。",
|
||||||
|
"txt_backup_recommend_koofr_step_2_prefix": "打開",
|
||||||
|
"txt_backup_recommend_koofr_step_2_suffix": ",生成新的應用密碼。註冊郵箱用作 WebDAV 用戶名,應用密碼用作 WebDAV 密碼。",
|
||||||
|
"txt_backup_recommend_koofr_step_3": "Koofr 自己的 WebDAV 地址是 https://app.koofr.net/dav/Koofr。",
|
||||||
|
"txt_backup_recommend_koofr_step_4": "Koofr 最方便的地方,是還能接 Google Drive、OneDrive、Dropbox 這三大雲盤;免費用戶最多能連接兩個。",
|
||||||
|
"txt_backup_recommend_koofr_step_5_prefix": "打開",
|
||||||
|
"txt_backup_recommend_koofr_step_5_suffix": ",在左側欄點擊“連接”,選擇你要連接的儲存即可。",
|
||||||
|
"txt_backup_recommend_koofr_dav_intro": "連接好儲存後,賬號和應用密碼都不變,只需要切換 WebDAV 地址:",
|
||||||
|
"txt_backup_recommend_koofr_dav_self": "Koofr",
|
||||||
|
"txt_backup_recommend_pcloud_summary": "只需郵箱即可註冊。免費最高 10 GB,並且自帶標準 WebDAV 訪問。",
|
||||||
|
"txt_backup_recommend_pcloud_step_1": "先用郵箱註冊一個 pCloud 賬號。",
|
||||||
|
"txt_backup_recommend_pcloud_step_2": "WebDAV 地址填寫 https://webdav.pcloud.com/ 。",
|
||||||
|
"txt_backup_recommend_pcloud_step_3": "註冊郵箱用作 WebDAV 用戶名,註冊密碼用作 WebDAV 密碼。",
|
||||||
|
"txt_backup_add_destination": "新增地點",
|
||||||
|
"txt_backup_schedule_panel_title": "自動備份計劃",
|
||||||
|
"txt_backup_schedule_panel_note": "每個備份地點都可以單獨配置自己的每日自動備份計劃。",
|
||||||
|
"txt_backup_scheduled_target": "當前計劃目標",
|
||||||
|
"txt_backup_destination_active_badge": "已啟用計劃",
|
||||||
|
"txt_backup_destination_idle_badge": "未啟用計劃",
|
||||||
|
"txt_backup_destination_last_success": "上次成功:{time}",
|
||||||
|
"txt_backup_destination_never_run": "還沒有成功執行過",
|
||||||
|
"txt_backup_destination_detail_title": "地點詳情",
|
||||||
|
"txt_backup_destination_detail_note": "",
|
||||||
|
"txt_backup_destination_name": "地點名稱",
|
||||||
|
"txt_backup_set_scheduled_target": "設為每日備份目標",
|
||||||
|
"txt_backup_delete_destination": "刪除",
|
||||||
|
"txt_backup_destination_deleted": "備份地點已刪除",
|
||||||
|
"txt_backup_delete_destination_confirm_message": "刪除備份地點“{name}”?此操作不可撤銷。",
|
||||||
|
"txt_backup_select_destination": "請先從左側列表選擇一個備份地點",
|
||||||
|
"txt_backup_remote_save_first": "請先保存這個備份地點,再瀏覽它的遠端備份文件",
|
||||||
|
"txt_backup_automation": "自動備份",
|
||||||
|
"txt_backup_automation_description": "選擇備份地點,保存連接信息後,系統會按設定時間每天自動上傳一份備份。",
|
||||||
|
"txt_backup_settings_saved": "備份設置已保存",
|
||||||
|
"txt_backup_settings_save_failed": "備份設置保存失敗",
|
||||||
|
"txt_backup_settings_load_failed": "備份設置加載失敗",
|
||||||
|
"txt_backup_save_settings": "保存設置",
|
||||||
|
"txt_backup_saving": "正在保存...",
|
||||||
|
"txt_backup_enable_action": "啟用",
|
||||||
|
"txt_backup_disable_action": "停用",
|
||||||
|
"txt_backup_run_now": "立即執行遠程備份",
|
||||||
|
"txt_backup_run_manual": "手動執行",
|
||||||
|
"txt_backup_running_now": "執行中...",
|
||||||
|
"txt_backup_remote_run_success": "遠程備份已完成",
|
||||||
|
"txt_backup_remote_run_success_verified": "遠程備份已完成,且完整性校驗已通過。",
|
||||||
|
"txt_backup_remote_run_failed": "遠程備份失敗",
|
||||||
|
"txt_backup_remote_title": "遠端備份",
|
||||||
|
"txt_backup_remote_note": "瀏覽已保存的備份地點,選擇某個備份 ZIP 後可以下載,也可以直接還原。",
|
||||||
|
"txt_backup_remote_saved_basis": "遠端瀏覽使用的是“已保存”的備份地點配置,不會讀取你當前未保存的表單內容。",
|
||||||
|
"txt_backup_remote_refresh": "刷新",
|
||||||
|
"txt_backup_remote_root": "根目錄",
|
||||||
|
"txt_backup_remote_up": "上一級",
|
||||||
|
"txt_backup_remote_open": "打開",
|
||||||
|
"txt_backup_remote_download": "下載",
|
||||||
|
"txt_backup_remote_downloading": "下載中...",
|
||||||
|
"txt_backup_remote_restore": "還原",
|
||||||
|
"txt_backup_remote_restore_stage_prepare": "正在讀取遠端備份並檢查可恢復內容...",
|
||||||
|
"txt_backup_remote_restore_stage_replace": "正在清空當前數據並還原遠端備份,請稍候...",
|
||||||
|
"txt_backup_progress_kicker": "備份任務",
|
||||||
|
"txt_backup_progress_subject": "當前對象:{name}",
|
||||||
|
"txt_backup_restore_progress_kicker": "還原進度",
|
||||||
|
"txt_backup_restore_progress_local_title": "正在還原本地備份",
|
||||||
|
"txt_backup_restore_progress_remote_title": "正在還原遠端備份",
|
||||||
|
"txt_backup_export_progress_title": "正在導出備份",
|
||||||
|
"txt_backup_remote_run_progress_title": "正在執行遠程備份",
|
||||||
|
"txt_backup_restore_progress_file": "當前文件:{name}",
|
||||||
|
"txt_backup_restore_progress_elapsed": "已耗時 {seconds} 秒",
|
||||||
|
"txt_backup_archive_progress_collect_title": "正在收集密碼庫數據",
|
||||||
|
"txt_backup_archive_progress_collect_detail": "服務器正在讀取數據庫表,並整理備份所需的數據內容。",
|
||||||
|
"txt_backup_archive_progress_collect_with_attachments_detail": "服務器正在讀取數據庫表,並整理附件元數據與備份內容。",
|
||||||
|
"txt_backup_archive_progress_package_title": "正在打包備份壓縮包",
|
||||||
|
"txt_backup_archive_progress_package_detail": "服務器正在生成備份 ZIP,並計算文件名校驗前綴。",
|
||||||
|
"txt_backup_archive_progress_package_with_attachments_detail": "服務器正在生成帶附件信息的備份 ZIP 元數據,並計算文件名校驗前綴。",
|
||||||
|
"txt_backup_archive_progress_ready_title": "正在準備下載",
|
||||||
|
"txt_backup_archive_progress_ready_detail": "備份壓縮包已經生成,服務器正在把它返回給瀏覽器。",
|
||||||
|
"txt_backup_export_progress_fetch_attachments_title": "正在下載附件文件",
|
||||||
|
"txt_backup_export_progress_fetch_attachments_detail": "瀏覽器正在讀取附件對象,並把它們補入導出備份包。",
|
||||||
|
"txt_backup_export_progress_rebuild_title": "正在重建導出壓縮包",
|
||||||
|
"txt_backup_export_progress_rebuild_detail": "瀏覽器正在重建最終 ZIP,並刷新文件名裡的校驗後綴。",
|
||||||
|
"txt_backup_export_progress_save_title": "正在保存導出文件",
|
||||||
|
"txt_backup_export_progress_save_detail": "瀏覽器正在準備最終的備份文件下載。",
|
||||||
|
"txt_backup_export_progress_complete_title": "備份導出已完成",
|
||||||
|
"txt_backup_export_progress_complete_detail": "導出備份已經準備完成。",
|
||||||
|
"txt_backup_export_progress_failed_title": "備份導出失敗",
|
||||||
|
"txt_backup_export_progress_failed_detail": "導出備份未能完成。",
|
||||||
|
"txt_backup_remote_run_progress_prepare_title": "正在準備遠程備份",
|
||||||
|
"txt_backup_remote_run_progress_prepare_detail": "服務器正在讀取當前備份目標,並準備執行這次遠程備份。",
|
||||||
|
"txt_backup_remote_run_progress_sync_attachments_title": "正在檢查附件索引",
|
||||||
|
"txt_backup_remote_run_progress_sync_attachments_detail": "服務器正在比對附件索引,只會上傳缺失或不一致的附件對象。",
|
||||||
|
"txt_backup_remote_run_progress_sync_attachments_skipped_detail": "當前備份未包含附件,因此跳過附件同步。",
|
||||||
|
"txt_backup_remote_run_progress_upload_title": "正在上傳備份壓縮包",
|
||||||
|
"txt_backup_remote_run_progress_upload_detail": "服務器正在把備份 ZIP 上傳到遠程備份目標。",
|
||||||
|
"txt_backup_remote_run_progress_verify_title": "正在校驗已上傳壓縮包",
|
||||||
|
"txt_backup_remote_run_progress_verify_detail": "服務器正在回讀剛上傳的 ZIP,並校驗它的哈希和大小。",
|
||||||
|
"txt_backup_remote_run_progress_cleanup_title": "正在清理舊備份",
|
||||||
|
"txt_backup_remote_run_progress_cleanup_detail": "服務器正在按保留策略清理舊備份文件。",
|
||||||
|
"txt_backup_remote_run_progress_complete_title": "遠程備份已完成",
|
||||||
|
"txt_backup_remote_run_progress_complete_detail": "遠程備份已上傳完成,並通過完整性校驗。",
|
||||||
|
"txt_backup_remote_run_progress_failed_title": "遠程備份失敗",
|
||||||
|
"txt_backup_remote_run_progress_failed_detail": "遠程備份未能完成。",
|
||||||
|
"txt_backup_restore_progress_local_upload_title": "正在上傳備份包",
|
||||||
|
"txt_backup_restore_progress_local_upload_detail": "已選 ZIP 正在發送到服務器,服務器收到後會開始執行還原。",
|
||||||
|
"txt_backup_restore_progress_local_shadow_title": "正在創建影子恢復區",
|
||||||
|
"txt_backup_restore_progress_local_shadow_detail": "服務器正在準備獨立的影子數據區,只有校驗通過後才會替換正式數據。",
|
||||||
|
"txt_backup_restore_progress_local_data_title": "正在寫入密碼庫數據",
|
||||||
|
"txt_backup_restore_progress_local_data_detail": "服務器正在把用戶、文件夾、密碼條目和相關元數據寫入影子表。",
|
||||||
|
"txt_backup_restore_progress_local_files_title": "正在恢復附件文件",
|
||||||
|
"txt_backup_restore_progress_local_files_detail": "服務器正在把附件對象寫回存儲,並剔除無法恢復的附件記錄。",
|
||||||
|
"txt_backup_restore_progress_local_finalize_title": "正在校驗並完成切換",
|
||||||
|
"txt_backup_restore_progress_local_finalize_detail": "服務器正在執行最終校驗,校驗通過後會把已驗證的數據切換為正式數據。",
|
||||||
|
"txt_backup_restore_progress_remote_fetch_title": "正在讀取遠端備份包",
|
||||||
|
"txt_backup_restore_progress_remote_fetch_detail": "服務器正在從遠端備份目標下載你選中的備份包。",
|
||||||
|
"txt_backup_restore_progress_remote_shadow_title": "正在創建影子恢復區",
|
||||||
|
"txt_backup_restore_progress_remote_shadow_detail": "服務器正在準備獨立的影子數據區,只有校驗通過後才會替換正式數據。",
|
||||||
|
"txt_backup_restore_progress_remote_data_title": "正在寫入密碼庫數據",
|
||||||
|
"txt_backup_restore_progress_remote_data_detail": "服務器正在把用戶、文件夾、密碼條目和相關元數據寫入影子表。",
|
||||||
|
"txt_backup_restore_progress_remote_files_title": "正在恢復遠端附件",
|
||||||
|
"txt_backup_restore_progress_remote_files_detail": "服務器正在從遠端存儲讀取所需附件,並寫回到當前實例的附件存儲。",
|
||||||
|
"txt_backup_restore_progress_remote_finalize_title": "正在校驗並完成切換",
|
||||||
|
"txt_backup_restore_progress_remote_finalize_detail": "服務器正在執行最終校驗,校驗通過後會把已驗證的數據切換為正式數據。",
|
||||||
|
"txt_backup_remote_loading": "正在讀取遠端備份...",
|
||||||
|
"txt_backup_remote_cached_empty": "點擊“刷新”後讀取",
|
||||||
|
"txt_backup_remote_empty": "這個目錄下還沒有備份文件",
|
||||||
|
"txt_backup_remote_folder": "文件夾",
|
||||||
|
"txt_backup_remote_unknown_time": "未知時間",
|
||||||
|
"txt_backup_remote_current_path": "當前目錄",
|
||||||
|
"txt_backup_remote_load_failed": "讀取遠端備份失敗",
|
||||||
|
"txt_backup_remote_invalid_response": "遠端備份響應無效",
|
||||||
|
"txt_backup_remote_download_failed": "下載遠端備份失敗",
|
||||||
|
"txt_backup_remote_delete_success": "遠端備份已刪除",
|
||||||
|
"txt_backup_remote_delete_failed": "刪除遠端備份失敗",
|
||||||
|
"txt_backup_remote_delete_confirm_message": "刪除備份文件“{name}”?此操作不可撤銷。",
|
||||||
|
"txt_backup_remote_deleting": "刪除中...",
|
||||||
|
"txt_backup_remote_restore_failed": "還原遠端備份失敗",
|
||||||
|
"txt_backup_restore_checksum_warning_title": "備份完整性警告",
|
||||||
|
"txt_backup_restore_checksum_warning_message": "所選備份文件“{name}”未通過文件名完整性校驗。期望前綴為 {expected},實際計算結果為 {actual}。該文件可能不完整或已經損壞。繼續還原可能會導入受損數據。",
|
||||||
|
"txt_backup_remote_restore_checksum_warning_message": "遠程備份文件“{name}”未通過文件名完整性校驗。期望前綴為 {expected},實際計算結果為 {actual}。該文件可能在上傳或存儲過程中損壞。繼續還原可能會導入受損數據,並可能造成嚴重後果。",
|
||||||
|
"txt_backup_restore_checksum_warning_message_fallback": "所選備份文件未通過完整性校驗。繼續還原可能會導入受損數據。",
|
||||||
|
"txt_backup_restore_checksum_warning_confirm": "繼續還原",
|
||||||
|
"txt_backup_remote_restore_invalid_response": "遠端備份還原響應無效",
|
||||||
|
"txt_backup_remote_run_invalid_response": "遠端備份執行響應無效",
|
||||||
|
"txt_backup_settings_invalid_response": "備份設置響應無效",
|
||||||
|
"txt_backup_import_invalid_response": "備份還原響應無效",
|
||||||
|
"txt_backup_destination": "備份地點",
|
||||||
|
"txt_backup_protocol_webdav": "WebDAV",
|
||||||
|
"txt_backup_protocol_e3": "E3",
|
||||||
|
"txt_backup_recommend_group_webdav": "WebDAV",
|
||||||
|
"txt_backup_recommend_group_s3": "S3",
|
||||||
|
"txt_backup_destination_name_default_webdav": "WebDAV {index}",
|
||||||
|
"txt_backup_destination_name_default_e3": "E3 {index}",
|
||||||
|
"txt_backup_type": "備份類型",
|
||||||
|
"txt_backup_destination_reserved": "預留位置",
|
||||||
|
"txt_backup_time": "備份時間",
|
||||||
|
"txt_backup_start_time": "開始時間",
|
||||||
|
"txt_backup_timezone": "時區",
|
||||||
|
"txt_backup_interval_hours": "每隔",
|
||||||
|
"txt_backup_interval_hours_suffix": "小時",
|
||||||
|
"txt_backup_interval_hours_presets": "快捷時間預設",
|
||||||
|
"txt_backup_frequency": "備份頻率",
|
||||||
|
"txt_backup_frequency_daily": "每天",
|
||||||
|
"txt_backup_frequency_weekly": "每週",
|
||||||
|
"txt_backup_frequency_monthly": "每月",
|
||||||
|
"txt_backup_day_of_week": "星期",
|
||||||
|
"txt_backup_day_of_month": "日期",
|
||||||
|
"txt_backup_weekday_monday": "週一",
|
||||||
|
"txt_backup_weekday_tuesday": "週二",
|
||||||
|
"txt_backup_weekday_wednesday": "週三",
|
||||||
|
"txt_backup_weekday_thursday": "週四",
|
||||||
|
"txt_backup_weekday_friday": "週五",
|
||||||
|
"txt_backup_weekday_saturday": "週六",
|
||||||
|
"txt_backup_weekday_sunday": "週日",
|
||||||
|
"txt_backup_retention_count": "只保留",
|
||||||
|
"txt_backup_retention_count_suffix": "個",
|
||||||
|
"txt_backup_retention_count_hint": "留空表示不限,新建備份地點默認保留 30 個",
|
||||||
|
"txt_backup_destination_include_attachments": "包含附件",
|
||||||
|
"txt_backup_include_attachments_help_button": "附件備份說明",
|
||||||
|
"txt_backup_include_attachments_help": "附件會以增量方式保存在遠端的 attachments 文件夾中,後續備份通常只上傳新增文件。你在本地刪除附件時,已經備份到遠端的舊文件不會自動刪除。恢復時會按需從 attachments 文件夾讀取對應附件,找不到的附件會自動跳過。",
|
||||||
|
"txt_backup_enable_schedule": "啟用每日自動備份",
|
||||||
|
"txt_backup_schedule_note": "Worker 每 5 分鐘檢查一次計劃。會先按你選擇的時區和開始時間起跑,再按小時間隔繼續執行;到了下一天,會重新從開始時間開始。",
|
||||||
|
"txt_backup_schedule_disabled": "未啟用",
|
||||||
|
"txt_backup_schedule_status": "計劃狀態",
|
||||||
|
"txt_backup_schedule_summary": "從 {time} 開始,每隔 {interval} 小時({timezone})",
|
||||||
|
"txt_backup_schedule_empty": "還沒有啟用任何自動備份計劃",
|
||||||
|
"txt_backup_last_success": "上次成功時間",
|
||||||
|
"txt_backup_last_target": "上次備份位置",
|
||||||
|
"txt_backup_last_file": "上次備份文件",
|
||||||
|
"txt_backup_last_error_prefix": "上次錯誤",
|
||||||
|
"txt_backup_none_yet": "還沒有成功完成過遠程備份",
|
||||||
|
"txt_backup_not_configured": "尚未配置",
|
||||||
|
"txt_backup_never": "從未",
|
||||||
|
"txt_backup_unknown_size": "大小未知",
|
||||||
|
"txt_backup_webdav_url": "WebDAV 服務地址",
|
||||||
|
"txt_backup_webdav_username": "WebDAV 用戶名",
|
||||||
|
"txt_backup_webdav_password": "WebDAV 密碼",
|
||||||
|
"txt_backup_webdav_path": "遠程目錄",
|
||||||
|
"txt_backup_e3_endpoint": "E3 Endpoint",
|
||||||
|
"txt_backup_e3_bucket": "Bucket",
|
||||||
|
"txt_backup_e3_region": "Region",
|
||||||
|
"txt_backup_e3_access_key": "Access Key",
|
||||||
|
"txt_backup_e3_secret_key": "Secret Key",
|
||||||
|
"txt_backup_e3_path": "遠程路徑",
|
||||||
|
"txt_backup_reserved_name": "預留類型名稱",
|
||||||
|
"txt_backup_reserved_notes": "預留備註",
|
||||||
|
"txt_backup_reserved_notes_placeholder": "給下一個備份地點先留個說明",
|
||||||
|
"txt_backup_reserved_hint": "這個位置先預留給後續備份地點。你現在可以先保存備註,但自動上傳不會啟用。",
|
||||||
|
"txt_backup_file": "備份文件",
|
||||||
|
"txt_backup_file_required": "請選擇備份文件",
|
||||||
|
"txt_backup_no_file_selected": "尚未選擇備份文件",
|
||||||
|
"txt_backup_selected_file_name": "已選擇文件:{name}",
|
||||||
|
"txt_backup_replace_confirm_title": "替換當前實例數據",
|
||||||
|
"txt_backup_replace_confirm_message": "當前實例裡已經有數據。確認後,系統會先完成校驗與恢復準備,只有在恢復成功後才會用所選備份替換當前實例數據。是否繼續?",
|
||||||
|
"txt_backup_clear_and_import": "替換並導入",
|
||||||
|
"txt_backup_clear_and_restore": "替換並還原",
|
||||||
|
"txt_access_count": "訪問次數",
|
||||||
|
"txt_accessed_count_times": "已訪問 {count} 次",
|
||||||
|
"txt_actions": "操作",
|
||||||
|
"txt_add": "新增",
|
||||||
|
"txt_add_field": "添加字段",
|
||||||
|
"txt_add_website": "添加網站",
|
||||||
|
"txt_added": "已添加",
|
||||||
|
"txt_additional_options": "附加選項",
|
||||||
|
"txt_address": "地址",
|
||||||
|
"txt_address_1": "地址 1",
|
||||||
|
"txt_address_2": "地址 2",
|
||||||
|
"txt_address_3": "地址 3",
|
||||||
|
"txt_all_device_authorizations_revoked": "已撤銷所有設備信任",
|
||||||
|
"txt_all_invites_deleted": "已刪除所有邀請碼",
|
||||||
|
"txt_all_items": "所有項目",
|
||||||
|
"txt_all_sends": "所有發送",
|
||||||
|
"txt_android": "安卓",
|
||||||
|
"txt_are_you_sure_you_want_to_delete_count_selected_items": "確認刪除所選的 {count} 個項目?",
|
||||||
|
"txt_are_you_sure_you_want_to_delete_count_selected_items_permanently": "確認永久刪除所選的 {count} 個項目?",
|
||||||
|
"txt_are_you_sure_you_want_to_delete_this_item": "確認刪除此項目?",
|
||||||
|
"txt_are_you_sure_you_want_to_delete_this_passkey": "確認刪除這個通行密鑰?",
|
||||||
|
"txt_are_you_sure_you_want_to_log_out": "確認要退出登錄嗎?",
|
||||||
|
"txt_authenticator_key": "驗證器密鑰",
|
||||||
|
"txt_authorized_devices": "已授權設備",
|
||||||
|
"txt_auto_copy_link_after_save": "保存後自動複製鏈接",
|
||||||
|
"txt_autofill_options": "自動填充選項",
|
||||||
|
"txt_back_to_login": "返回登錄",
|
||||||
|
"txt_ban": "封禁",
|
||||||
|
"txt_boolean": "布爾",
|
||||||
|
"txt_brand": "品牌",
|
||||||
|
"txt_bulk_delete_failed": "批量刪除失敗",
|
||||||
|
"txt_bulk_permanent_delete_failed": "批量永久刪除失敗",
|
||||||
|
"txt_bulk_restore_failed": "批量恢復失敗",
|
||||||
|
"txt_bulk_delete_sends_failed": "批量刪除發送失敗",
|
||||||
|
"txt_bulk_move_failed": "批量移動失敗",
|
||||||
|
"txt_cancel": "取消",
|
||||||
|
"txt_continue": "繼續",
|
||||||
|
"txt_card": "銀行卡",
|
||||||
|
"txt_card_details": "銀行卡詳情",
|
||||||
|
"txt_cardholder_name": "持卡人姓名",
|
||||||
|
"txt_change_master_password": "修改主密碼",
|
||||||
|
"txt_change_password": "修改密碼",
|
||||||
|
"txt_change_password_failed": "修改密碼失敗",
|
||||||
|
"txt_change_password_confirm_and_sign_out_all_devices": "修改主密碼後會強制退出所有設備,包括當前網頁端。確認繼續嗎",
|
||||||
|
"txt_copy_failed": "複製失敗",
|
||||||
|
"txt_checked": "已勾選",
|
||||||
|
"txt_choose_destination_folder": "選擇目標文件夾。",
|
||||||
|
"txt_chrome_browser": "Chrome 瀏覽器",
|
||||||
|
"txt_chrome_extension": "Chrome 擴展",
|
||||||
|
"txt_city_town": "城市 / 城鎮",
|
||||||
|
"txt_code": "代碼",
|
||||||
|
"txt_company": "公司",
|
||||||
|
"txt_configure_custom_field_values": "配置自定義字段值。",
|
||||||
|
"txt_confirm": "確認",
|
||||||
|
"txt_confirm_master_password": "確認主密碼",
|
||||||
|
"txt_confirm_password": "確認密碼",
|
||||||
|
"txt_copy": "複製",
|
||||||
|
"txt_code_copied": "驗證碼已複製",
|
||||||
|
"txt_copy_code": "複製代碼",
|
||||||
|
"txt_copy_link": "複製鏈接",
|
||||||
|
"txt_copy_secret": "複製密鑰",
|
||||||
|
"txt_country": "國家",
|
||||||
|
"txt_create": "創建",
|
||||||
|
"txt_create_account": "創建賬戶",
|
||||||
|
"txt_registering": "正在註冊...",
|
||||||
|
"txt_create_folder": "創建文件夾",
|
||||||
|
"txt_create_folder_failed": "創建文件夾失敗",
|
||||||
|
"txt_create_item_failed": "創建項目失敗",
|
||||||
|
"txt_create_send_failed": "創建發送失敗",
|
||||||
|
"txt_create_timed_invite": "創建時效邀請碼",
|
||||||
|
"txt_created_value": "創建於:{value}",
|
||||||
|
"txt_current_new_password_is_required": "需要輸入當前密碼和新密碼",
|
||||||
|
"txt_current_password": "當前密碼",
|
||||||
|
"txt_custom_fields": "自定義字段",
|
||||||
|
"txt_decrypt_failed": "(解密失敗)",
|
||||||
|
"txt_decrypt_failed_2": "解密失敗",
|
||||||
|
"txt_delete": "刪除",
|
||||||
|
"txt_delete_all": "全部刪除",
|
||||||
|
"txt_delete_all_invite_codes_active_inactive": "刪除所有邀請碼(有效/無效)?",
|
||||||
|
"txt_delete_all_invites": "刪除所有邀請碼",
|
||||||
|
"txt_delete_item": "刪除項目",
|
||||||
|
"txt_delete_passkey": "刪除通行密鑰",
|
||||||
|
"txt_delete_item_failed": "刪除項目失敗",
|
||||||
|
"txt_delete_permanently": "永久刪除",
|
||||||
|
"txt_archive": "歸檔",
|
||||||
|
"txt_archive_item": "歸檔項目",
|
||||||
|
"txt_archive_item_message": "歸檔後,此項目將被排除在一般搜索結果和自動填充建議之外。",
|
||||||
|
"txt_archive_selected_items": "歸檔項目",
|
||||||
|
"txt_archive_selected_items_message": "歸檔後,所選的 {count} 個項目將被排除在一般搜索結果和自動填充建議之外。",
|
||||||
|
"txt_archived": "已歸檔",
|
||||||
|
"txt_archive_selected": "歸檔",
|
||||||
|
"txt_item_archived": "項目已歸檔",
|
||||||
|
"txt_item_unarchived": "項目已取消歸檔",
|
||||||
|
"txt_archived_selected_items": "已歸檔所選項目",
|
||||||
|
"txt_unarchived_selected_items": "已取消歸檔所選項目",
|
||||||
|
"txt_archive_item_failed": "歸檔項目失敗",
|
||||||
|
"txt_unarchive_item_failed": "取消歸檔項目失敗",
|
||||||
|
"txt_bulk_archive_failed": "批量歸檔失敗",
|
||||||
|
"txt_bulk_unarchive_failed": "批量取消歸檔失敗",
|
||||||
|
"txt_unarchive": "取消歸檔",
|
||||||
|
"txt_delete_selected": "刪除",
|
||||||
|
"txt_delete_selected_items": "刪除所選項目",
|
||||||
|
"txt_delete_selected_items_permanently": "Delete Selected Items Permanently",
|
||||||
|
"txt_delete_send_failed": "刪除發送失敗",
|
||||||
|
"txt_delete_this_user_and_all_user_data": "刪除此用戶及其所有數據?",
|
||||||
|
"txt_delete_user": "刪除用戶",
|
||||||
|
"txt_deleted_selected_items": "已刪除所選項目",
|
||||||
|
"txt_deleted_selected_items_permanently": "已永久刪除所選項目",
|
||||||
|
"txt_restored_selected_items": "已恢復所選項目",
|
||||||
|
"txt_deleted_selected_sends": "已刪除所選發送",
|
||||||
|
"txt_deletion_date": "刪除日期",
|
||||||
|
"txt_deletion_days": "刪除天數",
|
||||||
|
"txt_device": "設備",
|
||||||
|
"txt_device_authorization_revoked": "設備信任已撤銷",
|
||||||
|
"txt_device_management": "設備管理",
|
||||||
|
"txt_device_note": "備註",
|
||||||
|
"txt_device_note_required": "設備名稱不能為空",
|
||||||
|
"txt_device_note_updated": "設備名稱已更新",
|
||||||
|
"txt_device_removed": "設備已移除",
|
||||||
|
"txt_load_devices_failed": "加載設備失敗",
|
||||||
|
"txt_disable_this_send": "禁用此發送",
|
||||||
|
"txt_disable_totp": "停用 TOTP",
|
||||||
|
"txt_disable_totp_failed": "禁用 TOTP 失敗",
|
||||||
|
"txt_download": "下載",
|
||||||
|
"txt_downloading": "下載中...",
|
||||||
|
"txt_downloading_percent": "下載中 {percent}%",
|
||||||
|
"txt_attachment": "附件",
|
||||||
|
"txt_uploading_attachment_named": "正在上傳 {name}...",
|
||||||
|
"txt_uploading_attachment_named_percent": "正在上傳 {name} {percent}%",
|
||||||
|
"txt_uploading_file_named": "正在上傳 {name}...",
|
||||||
|
"txt_uploading_file_named_percent": "正在上傳 {name} {percent}%",
|
||||||
|
"txt_download_failed": "下載失敗",
|
||||||
|
"txt_edge_browser": "Edge 瀏覽器",
|
||||||
|
"txt_edge_extension": "Edge 擴展",
|
||||||
|
"txt_edit": "編輯",
|
||||||
|
"txt_edit_send": "編輯發送",
|
||||||
|
"txt_email": "郵箱",
|
||||||
|
"txt_email_password_and_recovery_code_are_required": "需要輸入郵箱、密碼和恢復代碼",
|
||||||
|
"txt_enable_totp": "啟用 TOTP",
|
||||||
|
"txt_enable_totp_failed": "啟用 TOTP 失敗",
|
||||||
|
"txt_enabled": "已啟用",
|
||||||
|
"txt_encrypted_file": "加密文件",
|
||||||
|
"txt_encrypted_file_2": "加密文件",
|
||||||
|
"txt_enter_a_folder_name": "請輸入文件夾名稱",
|
||||||
|
"txt_enter_master_password_to_disable_two_step_verification": "輸入主密碼以禁用兩步驗證",
|
||||||
|
"txt_enter_master_password_to_continue": "輸入主密碼以繼續",
|
||||||
|
"txt_enter_master_password_to_view_this_item": "輸入主密碼以查看此項目",
|
||||||
|
"txt_expiration_date": "過期日期",
|
||||||
|
"txt_expiration_days_0_never": "過期天數(0 表示不過期)",
|
||||||
|
"txt_expires_at": "過期時間",
|
||||||
|
"txt_expires_at_value": "過期於:{value}",
|
||||||
|
"txt_expiry": "有效期",
|
||||||
|
"txt_expiry_month": "有效期月",
|
||||||
|
"txt_expiry_year": "有效期年",
|
||||||
|
"txt_failed_to_open_send": "打開發送失敗",
|
||||||
|
"txt_favorite": "收藏",
|
||||||
|
"txt_favorites": "收藏",
|
||||||
|
"txt_duplicates": "重複項",
|
||||||
|
"txt_field": "字段",
|
||||||
|
"txt_field_label": "字段標籤",
|
||||||
|
"txt_field_label_is_required": "字段標籤不能為空",
|
||||||
|
"txt_field_type": "字段類型",
|
||||||
|
"txt_field_value": "字段值",
|
||||||
|
"txt_file": "文件",
|
||||||
|
"txt_file_name": "文件名",
|
||||||
|
"txt_file_send": "文件發送",
|
||||||
|
"txt_file_size": "文件大小",
|
||||||
|
"txt_fingerprint": "指紋",
|
||||||
|
"txt_firefox_browser": "Firefox 瀏覽器",
|
||||||
|
"txt_firefox_extension": "Firefox 擴展",
|
||||||
|
"txt_first_name": "名",
|
||||||
|
"txt_folder": "文件夾",
|
||||||
|
"txt_folder_created": "文件夾已創建",
|
||||||
|
"txt_folder_name": "文件夾名稱",
|
||||||
|
"txt_folder_name_is_required": "文件夾名稱不能為空",
|
||||||
|
"txt_folders": "文件夾",
|
||||||
|
"txt_hidden": "隱藏",
|
||||||
|
"txt_hide": "隱藏",
|
||||||
|
"txt_identity": "身份",
|
||||||
|
"txt_identity_details": "身份詳情",
|
||||||
|
"txt_ie_browser": "IE 瀏覽器",
|
||||||
|
"txt_invite_code_optional": "邀請碼(首位註冊者無需填寫,其他人必填)",
|
||||||
|
"txt_invite_created": "邀請碼已創建",
|
||||||
|
"txt_invite_revoked": "邀請碼已撤銷",
|
||||||
|
"txt_invite_validity_hours": "邀請碼有效期(小時)",
|
||||||
|
"txt_invites": "邀請碼",
|
||||||
|
"txt_ios": "iOS",
|
||||||
|
"txt_item": "項目",
|
||||||
|
"txt_item_created": "項目已創建",
|
||||||
|
"txt_item_deleted": "項目已刪除",
|
||||||
|
"txt_item_history": "項目歷史",
|
||||||
|
"txt_password_history": "密碼歷史記錄",
|
||||||
|
"txt_password_updated_value": "密碼新於: {value}",
|
||||||
|
"txt_item_name_is_required": "項目名稱不能為空",
|
||||||
|
"txt_item_updated": "項目已更新",
|
||||||
|
"txt_last_edited_value": "最後編輯:{value}",
|
||||||
|
"txt_last_name": "姓",
|
||||||
|
"txt_last_seen": "最後在線",
|
||||||
|
"txt_license_number": "證件號",
|
||||||
|
"txt_link_copied": "鏈接已複製",
|
||||||
|
"txt_linked": "已關聯",
|
||||||
|
"txt_linux_desktop": "Linux 桌面端",
|
||||||
|
"txt_loading": "加載中...",
|
||||||
|
"txt_loading_nodewarden": "正在加載 NodeWarden...",
|
||||||
|
"txt_jwt_warning_title": "JWT_SECRET 配置警告",
|
||||||
|
"txt_jwt_warning_subtitle": "JWT 密鑰當前不安全,請先修復後再繼續。",
|
||||||
|
"txt_jwt_title_missing": "未檢測到 JWT_SECRET",
|
||||||
|
"txt_jwt_title_too_short": "JWT_SECRET 長度過短",
|
||||||
|
"txt_jwt_title_default": "JWT_SECRET使用默認值",
|
||||||
|
"txt_jwt_reason_missing": "未檢測到 JWT_SECRET。",
|
||||||
|
"txt_jwt_reason_default": "JWT_SECRET 仍在使用默認示例值。",
|
||||||
|
"txt_jwt_reason_too_short": "JWT_SECRET 長度過短,至少需要 {min} 位。",
|
||||||
|
"txt_jwt_how_to_fix_add": "處理步驟(添加 JWT_SECRET)",
|
||||||
|
"txt_jwt_how_to_fix_replace": "處理步驟(更換 JWT_SECRET)",
|
||||||
|
"txt_jwt_add_step_1": "使用下方 32 位隨機生成器,複製一個新密鑰。",
|
||||||
|
"txt_jwt_add_step_2_prefix": "到 Cloudflare 控制檯 -> Workers 和 Pages -> 你的服務 -> ",
|
||||||
|
"txt_jwt_add_step_2_suffix": " -> 變量和機密 -> 新增",
|
||||||
|
"txt_jwt_add_step_3": "保存並等待重新部署完成,然後刷新本頁確認。",
|
||||||
|
"txt_jwt_replace_step_1": "使用下方 32 位隨機生成器,生成更強的密鑰(至少 {min} 位)。",
|
||||||
|
"txt_jwt_replace_step_2_prefix": "到 Cloudflare 控制檯 -> Workers 和 Pages -> 你的服務 -> ",
|
||||||
|
"txt_jwt_replace_step_2_suffix": " -> 變量和機密 -> 更新 JWT_SECRET",
|
||||||
|
"txt_jwt_replace_step_3": "保存並等待重新部署完成,然後刷新本頁確認。",
|
||||||
|
"txt_jwt_secret_type_label": "類型:",
|
||||||
|
"txt_jwt_secret_type_value": "密鑰",
|
||||||
|
"txt_jwt_secret_name_label": "變量名稱:",
|
||||||
|
"txt_jwt_secret_value_label": "值:",
|
||||||
|
"txt_jwt_secret_value_requirement": "最低 {min} 位隨機字符",
|
||||||
|
"txt_jwt_what_is": "JWT 是什麼",
|
||||||
|
"txt_jwt_what_is_body": "JWT_SECRET 是服務端用來簽發和校驗登錄令牌的密鑰。如果它缺失、過短,或者仍然使用示例值,實例就不能安全地正常使用。",
|
||||||
|
"txt_how_to_fix": "處理步驟(添加 / 更換)",
|
||||||
|
"txt_jwt_fix_step_1": "你可以繼續下一步,不影響使用。",
|
||||||
|
"txt_jwt_fix_step_2": "如果當前密鑰不是強隨機值,建議使用下方 32 位生成器。",
|
||||||
|
"txt_jwt_fix_step_3": "到 Cloudflare 控制檯 -> Workers 和 Pages -> 你的服務 -> 設置 -> 變量和機密,更新 JWT_SECRET。",
|
||||||
|
"txt_jwt_fix_step_4": "保存並等待重新部署完成,然後刷新本頁確認。",
|
||||||
|
"txt_random_secret_generator": "隨機密鑰生成器",
|
||||||
|
"txt_copied": "已複製",
|
||||||
|
"txt_log_in": "登錄",
|
||||||
|
"txt_logging_in": "正在登錄...",
|
||||||
|
"txt_log_out": "退出",
|
||||||
|
"txt_lock": "鎖定",
|
||||||
|
"txt_menu": "菜單",
|
||||||
|
"txt_settings": "設置",
|
||||||
|
"txt_back": "返回",
|
||||||
|
"txt_login": "登錄",
|
||||||
|
"txt_login_credentials": "登錄信息",
|
||||||
|
"txt_login_failed": "登錄失敗",
|
||||||
|
"txt_login_success": "登錄成功",
|
||||||
|
"txt_macos_desktop": "macOS 桌面端",
|
||||||
|
"txt_manage_authorized_devices_and_30_day_totp_trusted_sessions": "管理已授權設備和 30 天 TOTP 受信會話。",
|
||||||
|
"txt_manage_device_sessions_and_30_day_totp_trusted_sessions": "管理設備會話和 30 天 TOTP 受信狀態。",
|
||||||
|
"txt_master_password": "主密碼",
|
||||||
|
"txt_master_password_changed_please_login_again": "主密碼已修改,請重新登錄",
|
||||||
|
"txt_master_password_changed_signing_out_everywhere": "主密碼已修改,正在退出所有設備",
|
||||||
|
"txt_master_password_is_required": "主密碼不能為空",
|
||||||
|
"txt_master_password_is_required_2": "請輸入主密碼",
|
||||||
|
"txt_master_password_must_be_at_least_12_chars": "主密碼至少需要 12 個字符",
|
||||||
|
"txt_master_password_reprompt": "主密碼二次確認",
|
||||||
|
"txt_master_password_reprompt_2": "主密碼二次確認",
|
||||||
|
"txt_max_access_count": "最大訪問次數",
|
||||||
|
"txt_middle_name": "中間名",
|
||||||
|
"txt_drag_to_reorder": "拖動調整順序",
|
||||||
|
"txt_move": "移動",
|
||||||
|
"txt_move_selected_items": "移動所選項目",
|
||||||
|
"txt_moved_selected_items": "已移動所選項目",
|
||||||
|
"txt_name": "名稱",
|
||||||
|
"txt_name_is_required": "名稱不能為空",
|
||||||
|
"txt_new_password": "新密碼",
|
||||||
|
"txt_nothing_to_copy": "沒有可複製的內容",
|
||||||
|
"txt_new_password_must_be_at_least_12_chars": "新密碼至少需要 12 個字符",
|
||||||
|
"txt_new_passwords_do_not_match": "兩次輸入的新密碼不一致",
|
||||||
|
"txt_new_send": "新建發送",
|
||||||
|
"txt_next": "下一頁",
|
||||||
|
"txt_no": "否",
|
||||||
|
"txt_no_devices_found": "未找到設備",
|
||||||
|
"txt_no_folder": "無文件夾",
|
||||||
|
"txt_no_items": "沒有項目",
|
||||||
|
"txt_no_username": "無用戶名",
|
||||||
|
"txt_no_verification_codes": "沒有驗證碼",
|
||||||
|
"txt_no_name": "(無名稱)",
|
||||||
|
"txt_no_sends": "沒有發送",
|
||||||
|
"txt_nodewarden_send": "NodeWarden 發送",
|
||||||
|
"txt_not_trusted": "未信任",
|
||||||
|
"txt_note": "筆記",
|
||||||
|
"txt_notes": "備註",
|
||||||
|
"txt_replace_device_name_with_note": "為這臺設備設置自定義名稱,不會改變系統識別到的設備類型。",
|
||||||
|
"txt_number": "數字",
|
||||||
|
"txt_open": "打開",
|
||||||
|
"txt_opera_browser": "Opera 瀏覽器",
|
||||||
|
"txt_opera_extension": "Opera 擴展",
|
||||||
|
"txt_or": "或",
|
||||||
|
"txt_options": "選項",
|
||||||
|
"txt_passport_number": "護照號",
|
||||||
|
"txt_password": "密碼",
|
||||||
|
"txt_password_is_already_verified": "密碼已驗證",
|
||||||
|
"txt_passwords_do_not_match": "兩次輸入的密碼不一致",
|
||||||
|
"txt_password_hint": "密碼提示",
|
||||||
|
"txt_password_hint_optional": "密碼提示(可選)",
|
||||||
|
"txt_password_hint_placeholder": "寫一句只有你自己看得懂的線索",
|
||||||
|
"txt_password_hint_register_placeholder": "這個提示可以在網頁登錄頁直接顯示。",
|
||||||
|
"txt_password_hint_register_help": "這個提示可以在網頁登錄頁直接顯示。不要填寫主密碼、恢復代碼,或任何能直接暴露密碼的信息。",
|
||||||
|
"txt_password_hint_login_help": "忘記主密碼時,可以查看註冊時保存的提示。",
|
||||||
|
"txt_password_hint_login_note": "這裡只會顯示提示語,不會顯示你的主密碼本身。",
|
||||||
|
"txt_show_password_hint": "查看密碼提示",
|
||||||
|
"txt_hide_password_hint": "隱藏密碼提示",
|
||||||
|
"txt_loading_password_hint": "正在加載提示...",
|
||||||
|
"txt_password_hint_not_set": "這個郵箱沒有可顯示的密碼提示。",
|
||||||
|
"txt_password_hint_load_failed": "加載密碼提示失敗",
|
||||||
|
"txt_password_hint_too_long": "密碼提示最多隻能輸入 120 個字符",
|
||||||
|
"txt_passkey": "通行密鑰",
|
||||||
|
"txt_passkeys": "通行密鑰",
|
||||||
|
"txt_passkey_created_at_value": "創建於 {value}",
|
||||||
|
"txt_phone": "電話",
|
||||||
|
"txt_please_input_email_and_password": "請輸入郵箱和密碼",
|
||||||
|
"txt_please_input_master_password": "請輸入主密碼",
|
||||||
|
"txt_please_input_totp_code": "請輸入 TOTP 驗證碼",
|
||||||
|
"txt_please_select_a_file": "請選擇文件",
|
||||||
|
"txt_postal_code": "郵政編碼",
|
||||||
|
"txt_prev": "上一頁",
|
||||||
|
"txt_private_key": "私鑰",
|
||||||
|
"txt_profile": "資料",
|
||||||
|
"txt_profile_unavailable": "資料不可用",
|
||||||
|
"txt_profile_updated": "資料已更新",
|
||||||
|
"txt_public_key": "公鑰",
|
||||||
|
"txt_recover_2fa_failed": "恢復 2FA 失敗",
|
||||||
|
"txt_recover_two_step_login": "恢復兩步登錄",
|
||||||
|
"txt_recovered_but_auto_login_failed_please_sign_in": "已恢復,但自動登錄失敗,請手動登錄",
|
||||||
|
"txt_recovery_code": "恢復代碼",
|
||||||
|
"txt_recovery_code_and_api_key": "恢復代碼和 API 密鑰",
|
||||||
|
"txt_recovery_code_copied": "恢復代碼已複製",
|
||||||
|
"txt_recovery_code_is_empty": "恢復代碼為空",
|
||||||
|
"txt_recovery_code_loaded": "恢復代碼已加載",
|
||||||
|
"txt_api_key": "API 密鑰",
|
||||||
|
"txt_view_api_key": "查看 API 密鑰",
|
||||||
|
"txt_rotate_api_key": "輪換 API 密鑰",
|
||||||
|
"txt_api_key_copied": "API 密鑰已複製",
|
||||||
|
"txt_api_key_loaded": "API 密鑰已加載",
|
||||||
|
"txt_api_key_rotated": "API 密鑰已輪換",
|
||||||
|
"txt_rotate_api_key_confirm": "輪換 API 密鑰?當前密鑰將立即失效。",
|
||||||
|
"txt_api_key_is_empty": "API 密鑰為空",
|
||||||
|
"txt_api_key_dialog_intro": "您的 API 密鑰可用於在 Bitwarden CLI 中進行身份驗證。",
|
||||||
|
"txt_api_key_warning_body": "您的 API 密鑰是一種替代身份驗證機制。請嚴格保密。",
|
||||||
|
"txt_oauth_client_credentials": "OAuth 2.0 客戶端憑據",
|
||||||
|
"txt_client_id": "client_id",
|
||||||
|
"txt_client_secret": "client_secret",
|
||||||
|
"txt_scope": "scope",
|
||||||
|
"txt_grant_type": "grant_type",
|
||||||
|
"txt_refresh": "刷新",
|
||||||
|
"txt_refresh_in_seconds_s": "{seconds} 秒後刷新",
|
||||||
|
"txt_regenerate": "重新生成",
|
||||||
|
"txt_registration_succeeded_please_sign_in": "註冊成功,請登錄",
|
||||||
|
"txt_remove": "移除",
|
||||||
|
"txt_remove_device": "移除設備",
|
||||||
|
"txt_remove_device_2": "移除設備",
|
||||||
|
"txt_remove_all_devices": "移除所有設備",
|
||||||
|
"txt_remove_all_devices_and_clear_all_2fa_trust": "確認移除所有設備並清除全部 2FA 信任嗎?",
|
||||||
|
"txt_remove_all_devices_and_sign_out_all_sessions": "確認移除所有設備、清除全部信任,並讓所有設備重新登錄嗎?",
|
||||||
|
"txt_remove_device_name_and_clear_its_2fa_trust": "確認移除設備“{name}”並清除其 2FA 信任嗎?",
|
||||||
|
"txt_remove_device_and_sign_out_name": "確認移除設備“{name}”,清除其信任,並讓它重新登錄嗎?",
|
||||||
|
"txt_reveal": "顯示",
|
||||||
|
"txt_restore": "恢復",
|
||||||
|
"txt_revoke": "撤銷",
|
||||||
|
"txt_revoke_30_day_totp_trust_for_name": "確認撤銷“{name}”的 30 天 TOTP 信任嗎?",
|
||||||
|
"txt_revoke_30_day_totp_trust_from_all_devices": "確認撤銷所有設備的 30 天 TOTP 信任嗎?",
|
||||||
|
"txt_revoke_all_trusted": "撤銷全部受信任設備",
|
||||||
|
"txt_revoke_all_trusted_devices": "撤銷所有設備信任",
|
||||||
|
"txt_revoke_device_authorization": "撤銷設備信任",
|
||||||
|
"txt_revoke_device_trust_failed": "撤銷設備信任失敗",
|
||||||
|
"txt_revoke_all_device_trust_failed": "撤銷所有設備信任失敗",
|
||||||
|
"txt_revoke_trust": "撤銷信任",
|
||||||
|
"txt_untrust": "不信任",
|
||||||
|
"txt_update_device_note_failed": "更新設備備註失敗",
|
||||||
|
"txt_role": "角色",
|
||||||
|
"txt_save": "保存",
|
||||||
|
"txt_save_profile": "保存資料",
|
||||||
|
"txt_save_profile_failed": "保存資料失敗",
|
||||||
|
"txt_search_sends": "搜索發送...",
|
||||||
|
"txt_search_your_secure_vault": "搜索你的密碼庫...",
|
||||||
|
"txt_clear_search": "清空搜索",
|
||||||
|
"txt_clear_search_esc": "清空搜索(Esc)",
|
||||||
|
"txt_sort": "排序",
|
||||||
|
"txt_sort_last_edited": "最近修改",
|
||||||
|
"txt_sort_created": "最近創建",
|
||||||
|
"txt_sort_name": "A-Z",
|
||||||
|
"txt_secret_and_code_are_required": "密鑰和代碼不能為空",
|
||||||
|
"txt_secret_copied": "密鑰已複製",
|
||||||
|
"txt_secure_note": "安全筆記",
|
||||||
|
"txt_security_code": "安全碼",
|
||||||
|
"txt_security_code_cvv": "安全碼 (CVV)",
|
||||||
|
"txt_select_all": "全選",
|
||||||
|
"txt_select_duplicate_items": "選擇重複項",
|
||||||
|
"txt_select_an_item": "請選擇一個項目",
|
||||||
|
"txt_send_created": "發送已創建",
|
||||||
|
"txt_send_deleted": "發送已刪除",
|
||||||
|
"txt_send_details": "發送詳情",
|
||||||
|
"txt_send_file": "發送文件",
|
||||||
|
"txt_send_unavailable": "發送不可用。",
|
||||||
|
"txt_send_updated": "發送已更新",
|
||||||
|
"txt_sign_out": "退出登錄",
|
||||||
|
"txt_ssh_key": "SSH 密鑰",
|
||||||
|
"txt_ssn": "社保號",
|
||||||
|
"txt_state_province": "省 / 州",
|
||||||
|
"txt_status": "狀態",
|
||||||
|
"txt_online": "在線",
|
||||||
|
"txt_offline": "離線",
|
||||||
|
"txt_submit": "提交",
|
||||||
|
"txt_sync": "同步",
|
||||||
|
"txt_sync_vault": "同步",
|
||||||
|
"txt_switch_to_dark_mode": "切換到暗黑模式",
|
||||||
|
"txt_switch_to_light_mode": "切換到明亮模式",
|
||||||
|
"txt_dash": "-",
|
||||||
|
"txt_text": "文本",
|
||||||
|
"txt_text_2fa_recovered": "2FA 已恢復",
|
||||||
|
"txt_text_2fa_recovered_new_recovery_code_code": "2FA 已恢復,新的恢復代碼:{code}",
|
||||||
|
"txt_text_3": "------",
|
||||||
|
"txt_text_is_required": "文本不能為空",
|
||||||
|
"txt_text_send": "文本發送",
|
||||||
|
"txt_this_is_a_one_time_code_after_it_is_used_a_new_code_is_generated_automatically": "這是一次性恢復代碼,使用後將自動生成新的恢復代碼。",
|
||||||
|
"txt_this_item_requires_master_password_every_time_before_viewing_details": "每次查看詳情前均需輸入主密碼",
|
||||||
|
"txt_this_link_is_missing_decryption_key": "此鏈接缺少解密密鑰",
|
||||||
|
"txt_this_send_is_password_protected": "此發送受密碼保護",
|
||||||
|
"txt_title": "稱謂",
|
||||||
|
"txt_totp": "TOTP",
|
||||||
|
"txt_totp_code": "TOTP 驗證碼",
|
||||||
|
"txt_totp_disabled": "TOTP 已禁用",
|
||||||
|
"txt_totp_enabled": "TOTP 已啟用",
|
||||||
|
"txt_totp_is_enabled_for_this_account": "此賬戶已啟用 TOTP。",
|
||||||
|
"txt_total_items_count": "共 {count} 項",
|
||||||
|
"txt_totp_secret": "TOTP 密鑰",
|
||||||
|
"txt_totp_verify_failed": "TOTP 驗證失敗",
|
||||||
|
"txt_attachments": "附件",
|
||||||
|
"txt_upload_attachments": "上傳附件",
|
||||||
|
"txt_new_attachments": "待上傳附件",
|
||||||
|
"txt_marked_for_removal_count": "保存後將刪除 {count} 個附件",
|
||||||
|
"txt_trash": "回收站",
|
||||||
|
"txt_trust_this_device_for_30_days": "信任此設備 30 天",
|
||||||
|
"txt_trusted_until": "信任至",
|
||||||
|
"txt_two_step_verification": "兩步驗證",
|
||||||
|
"txt_type": "類型",
|
||||||
|
"txt_type_type": "類型 {type}",
|
||||||
|
"txt_unban": "解封",
|
||||||
|
"txt_unchecked": "未勾選",
|
||||||
|
"txt_unknown_device": "未知設備",
|
||||||
|
"txt_unlock": "解鎖",
|
||||||
|
"txt_unlocking": "正在解鎖...",
|
||||||
|
"txt_unlock_details": "解鎖詳情",
|
||||||
|
"txt_unlock_failed": "解鎖失敗",
|
||||||
|
"txt_unlock_failed_master_password_is_incorrect": "解鎖失敗,主密碼不正確。",
|
||||||
|
"txt_unlock_item": "解鎖項目",
|
||||||
|
"txt_unlock_send": "解鎖發送",
|
||||||
|
"txt_unlock_vault": "解鎖密碼庫",
|
||||||
|
"txt_unlocked": "已解鎖",
|
||||||
|
"txt_all_devices_removed": "已移除所有設備",
|
||||||
|
"txt_remove_device_failed": "移除設備失敗",
|
||||||
|
"txt_remove_all_devices_failed": "移除所有設備失敗",
|
||||||
|
"txt_update_item_failed": "更新項目失敗",
|
||||||
|
"txt_update_send_failed": "更新發送失敗",
|
||||||
|
"txt_use_recovery_code": "使用恢復代碼",
|
||||||
|
"txt_use_your_one_time_recovery_code_to_disable_two_step_verification": "使用一次性恢復代碼禁用兩步驗證。",
|
||||||
|
"txt_user_deleted": "用戶已刪除",
|
||||||
|
"txt_user_status_updated": "用戶狀態已更新",
|
||||||
|
"txt_username": "用戶名",
|
||||||
|
"txt_uri_match_default_base_domain": "默認(基礎域名)",
|
||||||
|
"txt_uri_match_base_domain": "基礎域名",
|
||||||
|
"txt_uri_match_host": "主機",
|
||||||
|
"txt_uri_match_exact": "精確",
|
||||||
|
"txt_uri_match_never": "從不",
|
||||||
|
"txt_uri_match_starts_with": "開始於",
|
||||||
|
"txt_uri_match_regular_expression": "正則表達式",
|
||||||
|
"txt_users": "用戶",
|
||||||
|
"txt_vault_synced": "密碼庫已同步",
|
||||||
|
"txt_verification_code": "驗證碼",
|
||||||
|
"txt_verify": "驗證",
|
||||||
|
"txt_warning": "警告",
|
||||||
|
"txt_view_recovery_code": "查看恢復代碼",
|
||||||
|
"txt_web": "網頁",
|
||||||
|
"txt_website": "網站",
|
||||||
|
"txt_websites": "網站",
|
||||||
|
"txt_windows_desktop": "Windows 桌面端",
|
||||||
|
"txt_yes": "是",
|
||||||
|
"txt_auto_lock": "會話超時",
|
||||||
|
"txt_auto_lock_description": "頁面閒置後執行會話超時動作;關閉頁面或瀏覽器後再次打開始終進入鎖定頁。",
|
||||||
|
"txt_auto_lock_updated": "會話超時已更新",
|
||||||
|
"txt_session_timeout": "會話超時",
|
||||||
|
"txt_session_timeout_updated": "會話超時已更新",
|
||||||
|
"txt_timeout_time": "超時時間",
|
||||||
|
"txt_timeout_action": "超時動作",
|
||||||
|
"txt_timeout_action_logout": "註銷",
|
||||||
|
"txt_timeout_action_lock": "鎖定",
|
||||||
|
"txt_in_planning": "構思中",
|
||||||
|
"txt_security_preferences": "安全偏好",
|
||||||
|
"txt_timeout_1_minute": "1 分鐘",
|
||||||
|
"txt_timeout_5_minutes": "5 分鐘",
|
||||||
|
"txt_timeout_15_minutes": "15 分鐘",
|
||||||
|
"txt_timeout_30_minutes": "30 分鐘",
|
||||||
|
"txt_timeout_never": "從不",
|
||||||
|
"txt_lock_after_1_minute": "閒置 1 分鐘後",
|
||||||
|
"txt_lock_after_5_minutes": "閒置 5 分鐘後",
|
||||||
|
"txt_lock_after_15_minutes": "閒置 15 分鐘後",
|
||||||
|
"txt_lock_after_30_minutes": "閒置 30 分鐘後",
|
||||||
|
"txt_lock_after_never": "不因閒置鎖定",
|
||||||
|
"txt_import": "導入",
|
||||||
|
"txt_export": "導出",
|
||||||
|
"txt_format": "格式",
|
||||||
|
"txt_source_file": "源文件",
|
||||||
|
"txt_folder_handling": "文件夾處理",
|
||||||
|
"txt_import_folder_mode_original": "保留導入文件中的原始路徑",
|
||||||
|
"txt_import_folder_mode_none": "不使用文件夾",
|
||||||
|
"txt_import_folder_mode_target": "導入到指定文件夾",
|
||||||
|
"txt_target_folder": "目標文件夾",
|
||||||
|
"txt_select_folder_placeholder": "-- 選擇文件夾 --",
|
||||||
|
"txt_import_vault_data_hint": "將數據導入到當前賬號。",
|
||||||
|
"txt_export_vault_data_hint": "從當前賬號導出數據。",
|
||||||
|
"txt_import_export_title": "導入導出",
|
||||||
|
"txt_encrypted_mode": "加密方式",
|
||||||
|
"txt_account_verification": "賬號驗證",
|
||||||
|
"txt_password_verification": "密碼驗證",
|
||||||
|
"txt_file_password": "文件密碼",
|
||||||
|
"txt_zip_password_optional": "ZIP 密碼(可選)",
|
||||||
|
"txt_zip_password": "ZIP 密碼",
|
||||||
|
"txt_close": "關閉",
|
||||||
|
"txt_total": "總計",
|
||||||
|
"txt_import_success": "數據導入成功",
|
||||||
|
"txt_import_success_number_of_items": "一共導入了 {count} 個項目。",
|
||||||
|
"txt_import_attachment_summary": "附件已導入 {imported}/{total} 個。",
|
||||||
|
"txt_import_failed_attachments_title": "以下 {count} 個附件未導入:",
|
||||||
|
"txt_import_attachment_target_not_found": "沒有找到對應的導入項目。",
|
||||||
|
"txt_upload_attachment_failed": "附件上傳失敗。",
|
||||||
|
"txt_import_file_password_required": "請輸入文件密碼。",
|
||||||
|
"txt_import_invalid_zip_password": "ZIP 密碼錯誤。",
|
||||||
|
"txt_export_completed": "導出完成",
|
||||||
|
"txt_export_failed": "導出失敗",
|
||||||
|
"txt_import_invalid_password_protected_file": "密碼保護導出文件格式無效。",
|
||||||
|
"txt_import_decrypt_failed": "導入文件解密失敗。",
|
||||||
|
"txt_import_empty_zip_archive": "ZIP 壓縮包為空。",
|
||||||
|
"txt_import_no_json_found_in_zip": "ZIP 內未找到可導入的 JSON 數據。",
|
||||||
|
"txt_import_data_json_not_found": "ZIP 內未找到 data.json。",
|
||||||
|
"txt_import_zip_password_required": "該 ZIP 需要密碼。",
|
||||||
|
"txt_import_invalid_json_file": "JSON 文件無效",
|
||||||
|
"txt_import_failed": "導入失敗",
|
||||||
|
"txt_import_encrypted_file_title": "導入加密文件",
|
||||||
|
"txt_import_encrypted_file_message": "該 Bitwarden 導出文件已加密,請輸入文件密碼繼續。",
|
||||||
|
"txt_import_encrypted_zip_title": "導入加密 ZIP",
|
||||||
|
"txt_import_encrypted_zip_message": "該 ZIP 壓縮包已加密,請輸入 ZIP 密碼繼續。",
|
||||||
|
"txt_new_type_header": "新建{type}",
|
||||||
|
"txt_edit_type_header": "編輯{type}",
|
||||||
|
"txt_delete_folder": "刪除文件夾",
|
||||||
|
"txt_delete_folder_message": "刪除文件夾「{name}」?其中的項目將移至無文件夾。",
|
||||||
|
"txt_delete_all_folders": "刪除全部文件夾",
|
||||||
|
"txt_delete_all_folders_message": "確認刪除全部文件夾嗎?其中的項目將移至無文件夾。",
|
||||||
|
"txt_folder_not_found": "文件夾不存在",
|
||||||
|
"txt_folder_deleted": "文件夾已刪除",
|
||||||
|
"txt_folder_updated": "文件夾已重命名",
|
||||||
|
"txt_folders_deleted": "文件夾已刪除",
|
||||||
|
"txt_update_folder_failed": "重命名文件夾失敗",
|
||||||
|
"txt_delete_folder_failed": "刪除文件夾失敗",
|
||||||
|
"txt_delete_all_folders_failed": "刪除全部文件夾失敗",
|
||||||
|
"txt_other": "其他",
|
||||||
|
"txt_vault_key_unavailable": "賬戶密鑰不可用,請先解鎖密碼庫後重試。",
|
||||||
|
"txt_vault_not_ready": "密碼庫數據尚未就緒",
|
||||||
|
"txt_unsupported_export_format": "不支持的導出格式",
|
||||||
|
"txt_invalid_encrypted_export": "加密導出文件無效。",
|
||||||
|
"txt_export_belongs_to_another_account": "此加密導出文件屬於另一個賬號。",
|
||||||
|
"txt_invalid_argon2id_params": "導出文件中的 Argon2id 參數無效。",
|
||||||
|
"txt_unsupported_kdf_type": "不支持的 KDF 類型:{type}",
|
||||||
|
"txt_invalid_file_password": "文件密碼錯誤。",
|
||||||
|
"txt_failed_to_map_attachments": "無法將 {count} 個附件匹配到導入項目。",
|
||||||
|
"txt_role_admin": "管理員",
|
||||||
|
"txt_role_user": "用戶",
|
||||||
|
"txt_status_active": "正常",
|
||||||
|
"txt_status_banned": "已封禁",
|
||||||
|
"txt_status_inactive": "未激活",
|
||||||
|
"txt_language": "語言",
|
||||||
|
"txt_display_language": "顯示語言",
|
||||||
|
"txt_language_saved_locally": "此偏好會保存在當前瀏覽器中,下次打開應用前就會生效。"
|
||||||
|
};
|
||||||
|
|
||||||
|
export default zhTW;
|
||||||
@@ -36,6 +36,14 @@ export default defineConfig({
|
|||||||
return 'i18n-zh-CN';
|
return 'i18n-zh-CN';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (normalized.includes('/src/lib/i18n/locales/zh-TW.ts')) {
|
||||||
|
return 'i18n-zh-TW';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalized.includes('/src/lib/i18n/locales/ru.ts')) {
|
||||||
|
return 'i18n-ru';
|
||||||
|
}
|
||||||
|
|
||||||
if (normalized.includes('/src/lib/i18n.ts')) {
|
if (normalized.includes('/src/lib/i18n.ts')) {
|
||||||
return 'i18n-core';
|
return 'i18n-core';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user