diff --git a/plugins/acme-ssl/locales/en.json b/plugins/acme-ssl/locales/en.json index 5c0aaa55b..cc7e8300a 100644 --- a/plugins/acme-ssl/locales/en.json +++ b/plugins/acme-ssl/locales/en.json @@ -54,5 +54,8 @@ "request": "Request certificate now", "requesting": "Requesting certificate...", "issued": "Certificate issued and installed" + }, + "plugin": { + "name": "ACME Certificates" } } diff --git a/plugins/acme-ssl/locales/translated/zh_CN.json b/plugins/acme-ssl/locales/translated/zh_CN.json index 75ebb08f9..a9646254c 100644 --- a/plugins/acme-ssl/locales/translated/zh_CN.json +++ b/plugins/acme-ssl/locales/translated/zh_CN.json @@ -1,14 +1,14 @@ { "permissions": { "manage": { - "title": "Manage ACME certificates", - "description": "See the certificate status and request a new certificate now." + "title": "管理 ACME 证书", + "description": "查看证书状态并立即申请新证书。" } }, "settings": { "autoRenew": { - "label": "Renew automatically", - "description": "Check twice a day and get a new certificate when there is none, it does not cover the domain, or it expires within 30 days." + "label": "自动续期", + "description": "每天检查两次。在没有证书、证书未覆盖域名或将在 30 天内过期时申请新证书。" }, "domain": { "label": "域名", @@ -17,42 +17,45 @@ }, "email": { "label": "邮箱", - "description": "Contact email for the ACME account and expiry notices.", + "description": "用于 ACME 账户和到期通知的联系邮箱。", "placeholder": "admin@example.com" }, "provider": { "label": "证书颁发机构", - "description": "Where to get the certificate. Use staging to test without hitting Let's Encrypt rate limits.", + "description": "证书申请来源。测试时使用测试环境,以免触发 Let's Encrypt 频率限制。", "letsencrypt": "Let's Encrypt", - "letsencryptStaging": "Let's Encrypt (staging)", - "custom": "Custom ACME directory" + "letsencryptStaging": "Let's Encrypt(测试环境)", + "custom": "自定义 ACME 目录" }, "directoryUrl": { - "label": "ACME directory URL", - "description": "Only for a custom certificate authority. Must be an https URL." + "label": "ACME 目录 URL", + "description": "仅用于自定义证书颁发机构,必须为 HTTPS URL。" }, "challengeType": { - "label": "Challenge type", - "description": "How to prove you own the domain.", - "http": "HTTP - needs port 80 reachable from the internet", - "cloudflare": "DNS (Cloudflare) - needs a Cloudflare API token" + "label": "验证类型", + "description": "用于证明域名所有权的方式。", + "http": "HTTP:需要互联网能够访问端口 80", + "cloudflare": "DNS(Cloudflare):需要 Cloudflare API 令牌" }, "cloudflareToken": { - "label": "Cloudflare API token", + "label": "Cloudflare API 令牌", "description": "具有您域名的 Zone:DNS:Edit 权限的限定作用域令牌。" } }, "status": { - "title": "Certificate status", + "title": "证书状态", "none": "无证书", - "names": "Covers {{names}}", - "issuer": "Issued by {{issuer}}", + "names": "覆盖域名:{{names}}", + "issuer": "签发者:{{issuer}}", "expires": "过期于 {{date}}", "lastIssued": "上次签发于 {{date}}", - "lastError": "Last attempt failed: {{error}}", - "missing": "Set the domain, email and the fields your challenge type needs, then save, before requesting a certificate.", - "request": "Request certificate now", + "lastError": "上次尝试失败:{{error}}", + "missing": "请先设置域名、邮箱及所选验证方式需要的字段,保存后再申请证书。", + "request": "立即申请证书", "requesting": "正在请求证书...", - "issued": "Certificate issued and installed" + "issued": "证书已签发并安装" + }, + "plugin": { + "name": "ACME 证书" } } diff --git a/plugins/ai/locales/en.json b/plugins/ai/locales/en.json index 7b5758ffa..25ac9b8bb 100644 --- a/plugins/ai/locales/en.json +++ b/plugins/ai/locales/en.json @@ -115,5 +115,8 @@ }, "hosts": { "docsLink": "View docs" + }, + "plugin": { + "name": "AI Assistant" } } diff --git a/plugins/ai/locales/translated/zh_CN.json b/plugins/ai/locales/translated/zh_CN.json index a3f2e1867..cc88ec8f6 100644 --- a/plugins/ai/locales/translated/zh_CN.json +++ b/plugins/ai/locales/translated/zh_CN.json @@ -1,29 +1,29 @@ { "permissions": { "use": { - "title": "Use the assistant", - "description": "Open the assistant and ask it things." + "title": "使用助手", + "description": "打开助手并向其提问。" }, "manage_providers": { - "title": "Manage providers", - "description": "Add, edit and remove the AI providers and their API keys." + "title": "管理服务提供商", + "description": "添加、编辑和移除 AI 服务提供商及其 API 密钥。" }, "apply_proposals": { - "title": "Apply proposals", - "description": "Let the assistant carry out the changes it suggests." + "title": "应用建议", + "description": "允许助手执行其建议的更改。" }, "services.use": { - "title": "Use AI from other features", - "description": "Other features may call the assistant on your behalf." + "title": "在其他功能中使用 AI", + "description": "其他功能可以代表你调用助手。" }, "secrets.share": { - "title": "Share the API key", - "description": "Other features may use the stored AI API key without seeing it." + "title": "共享 API 密钥", + "description": "其他功能可以使用已保存的 AI API 密钥,但无法查看其内容。" } }, "settings": { - "assistantUnavailable": "The AI assistant is turned off on this server.", - "providersNeedOptIn": "Turn on the AI assistant above to add providers.", + "assistantUnavailable": "此服务器已关闭 AI 助手。", + "providersNeedOptIn": "请先在上方启用 AI 助手,再添加服务提供商。", "admin": { "globallyEnabled": { "label": "AI 助手", @@ -31,74 +31,74 @@ }, "privateEndpoints": { "label": "允许的私有 AI 主机", - "description": "Hosts on your private network that users may point a provider at, such as a self-hosted Ollama. Put one host on each line." + "description": "允许用户将服务提供商指向的内网主机,例如自托管的 Ollama。每行填写一台主机。" } }, "host": { "enableAiAssistant": { - "label": "Enable AI Assistant", - "description": "Allow the AI assistant to help in this host's terminal. Off by default, and still needs AI enabled for your account." + "label": "启用 AI 助手", + "description": "允许 AI 助手在此主机的终端中提供帮助。默认关闭,且你的账户也必须启用 AI。" } } }, "ai": { - "title": "Assistant", - "send": "Send", + "title": "助手", + "send": "发送", "stop": "停止", "save": "保存", "cancel": "取消", "running": "运行中", - "approve": "Approve", - "reject": "Reject", - "inputPlaceholder": "Ask about your servers, or describe a change to propose", - "selectProvider": "Select a provider", - "providerSettings": "Provider settings", - "addProvider": "Add provider", + "approve": "批准", + "reject": "拒绝", + "inputPlaceholder": "询问服务器相关问题,或描述你想进行的更改", + "selectProvider": "选择服务提供商", + "providerSettings": "服务提供商设置", + "addProvider": "添加服务提供商", "editProvider": "编辑提供商", - "removeProvider": "Remove provider", + "removeProvider": "移除服务提供商", "providerType": "提供商", "providerLabel": "名称", "providerLabelPlaceholder": "例如:本地 Ollama", - "baseUrl": "Server address", + "baseUrl": "服务器地址", "apiKey": "API 密钥", - "defaultModel": "Default model", - "defaultModelPlaceholder": "For example: llama3.1 or claude-opus-5", + "defaultModel": "默认模型", + "defaultModelPlaceholder": "例如 llama3.1 或 claude-opus-5", "labelRequired": "给此提供商起个名字", - "providerSaveFailed": "Could not save the provider", - "providerUpdated": "Provider updated", - "providerDeleteFailed": "Could not remove the provider", - "privateEndpointHint": "Addresses on your private network need an administrator to allow the host first.", + "providerSaveFailed": "无法保存服务提供商", + "providerUpdated": "服务提供商已更新", + "providerDeleteFailed": "无法移除服务提供商", + "privateEndpointHint": "使用内网地址前,需要管理员先允许该主机。", "providerOllama": "Ollama", "providerAnthropic": "Anthropic", "providerOpenai": "OpenAI", "providerGemini": "Google Gemini", - "providerOpenaiCompatible": "OpenAI compatible", + "providerOpenaiCompatible": "兼容 OpenAI", "toolArguments": "输入", - "toolResult": "Result", + "toolResult": "结果", "statusApplied": "已应用", - "statusRejected": "Rejected", - "proposalApplied": "Change applied", - "proposalApplyFailed": "Could not apply the change", - "proposalRejectFailed": "Could not reject the change", + "statusRejected": "已拒绝", + "proposalApplied": "更改已应用", + "proposalApplyFailed": "无法应用更改", + "proposalRejectFailed": "无法拒绝更改", "enableTitle": "启用 AI 助手", - "enableDescription": "Let the assistant read your setup and suggest changes for you to approve.", - "readOnlyCommands": "Allow read-only diagnostic commands", - "readOnlyCommandsDescription": "The assistant may run a short list of safe commands like df and uptime without asking each time. Anything that changes a server is always proposed first.", + "enableDescription": "允许助手读取你的配置并提出更改建议,由你批准后执行。", + "readOnlyCommands": "允许只读诊断命令", + "readOnlyCommandsDescription": "助手可以执行 df、uptime 等少量安全命令,无需每次询问。任何会修改服务器的操作都会先提交建议。", "modelDetectFailed": "无法联系到提供商,所以这里提供的是通用列表。您可以输入任何模型名称。", "modelCustom": "请输入模型名称", - "modelRefresh": "Refresh list", + "modelRefresh": "刷新列表", "modelPlaceholder": "选择或输入模型", - "attachHint": "Type @ to reference a host, snippet or automation. Changes are proposed for you to approve.", - "runCommandTitle": "Run command", - "assistant": "AI Assistant", - "terminalPanelEmpty": "Ask the assistant about this host. Anything that changes state needs your approval first.", - "terminalPanelPlaceholder": "Ask about this host...", - "noProvidersConfigured": "No AI provider is configured yet. Add one in the AI assistant tab.", - "runsInOpenTerminal": "Runs in your open terminal session.", + "attachHint": "输入 @ 引用主机、代码片段或自动化。更改会先提交给你批准。", + "runCommandTitle": "执行命令", + "assistant": "AI 助手", + "terminalPanelEmpty": "向助手询问此主机的相关问题。任何会改变状态的操作都需要先获得你的批准。", + "terminalPanelPlaceholder": "询问此主机的相关问题……", + "noProvidersConfigured": "尚未配置 AI 服务提供商,请在 AI 助手标签页中添加。", + "runsInOpenTerminal": "在你已打开的终端会话中执行。", "runInTerminal": "运行", - "terminalContextPrefill": "Here is my terminal output:\n\n{{output}}\n\n", + "terminalContextPrefill": "以下是我的终端输出:\n\n{{output}}\n\n", "secrets": { - "shareApiKey": "Let other features use your AI provider API key for their own requests. The key is never copied, and you can revoke this at any time." + "shareApiKey": "允许其他功能使用你的 AI 服务提供商 API 密钥发起请求。密钥不会被复制,你可以随时撤销授权。" } }, "nav": { @@ -106,7 +106,7 @@ }, "onboarding": { "aiTitle": "AI 助手", - "aiIntro": "Termix can include an optional AI assistant. You can change this later in your settings.", + "aiIntro": "Termix 提供可选的 AI 助手,你可以稍后在设置中更改。", "aiSkipTitle": "禁用", "aiSkipDesc": "Termix 正常工作,AI 助手将保持隐藏状态。", "aiEnableTitle": "启用", @@ -115,5 +115,8 @@ }, "hosts": { "docsLink": "查看文档" + }, + "plugin": { + "name": "AI 助手" } } diff --git a/plugins/alerts/locales/en.json b/plugins/alerts/locales/en.json index 9d7514f0d..b3203e591 100644 --- a/plugins/alerts/locales/en.json +++ b/plugins/alerts/locales/en.json @@ -168,5 +168,8 @@ "showRead": "Show read alerts", "allClear": "All clear", "loading": "Loading..." + }, + "plugin": { + "name": "Alerts" } } diff --git a/plugins/alerts/locales/translated/zh_CN.json b/plugins/alerts/locales/translated/zh_CN.json index 3b8ac1c4c..bc0c435f5 100644 --- a/plugins/alerts/locales/translated/zh_CN.json +++ b/plugins/alerts/locales/translated/zh_CN.json @@ -4,13 +4,13 @@ }, "permissions": { "use": { - "title": "Use alerts", - "description": "Get alerts in the inbox and send them to your own channels." + "title": "使用告警", + "description": "在收件箱中接收告警,并发送到你自己的渠道。" } }, "onboarding": { "feature": "告警", - "featureDesc": "Every alert in one inbox, sent on to Discord, ntfy, email or a webhook if you want." + "featureDesc": "在统一收件箱中查看所有告警,也可将它们发送到 Discord、ntfy、电子邮箱或 Webhook。" }, "settings": { "group": { @@ -19,97 +19,97 @@ }, "admin": { "announcements": { - "label": "Termix announcements", - "description": "Show news from the Termix team, like security notices and releases, in everyone's inbox." + "label": "Termix 公告", + "description": "在所有用户的收件箱中显示 Termix 团队发布的安全通知、版本更新等消息。" }, "retentionDays": { - "label": "Keep alerts for (days)", - "description": "Older alerts are removed from every inbox." + "label": "告警保留天数", + "description": "超过保留时间的告警将从所有收件箱中移除。" }, "smtpHost": { - "label": "SMTP server", - "description": "Needed for email channels. Leave empty to turn email off.", + "label": "SMTP 服务器", + "description": "邮件渠道需要此项,留空则关闭邮件发送。", "placeholder": "smtp.example.com" }, "smtpPort": { - "label": "SMTP port", - "description": "Usually 587 with STARTTLS or 465 with TLS." + "label": "SMTP 端口", + "description": "通常使用 587(STARTTLS)或 465(TLS)。" }, "smtpSecure": { - "label": "Use TLS from the start", - "description": "Turn on for port 465. Leave off for 587, which upgrades to TLS on its own." + "label": "连接时直接使用 TLS", + "description": "使用端口 465 时开启。使用端口 587 时关闭,该端口会自动升级为 TLS。" }, "smtpUser": { - "label": "SMTP username", - "description": "Leave empty if the server does not need a login." + "label": "SMTP 用户名", + "description": "服务器无需登录时留空。" }, "smtpPassword": { - "label": "SMTP password", - "description": "Stored encrypted." + "label": "SMTP 密码", + "description": "加密保存。" }, "smtpFrom": { - "label": "From address", - "description": "The sender alerts come from.", + "label": "发件人地址", + "description": "告警邮件的发件人。", "placeholder": "Termix " } }, "user": { "popups": { - "label": "Alert popups", - "description": "Which new alerts pop up while you use Termix. They always land in the inbox.", - "all": "All alerts", - "warning": "Warnings and critical", - "critical": "Critical only", + "label": "告警弹窗", + "description": "选择使用 Termix 时哪些新告警会弹出提示。所有告警都会保留在收件箱中。", + "all": "所有告警", + "warning": "警告和严重告警", + "critical": "仅严重告警", "off": "全不选" } } }, "sections": { - "inbox": "Inbox", + "inbox": "收件箱", "channels": "通道", - "rules": "Delivery rules" + "rules": "投递规则" }, "severity": { "info": "信息", "success": "成功", "warning": "警告", - "critical": "Critical" + "critical": "严重" }, "inbox": { "sourceTermix": "Termix", "openLink": "打开", "view": "查看", - "unread": "Unread", - "deliveryFailed_one": "{{count}} channel failed", - "deliveryFailed_other": "{{count}} channels failed", - "markRead": "Mark as read", - "markUnread": "Mark as unread", - "markAllRead": "Mark all as read", + "unread": "未读", + "deliveryFailed_one": "{{count}} 个渠道发送失败", + "deliveryFailed_other": "{{count}} 个渠道发送失败", + "markRead": "标记为已读", + "markUnread": "标记为未读", + "markAllRead": "全部标记为已读", "delete": "删除", - "clearRead": "Delete read alerts", - "cleared_one": "Deleted {{count}} alert", - "cleared_other": "Deleted {{count}} alerts", + "clearRead": "删除已读告警", + "cleared_one": "已删除 {{count}} 条告警", + "cleared_other": "已删除 {{count}} 条告警", "filterAll": "全部", - "filterUnread": "Unread", - "anySeverity": "Any severity", - "anySource": "Any source", - "openAll": "Open in a tab", - "empty": "No alerts yet.", - "emptyUnread": "You are all caught up.", - "loadMore": "Load more" + "filterUnread": "未读", + "anySeverity": "任意严重程度", + "anySource": "任意来源", + "openAll": "在标签页中打开", + "empty": "暂无告警。", + "emptyUnread": "没有未读消息。", + "loadMore": "加载更多" }, "channels": { - "intro": "Channels are where alerts can go outside Termix. Delivery rules pick which alerts use them.", - "add": "Add channel", - "edit": "Edit channel", - "test": "Send a test", - "testSent": "Test alert sent", - "testFailed": "Test failed: {{error}}", - "deleteConfirm": "Delete the channel \"{{name}}\"?", - "deleted": "Channel deleted", - "empty": "No channels yet.", + "intro": "渠道用于将告警发送到 Termix 之外,投递规则决定哪些告警使用这些渠道。", + "add": "添加渠道", + "edit": "编辑渠道", + "test": "发送测试消息", + "testSent": "测试告警已发送", + "testFailed": "测试失败:{{error}}", + "deleteConfirm": "删除渠道“{{name}}”?", + "deleted": "渠道已删除", + "empty": "暂无渠道。", "enabled": "已启用", - "needsSave": "This channel needs to be opened and saved again before it can send.", + "needsSave": "此渠道需要重新打开并保存后才能发送。", "name": "名称", "nameRequired": "名称为必填项", "type": "类型", @@ -119,41 +119,41 @@ "discord": "Discord", "email": "邮箱" }, - "emailUnavailable": "Email needs an SMTP server, which an admin sets up in the Alerts settings.", + "emailUnavailable": "邮件需要 SMTP 服务器,由管理员在告警设置中配置。", "webhookUrl": "URL", - "webhookHint": "Gets a JSON body for every alert.", - "method": "Method", - "headers": "Headers", - "headersHint": "One per line, like Name: value.", + "webhookHint": "每条告警都会发送包含 JSON 数据的请求体。", + "method": "请求方法", + "headers": "请求头", + "headersHint": "每行一项,例如 Name: value。", "ntfyServer": "服务器 URL", "ntfyTopic": "主题", - "ntfyToken": "Access token (optional)", - "discordUrl": "Discord webhook URL", - "discordHint": "From the channel's settings in Discord, under Integrations.", - "discordUsername": "Display name (optional)", - "discordAvatar": "Avatar URL (optional)", - "emailTo": "Send to", - "emailHint": "Separate more than one address with commas.", - "privateNetwork": "Allow a private network address", - "privateNetworkHint": "Only works for hosts an admin allows in the private endpoint list." + "ntfyToken": "访问令牌(可选)", + "discordUrl": "Discord Webhook 地址", + "discordHint": "可在 Discord 频道设置的“集成”中获取。", + "discordUsername": "显示名称(可选)", + "discordAvatar": "头像 URL(可选)", + "emailTo": "发送至", + "emailHint": "多个地址之间用逗号分隔。", + "privateNetwork": "允许内网地址", + "privateNetworkHint": "仅适用于管理员在私有端点列表中允许的主机。" }, "rules": { - "intro": "A delivery rule sends matching alerts to your channels. Alerts always stay in the inbox too.", - "add": "Add rule", - "edit": "Edit rule", - "empty": "No rules yet, so alerts only show up in the inbox.", - "needChannel": "Add a channel first.", + "intro": "投递规则将匹配的告警发送到你的渠道,告警也会始终保留在收件箱中。", + "add": "添加规则", + "edit": "编辑规则", + "empty": "暂无规则,告警仅显示在收件箱中。", + "needChannel": "请先添加渠道。", "enabled": "已启用", "name": "名称", "nameRequired": "名称为必填项", - "match": "Alerts to send", - "matchHint": "* for everything, automations.* for everything from automations, or one exact kind.", - "minSeverity": "At least", - "channels": "Send to", - "channelRequired": "Pick at least one channel", - "deleteConfirm": "Delete the rule \"{{name}}\"?", - "everything": "Everything", - "summary": "{{match}}, {{severity}} or higher, to {{channels}}" + "match": "要发送的告警", + "matchHint": "使用 * 匹配全部,automations.* 匹配所有自动化告警,或填写一个精确的类型。", + "minSeverity": "最低严重程度", + "channels": "发送至", + "channelRequired": "请至少选择一个渠道", + "deleteConfirm": "删除规则“{{name}}”?", + "everything": "全部", + "summary": "{{match}},{{severity}} 及以上,发送至 {{channels}}" }, "actions": { "cancel": "取消", @@ -163,10 +163,13 @@ }, "widget": { "name": "告警信息流", - "description": "Your latest alerts, with a quick way to mark them read", - "maxItems": "Max items", - "showRead": "Show read alerts", + "description": "显示最新告警,并可快速标记为已读", + "maxItems": "最大条目数", + "showRead": "显示已读告警", "allClear": "一切正常", "loading": "加载中..." + }, + "plugin": { + "name": "告警" } } diff --git a/plugins/automations/locales/en.json b/plugins/automations/locales/en.json index b459b4ade..77a517290 100644 --- a/plugins/automations/locales/en.json +++ b/plugins/automations/locales/en.json @@ -207,5 +207,19 @@ "remove": "Remove schedule", "loadFailed": "Could not refresh maintenance status. Changes are disabled until it can be loaded.", "loading": "Loading maintenance status…" + }, + "ui": { + "sidebar": { + "automations": { + "options": { + "connect": "connect", + "disconnect": "disconnect", + "offline": "offline", + "online": "online", + "failing": "failing", + "recovered": "recovered" + } + } + } } } diff --git a/plugins/automations/locales/translated/zh_CN.json b/plugins/automations/locales/translated/zh_CN.json index 2c9989a4a..05f31bc25 100644 --- a/plugins/automations/locales/translated/zh_CN.json +++ b/plugins/automations/locales/translated/zh_CN.json @@ -1,110 +1,110 @@ { "permissions": { "view": { - "title": "View automations", - "description": "See the automations and their history." + "title": "查看自动化", + "description": "查看自动化及其执行历史。" }, "create": { - "title": "Create automations", - "description": "Add new automations." + "title": "创建自动化", + "description": "添加新的自动化。" }, "edit": { - "title": "Edit automations", - "description": "Change existing automations." + "title": "编辑自动化", + "description": "修改现有自动化。" }, "delete": { - "title": "Delete automations", - "description": "Remove automations." + "title": "删除自动化", + "description": "移除自动化。" }, "run": { - "title": "Run automations", - "description": "Trigger an automation by hand." + "title": "运行自动化", + "description": "手动触发自动化。" } }, "newUi": { "sidebar": { "automations": { - "title": "Automations", - "tabAutomations": "Automations", + "title": "自动化", + "tabAutomations": "自动化", "tabRuns": "运行记录", "tabChannels": "通道", - "createAutomation": "New Automation", - "backToAutomations": "Back to Automations", - "createTitle": "New Automation", - "editTitle": "Edit Automation", - "empty": "No automations yet. Create one to react to a metric, a schedule, or an event.", + "createAutomation": "新建自动化", + "backToAutomations": "返回自动化", + "createTitle": "新建自动化", + "editTitle": "编辑自动化", + "empty": "暂无自动化。创建自动化以响应指标、计划或事件。", "emptyRuns": "暂无运行记录。", - "channelsHint": "Channels are set up in Alerts", - "noChannelsHint": "The alert always goes to your inbox. Add channels in Alerts to also send it somewhere else.", + "channelsHint": "渠道在“告警”中设置", + "noChannelsHint": "告警始终会发送到收件箱。在“告警”中添加渠道后,也可发送到其他位置。", "nameLabel": "名称", - "namePlaceholder": "e.g., Clean up /data when it fills", + "namePlaceholder": "例如:/data 空间不足时自动清理", "nameRequired": "名称为必填项", "descriptionLabel": "描述", "descriptionPlaceholder": "可选描述", "enabledLabel": "已启用", - "concurrencyLabel": "If it is already running", - "concurrencyHint": "What to do when this is triggered again before the last run has finished.", + "concurrencyLabel": "已有任务运行时", + "concurrencyHint": "上次运行尚未结束时再次触发的处理方式。", "concurrency": { - "skip": "Skip the new run", + "skip": "跳过本次运行", "queue": "稍等会再运行", - "allow": "Run both at once" + "allow": "同时运行两个任务" }, "save": "保存", "created": "自动化已创建", "updated": "自动化已保存", "deleted": "自动化已删除", - "deleteConfirm": "Delete this automation? Its run history is deleted too.", - "runNow": "Run now", - "testRun": "Test run", - "testRunHint": "Runs every step but does not touch anything outside Termix.", - "runStarted": "Run started", - "runFinished": "Run finished: {{status}}", + "deleteConfirm": "删除此自动化?其运行历史也会一并删除。", + "runNow": "立即运行", + "testRun": "测试运行", + "testRunHint": "执行每个步骤,但不会修改 Termix 之外的任何内容。", + "runStarted": "已开始运行", + "runFinished": "运行结束:{{status}}", "trigger": "触发器", - "steps": "Steps", - "addStep": "Add step", - "removeStep": "Remove step", - "moveUp": "Move up", - "moveDown": "Move down", - "noSteps": "No steps yet. Add one to say what should happen.", - "webhookTokenTitle": "Webhook URL", - "webhookTokenDescription": "This is shown once. Save it now, it cannot be retrieved later.", + "steps": "步骤", + "addStep": "添加步骤", + "removeStep": "移除步骤", + "moveUp": "上移", + "moveDown": "下移", + "noSteps": "暂无步骤。添加步骤以定义要执行的操作。", + "webhookTokenTitle": "Webhook 地址", + "webhookTokenDescription": "此内容仅显示一次,请立即保存,之后无法再次获取。", "copy": "复制", "copied": "已复制", "viewJson": "JSON", "viewBuilder": "构建器", - "viewGraph": "Graph", + "viewGraph": "流程图", "lastRun": "上次运行", "never": "从未", - "duration": "{{seconds}}s", + "duration": "{{seconds}} 秒", "stepOutput": "输出", "stepError": "错误", - "dryRunBadge": "Test run", + "dryRunBadge": "测试运行", "hostSelector": { - "trigger": "Triggering host", - "host": "Specific host", - "fleet": "Fleet", + "trigger": "触发事件的主机", + "host": "指定主机", + "fleet": "主机组", "all": "所有主机" }, "triggerKinds": { - "metric_threshold": "Metric threshold", + "metric_threshold": "指标阈值", "host_status": "主机上线或离线", - "health_check": "Health check changes", - "schedule": "On a schedule", - "docker_event": "Container event", + "health_check": "健康检查状态变化", + "schedule": "按计划运行", + "docker_event": "容器事件", "internal_event": "Termix 事件", - "webhook": "Incoming webhook" + "webhook": "接收 Webhook" }, "stepTypes": { - "notify": "Send an alert", - "http": "Call a URL", - "run_snippet": "Run a snippet", - "run_command": "Run a command", - "docker": "Control a container", - "tunnel": "Control a tunnel", - "wol": "Wake a host", - "wait": "Wait", - "set_var": "Set a variable", - "if": "If / otherwise", + "notify": "发送告警", + "http": "请求 URL", + "run_snippet": "执行代码片段", + "run_command": "执行命令", + "docker": "控制容器", + "tunnel": "控制隧道", + "wol": "唤醒主机", + "wait": "等待", + "set_var": "设置变量", + "if": "如果 / 否则", "run_automation": "运行另一个自动化程序", "stop": "停止" }, @@ -112,52 +112,52 @@ "running": "运行中", "success": "成功", "failed": "失败", - "timeout": "Timed out", - "skipped": "Skipped", + "timeout": "已超时", + "skipped": "已跳过", "cancelled": "已取消" }, "fields": { "host": "主机", "metric": "指标", "mount": "挂载点", - "operator": "Is", + "operator": "等于", "value": "值", - "forSeconds": "Sustained for (seconds)", + "forSeconds": "持续时间(秒)", "cooldown": "冷却时间(分钟)", "cron": "Cron 表达式", - "intervalSeconds": "Every (seconds)", - "timezone": "Time zone", - "timezoneServer": "Server time", - "timezoneHint": "Cron times are read in this zone. Does not apply to interval schedules.", - "container": "Container", + "intervalSeconds": "间隔(秒)", + "timezone": "时区", + "timezoneServer": "服务器时间", + "timezoneHint": "Cron 时间按此时区解释,不适用于按间隔运行的计划。", + "container": "容器", "command": "命令", "url": "URL", - "method": "Method", + "method": "请求方法", "body": "请求体", - "channels": "Also send to", + "channels": "同时发送至", "title": "标题", "message": "消息", - "snippet": "Snippet", - "seconds": "Seconds", - "conditionLeftPlaceholder": "Value to check", - "conditionRightPlaceholder": "Compare against", + "snippet": "代码片段", + "seconds": "秒", + "conditionLeftPlaceholder": "待检查的值", + "conditionRightPlaceholder": "比较目标值", "variableName": "变量名", "variableValue": "值", - "elevated": "Run with sudo", - "onError": "If this fails", - "allowPrivateNetwork": "Allow local network addresses", - "allowPrivateNetworkHint": "Needed for a self-hosted service on your LAN. Off by default to prevent requests to internal addresses." + "elevated": "使用 sudo 执行", + "onError": "失败时", + "allowPrivateNetwork": "允许局域网地址", + "allowPrivateNetworkHint": "访问局域网内的自托管服务时需要开启。默认关闭,以防止请求内部地址。" }, "onError": { "stop": "停止运行", - "continue": "Carry on" + "continue": "继续执行" }, - "needsPlugin": "Needs {{plugin}}", - "needsPluginHint": "This automation is skipped until the feature it needs is available again.", + "needsPlugin": "需要 {{plugin}}", + "needsPluginHint": "在所需功能恢复可用之前,此自动化将被跳过。", "offBadge": "关闭", "docsLink": "查看文档", "ago": { - "seconds": "{{count}}s ago", + "seconds": "{{count}} 秒前", "minutes": "{{count}} 分钟前", "hours": "{{count}} 小时前", "days": "{{count}} 天前" @@ -166,46 +166,60 @@ } }, "nav": { - "automations": "Automations" + "automations": "自动化" }, "onboarding": { - "feature_automations": "Automations", + "feature_automations": "自动化", "feature_automations_desc": "触发特定事件时自动执行任务,并接收通知。" }, "maintenance": { "title": "维护中", - "description": "Pause host status, health, metric, container and tunnel-disconnection automations while work is in progress. Monitoring, manual runs and scheduled automations continue.", - "denied": "You do not have permission to view maintenance.", - "sharedReadOnly": "This host was shared with you. Only its owner can change maintenance.", - "failed": "Maintenance could not be updated.", - "active": "Maintenance active", - "estimated": "Estimated completion", - "noAutoEnd": "The estimate does not end maintenance. End it explicitly when the work is complete.", - "endConfirm": "End maintenance and resume event-triggered automations for this host?", - "confirmEnd": "Confirm end", + "description": "维护期间暂停由主机状态、健康检查、指标、容器和隧道断开事件触发的自动化。监控、手动执行和定时自动化继续运行。", + "denied": "你没有查看维护信息的权限。", + "sharedReadOnly": "此主机由他人共享给你,只有所有者才能修改维护设置。", + "failed": "无法更新维护设置。", + "active": "维护中", + "estimated": "预计完成时间", + "noAutoEnd": "预计时间不会自动结束维护,请在工作完成后手动结束。", + "endConfirm": "结束维护并恢复此主机的事件触发自动化?", + "confirmEnd": "确认结束", "cancel": "取消", - "end": "End maintenance", + "end": "结束维护", "action": "操作", - "startNow": "Start now", - "schedule": "Schedule for later", - "reason": "Reason", - "startUtc": "First start (UTC)", - "repeat": "Repeat", - "once": "Once", - "weekly": "Weekly", - "monthly": "Monthly", - "utcHelp": "Schedules use UTC throughout the year. Monthly schedules skip months without the selected day. Planned windows cannot overlap; overrunning maintenance continues across later windows.", - "duration": "Estimated duration (minutes)", - "grace": "Grace period (minutes)", - "notify": "Notify once if still offline after the estimate plus grace period", - "addSchedule": "Add schedule", - "schedules": "Schedules", - "noSchedules": "No maintenance schedules.", - "completed": "Already started", - "minutes_one": "{{count}} minute", - "minutes_other": "{{count}} minutes", - "remove": "Remove schedule", - "loadFailed": "Could not refresh maintenance status. Changes are disabled until it can be loaded.", - "loading": "Loading maintenance status…" + "startNow": "立即开始", + "schedule": "安排稍后执行", + "reason": "原因", + "startUtc": "首次开始时间(UTC)", + "repeat": "重复", + "once": "仅一次", + "weekly": "每周", + "monthly": "每月", + "utcHelp": "计划全年使用 UTC。每月计划会跳过没有指定日期的月份。计划窗口不能重叠;超时未结束的维护会持续到后续窗口。", + "duration": "预计时长(分钟)", + "grace": "宽限期(分钟)", + "notify": "预计完成时间加宽限期后仍离线时,发送一次通知", + "addSchedule": "添加计划", + "schedules": "计划", + "noSchedules": "暂无维护计划。", + "completed": "已开始", + "minutes_one": "{{count}} 分钟", + "minutes_other": "{{count}} 分钟", + "remove": "移除计划", + "loadFailed": "无法刷新维护状态,在成功加载之前无法更改设置。", + "loading": "正在加载维护状态……" + }, + "ui": { + "sidebar": { + "automations": { + "options": { + "connect": "连接", + "disconnect": "断开连接", + "offline": "离线", + "online": "在线", + "failing": "故障", + "recovered": "已恢复" + } + } + } } } diff --git a/plugins/automations/src/frontend/automations/StepBlock.tsx b/plugins/automations/src/frontend/automations/StepBlock.tsx index 1927052c3..653b7a51a 100644 --- a/plugins/automations/src/frontend/automations/StepBlock.tsx +++ b/plugins/automations/src/frontend/automations/StepBlock.tsx @@ -368,8 +368,12 @@ export function StepBlock({ - connect - disconnect + + {t("ui.sidebar.automations.options.connect")} + + + {t("ui.sidebar.automations.options.disconnect")} + {trigger.kind === "host_status" ? ( <> - offline - online + + {t("ui.sidebar.automations.options.offline")} + + + {t("ui.sidebar.automations.options.online")} + ) : ( <> - failing - recovered + + {t("ui.sidebar.automations.options.failing")} + + + {t("ui.sidebar.automations.options.recovered")} + )} diff --git a/plugins/docker/locales/translated/zh_CN.json b/plugins/docker/locales/translated/zh_CN.json index b1a43f784..e6a47976d 100644 --- a/plugins/docker/locales/translated/zh_CN.json +++ b/plugins/docker/locales/translated/zh_CN.json @@ -24,8 +24,8 @@ "stop": "停止", "status": "状态", "actions": "操作", - "cardView": "Card view", - "listView": "List view", + "cardView": "卡片视图", + "listView": "列表视图", "confirmRemoveContainer": "确定要移除容器 '{{name}}' 吗?此操作无法撤销。", "runningContainerWarning": "警告:此容器正在运行。移除操作将先停止容器。", "loadingContainers": "正在加载容器...", @@ -70,7 +70,7 @@ "blockIo": "块 I/O", "read": "读取", "write": "写入", - "pids": "PIDs", + "pids": "进程 ID", "containerInformation": "容器信息", "name": "名称", "id": "ID", @@ -78,7 +78,7 @@ "containerMustBeRunning": "访问控制台需要容器处于运行状态", "verificationCodePrompt": "输入验证码", "totpVerificationFailed": "TOTP 验证失败,请重试。", - "browserSignInFailed": "Sign-in failed. Please try again.", + "browserSignInFailed": "登录失败,请重试。", "connectedTo": "已连接到 {{containerName}}", "disconnected": "已断开连接", "consoleError": "控制台错误", @@ -118,15 +118,15 @@ }, "permissions": { "use": { - "title": "Use Docker", - "description": "Open the Docker manager and container consoles on hosts with Docker enabled." + "title": "使用 Docker", + "description": "在启用了 Docker 的主机上打开 Docker 管理器和容器控制台。" } }, "settings": { "host": { "enable": { "label": "启用 Docker", - "description": "Manage containers on this host." + "description": "管理此主机上的容器。" }, "containerRuntime": { "label": "容器运行时", @@ -137,7 +137,7 @@ } }, "errors": { - "remoteServerRequired": "Remote server required. Connect a remote server in Settings to use this connection type." + "remoteServerRequired": "需要远程服务器。请在设置中连接远程服务器以使用此连接类型。" }, "hosts": { "docsLink": "查看文档", diff --git a/plugins/file-manager/locales/en.json b/plugins/file-manager/locales/en.json index dc86761ce..e162e7c37 100644 --- a/plugins/file-manager/locales/en.json +++ b/plugins/file-manager/locales/en.json @@ -323,7 +323,7 @@ "sideBySide": "Side by Side", "inline": "Inline", "fileComparison": "File Comparison: {{file1}} vs {{file2}}", - "fileTooLarge": "File too large: {{error}}", + "fileTooLarge": "File is too large (> 10MB) and cannot be opened as text for security reasons.", "sshConnectionFailed": "SSH connection failed. Please check your connection to {{name}} ({{ip}}:{{port}})", "loadFileFailed": "Failed to load file: {{error}}", "connecting": "Connecting...", @@ -365,7 +365,7 @@ "comfortableLayout": "Use comfortable layout", "cannotLoadPdf": "Cannot load PDF", "pdfLoadError": "There was an error loading this PDF file.", - "loadingPdf": "Loading PDF...", + "loadingPdf": "Loading PDF viewer...", "loadingPage": "Loading page...", "cancel": "Cancel", "copiedItems_one": "Copied {{count}} item", @@ -383,7 +383,16 @@ "videoUnsupported": "Your browser cannot play this video format.", "downloadToPlay": "Download to play it elsewhere", "cannotPreviewType": "Cannot preview this file type", - "cannotPreviewTypeHint": "This file type has no preview. Download it to open it in another app." + "cannotPreviewTypeHint": "This file type has no preview. Download it to open it in another app.", + "loadingFile": "Loading file...", + "loadingImage": "Loading image...", + "loadingEditor": "Loading editor...", + "loadingPreview": "Loading preview...", + "loadingAudio": "Loading audio player...", + "emptyPreview": "Nothing to preview yet...", + "revert": "Revert", + "openAsText": "Open as Text", + "confirmOpenAsText": "Do you want to continue opening this file as text? This may slow down your browser." }, "sftpTransfer": { "title": "SFTP", @@ -539,5 +548,8 @@ "metricsHopSourceRead": "Source → server: {{throughput}}", "metricsHopDestSftpWrite": "Server → dest (SFTP): {{throughput}}", "metricsHopDestLocalWrite": "Server → dest (local): {{throughput}}" + }, + "plugin": { + "name": "File Manager" } } diff --git a/plugins/file-manager/locales/translated/zh_CN.json b/plugins/file-manager/locales/translated/zh_CN.json index d137a28cc..aa5d71a0c 100644 --- a/plugins/file-manager/locales/translated/zh_CN.json +++ b/plugins/file-manager/locales/translated/zh_CN.json @@ -6,15 +6,15 @@ }, "permissions": { "use": { - "title": "Use file manager", - "description": "Browse, edit and transfer files over SFTP." + "title": "使用文件管理器", + "description": "通过 SFTP 浏览、编辑和传输文件。" } }, "settings": { "host": { "enable": { "label": "启用文件管理器", - "description": "Browse and edit files on this host over SFTP." + "description": "通过 SFTP 浏览和编辑此主机上的文件。" }, "defaultPath": { "label": "默认路径" @@ -25,12 +25,12 @@ }, "user": { "transferConcurrency": { - "label": "Simultaneous File Transfers", - "description": "How many files the side by side local/remote manager uploads or downloads at the same time. Lower this if your server limits SFTP channels." + "label": "同时传输文件数", + "description": "本地与远程分栏文件管理器同时上传或下载的文件数。如果服务器限制 SFTP 通道数,请调低此值。" }, "confirmBeforeTrash": { - "label": "Confirm before moving files to trash", - "description": "Ask before moving remote files to trash. Permanent deletion still requires confirmation." + "label": "移入回收站前确认", + "description": "将远程文件移入回收站前询问。永久删除仍需确认。" } } }, @@ -72,14 +72,14 @@ "rename": "重命名", "uploading": "上传中...", "uploadingFile": "正在上传 {{name}}...", - "uploadingChunk": "Uploading {{name}}: {{percent}}% (part {{chunk}} of {{total}})", + "uploadingChunk": "正在上传 {{name}}:{{percent}}%(第 {{chunk}} 部分,共 {{total}} 部分)", "fileName": "文件名", "folderName": "文件夹名称", "fileUploadedSuccessfully": "文件 \"{{name}}\" 上传成功", "failedToUploadFile": "上传文件失败", - "uploadingFolderFiles": "Uploading {{count}} file(s)...", - "uploadedFolderFiles": "Uploaded {{count}} file(s) successfully", - "uploadedFolderPartial": "Uploaded {{uploaded}} file(s), {{failed}} failed", + "uploadingFolderFiles": "正在上传 {{count}} 个文件……", + "uploadedFolderFiles": "成功上传 {{count}} 个文件", + "uploadedFolderPartial": "已上传 {{uploaded}} 个文件,{{failed}} 个失败", "fileDownloadedSuccessfully": "文件 \"{{name}}\" 下载成功", "failedToDownloadFile": "下载文件失败", "fileCreatedSuccessfully": "文件 \"{{name}}\" 创建成功", @@ -95,58 +95,58 @@ "sudoOperationFailed": "Sudo 操作失败", "sudoAuthFailed": "Sudo 认证失败", "dragFilesToUpload": "将文件拖放到此处以上传", - "dropToUploadHere": "Drop to upload here", - "dropToDownloadHere": "Drop to download here", + "dropToUploadHere": "拖放到此处上传", + "dropToDownloadHere": "拖放到此处下载", "localFiles": "本地", - "showLocalFiles": "Show local files (split view)", - "hideLocalFiles": "Hide local files", - "localHome": "Home folder", - "localPathPlaceholder": "Local folder path", - "localShowHidden": "Show hidden files", - "localHideHidden": "Hide hidden files", - "localRevealInFileManager": "Reveal in system file manager", - "localCannotOpenFolder": "Cannot open folder", + "showLocalFiles": "显示本地文件(分栏视图)", + "hideLocalFiles": "隐藏本地文件", + "localHome": "主目录", + "localPathPlaceholder": "本地文件夹路径", + "localShowHidden": "显示隐藏文件", + "localHideHidden": "隐藏隐藏文件", + "localRevealInFileManager": "在系统文件管理器中显示", + "localCannotOpenFolder": "无法打开文件夹", "localItemCount": "{{count}} 个项目", "localSelectedCount": "已选择 {{count}} 项", "back": "返回", - "forward": "Forward", - "up": "Up", - "kind": "Kind", - "localUploadingProgress": "Uploading {{current}} of {{total}}", - "localDownloadingProgress": "Downloading {{current}} of {{total}}", - "localTransferInFlight": "{{count}} at once", - "localPreparingDownload": "Preparing download...", + "forward": "前进", + "up": "上一级", + "kind": "类型", + "localUploadingProgress": "正在上传第 {{current}} 个,共 {{total}} 个", + "localDownloadingProgress": "正在下载第 {{current}} 个,共 {{total}} 个", + "localTransferInFlight": "同时 {{count}} 个", + "localPreparingDownload": "正在准备下载……", "localTransferCancelled": "传输已取消", - "localNothingToTransfer": "Nothing to transfer", - "localUploadComplete": "Uploaded {{count}} file(s)", - "localUploadFailed": "Upload failed", - "localUploadPartial": "Uploaded {{done}} file(s), {{failed}} failed", - "localDownloadComplete": "Downloaded {{count}} file(s)", + "localNothingToTransfer": "没有需要传输的内容", + "localUploadComplete": "已上传 {{count}} 个文件", + "localUploadFailed": "上传失败", + "localUploadPartial": "已上传 {{done}} 个文件,{{failed}} 个失败", + "localDownloadComplete": "已下载 {{count}} 个文件", "localDownloadFailed": "下载失败", - "localDownloadPartial": "Downloaded {{done}} file(s), {{failed}} failed", - "localReplaceExistingPrompt": "{{count}} item(s) already exist in this folder. Replace them?", + "localDownloadPartial": "已下载 {{done}} 个文件,{{failed}} 个失败", + "localReplaceExistingPrompt": "此文件夹中已有 {{count}} 个同名项目,是否替换?", "localReplace": "替换", - "localSkipExisting": "Skip", - "localSkippedExisting": "Skipped {{count}} existing item(s)", - "localUnsafeNamesSkipped": "Skipped {{count}} item(s) whose names cannot be used on this computer", + "localSkipExisting": "跳过", + "localSkippedExisting": "已跳过 {{count}} 个现有项目", + "localUnsafeNamesSkipped": "已跳过 {{count}} 个名称无法在此计算机上使用的项目", "localOpen": "打开", - "localOpenFolder": "Open folder", - "localUploadToRemote": "Upload to server", - "localUploadToRemoteMany": "Upload {{count}} items to server", - "localMoveToTrash": "Move to Trash", - "localMoveToTrashMany": "Move {{count}} items to Trash", - "localTrashConfirmSingle": "Move \"{{name}}\" to the Trash?", - "localTrashConfirmFolder": "Move the folder \"{{name}}\" and all its contents to the Trash?", - "localTrashConfirmMany": "Move {{count}} items to the Trash?", - "localTrashed": "Moved {{count}} item(s) to the Trash", - "localTrashFailed": "Could not move to the Trash", - "localRenameFailed": "Rename failed", - "localCreateFailed": "Could not create item", - "goToParentFolder": "Go to parent folder", - "resizeSidebar": "Drag to resize the sidebar (double-click to reset)", - "resizeLocalPane": "Drag to resize the local pane (double-click to reset)", + "localOpenFolder": "打开文件夹", + "localUploadToRemote": "上传到服务器", + "localUploadToRemoteMany": "将 {{count}} 个项目上传到服务器", + "localMoveToTrash": "移入回收站", + "localMoveToTrashMany": "将 {{count}} 个项目移入回收站", + "localTrashConfirmSingle": "将“{{name}}”移入回收站?", + "localTrashConfirmFolder": "将文件夹“{{name}}”及其中所有内容移入回收站?", + "localTrashConfirmMany": "将 {{count}} 个项目移入回收站?", + "localTrashed": "已将 {{count}} 个项目移入回收站", + "localTrashFailed": "无法移入回收站", + "localRenameFailed": "重命名失败", + "localCreateFailed": "无法创建项目", + "goToParentFolder": "转到父文件夹", + "resizeSidebar": "拖动调整侧边栏宽度(双击重置)", + "resizeLocalPane": "拖动调整本地窗格大小(双击重置)", "columns": "列", - "columnsHint": "Right-click to choose columns", + "columnsHint": "右键点击选择显示的列", "emptyFolder": "此文件夹为空", "searchFiles": "搜索文件...", "upload": "上传", @@ -203,25 +203,25 @@ "confirmDeleteFolder": "确定要永久删除文件夹“{{name}}”及其所有内容吗?", "permanentDeleteWarning": "此操作无法撤销。项目将从服务器永久删除。", "moveToTrashWarning": "该项目将被移至 Termix 回收站,可在保留期到期前恢复。", - "itemsMovedToTrash": "{{count}} item(s) moved to Trash", + "itemsMovedToTrash": "已将 {{count}} 个项目移入回收站", "trash": "回收站", - "trashDescription": "Deleted items are retained for {{days}} day(s) on this host.", - "trashLoadFailed": "Failed to load Trash", + "trashDescription": "删除的项目将在此主机上保留 {{days}} 天。", + "trashLoadFailed": "加载回收站失败", "trashEmpty": "回收站是空的", "trashRestore": "恢复", - "trashRestored": "Restored {{name}}", - "trashRestoreFailed": "Failed to restore item. The original path may already exist.", - "trashDeletePermanently": "Delete permanently", - "trashDeleteConfirm": "Permanently delete {{name}}? This cannot be undone.", - "trashPermanentlyDeleted": "Permanently deleted {{name}}", - "trashDeleteFailed": "Failed to permanently delete item", + "trashRestored": "已恢复 {{name}}", + "trashRestoreFailed": "恢复项目失败,原路径可能已存在。", + "trashDeletePermanently": "永久删除", + "trashDeleteConfirm": "永久删除 {{name}}?此操作无法撤销。", + "trashPermanentlyDeleted": "已永久删除 {{name}}", + "trashDeleteFailed": "永久删除项目失败", "trashEmptyAction": "清空回收站", - "trashEmptyConfirm": "Permanently delete every item in Trash? This cannot be undone.", + "trashEmptyConfirm": "永久删除回收站中的所有项目?此操作无法撤销。", "trashEmptied": "回收站已清空", "trashRetention": "自动清理(N 天后)", "trashRetentionSaved": "回收站保留设置已更新", "trashRetentionFailed": "更新回收站保留设置失败", - "trashUnavailableConfirm": "This item cannot be moved to Trash, usually because it is on another filesystem or requires elevated permissions. Delete it permanently instead?", + "trashUnavailableConfirm": "此项目无法移入回收站,通常是因为它位于其他文件系统中或需要更高权限。是否改为永久删除?", "recent": "最近", "pinned": "已固定", "folderShortcuts": "文件夹快捷方式", @@ -303,7 +303,7 @@ "operationCompleted": "{{operation}}了{{count}}个项目", "downloadFileSuccess": "文件 {{name}} 下载成功", "downloadFileFailed": "下载失败", - "downloadingFile": "Downloading {{name}}…", + "downloadingFile": "正在下载 {{name}}……", "downloadProgressBytes": "{{transferred}} / {{total}}", "moveTo": "移动到 {{name}}", "diffCompareWith": "与 {{name}} 对比差异", @@ -323,13 +323,13 @@ "sideBySide": "并排", "inline": "内联", "fileComparison": "文件比较: {{file1}} 对比 {{file2}}", - "fileTooLarge": "文件过大: {{error}}", + "fileTooLarge": "文件过大(超过 10 MB),出于安全考虑无法作为文本打开。", "sshConnectionFailed": "SSH 连接失败。请检查您到 {{name}} ({{ip}}:{{port}}) 的连接", "loadFileFailed": "加载文件失败: {{error}}", "connecting": "连接中...", "connectedSuccessfully": "连接成功", "totpVerificationFailed": "TOTP 验证失败", - "browserSignInFailed": "Sign-in failed. Please try again.", + "browserSignInFailed": "登录失败,请重试。", "authenticationFailed": "认证失败", "incorrectPassphrase": "密码错误。请重试。", "verificationCodePrompt": "验证码:", @@ -361,73 +361,82 @@ "used": "已用", "of": "/", "toggleSidebar": "切换侧边栏", - "compactLayout": "Use compact layout", - "comfortableLayout": "Use comfortable layout", + "compactLayout": "使用紧凑布局", + "comfortableLayout": "使用宽松布局", "cannotLoadPdf": "无法加载 PDF", "pdfLoadError": "加载此 PDF 文件时出错。", - "loadingPdf": "正在加载 PDF...", + "loadingPdf": "正在加载 PDF 查看器……", "loadingPage": "正在加载页面...", "cancel": "取消", - "copiedItems_one": "Copied {{count}} item", - "copiedItems_other": "Copied {{count}} items", - "deleteCopiedFileFailed": "Could not delete the copy of {{name}}: {{error}}", - "dragMovedItems_one": "Moved {{count}} item to {{target}}", - "dragMovedItems_other": "Moved {{count}} items to {{target}}", - "moveBackFileFailed": "Could not move {{name}} back: {{error}}", - "terminal": "Terminal: {{host}} ({{path}})", - "dragToDesktop": "Dragging {{name}} to the desktop", - "dragFilesToDesktop": "Dragging {{count}} files to the desktop", - "folderDragUnsupported": "Dragging folders to the desktop is not supported yet", - "saveToDesktopFailed": "Save failed: {{error}}", - "dragFailedDetail": "Drag failed: {{error}}", - "videoUnsupported": "Your browser cannot play this video format.", - "downloadToPlay": "Download to play it elsewhere", - "cannotPreviewType": "Cannot preview this file type", - "cannotPreviewTypeHint": "This file type has no preview. Download it to open it in another app." + "copiedItems_one": "已复制 {{count}} 个项目", + "copiedItems_other": "已复制 {{count}} 个项目", + "deleteCopiedFileFailed": "无法删除 {{name}} 的副本:{{error}}", + "dragMovedItems_one": "已将 {{count}} 个项目移至 {{target}}", + "dragMovedItems_other": "已将 {{count}} 个项目移至 {{target}}", + "moveBackFileFailed": "无法将 {{name}} 移回原处:{{error}}", + "terminal": "终端:{{host}}({{path}})", + "dragToDesktop": "正在将 {{name}} 拖到桌面", + "dragFilesToDesktop": "正在将 {{count}} 个文件拖到桌面", + "folderDragUnsupported": "暂不支持将文件夹拖到桌面", + "saveToDesktopFailed": "保存失败:{{error}}", + "dragFailedDetail": "拖放失败:{{error}}", + "videoUnsupported": "你的浏览器无法播放此视频格式。", + "downloadToPlay": "下载后使用其他程序播放", + "cannotPreviewType": "无法预览此文件类型", + "cannotPreviewTypeHint": "此文件类型不支持预览,请下载后使用其他应用打开。", + "loadingFile": "正在加载文件……", + "loadingImage": "正在加载图片……", + "loadingEditor": "正在加载编辑器……", + "loadingPreview": "正在加载预览……", + "loadingAudio": "正在加载音频播放器……", + "emptyPreview": "暂无可预览内容……", + "revert": "还原", + "openAsText": "作为文本打开", + "confirmOpenAsText": "是否继续将此文件作为文本打开?这可能导致浏览器运行变慢。" }, "sftpTransfer": { "title": "SFTP", - "description": "Transfer files between two SSH hosts.", - "sourceServer": "Source Server", - "destinationServer": "Destination Server", - "selectHost": "Select host", + "description": "在两台 SSH 主机之间传输文件。", + "sourceServer": "源服务器", + "destinationServer": "目标服务器", + "selectHost": "选择主机", "noHostSelected": "未选择主机", "move": "移动", "copy": "复制", "upload": "上传", - "itemsSelected": "{{count}} item selected", - "itemsSelected_other": "{{count}} items selected", + "itemsSelected": "已选择 {{count}} 个项目", + "itemsSelected_other": "已选择 {{count}} 个项目", "ready": "就绪", "loadingHosts": "正在加载主机...", "name": "名称", "modified": "修改时间", "size": "大小", - "noFiles": "No files", + "noFiles": "没有文件", "open": "打开", - "up": "Up", + "up": "上一级", "refresh": "刷新", - "copyToTarget": "Copy to Target Directory", + "copyToTarget": "复制到目标目录", "rename": "重命名", "delete": "删除", - "editPermissions": "Edit Permissions", - "createNewFolder": "Create New Folder", - "deleteSelectedItems": "Delete Selected Items", - "deleteConfirm": "Delete {{count}} selected item?", - "deleteConfirm_other": "Delete {{count}} selected items?", + "editPermissions": "编辑权限", + "createNewFolder": "新建文件夹", + "deleteSelectedItems": "删除所选项目", + "deleteConfirm": "删除选中的 {{count}} 个项目?", + "deleteConfirm_other": "删除选中的 {{count}} 个项目?", "cancel": "取消", "save": "保存", - "folderCreated": "Folder created", - "itemRenamed": "Item renamed", + "folderCreated": "文件夹已创建", + "itemRenamed": "项目已重命名", "actionFailed": "操作失败", - "itemsDeleted": "{{count}} item deleted", - "itemsDeleted_other": "{{count}} items deleted", - "deleteFailed": "Delete failed", - "permissionsUpdated": "Permissions updated", - "noRemoteSessionConnected": "No remote session connected", + "itemsDeleted": "已删除 {{count}} 个项目", + "itemsDeleted_other": "已删除 {{count}} 个项目", + "deleteFailed": "删除失败", + "permissionsUpdated": "权限已更新", + "noRemoteSessionConnected": "尚未连接远程会话", "failedToListFiles": "文件列表失败", - "failedToRefresh": "Failed to refresh", - "destinationInsideSource": "Destination cannot be inside the selected source path.", - "sameHostNoOp": "Source and destination are the same folder." + "failedToRefresh": "刷新失败", + "destinationInsideSource": "目标路径不能位于所选源路径内。", + "sameHostNoOp": "源路径与目标路径为同一文件夹。" }, "hosts": { "fileManager": "文件管理器", @@ -438,7 +447,7 @@ "loadingHost": "正在加载主机..." }, "onboarding": { - "feature_files": "File manager", + "feature_files": "文件管理器", "feature_files_desc": "无需离开应用,即可通过 SFTP 浏览、上传、下载及编辑文件。" }, "terminal": { @@ -464,7 +473,7 @@ "destinationPath": "目标路径", "destMustBeDirectory": "对于多项目传输,目标必须是一个目录", "goUp": "向上", - "hostAuthRequired": "Authentication required. Open File Manager on this host first", + "hostAuthRequired": "需要身份验证,请先在此主机上打开文件管理器", "hostConnecting": "连接中…", "hostConnectionFailed": "连接失败", "hostDisconnected": "未连接", @@ -485,12 +494,12 @@ "methodReason": { "user_item_sftp": "您选择了逐文件 SFTP。", "user_tar": "您选择了 Tar 归档。", - "tar_unavailable": "Tar is not available on one or both hosts, so per-file SFTP will be used instead.", - "windows_host": "A Windows host is involved, so tar is not used.", - "auto_multi_large": "Auto: multiple files including a large file ({{largestSize}}) with compressible data. Tar bundles them into one transfer.", - "auto_single_large_in_archive": "Auto: one large file ({{largestSize}}) in this set, so per-file SFTP.", - "auto_many_incompressible": "Auto: mostly incompressible data, so per-file SFTP.", - "auto_many_files": "Auto: many files ({{fileCount}}), tar cuts the per-file overhead.", + "tar_unavailable": "一台或两台主机未安装 tar,将改为逐文件使用 SFTP 传输。", + "windows_host": "传输涉及 Windows 主机,因此不使用 tar。", + "auto_multi_large": "自动选择:多个文件中包含可压缩的大文件({{largestSize}}),使用 tar 打包后统一传输。", + "auto_single_large_in_archive": "自动选择:文件集中包含一个大文件({{largestSize}}),采用逐文件 SFTP 传输。", + "auto_many_incompressible": "自动选择:数据大多不可压缩,采用逐文件 SFTP 传输。", + "auto_many_files": "自动选择:文件较多({{fileCount}} 个),使用 tar 减少逐文件传输开销。", "auto_default": "自动:此集合使用逐文件 SFTP。" }, "methodTar": "Tar 归档", @@ -498,11 +507,11 @@ "metricsCompress": "源端压缩:{{duration}}", "metricsExtract": "目标端解压:{{duration}}", "metricsPrepare": "准备目标:{{duration}}", - "metricsRouteBenchmark": "Route probe: direct {{direct}}, relay {{relay}}", + "metricsRouteBenchmark": "路径探测:直连 {{direct}},中转 {{relay}}", "metricsSourceDelete": "从源端删除:{{duration}}", "metricsTotal": "总计:{{duration}}", "metricsTransfer": "端到端:{{throughput}} ({{duration}})", - "metricsVerify": "SHA-256 verified: {{duration}}", + "metricsVerify": "SHA-256 校验通过:{{duration}}", "moveFolderToHost": "移动文件夹到主机…", "moveItemsToHost": "移动 {{count}} 个项目到主机…", "moveToHost": "移动到主机…", @@ -511,7 +520,7 @@ "parallelSegmentsHint": "大文件会被拆分为 256 MB 的块。多个通道使用独立连接(如同同时进行多个传输),以获得更高的总吞吐量。", "parallelSegmentsLabel": "并行传输通道", "parallelSegmentsOption": "{{count}} 个通道", - "progressBenchmarking": "Selecting the fastest transfer route…", + "progressBenchmarking": "正在选择最快的传输路径……", "progressBytes": "{{transferred}} / {{total}}", "progressCancel": "取消", "progressCancelling": "正在取消…", @@ -523,7 +532,7 @@ "progressTotalSpeed": "{{speed}} 总计({{lanes}} 通道)", "progressTransferring": "正在传输数据…", "progressTransferringItems": "正在传输文件({{current}}/{{total}})…", - "progressVerifying": "Verifying file integrity…", + "progressVerifying": "正在校验文件完整性……", "recentDestinations": "最近目标", "resumedHint": "已重新连接到在另一个窗口中启动的进行中的传输。", "retryTransfer": "重试", @@ -539,5 +548,8 @@ "metricsHopSourceRead": "源 → 服务器:{{throughput}}", "metricsHopDestSftpWrite": "服务器 → 目标 (SFTP):{{throughput}}", "metricsHopDestLocalWrite": "服务器 → 目标 (本地):{{throughput}}" + }, + "plugin": { + "name": "文件管理器" } } diff --git a/plugins/file-manager/src/frontend/components/FileViewer.tsx b/plugins/file-manager/src/frontend/components/FileViewer.tsx index edca6e27f..3d0d1e685 100644 --- a/plugins/file-manager/src/frontend/components/FileViewer.tsx +++ b/plugins/file-manager/src/frontend/components/FileViewer.tsx @@ -350,7 +350,9 @@ export function FileViewer({
-

Loading file...

+

+ {t("fileManager.loadingFile")} +

); @@ -446,7 +448,7 @@ export function FileViewer({ className="flex items-center gap-2" > - Revert + {t("fileManager.revert")} )} @@ -647,14 +649,12 @@ export function FileViewer({ {isTooLarge ? (

- File is too large (> 10MB) and cannot be opened as - text for security reasons. + {t("fileManager.fileTooLarge")}

) : (

- Do you want to continue opening this file as text? This - may slow down your browser. + {t("fileManager.confirmOpenAsText")}

)} @@ -669,7 +669,7 @@ export function FileViewer({ className="flex items-center gap-2" > - Open as Text + {t("fileManager.openAsText")} )} @@ -694,7 +694,9 @@ export function FileViewer({ )} {fileTypeInfo.type === "image" && !showLargeFileWarning && ( - }> + } + > {isEditable ? ( } + fallback={ + + } > + } > @@ -872,7 +880,11 @@ export function FileViewer({
} + fallback={ + + } > @@ -885,7 +897,7 @@ export function FileViewer({ {fileTypeInfo.type === "pdf" && !showLargeFileWarning && ( } + fallback={} > } + fallback={} > {file.path} {hasChanges && ( - ● Unsaved changes + ● {t("common.unsavedChanges")} )}
diff --git a/plugins/file-manager/src/frontend/components/ImagePreview.tsx b/plugins/file-manager/src/frontend/components/ImagePreview.tsx index 9ce597953..3d4f86915 100644 --- a/plugins/file-manager/src/frontend/components/ImagePreview.tsx +++ b/plugins/file-manager/src/frontend/components/ImagePreview.tsx @@ -103,7 +103,9 @@ export function ImagePreview({
-

Loading image...

+

+ {t("fileManager.loadingImage")} +

)} diff --git a/plugins/fleets/locales/translated/zh_CN.json b/plugins/fleets/locales/translated/zh_CN.json index 738686f00..83f335c69 100644 --- a/plugins/fleets/locales/translated/zh_CN.json +++ b/plugins/fleets/locales/translated/zh_CN.json @@ -1,77 +1,77 @@ { "permissions": { "view": { - "title": "View fleets", - "description": "See fleets, their members and inventory." + "title": "查看主机组", + "description": "查看主机组、成员及资产信息。" }, "manage": { - "title": "Manage fleets", - "description": "Create, edit and delete fleets, change membership, and share fleets with other users or roles." + "title": "管理主机组", + "description": "创建、编辑和删除主机组,调整成员,并与其他用户或角色共享主机组。" }, "execute": { - "title": "Run fleet actions", - "description": "Run commands and package actions across a fleet, and transfer files to and from its member hosts." + "title": "执行主机组操作", + "description": "在主机组内批量执行命令、软件包操作,以及与成员主机传输文件。" } }, "newUi": { "sidebar": { "fleets": { - "title": "Fleets", - "createFleet": "Create Fleet", - "createFleetTitle": "Create Fleet", - "editFleetTitle": "Edit Fleet", - "createFleetDescription": "舰队是一个命名的主机组,你可以将其作为一个整体来执行操作。", + "title": "主机组", + "createFleet": "创建主机组", + "createFleetTitle": "创建主机组", + "editFleetTitle": "编辑主机组", + "createFleetDescription": "主机组是一组已命名的主机,可作为整体执行操作。", "nameLabel": "名称", "namePlaceholder": "例如:Web 服务器", - "nameRequired": "需要填写舰队名称。", + "nameRequired": "需要填写主机组名称。", "descriptionLabel": "描述", "descriptionPlaceholder": "可选描述", "colorLabel": "颜色", - "tagRulesLabel": "Tag rules", + "tagRulesLabel": "标签规则", "tagRulesPlaceholder": "prod-web, edge", - "tagRulesHint": "Hosts with any of these tags are automatically included, in addition to hosts added manually.", - "fleetCreated": "舰队已创建", - "fleetUpdated": "舰队已更新", - "fleetDeleted": "Fleet deleted", - "saveFailed": "保存舰队失败", - "deleteFailed": "Failed to delete fleet", - "loadFailed": "Failed to load fleets", - "deleteFleetTitle": "Delete Fleet", - "deleteFleetDescription": "Are you sure you want to delete \"{{name}}\"? This does not delete the member hosts themselves.", - "searchFleets": "Search fleets...", - "noFleets": "No fleets yet. Create one to get started.", + "tagRulesHint": "除手动添加的主机外,具有任一指定标签的主机也会自动加入。", + "fleetCreated": "主机组已创建", + "fleetUpdated": "主机组已更新", + "fleetDeleted": "主机组已删除", + "saveFailed": "保存主机组失败", + "deleteFailed": "删除主机组失败", + "loadFailed": "加载主机组失败", + "deleteFleetTitle": "删除主机组", + "deleteFleetDescription": "确定删除“{{name}}”?此操作不会删除成员主机本身。", + "searchFleets": "搜索主机组……", + "noFleets": "暂无主机组,请创建一个以开始使用。", "memberCount": "{{count}} 台主机", "memberCount_other": "{{count}} 台主机", - "manageMembers": "Manage Members", - "manageMembersTitle": "管理舰队成员", - "manageMembersDescription": "Toggle hosts in or out of this fleet's static membership. Hosts matched by tag rules are always included.", + "manageMembers": "管理成员", + "manageMembersTitle": "管理主机组成员", + "manageMembersDescription": "将主机加入或移出此主机组的固定成员列表。匹配标签规则的主机始终包含在内。", "searchHosts": "搜索主机...", "noHostsFound": "未找到主机", - "noMembers": "This fleet has no members yet. Add hosts or set a tag rule.", - "membersLoadFailed": "Failed to load fleet members", - "memberUpdateFailed": "Failed to update fleet membership", - "tabRun": "Run Command", - "tabTransfer": "Transfer Files", + "noMembers": "此主机组暂无成员,请添加主机或设置标签规则。", + "membersLoadFailed": "加载主机组成员失败", + "memberUpdateFailed": "更新主机组成员失败", + "tabRun": "执行命令", + "tabTransfer": "传输文件", "tabInventory": "清单", - "openInventoryTab": "Open in full tab", + "openInventoryTab": "在完整标签页中打开", "tabPackages": "软件包", - "runOnFleet": "在舰队上运行", + "runOnFleet": "在主机组上运行", "commandPlaceholder": "uptime && df -h", - "commandRequired": "A command is required", - "commandInputsLabel": "Command inputs", - "commandSucceeded": "Command succeeded on all hosts", + "commandRequired": "必须填写命令", + "commandInputsLabel": "命令输入", + "commandSucceeded": "命令已在所有主机上执行成功", "commandPartialFailure": "{{total}} 台主机中有 {{failed}} 台失败", - "commandFailed": "Failed to run command", + "commandFailed": "执行命令失败", "resultSuccess": "成功", "resultFailed": "失败", "push": "推送", "pull": "拉取", - "remotePathLabel": "Remote path", - "remotePathRequired": "A remote path is required", + "remotePathLabel": "远程路径", + "remotePathRequired": "必须填写远程路径", "fileLabel": "文件", "fileRequired": "需要选择文件", - "pushHint": "选定的文件将被写入舰队中每台主机上的指定路径。", - "pullHint": "The file at this path is read from every host and downloaded as a single zip, one folder per host.", + "pushHint": "选定的文件将被写入主机组中每台主机上的指定路径。", + "pullHint": "从每台主机读取此路径下的文件,按主机分文件夹打包为一个 ZIP 文件下载。", "transferComplete": "传输完成", "transferFailed": "传输失败", "refreshInventory": "刷新清单", @@ -85,27 +85,27 @@ "inventoryKernel": "内核", "inventoryArch": "架构", "inventoryUptime": "运行时间", - "inventoryPackageManager": "Package manager", - "inventoryCollectedAt": "Collected", + "inventoryPackageManager": "软件包管理器", + "inventoryCollectedAt": "已收集", "packageActionLabel": "操作", - "packageInstall": "Install", + "packageInstall": "安装", "packageRemove": "移除", "packageUpgradeAll": "升级所有软件包", - "packageNameLabel": "Package name", - "packageNameRequired": "A package name is required", - "packageHint": "Requires manage-level access per host and elevates using the host's stored sudo password.", - "shareFleet": "Share Fleet", - "shareFleetTitle": "Share \"{{name}}\"", - "shareFleetDescription": "Shares this fleet's current member hosts with the selected users or roles. Hosts added to the fleet later are not shared automatically - share again to include them.", - "shareSelectionRequired": "Select at least one user or role", - "fleetSharedSuccessfully": "Shared {{shared}} of {{total}} host(s) in this fleet", - "failedToShareFleet": "Failed to share fleet", - "noMembersToShare": "This fleet has no member hosts to share yet." + "packageNameLabel": "软件包名称", + "packageNameRequired": "必须填写软件包名称", + "packageHint": "需要对每台主机具有管理级别权限,并使用主机保存的 sudo 密码提升权限。", + "shareFleet": "共享主机组", + "shareFleetTitle": "共享“{{name}}”", + "shareFleetDescription": "将此主机组当前的成员主机共享给所选用户或角色。后续加入的主机不会自动共享,需要再次执行共享操作。", + "shareSelectionRequired": "请至少选择一个用户或角色", + "fleetSharedSuccessfully": "已共享此主机组中的 {{shared}}/{{total}} 台主机", + "failedToShareFleet": "共享主机组失败", + "noMembersToShare": "此主机组尚无可共享的成员主机。" } } }, "nav": { - "fleets": "Fleets" + "fleets": "主机组" }, "hosts": { "docsLink": "查看文档", @@ -131,7 +131,7 @@ }, "edit": { "label": "编辑", - "description": "View, plus modify non-authentication host settings. The owner's SSH authentication stays private and owner-only." + "description": "允许查看和修改与身份验证无关的主机设置。所有者的 SSH 身份验证信息保持私密,仅供所有者使用。" }, "manage": { "label": "管理", diff --git a/plugins/homepage/locales/en.json b/plugins/homepage/locales/en.json index 760b3a445..9835baa55 100644 --- a/plugins/homepage/locales/en.json +++ b/plugins/homepage/locales/en.json @@ -169,7 +169,139 @@ "noServices": "No services set up", "configureLocation": "Set a location in the widget settings", "bannerTextPlaceholder": "Banner text", - "serviceNamePlaceholder": "My service" + "serviceNamePlaceholder": "My service", + "emptyNote": "Empty note...", + "weatherLoadFailed": "Could not load weather for \"{{location}}\"", + "feelsLike": "Feels like {{temperature}}", + "timezonePlaceholder": "America/New_York (leave blank for local)", + "notesPlaceholder": "Write your notes here...", + "locationPlaceholder": "New York, London, Tokyo...", + "widgets": { + "bookmark_list": { + "name": "Bookmarks", + "description": "A list of quick links" + }, + "calendar": { + "name": "Calendar", + "description": "A month calendar with today highlighted" + }, + "clock": { + "name": "Clock", + "description": "A live clock with configurable timezone" + }, + "countdown": { + "name": "Countdown", + "description": "Counts down to a target date and time" + }, + "custom_api": { + "name": "Custom API", + "description": "Fetch and display data from any JSON API" + }, + "dashboard_links": { + "name": "Dashboard Links", + "description": "Shows your saved dashboard service links" + }, + "folder": { + "name": "Folder", + "description": "A background card for grouping widgets visually" + }, + "host_grid": { + "name": "Host Grid", + "description": "Live status overview grid for all your SSH hosts" + }, + "host_status": { + "name": "Host Status", + "description": "Shows live status and metrics for an SSH host" + }, + "iframe_embed": { + "name": "iFrame Embed", + "description": "Embed any URL in an iframe" + }, + "image_widget": { + "name": "Image", + "description": "Display any image from a URL" + }, + "link_tree": { + "name": "Link Tree", + "description": "Grouped links organized into labeled sections" + }, + "markdown_notes": { + "name": "Markdown Notes", + "description": "Notes with optional Markdown rendering and inline editing" + }, + "notes": { + "name": "Notes", + "description": "A text notes widget" + }, + "ping_status": { + "name": "Ping Status", + "description": "Check if URLs or services are reachable" + }, + "quick_connect": { + "name": "Quick Connect", + "description": "Launch terminal, files, docker, tunnels, and more for your hosts" + }, + "recent_activity": { + "name": "Recent Activity", + "description": "Shows recent terminal, Docker, file, and tunnel activity" + }, + "rss_feed": { + "name": "RSS Feed", + "description": "Display items from an RSS or Atom feed" + }, + "search_bar": { + "name": "Search Bar", + "description": "Quick search with Google, DuckDuckGo, Bing, or a custom engine" + }, + "search_links": { + "name": "Search Shortcuts", + "description": "Quick buttons to search different engines" + }, + "service_grid": { + "name": "Service Grid", + "description": "A grid of service tiles with icons and links" + }, + "service_link": { + "name": "Service Link", + "description": "A clickable tile linking to a service URL" + }, + "ssh_terminal": { + "name": "SSH Terminal", + "description": "An inline SSH terminal connected to a configured host" + }, + "system_overview": { + "name": "System Overview", + "description": "Termix version, database health, and uptime at a glance" + }, + "termix_uptime": { + "name": "Termix Uptime", + "description": "Shows how long the Termix server has been running" + }, + "text_banner": { + "name": "Text Banner", + "description": "A styled text label for sections and headings" + }, + "weather": { + "name": "Weather", + "description": "Live weather for any location" + }, + "docker_widget": { + "name": "Docker Manager", + "description": "Embedded Docker container manager for a configured host" + }, + "file_manager_widget": { + "name": "File Manager", + "description": "Embedded SFTP file manager for a configured host" + }, + "tunnel_widget": { + "name": "Tunnel Manager", + "description": "Embedded SSH tunnel manager for a configured host" + }, + "metrics_chart": { + "name": "Metrics Chart", + "description": "Historical CPU, memory, disk, or network chart for a host" + } + } }, "permissions": { "use": { @@ -186,5 +318,8 @@ "label": "Private certificate authority (PEM)", "description": "Optional trusted CA bundle for allowlisted hosts. Certificate verification remains enabled. Leave empty to use the system trust store." } + }, + "plugin": { + "name": "Homepage" } } diff --git a/plugins/homepage/locales/translated/zh_CN.json b/plugins/homepage/locales/translated/zh_CN.json index 749418b96..509e59a17 100644 --- a/plugins/homepage/locales/translated/zh_CN.json +++ b/plugins/homepage/locales/translated/zh_CN.json @@ -18,7 +18,7 @@ "homepage": { "title": "主页", "addWidget": "添加小部件", - "noWidgetsInCategory": "No widgets in this category", + "noWidgetsInCategory": "此分类没有组件", "editWidget": "编辑小部件", "zoomIn": "放大", "zoomOut": "缩小", @@ -39,7 +39,7 @@ "description": "描述", "color": "颜色", "timezone": "时区", - "invalidTimezone": "Invalid timezone. Use an IANA name such as America/New_York", + "invalidTimezone": "时区无效,请使用 America/New_York 等 IANA 时区名称", "showSeconds": "显示秒", "format12h": "12 小时制", "content": "内容", @@ -60,9 +60,9 @@ "maxItems": "最大条目数", "showDescription": "显示描述", "widgetRssName": "RSS 订阅源", - "rssNoFeedUrl": "Configure a feed URL in widget settings", - "rssLoadError": "Could not load feed", - "rssNoItems": "No items", + "rssNoFeedUrl": "请在组件设置中配置订阅源 URL", + "rssLoadError": "无法加载订阅源", + "rssNoItems": "暂无项目", "noHostSelected": "未选择主机", "displayedMetrics": "显示指标", "metricCpu": "CPU", @@ -162,29 +162,164 @@ "selectHosts": "选择主机", "listLayout": "列表", "gridLayout": "网格", - "configureUrl": "Set a URL in the widget settings", - "embeddedContent": "Embedded content", - "noBookmarks": "No bookmarks", - "noSections": "No sections set up", - "noServices": "No services set up", - "configureLocation": "Set a location in the widget settings", - "bannerTextPlaceholder": "Banner text", - "serviceNamePlaceholder": "My service" + "configureUrl": "请在组件设置中填写 URL", + "embeddedContent": "嵌入内容", + "noBookmarks": "暂无书签", + "noSections": "尚未设置分区", + "noServices": "尚未设置服务", + "configureLocation": "请在组件设置中选择位置", + "bannerTextPlaceholder": "横幅文字", + "serviceNamePlaceholder": "我的服务", + "emptyNote": "暂无笔记内容……", + "weatherLoadFailed": "无法加载“{{location}}”的天气", + "feelsLike": "体感温度 {{temperature}}", + "timezonePlaceholder": "Asia/Shanghai(留空使用本地时区)", + "notesPlaceholder": "在此填写笔记……", + "locationPlaceholder": "北京、上海、东京……", + "widgets": { + "bookmark_list": { + "name": "书签", + "description": "显示快捷链接列表" + }, + "calendar": { + "name": "日历", + "description": "显示月历并突出显示今天" + }, + "clock": { + "name": "时钟", + "description": "显示实时时钟,可配置时区" + }, + "countdown": { + "name": "倒计时", + "description": "距离目标日期和时间的倒计时" + }, + "custom_api": { + "name": "自定义 API", + "description": "获取并展示 JSON API 数据" + }, + "dashboard_links": { + "name": "仪表盘链接", + "description": "显示已保存的仪表盘服务链接" + }, + "folder": { + "name": "文件夹", + "description": "用于对组件进行视觉分组的背景卡片" + }, + "host_grid": { + "name": "主机网格", + "description": "以网格展示所有 SSH 主机的实时状态" + }, + "host_status": { + "name": "主机状态", + "description": "显示 SSH 主机的实时状态和指标" + }, + "iframe_embed": { + "name": "嵌入网页", + "description": "通过 iframe 嵌入指定 URL" + }, + "image_widget": { + "name": "图片", + "description": "显示指定 URL 的图片" + }, + "link_tree": { + "name": "链接树", + "description": "按分组展示链接与服务入口" + }, + "markdown_notes": { + "name": "Markdown 笔记", + "description": "支持 Markdown 渲染和行内编辑的笔记" + }, + "notes": { + "name": "笔记", + "description": "显示文本笔记" + }, + "ping_status": { + "name": "连通性状态", + "description": "检查 URL 或服务是否可访问" + }, + "quick_connect": { + "name": "快速连接", + "description": "为主机打开终端、文件、Docker、隧道等功能" + }, + "recent_activity": { + "name": "最近活动", + "description": "显示最近的终端、Docker、文件和隧道活动" + }, + "rss_feed": { + "name": "RSS 订阅源", + "description": "显示 RSS 或 Atom 订阅源的内容" + }, + "search_bar": { + "name": "搜索栏", + "description": "快速使用 Google、DuckDuckGo、Bing 或自定义搜索引擎" + }, + "search_links": { + "name": "搜索快捷方式", + "description": "快速使用不同搜索引擎" + }, + "service_grid": { + "name": "服务网格", + "description": "以包含图标和链接的网格展示服务" + }, + "service_link": { + "name": "服务链接", + "description": "点击卡片即可打开服务 URL" + }, + "ssh_terminal": { + "name": "SSH 终端", + "description": "连接到指定主机的内嵌 SSH 终端" + }, + "system_overview": { + "name": "系统概览", + "description": "显示 Termix 系统状态概览" + }, + "termix_uptime": { + "name": "Termix 运行时间", + "description": "显示 Termix 服务器已运行的时长" + }, + "text_banner": { + "name": "文字横幅", + "description": "用于分区和标题的样式化文字标签" + }, + "weather": { + "name": "天气", + "description": "显示指定地点的实时天气" + }, + "docker_widget": { + "name": "Docker 管理器", + "description": "用于管理指定主机 Docker 容器的内嵌管理器" + }, + "file_manager_widget": { + "name": "文件管理器", + "description": "用于管理指定主机文件的内嵌 SFTP 管理器" + }, + "tunnel_widget": { + "name": "隧道管理器", + "description": "用于管理指定主机 SSH 隧道的内嵌管理器" + }, + "metrics_chart": { + "name": "指标图表", + "description": "显示主机 CPU、内存、磁盘或网络的历史指标图表" + } + } }, "permissions": { "use": { - "title": "Use the homepage", - "description": "View and edit the homepage canvas and dashboard service links." + "title": "使用首页", + "description": "查看和编辑首页画布及仪表盘服务链接。" } }, "settings": { "privateEndpoints": { - "label": "Allowed private hosts", - "description": "Exact private or loopback hostnames/IPs for Ping Status and Custom API widgets. Separate entries with commas or newlines; omit schemes, ports and paths. Empty blocks private destinations." + "label": "允许访问的内网主机", + "description": "供连通性状态和自定义 API 组件使用的精确内网或回环主机名/IP。用逗号或换行分隔,不包含协议、端口和路径。留空会阻止访问内网目标。" }, "privateCertificateAuthority": { - "label": "Private certificate authority (PEM)", - "description": "Optional trusted CA bundle for allowlisted hosts. Certificate verification remains enabled. Leave empty to use the system trust store." + "label": "私有证书颁发机构(PEM)", + "description": "可选的受信任 CA 证书包,用于允许列表中的主机。证书验证保持开启,留空则使用系统信任库。" } + }, + "plugin": { + "name": "首页" } } diff --git a/plugins/homepage/src/frontend/dialogs/AddWidgetMenu.tsx b/plugins/homepage/src/frontend/dialogs/AddWidgetMenu.tsx index 53e1d8773..8a3763674 100644 --- a/plugins/homepage/src/frontend/dialogs/AddWidgetMenu.tsx +++ b/plugins/homepage/src/frontend/dialogs/AddWidgetMenu.tsx @@ -140,14 +140,18 @@ export function AddWidgetMenu({ state, onAdd, onClose }: AddWidgetMenuProps) { {type.labelComponent ? ( ) : ( - type.name + t(`homepage.widgets.${type.id}.name`, { + defaultValue: type.name, + }) )} {type.labelComponent ? ( ) : ( - type.description + t(`homepage.widgets.${type.id}.description`, { + defaultValue: type.description, + }) )}
diff --git a/plugins/homepage/src/frontend/dialogs/ClockEditForm.tsx b/plugins/homepage/src/frontend/dialogs/ClockEditForm.tsx index 7a1833739..5d306fb47 100644 --- a/plugins/homepage/src/frontend/dialogs/ClockEditForm.tsx +++ b/plugins/homepage/src/frontend/dialogs/ClockEditForm.tsx @@ -23,7 +23,7 @@ export function ClockEditForm({ onChange={(e) => onChange({ ...config, timezone: e.target.value || undefined }) } - placeholder="America/New_York (leave blank for local)" + placeholder={t("homepage.timezonePlaceholder")} aria-invalid={invalidTimezone} className={ invalidTimezone ? "h-8 text-sm border-destructive" : "h-8 text-sm" diff --git a/plugins/homepage/src/frontend/dialogs/NotesEditForm.tsx b/plugins/homepage/src/frontend/dialogs/NotesEditForm.tsx index c75e3b476..61195b04a 100644 --- a/plugins/homepage/src/frontend/dialogs/NotesEditForm.tsx +++ b/plugins/homepage/src/frontend/dialogs/NotesEditForm.tsx @@ -16,7 +16,7 @@ export function NotesEditForm({