mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 23:25:24 +00:00
fix(i18n): complete Simplified Chinese core and plugin translations (#1542)
* fix(i18n): complete Chinese onboarding and navigation labels * fix(i18n): translate remaining Chinese core and plugin interfaces * fix(i18n): translate host editor tab overflow controls * fix(i18n): use consistent Chinese fleet terminology * fix(i18n): localize hardcoded controls and plugin views * fix(i18n): translate built-in homepage widget catalog * test(homepage): follow translated timezone placeholder * fix(i18n): translate plugin-provided homepage widgets * fix(i18n): localize feature settings section titles
This commit is contained in:
1 parent
13f5736d8f
commit
0214a81e5d
78 files changed
+2423
-1833
No files matched your search
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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": "首页"
|
||||
}
|
||||
}
|
||||
@@ -140,14 +140,18 @@ export function AddWidgetMenu({ state, onAdd, onClose }: AddWidgetMenuProps) {
|
||||
{type.labelComponent ? (
|
||||
<type.labelComponent part="name" />
|
||||
) : (
|
||||
type.name
|
||||
t(`homepage.widgets.${type.id}.name`, {
|
||||
defaultValue: type.name,
|
||||
})
|
||||
)}
|
||||
</span>
|
||||
<span className="text-[10px] text-muted-foreground truncate">
|
||||
{type.labelComponent ? (
|
||||
<type.labelComponent part="description" />
|
||||
) : (
|
||||
type.description
|
||||
t(`homepage.widgets.${type.id}.description`, {
|
||||
defaultValue: type.description,
|
||||
})
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -16,7 +16,7 @@ export function NotesEditForm({
|
||||
<Textarea
|
||||
value={config.content}
|
||||
onChange={(e) => onChange({ ...config, content: e.target.value })}
|
||||
placeholder="Write your notes here..."
|
||||
placeholder={t("homepage.notesPlaceholder")}
|
||||
className="text-sm min-h-[120px] resize-none rounded-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@ export function WeatherEditForm({
|
||||
<Input
|
||||
value={config.location}
|
||||
onChange={(e) => onChange({ ...config, location: e.target.value })}
|
||||
placeholder="New York, London, Tokyo..."
|
||||
placeholder={t("homepage.locationPlaceholder")}
|
||||
className="h-8 text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useTranslation } from "@termix/plugin-sdk/frontend";
|
||||
import { StickyNote } from "lucide-react";
|
||||
import { registerWidget } from "./WidgetRegistry";
|
||||
import {
|
||||
@@ -8,6 +9,7 @@ import {
|
||||
import { WidgetTitle } from "@termix/plugin-sdk/ui";
|
||||
|
||||
function NotesWidget({ widget, config }: WidgetComponentProps<NotesConfig>) {
|
||||
const { t } = useTranslation();
|
||||
const { content, backgroundColor } = config;
|
||||
|
||||
return (
|
||||
@@ -19,7 +21,9 @@ function NotesWidget({ widget, config }: WidgetComponentProps<NotesConfig>) {
|
||||
<div className="flex-1 overflow-auto p-3">
|
||||
<pre className="text-xs text-foreground whitespace-pre-wrap break-words font-sans leading-relaxed select-text w-full">
|
||||
{content || (
|
||||
<span className="text-muted-foreground italic">Empty note...</span>
|
||||
<span className="text-muted-foreground italic">
|
||||
{t("homepage.emptyNote")}
|
||||
</span>
|
||||
)}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
@@ -100,7 +100,7 @@ function WeatherWidget({
|
||||
if (error) {
|
||||
return (
|
||||
<div className="flex items-center justify-center w-full h-full text-xs text-destructive/70 p-3 text-center">
|
||||
Could not load weather for "{location}"
|
||||
{t("homepage.weatherLoadFailed", { location })}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -108,7 +108,7 @@ function WeatherWidget({
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="flex items-center justify-center w-full h-full text-xs text-muted-foreground/50">
|
||||
Loading...
|
||||
{t("common.loading")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -138,7 +138,7 @@ function WeatherWidget({
|
||||
{desc}
|
||||
</span>
|
||||
<span className="text-[10px] text-muted-foreground/70">
|
||||
Feels like {displayFeels}
|
||||
{t("homepage.feelsLike", { temperature: displayFeels })}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -45,7 +45,9 @@ function renderForm(config: Partial<ClockConfig> = {}) {
|
||||
);
|
||||
return {
|
||||
onChange,
|
||||
input: screen.getByPlaceholderText(/America\/New_York/) as HTMLInputElement,
|
||||
input: screen.getByPlaceholderText(
|
||||
"homepage.timezonePlaceholder",
|
||||
) as HTMLInputElement,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,9 @@ function open(timezone?: string) {
|
||||
return {
|
||||
onSave,
|
||||
onClose,
|
||||
input: screen.getByPlaceholderText(/America\/New_York/) as HTMLInputElement,
|
||||
input: screen.getByPlaceholderText(
|
||||
"homepage.timezonePlaceholder",
|
||||
) as HTMLInputElement,
|
||||
save: screen
|
||||
.getByText("homepage.save")
|
||||
.closest("button") as HTMLButtonElement,
|
||||
|
||||
Reference in new issue
Block a user