mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-08-01 03:16:58 +08:00
feat: add i18n with language switcher and English/Chinese translations
This commit is contained in:
58
web/src/i18n/index.tsx
Normal file
58
web/src/i18n/index.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { createContext, useContext, useMemo, useState, useEffect } from 'react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { zh } from './locales/zh';
|
||||
import { en } from './locales/en';
|
||||
|
||||
type Lang = 'zh' | 'en';
|
||||
type Dict = Record<string, string>;
|
||||
|
||||
const dicts: Record<Lang, Dict> = {
|
||||
zh,
|
||||
en,
|
||||
};
|
||||
|
||||
export interface I18nContextValue {
|
||||
lang: Lang;
|
||||
setLang: (lang: Lang) => void;
|
||||
t: (key: string, params?: Record<string, string | number>) => string;
|
||||
}
|
||||
|
||||
const I18nContext = createContext<I18nContextValue | null>(null);
|
||||
|
||||
function interpolate(template: string, params?: Record<string, string | number>): string {
|
||||
if (!params) return template;
|
||||
return template.replace(/\{(\w+)\}/g, (_, k) => String(params[k] ?? `{${k}}`));
|
||||
}
|
||||
|
||||
export function I18nProvider({ children }: PropsWithChildren) {
|
||||
const [lang, setLangState] = useState<Lang>(() => (localStorage.getItem('lang') as Lang) || 'zh');
|
||||
|
||||
const setLang = (l: Lang) => {
|
||||
setLangState(l);
|
||||
localStorage.setItem('lang', l);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.lang = lang;
|
||||
}, [lang]);
|
||||
|
||||
const t = (key: string, params?: Record<string, string | number>) => {
|
||||
const dict = dicts[lang] || {};
|
||||
const raw = dict[key] ?? key; // fallback to key (English)
|
||||
return interpolate(raw, params);
|
||||
};
|
||||
|
||||
const value = useMemo<I18nContextValue>(() => ({ lang, setLang, t }), [lang]);
|
||||
|
||||
return (
|
||||
<I18nContext.Provider value={value}>
|
||||
{children}
|
||||
</I18nContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useI18n() {
|
||||
const ctx = useContext(I18nContext);
|
||||
if (!ctx) throw new Error('useI18n must be used within I18nProvider');
|
||||
return ctx;
|
||||
}
|
||||
365
web/src/i18n/locales/en.ts
Normal file
365
web/src/i18n/locales/en.ts
Normal file
@@ -0,0 +1,365 @@
|
||||
export const en = {
|
||||
// General
|
||||
'All Files': 'All Files',
|
||||
'Manage': 'Manage',
|
||||
// 'System' defined above for navigation
|
||||
'Follow System': 'System',
|
||||
'Automation': 'Automation',
|
||||
'My Shares': 'My Shares',
|
||||
'Offline Downloads': 'Offline Downloads',
|
||||
'Adapters': 'Adapters',
|
||||
'Plugins': 'App Center',
|
||||
'System Settings': 'System Settings',
|
||||
'Backup & Restore': 'Backup & Restore',
|
||||
'System Logs': 'System Logs',
|
||||
|
||||
// Top header
|
||||
'Search files / tags / types': 'Search files / tags / types',
|
||||
'Log Out': 'Log Out',
|
||||
'Admin': 'Admin',
|
||||
'Language': 'Language',
|
||||
'Chinese': '中文',
|
||||
'English': 'English',
|
||||
|
||||
// Auth / Login
|
||||
'Welcome Back': 'Welcome Back',
|
||||
'Sign in to your Foxel account': 'Sign in to your Foxel account',
|
||||
'Username / Email': 'Username / Email',
|
||||
'Password': 'Password',
|
||||
'Sign In': 'Sign In',
|
||||
'Please enter username and password': 'Please enter username and password',
|
||||
'Login failed': 'Login failed',
|
||||
'Your next-generation file manager': 'Your next-generation file manager',
|
||||
'Cross-platform sync, access anywhere': 'Cross-platform sync, access anywhere',
|
||||
'AI-powered search for quick find': 'AI-powered search for quick find',
|
||||
'Flexible sharing and collaboration': 'Flexible sharing and collaboration',
|
||||
'Powerful automation to simplify tasks': 'Powerful automation to simplify tasks',
|
||||
'Join our community:': 'Join our community:',
|
||||
|
||||
// Share page
|
||||
'Refresh': 'Refresh',
|
||||
'Copy': 'Copy',
|
||||
// 'Cancel' already defined above
|
||||
'Copied link': 'Link copied',
|
||||
'Share canceled': 'Share canceled',
|
||||
'Cancel failed': 'Cancel failed',
|
||||
'Load failed': 'Load failed',
|
||||
'Are you sure to cancel share?': 'Are you sure to cancel share?',
|
||||
|
||||
'Share Name': 'Share Name',
|
||||
'Share Content': 'Share Content',
|
||||
'Created At': 'Created At',
|
||||
'Expires At': 'Expires At',
|
||||
'Forever': 'Forever',
|
||||
'Access': 'Access',
|
||||
'Public': 'Public',
|
||||
'By Password': 'By Password',
|
||||
|
||||
// Public share page
|
||||
'Password Required': 'Password Required',
|
||||
'Please enter password': 'Please enter password',
|
||||
'Confirm': 'Confirm',
|
||||
'Unable to load share info': 'Unable to load share info',
|
||||
'Share load failed': 'Failed to load share',
|
||||
'Wrong password': 'Wrong password',
|
||||
'Root': 'All Files',
|
||||
'Created on {date}': 'Created on {date}',
|
||||
'Expires on {date}': 'Expires on {date}',
|
||||
'Download File': 'Download File',
|
||||
'Preview not supported for this file type': 'Preview not supported for this file type',
|
||||
'Back': 'Back',
|
||||
'Download': 'Download',
|
||||
|
||||
// Offline download
|
||||
'No offline download tasks': 'No offline download tasks',
|
||||
// Header/File Explorer
|
||||
'Home': 'Home',
|
||||
'File Manager': 'File Manager',
|
||||
'New Folder': 'New Folder',
|
||||
'Upload': 'Upload',
|
||||
'Name': 'Name',
|
||||
'Size': 'Size',
|
||||
'Modified Time': 'Modified Time',
|
||||
'Grid': 'Grid',
|
||||
'List': 'List',
|
||||
'Mount Point': 'Mount Point',
|
||||
|
||||
// Context menu
|
||||
'Upload File': 'Upload File',
|
||||
'Open': 'Open',
|
||||
'Open With': 'Open With',
|
||||
'Default': 'Default',
|
||||
'Rename': 'Rename',
|
||||
'Delete': 'Delete',
|
||||
'Details': 'Details',
|
||||
'Get Direct Link': 'Get Direct Link',
|
||||
|
||||
// Side nav modals
|
||||
'Join Community': 'Join Community',
|
||||
'Scan to join WeChat group': 'Scan to join WeChat group',
|
||||
'If QR expires, add drizzle2001 to join': 'If QR expires, add drizzle2001 to join',
|
||||
'Version Info': 'Version Info',
|
||||
'Current Version': 'Current Version',
|
||||
'Latest Version': 'Latest Version',
|
||||
'New version found: {version}': 'New version found: {version}',
|
||||
'Please update to the latest for features and fixes': 'Please update to the latest for features and fixes',
|
||||
'Open Releases': 'Open Releases',
|
||||
'Changelog': 'Changelog',
|
||||
'Fetching latest version...': 'Fetching latest version...',
|
||||
'Update available': 'Update available',
|
||||
'You are on the latest: {version}': 'You are on the latest: {version}',
|
||||
'Up to date': 'Up to date',
|
||||
|
||||
// Share modal
|
||||
'Share {count} items': 'Share {count} items',
|
||||
'Share link created': 'Share link created',
|
||||
'Create failed': 'Create failed',
|
||||
'Copied to clipboard': 'Copied to clipboard',
|
||||
'Expiration (days)': 'Expiration (days)',
|
||||
'Set 0 or negative for forever': 'Set 0 or negative for forever',
|
||||
'Share link created successfully!': 'Share link created successfully!',
|
||||
'Share Link': 'Share Link',
|
||||
'Share created': 'Share created',
|
||||
'Create Share': 'Create Share',
|
||||
'Done': 'Done',
|
||||
'Create': 'Create',
|
||||
|
||||
// Direct link modal
|
||||
'Failed to generate link': 'Failed to generate link',
|
||||
'Markdown copied to clipboard': 'Markdown copied to clipboard',
|
||||
'Generate a direct link for {name}': 'Generate a direct link for {name}',
|
||||
'1 hour': '1 hour',
|
||||
'1 day': '1 day',
|
||||
'7 days': '7 days',
|
||||
'Generating link...': 'Generating link...',
|
||||
'Link will appear here': 'Link will appear here',
|
||||
'Copy Markdown': 'Copy Markdown',
|
||||
'Close': 'Close',
|
||||
|
||||
// File detail
|
||||
'Camera Make': 'Camera Make',
|
||||
'Camera Model': 'Camera Model',
|
||||
'Capture Time': 'Capture Time',
|
||||
'X Resolution': 'X Resolution',
|
||||
'Y Resolution': 'Y Resolution',
|
||||
'Exposure Time': 'Exposure Time',
|
||||
'Aperture': 'Aperture',
|
||||
'Focal Length': 'Focal Length',
|
||||
'Width': 'Width',
|
||||
'Height': 'Height',
|
||||
'No common EXIF info': 'No common EXIF info',
|
||||
'Bytes': 'Bytes',
|
||||
'File Properties': 'File Properties',
|
||||
'Loading file info...': 'Loading file info...',
|
||||
'Basic Info': 'Basic Info',
|
||||
'Type': 'Type',
|
||||
'Folder': 'Folder',
|
||||
'File': 'File',
|
||||
'Path': 'Path',
|
||||
'Path copied to clipboard': 'Path copied to clipboard',
|
||||
'Copy failed': 'Copy failed',
|
||||
'Permissions': 'Permissions',
|
||||
'EXIF Info': 'EXIF Info',
|
||||
|
||||
// Search dialog
|
||||
'Smart Search': 'Smart Search',
|
||||
'Name Search': 'Name Search',
|
||||
'Search Results': 'Search Results',
|
||||
'No files found': 'No files found',
|
||||
'Relevance': 'Relevance',
|
||||
|
||||
// System settings
|
||||
'Saved successfully': 'Saved successfully',
|
||||
'Save failed': 'Save failed',
|
||||
'Loading...': 'Loading...',
|
||||
'Appearance Settings': 'Appearance Settings',
|
||||
'Theme': 'Theme',
|
||||
'Theme Mode': 'Theme Mode',
|
||||
'Light': 'Light',
|
||||
'Dark': 'Dark',
|
||||
// 'Follow System' used for theme mode
|
||||
'Primary Color': 'Primary Color',
|
||||
'Border Radius': 'Border Radius',
|
||||
'Advanced': 'Advanced',
|
||||
'Override AntD Tokens (JSON)': 'Override AntD Tokens (JSON)',
|
||||
'e.g. {"colorText": "#222"}': 'e.g. {"colorText": "#222"}',
|
||||
'Custom CSS': 'Custom CSS',
|
||||
'Save': 'Save',
|
||||
'App Settings': 'App Settings',
|
||||
'AI Settings': 'AI Settings',
|
||||
'Vision Model': 'Vision Model',
|
||||
'Embedding Model': 'Embedding Model',
|
||||
'Vector Database': 'Vector Database',
|
||||
'Vector Database Settings': 'Vector Database Settings',
|
||||
'Database Type': 'Database Type',
|
||||
'Confirm clear vector database?': 'Confirm clear vector database?',
|
||||
'This will delete all collections irreversibly.': 'This will delete all collections irreversibly.',
|
||||
'Confirm Clear': 'Confirm Clear',
|
||||
// 'Cancel' defined above
|
||||
'Vector database cleared': 'Vector database cleared',
|
||||
'Clear failed': 'Clear failed',
|
||||
'Clear Vector DB': 'Clear Vector DB',
|
||||
'App Name': 'App Name',
|
||||
'Logo URL': 'Logo URL',
|
||||
'App Domain': 'App Domain',
|
||||
'File Domain': 'File Domain',
|
||||
'Vision API URL': 'Vision API URL',
|
||||
'Vision API Key': 'Vision API Key',
|
||||
'Embedding API URL': 'Embedding API URL',
|
||||
'Embedding API Key': 'Embedding API Key',
|
||||
|
||||
// Adapters
|
||||
'Missing required config:': 'Missing required config:',
|
||||
'Updated successfully': 'Updated successfully',
|
||||
'Created successfully': 'Created successfully',
|
||||
'Operation failed': 'Operation failed',
|
||||
'Deleted': 'Deleted',
|
||||
'Delete failed': 'Delete failed',
|
||||
'Status updated': 'Status updated',
|
||||
'Update failed': 'Update failed',
|
||||
'Mount Path': 'Mount Path',
|
||||
'Sub Path': 'Sub Path',
|
||||
'Sub Path (optional)': 'Sub Path (optional)',
|
||||
'Sub directory inside adapter': 'Sub directory inside adapter',
|
||||
'Enabled': 'Enabled',
|
||||
'Actions': 'Actions',
|
||||
'Edit': 'Edit',
|
||||
'Confirm delete?': 'Confirm delete?',
|
||||
'No config fields': 'No config fields',
|
||||
'Please input {label}': 'Please input {label}',
|
||||
'Storage Adapters': 'Storage Adapters',
|
||||
'Create Adapter': 'Create Adapter',
|
||||
'Unique name': 'Unique name',
|
||||
'Select adapter type': 'Select adapter type',
|
||||
'/ or /drive': '/ or /drive',
|
||||
'Adapter Config': 'Adapter Config',
|
||||
|
||||
// Tasks
|
||||
'Automation Tasks': 'Automation Tasks',
|
||||
'Running Tasks': 'Running Tasks',
|
||||
'Create Task': 'Create Task',
|
||||
'Edit Task': 'Edit Task',
|
||||
'Create Automation Task': 'Create Automation Task',
|
||||
'Task Name': 'Task Name',
|
||||
'Trigger Event': 'Trigger Event',
|
||||
'File Written': 'File Written',
|
||||
'File Deleted': 'File Deleted',
|
||||
'Matching Rules': 'Matching Rules',
|
||||
'Path Prefix (optional)': 'Path Prefix (optional)',
|
||||
'Filename Regex (optional)': 'Filename Regex (optional)',
|
||||
'Action': 'Action',
|
||||
'Current Task Queue': 'Current Task Queue',
|
||||
'Params': 'Params',
|
||||
'Status': 'Status',
|
||||
|
||||
// Logs
|
||||
'Confirm clear logs?': 'Confirm clear logs?',
|
||||
'This will delete logs in selected range irreversibly.': 'This will delete logs in selected range irreversibly.',
|
||||
'Cleared {count} logs': 'Cleared {count} logs',
|
||||
'Time': 'Time',
|
||||
'Level': 'Level',
|
||||
'Source': 'Source',
|
||||
'Message': 'Message',
|
||||
'Search source': 'Search source',
|
||||
'Clear': 'Clear',
|
||||
'Log Details': 'Log Details',
|
||||
|
||||
// Backup
|
||||
'Export started, check your downloads.': 'Export started, check your downloads.',
|
||||
'Export failed': 'Export failed',
|
||||
'Confirm import backup?': 'Confirm import backup?',
|
||||
'Are you sure to import from this file?': 'Are you sure to import from this file?',
|
||||
'Warning: This will overwrite all data including users (with passwords), settings, storages and tasks. Irreversible!': 'Warning: This will overwrite all data including users (with passwords), settings, storages and tasks. Irreversible!',
|
||||
'Confirm Import': 'Confirm Import',
|
||||
'Import succeeded! The page will refresh.': 'Import succeeded! The page will refresh.',
|
||||
'Import failed': 'Import failed',
|
||||
'Export': 'Export',
|
||||
'Import': 'Import',
|
||||
'Export all data (adapters, users, tasks, shares) into a JSON file.': 'Export all data (adapters, users, tasks, shares) into a JSON file.',
|
||||
'Keep your backup file safe.': 'Keep your backup file safe.',
|
||||
'Export Backup': 'Export Backup',
|
||||
'Restore data from a previously exported JSON file.': 'Restore data from a previously exported JSON file.',
|
||||
'Warning: This will clear and overwrite existing data.': 'Warning: This will clear and overwrite existing data.',
|
||||
'Choose File and Restore': 'Choose File and Restore',
|
||||
|
||||
// Empty state
|
||||
'No files yet here': 'No files yet here',
|
||||
'This folder is empty': 'This folder is empty',
|
||||
'Start uploading files or create folders to organize your content': 'Start uploading files or create folders to organize your content',
|
||||
'You can create folders or upload files here': 'You can create folders or upload files here',
|
||||
|
||||
// File actions
|
||||
'Please input name': 'Please input name',
|
||||
'Confirm delete {name}?': 'Confirm delete {name}?',
|
||||
'items': 'items',
|
||||
'Downloading folders is not supported': 'Downloading folders is not supported',
|
||||
'Download failed': 'Download failed',
|
||||
'Please select files or folders to share': 'Please select files or folders to share',
|
||||
'Direct links for folders are not supported': 'Direct links for folders are not supported',
|
||||
|
||||
// Processor flow
|
||||
'Processing finished': 'Processing finished',
|
||||
'Processing failed': 'Processing failed',
|
||||
|
||||
// Plugins page
|
||||
'Installed successfully': 'Installed successfully',
|
||||
'Plugin': 'Plugin',
|
||||
'Open Link': 'Open Link',
|
||||
'Link copied': 'Link copied',
|
||||
'Copy Link': 'Copy Link',
|
||||
'Confirm delete this plugin?': 'Confirm delete this plugin?',
|
||||
'Author': 'Author',
|
||||
'Website': 'Website',
|
||||
'Install App': 'Install App',
|
||||
'Search name/author/url/extension': 'Search name/author/url/extension',
|
||||
'No plugins': 'No plugins',
|
||||
'Install': 'Install',
|
||||
'App URL': 'App URL',
|
||||
'Please input a valid URL': 'Please input a valid URL',
|
||||
|
||||
// Setup page
|
||||
'Initialization succeeded! Logging you in...': 'Initialization succeeded! Logging you in...',
|
||||
'Initialization failed, please try later': 'Initialization failed, please try later',
|
||||
'Database Setup': 'Database Setup',
|
||||
'Choose database driver': 'Choose database driver',
|
||||
'Select database and vector database for system data': 'Select database and vector database for system data',
|
||||
'Database Driver': 'Database Driver',
|
||||
'Vector DB Driver': 'Vector DB Driver',
|
||||
'Initialize Mount': 'Initialize Mount',
|
||||
'Configure initial storage': 'Configure initial storage',
|
||||
'Create the first storage mount for your files': 'Create the first storage mount for your files',
|
||||
'Mount Name': 'Mount Name',
|
||||
'Local Storage': 'Local Storage',
|
||||
'Please input mount name!': 'Please input mount name!',
|
||||
'Storage Type': 'Storage Type',
|
||||
'Please input mount path!': 'Please input mount path!',
|
||||
'Root Directory': 'Root Directory',
|
||||
'Please input root directory!': 'Please input root directory!',
|
||||
'e.g., data/ or /var/foxel/data': 'e.g., data/ or /var/foxel/data',
|
||||
'Create Admin': 'Create Admin',
|
||||
'Create admin account': 'Create admin account',
|
||||
'This is the first account with full permissions': 'This is the first account with full permissions',
|
||||
'Username': 'Username',
|
||||
'Full Name': 'Full Name',
|
||||
'Email': 'Email',
|
||||
'Please input a valid email!': 'Please input a valid email!',
|
||||
'Confirm Password': 'Confirm Password',
|
||||
'Please confirm your password!': 'Please confirm your password!',
|
||||
'Passwords do not match!': 'Passwords do not match!',
|
||||
'System Initialization': 'System Initialization',
|
||||
'Previous': 'Previous',
|
||||
'Next': 'Next',
|
||||
'Finish Initialization': 'Finish Initialization',
|
||||
|
||||
// Plugin host
|
||||
'Plugin run failed': 'Plugin run failed',
|
||||
'Plugin Error': 'Plugin Error',
|
||||
'Cannot open file: no available app': 'Cannot open file: no available app',
|
||||
'Error': 'Error',
|
||||
'App "{key}" not found.': 'App "{key}" not found.',
|
||||
'Open with {app}': 'Open with {app}',
|
||||
'Set as default for .{ext}': 'Set as default for .{ext}',
|
||||
'Advanced tokens must be valid JSON': 'Advanced tokens must be valid JSON',
|
||||
} as const;
|
||||
|
||||
export type EnKeys = keyof typeof en;
|
||||
367
web/src/i18n/locales/zh.ts
Normal file
367
web/src/i18n/locales/zh.ts
Normal file
@@ -0,0 +1,367 @@
|
||||
import { en } from './en';
|
||||
|
||||
// Start from English defaults, then override with Chinese translations we have.
|
||||
export const zh = {
|
||||
...en,
|
||||
|
||||
// General
|
||||
'All Files': '全部文件',
|
||||
'Manage': '管理',
|
||||
'System': '系统',
|
||||
'Automation': '自动化',
|
||||
'My Shares': '我的分享',
|
||||
'Offline Downloads': '离线下载',
|
||||
'Adapters': '存储挂载',
|
||||
'Plugins': '应用中心',
|
||||
'System Settings': '系统设置',
|
||||
'Backup & Restore': '备份恢复',
|
||||
'System Logs': '系统日志',
|
||||
|
||||
// Top header
|
||||
'Search files / tags / types': '搜索文件 / 标签 / 类型',
|
||||
'Log Out': '退出登录',
|
||||
'Admin': '管理员',
|
||||
'Language': '语言',
|
||||
'Chinese': '中文',
|
||||
'English': '英文',
|
||||
|
||||
// Auth / Login
|
||||
'Welcome Back': '欢迎回来',
|
||||
'Sign in to your Foxel account': '登录到您的 Foxel 账户',
|
||||
'Username / Email': '用户名/邮箱',
|
||||
'Password': '密码',
|
||||
'Sign In': '登录',
|
||||
'Please enter username and password': '请输入用户名与密码',
|
||||
'Login failed': '登录失败',
|
||||
'Your next-generation file manager': '您的下一代文件管理系统',
|
||||
'Cross-platform sync, access anywhere': '跨平台同步,随时随地访问',
|
||||
'AI-powered search for quick find': 'AI 驱动的智能搜索,快速定位文件',
|
||||
'Flexible sharing and collaboration': '灵活的分享与协作,提升团队效率',
|
||||
'Powerful automation to simplify tasks': '强大的自动化工作流,简化繁琐任务',
|
||||
'Join our community:': '加入我们的社区:',
|
||||
|
||||
// Share page
|
||||
'Refresh': '刷新',
|
||||
'Copy': '复制',
|
||||
'Cancel': '取消',
|
||||
'Copied link': '链接已复制',
|
||||
'Share canceled': '分享已取消',
|
||||
'Cancel failed': '取消失败',
|
||||
'Load failed': '加载失败',
|
||||
'Are you sure to cancel share?': '确认取消分享?',
|
||||
'Share Name': '分享名称',
|
||||
'Share Content': '分享内容',
|
||||
'Created At': '创建时间',
|
||||
'Expires At': '过期时间',
|
||||
'Forever': '永久有效',
|
||||
'Access': '访问',
|
||||
'Public': '公开',
|
||||
'By Password': '密码',
|
||||
|
||||
// Public share page
|
||||
'Password Required': '需要密码',
|
||||
'Please enter password': '请输入密码',
|
||||
'Confirm': '确认',
|
||||
'Unable to load share info': '无法加载分享信息',
|
||||
'Share load failed': '加载分享失败',
|
||||
'Wrong password': '密码错误',
|
||||
'Root': '全部文件',
|
||||
'Created on {date}': '创建于 {date}',
|
||||
'Expires on {date}': '将于 {date} 过期',
|
||||
'Download File': '下载文件',
|
||||
'Preview not supported for this file type': '暂不支持在线预览此类型文件',
|
||||
'Back': '返回',
|
||||
'Download': '下载',
|
||||
|
||||
// Header/File Explorer
|
||||
'Home': '主页',
|
||||
'File Manager': '文件管理',
|
||||
'New Folder': '新建目录',
|
||||
'Upload': '上传',
|
||||
'Name': '名称',
|
||||
'Size': '大小',
|
||||
'Modified Time': '修改时间',
|
||||
'Grid': '网格',
|
||||
'List': '列表',
|
||||
'Mount Point': '挂载点',
|
||||
|
||||
// Context menu
|
||||
'Upload File': '上传文件',
|
||||
'Open': '打开',
|
||||
'Open With': '打开方式',
|
||||
'Default': '默认',
|
||||
'Rename': '重命名',
|
||||
'Delete': '删除',
|
||||
'Details': '详情',
|
||||
'Get Direct Link': '获取直链',
|
||||
|
||||
// Side nav modals
|
||||
'Join Community': '加入社区',
|
||||
'Scan to join WeChat group': '微信扫码加入交流群',
|
||||
'If QR expires, add drizzle2001 to join': '如二维码失效,请添加 drizzle2001 拉群',
|
||||
'Version Info': '版本信息',
|
||||
'Current Version': '当前版本',
|
||||
'Latest Version': '最新版本',
|
||||
'New version found: {version}': '发现新版本: {version}',
|
||||
'Please update to the latest for features and fixes': '建议尽快更新到最新版本,以获得新功能和安全修复。',
|
||||
'Open Releases': '前往发布页面',
|
||||
'Changelog': '更新日志',
|
||||
'Fetching latest version...': '正在获取最新版本信息...',
|
||||
'Update available': '有更新',
|
||||
'You are on the latest: {version}': '当前为最新版: {version}',
|
||||
'Up to date': '已是最新版',
|
||||
|
||||
// Share modal
|
||||
'Share {count} items': '分享 {count} 个项目',
|
||||
'Share link created': '分享链接已创建',
|
||||
'Create failed': '创建失败',
|
||||
'Copied to clipboard': '已复制到剪贴板',
|
||||
'Expiration (days)': '有效期 (天)',
|
||||
'Set 0 or negative for forever': '设置为 0 或负数表示永久有效',
|
||||
'Share link created successfully!': '分享链接已成功创建!',
|
||||
'Share Link': '分享链接',
|
||||
'Share created': '分享创建成功',
|
||||
'Create Share': '创建分享',
|
||||
'Done': '完成',
|
||||
'Create': '创建',
|
||||
|
||||
// Direct link modal
|
||||
'Failed to generate link': '生成链接失败',
|
||||
'Markdown copied to clipboard': 'Markdown 格式已复制到剪贴板',
|
||||
'Generate a direct link for {name}': '为 {name} 生成一个直接访问链接。',
|
||||
'1 hour': '1 小时',
|
||||
'1 day': '1 天',
|
||||
'7 days': '7 天',
|
||||
'Generating link...': '正在生成链接...',
|
||||
'Link will appear here': '链接将显示在这里',
|
||||
'Copy Markdown': '复制 Markdown',
|
||||
'Close': '关闭',
|
||||
|
||||
// File detail
|
||||
'Camera Make': '设备品牌',
|
||||
'Camera Model': '设备型号',
|
||||
'Capture Time': '拍摄时间',
|
||||
'X Resolution': '水平分辨率',
|
||||
'Y Resolution': '垂直分辨率',
|
||||
'Exposure Time': '曝光时间',
|
||||
'Aperture': '光圈值',
|
||||
'Focal Length': '焦距',
|
||||
'Width': '宽度',
|
||||
'Height': '高度',
|
||||
'No common EXIF info': '无常见EXIF信息',
|
||||
'Bytes': '字节',
|
||||
'File Properties': '文件属性',
|
||||
'Loading file info...': '加载文件信息...',
|
||||
'Basic Info': '基本信息',
|
||||
'Type': '类型',
|
||||
'Folder': '文件夹',
|
||||
'File': '文件',
|
||||
'Path': '路径',
|
||||
'Path copied to clipboard': '路径已复制到剪贴板',
|
||||
'Copy failed': '复制失败',
|
||||
'Permissions': '权限',
|
||||
'EXIF Info': 'EXIF信息',
|
||||
|
||||
// Search dialog
|
||||
'Smart Search': '智能搜索',
|
||||
'Name Search': '名称搜索',
|
||||
'Search Results': '搜索结果',
|
||||
'No files found': '未找到相关文件',
|
||||
'Relevance': '相关度',
|
||||
|
||||
// System settings
|
||||
'Saved successfully': '保存成功',
|
||||
'Save failed': '保存失败',
|
||||
'Loading...': '加载中...',
|
||||
'Appearance Settings': '外观设置',
|
||||
'Theme': '主题',
|
||||
'Theme Mode': '主题模式',
|
||||
'Light': '亮色',
|
||||
'Dark': '暗色',
|
||||
// 'Follow System' used for theme mode
|
||||
'Follow System': '跟随系统',
|
||||
'Primary Color': '主色',
|
||||
'Border Radius': '圆角',
|
||||
'Advanced': '高级',
|
||||
'Override AntD Tokens (JSON)': '覆盖 AntD Token(JSON)',
|
||||
'e.g. {"colorText": "#222"}': '例如:{"colorText": "#222"}',
|
||||
'Custom CSS': '自定义 CSS',
|
||||
'Save': '保存',
|
||||
'App Settings': '应用设置',
|
||||
'AI Settings': 'AI设置',
|
||||
'Vision Model': '视觉模型',
|
||||
'Embedding Model': '嵌入模型',
|
||||
'Vector Database': '向量数据库',
|
||||
'Vector Database Settings': '向量数据库设置',
|
||||
'Database Type': '数据库类型',
|
||||
'Confirm clear vector database?': '确认清空向量数据库?',
|
||||
'This will delete all collections irreversibly.': '此操作将删除所有集合中的所有数据,且不可逆。',
|
||||
'Confirm Clear': '确认清空',
|
||||
// 'Cancel' defined above
|
||||
'Vector database cleared': '向量数据库已清空',
|
||||
'Clear failed': '清空失败',
|
||||
'Clear Vector DB': '清空向量库',
|
||||
'App Name': '应用名称',
|
||||
'Logo URL': 'LOGO地址',
|
||||
'App Domain': '应用域名',
|
||||
'File Domain': '文件域名',
|
||||
'Vision API URL': '视觉模型 API 地址',
|
||||
'Vision API Key': '视觉模型 API Key',
|
||||
'Embedding API URL': '嵌入模型 API 地址',
|
||||
'Embedding API Key': '嵌入模型 API Key',
|
||||
|
||||
// Adapters
|
||||
'Missing required config:': '缺少必填配置:',
|
||||
'Updated successfully': '更新成功',
|
||||
'Created successfully': '创建成功',
|
||||
'Operation failed': '操作失败',
|
||||
'Deleted': '已删除',
|
||||
'Delete failed': '删除失败',
|
||||
'Status updated': '状态已更新',
|
||||
'Update failed': '更新失败',
|
||||
'Mount Path': '挂载路径',
|
||||
'Sub Path': '子路径',
|
||||
'Sub Path (optional)': '子路径(可选)',
|
||||
'Sub directory inside adapter': '适配器内部子目录',
|
||||
'Enabled': '启用',
|
||||
'Actions': '操作',
|
||||
'Edit': '编辑',
|
||||
'Confirm delete?': '确认删除?',
|
||||
'No config fields': '无配置项',
|
||||
'Please input {label}': '请输入{label}',
|
||||
'Storage Adapters': '存储适配器',
|
||||
'Create Adapter': '新建适配器',
|
||||
'Unique name': '唯一名称',
|
||||
'Select adapter type': '选择适配器类型',
|
||||
'/ or /drive': '/或/drive',
|
||||
'Adapter Config': '适配器配置',
|
||||
|
||||
// Tasks
|
||||
'Automation Tasks': '自动化任务',
|
||||
'Running Tasks': '运行中的任务',
|
||||
'Create Task': '新建任务',
|
||||
'Edit Task': '编辑任务',
|
||||
'Create Automation Task': '新建自动化任务',
|
||||
'Task Name': '任务名称',
|
||||
'Trigger Event': '触发事件',
|
||||
'File Written': '文件写入',
|
||||
'File Deleted': '文件删除',
|
||||
'Matching Rules': '匹配规则',
|
||||
'Path Prefix (optional)': '路径前缀 (可选)',
|
||||
'Filename Regex (optional)': '文件名正则 (可选)',
|
||||
'Action': '执行动作',
|
||||
'Current Task Queue': '当前任务队列',
|
||||
'Params': '参数',
|
||||
'Status': '状态',
|
||||
|
||||
// Logs
|
||||
'Confirm clear logs?': '确认清理日志?',
|
||||
'This will delete logs in selected range irreversibly.': '该操作将删除选定时间范围内的所有日志,且不可恢复。',
|
||||
'Cleared {count} logs': '成功清理 {count} 条日志',
|
||||
'Time': '时间',
|
||||
'Level': '级别',
|
||||
'Source': '来源',
|
||||
'Message': '消息',
|
||||
'Search source': '搜索来源',
|
||||
'Clear': '清理',
|
||||
'Log Details': '日志详情',
|
||||
|
||||
// Backup
|
||||
'Export started, check your downloads.': '导出已开始,请检查您的下载。',
|
||||
'Export failed': '导出失败',
|
||||
'Confirm import backup?': '确认导入备份?',
|
||||
'Are you sure to import from this file?': '您确定要从此文件导入数据吗?',
|
||||
'Warning: This will overwrite all data including users (with passwords), settings, storages and tasks. Irreversible!': '警告:此操作将覆盖当前数据库中的所有现有数据,包括用户(含密码)、设置、存储和任务。此操作不可逆!',
|
||||
'Confirm Import': '确认导入',
|
||||
'Import succeeded! The page will refresh.': '导入成功!页面将刷新。',
|
||||
'Import failed': '导入失败',
|
||||
'Export': '导出',
|
||||
'Import': '恢复',
|
||||
'Export all data (adapters, users, tasks, shares) into a JSON file.': '点击按钮将所有数据(包括存储、用户、自动化任务和分享)导出为一个 JSON 文件。',
|
||||
'Keep your backup file safe.': '请妥善保管您的备份文件。',
|
||||
'Export Backup': '导出备份',
|
||||
'Restore data from a previously exported JSON file.': '从之前导出的JSON文件恢复数据。',
|
||||
'Warning: This will clear and overwrite existing data.': '警告:此操作将清除并覆盖现有数据。',
|
||||
'Choose File and Restore': '选择文件并恢复',
|
||||
|
||||
// Empty state
|
||||
'No files yet here': '这里还没有任何文件',
|
||||
'This folder is empty': '此目录为空',
|
||||
'Start uploading files or create folders to organize your content': '开始上传文件或创建新目录来组织您的内容',
|
||||
'You can create folders or upload files here': '您可以在此目录中创建新的文件夹或上传文件',
|
||||
|
||||
// File actions
|
||||
'Please input name': '请输入名称',
|
||||
'Confirm delete {name}?': '确认删除 {name} ?',
|
||||
'items': '项',
|
||||
'Downloading folders is not supported': '暂不支持下载目录',
|
||||
'Download failed': '下载失败',
|
||||
'Please select files or folders to share': '请选择要分享的文件或目录',
|
||||
'Direct links for folders are not supported': '不支持获取目录的直链',
|
||||
|
||||
// Processor flow
|
||||
'Processing finished': '处理完成',
|
||||
'Processing failed': '处理失败',
|
||||
|
||||
// Plugins page
|
||||
'Installed successfully': '安装成功',
|
||||
'Plugin': '插件',
|
||||
'Open Link': '打开链接',
|
||||
'Link copied': '已复制链接',
|
||||
'Copy Link': '复制链接',
|
||||
'Confirm delete this plugin?': '确认删除该插件?',
|
||||
'Author': '作者',
|
||||
'Website': '官网',
|
||||
'Install App': '安装应用',
|
||||
'Search name/author/url/extension': '搜索 名称/作者/链接/扩展名',
|
||||
'No plugins': '暂无插件',
|
||||
'Install': '安装',
|
||||
'App URL': '应用链接',
|
||||
'Please input a valid URL': '请输入合法的 URL',
|
||||
|
||||
// Setup page
|
||||
'Initialization succeeded! Logging you in...': '初始化成功!正在为您登录,请不要刷新。',
|
||||
'Initialization failed, please try later': '初始化失败,请稍后重试',
|
||||
'Database Setup': '数据库设置',
|
||||
'Choose database driver': '选择数据库驱动',
|
||||
'Select database and vector database for system data': '选择用于存储系统数据的数据库和向量数据库。',
|
||||
'Database Driver': '数据库驱动',
|
||||
'Vector DB Driver': '向量数据库驱动',
|
||||
'Initialize Mount': '初始化挂载',
|
||||
'Configure initial storage': '配置初始存储',
|
||||
'Create the first storage mount for your files': '为您的文件创建第一个存储挂载点。',
|
||||
'Mount Name': '挂载名称',
|
||||
'Local Storage': '本地存储',
|
||||
'Please input mount name!': '请输入挂载名称!',
|
||||
'Storage Type': '存储类型',
|
||||
'Please input mount path!': '请输入挂载路径!',
|
||||
'Root Directory': '根目录',
|
||||
'Please input root directory!': '请输入根目录!',
|
||||
'e.g., data/ or /var/foxel/data': '例如: data/ 或 /var/foxel/data',
|
||||
'Create Admin': '创建管理员',
|
||||
'Create admin account': '创建管理员账户',
|
||||
'This is the first account with full permissions': '这是系统的第一个账户,将拥有最高权限。',
|
||||
'Username': '用户名',
|
||||
'Full Name': '昵称',
|
||||
'Email': '邮箱',
|
||||
'Please input a valid email!': '请输入有效的邮箱地址!',
|
||||
'Confirm Password': '确认密码',
|
||||
'Please confirm your password!': '请确认您的密码!',
|
||||
'Passwords do not match!': '两次输入的密码不一致!',
|
||||
'System Initialization': '系统初始化',
|
||||
'Previous': '上一步',
|
||||
'Next': '下一步',
|
||||
'Finish Initialization': '完成初始化',
|
||||
|
||||
// Plugin host
|
||||
'Plugin run failed': '插件运行失败',
|
||||
'Plugin Error': '插件错误',
|
||||
'Cannot open file: no available app': '无法打开该文件:没有可用的应用',
|
||||
'Error': '错误',
|
||||
'App "{key}" not found.': '应用 "{key}" 不存在。',
|
||||
'Open with {app}': '使用 {app} 打开',
|
||||
'Set as default for .{ext}': '设为该类型(.{ext})默认应用',
|
||||
'Advanced tokens must be valid JSON': '高级 Token 需为合法 JSON',
|
||||
} as const;
|
||||
|
||||
export type ZhKeys = keyof typeof zh;
|
||||
Reference in New Issue
Block a user