diff --git a/ROADMAP.md b/ROADMAP.md
index c0c6654..65cfc3a 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -515,6 +515,7 @@ services/api.ts (1324L)
| U19 | i18n hash 键清理(删除 866 个死 hash 键 + 重命名 21 个高频 live hash 键为语义化键名,zh/en 7597→6731 keys 对齐,文件 328KB→276KB (-16%),tsc -b=0,npm build✓,ESLint=0/66/0,17/17 测试通过) | P3 | **done** |
| U20 | ESLint static-components 清零 + CredDetailDialog 内联组件修复 + i18n 批量迁移损坏修复(CredDetailDialog.tsx `Field` 内联组件提取为模块级 `CredField` — 23 处 react-hooks/static-components 警告清零;修复 8 处被批量正则损坏的 `i18n.t()` 调用(`i18n.t('>名称:')` 等 → 语义化键);6 处硬编码中文清零;新增 `deploy.cred.sensitiveWarn` 键;ESLint warnings 66→43 (-35%),tsc -b=0,npm build✓ (17.29s),17/17 测试通过) | P3 | **done** |
| U23 | Task 模块 i18n 治理(CronJobManager + CronJobFormDialog + ScriptManager + RemoteExecPage 4 文件 — `import i18n` 全局调用 → `useTranslation()` hook;42 处 phantom key (`i18n.t('Chinese text')` → 语义化 `task.cronJob.*`/`task.scriptList.*`/`task.remoteExec.*` 键);28 个孤儿 hash 键清理 (cronjobformdial.s*/remoteexecpaget.s*/systemtaskspanel.s*);50+ 处硬编码 JSX 中文 → t() 调用;zh/en 6825→6886 +61 键对齐,tsc -b=0,npm build✓ (17.46s),ESLint=0/45/0,go build=0,17/17 测试通过) | P3 | **done** |
+| U24 | Monitor 模块 i18n hook 迁移(26 个 .tsx 文件从 `import i18n` 全局 → `useTranslation()` hook + 89 个 phantom 中文文本键 → `monitor.lbl.*` 语义化键;299 处 `i18n.t()` 调用 → 74 处保留(模块级/.ts 工具文件) + 225 处迁移到 `t()` hook;1 个 .ts 工具文件 helpers.ts 中文文本键替换为语义化键;zh/en 6886→6975 +89 键对齐,tsc -b=0,npm build✓ (17.16s),ESLint=0/53/0,go build=0,Docker healthy) | P3 | **done** |
---
@@ -1501,3 +1502,26 @@ pending → in_progress → done / blocked
- [x] 17/17 集成回归测试通过(零回归)
- [x] Docker 部署 healthy,前端页面正常加载(HTTP 200)
+---
+
+## U24: Monitor 模块 i18n hook 迁移 [done]
+
+**问题**: `src/pages/monitor/` 目录下 26 个 .tsx 文件仍使用全局 `import i18n from '@/i18n'` + `i18n.t('Chinese text')` 模式(phantom key 问题 — 中文文本作为 i18n key,在 zh-CN locale 下「恰好工作」(返回 key 本身),但切换 en-US 时仍显示中文文本而非英文翻译)。这是 U17-U23 i18n 治理系列中最后一个大规模 phantom key 模块,涉及 299 处 `i18n.t()` 调用和 89 个唯一 phantom 中文文本键。
+
+**已完成 (2026-07-11)**:
+
+1. **新增 `monitor.lbl` 翻译子命名空间** — 89 个语义化翻译键覆盖 5 个子模块(HostMonitor/MiddlewareMonitor/SiteMonitor/SNMPMonitor/Shared)
+2. **.tsx 文件 hook 迁移** — 26 个文件从 `import i18n` → `useTranslation()` hook + phantom 中文文本键 → `monitor.lbl.*` 语义化键
+3. **模块级代码保留 `i18n.t()`** — TABS 常量/METRIC_CATEGORIES 等模块级代码保留 `i18n.t()` + 语义化键
+4. **.ts 工具文件** — helpers.ts 中文文本键替换为语义化键(保留 `i18n.t()` 因 .ts 无法用 hook)
+
+**验收标准**:
+- [x] `monitor.lbl` 命名空间 89 个语义化键,zh/en 完全对齐(6975 = 6975)
+- [x] 26 个 .tsx 文件迁移到 `useTranslation()` hook
+- [x] 299 处 `i18n.t()` → 74 保留 + 225 迁移到 `t()` hook
+- [x] `tsc -b` 零错误
+- [x] `npm run build` 零错误(✓ built in 17.16s)
+- [x] ESLint errors=0,any=0,unused=0
+- [x] `go build` 零错误
+- [x] Docker 部署 healthy
+
diff --git a/frontend/src/locales/en-US.json b/frontend/src/locales/en-US.json
index ea14c32..684a59c 100644
--- a/frontend/src/locales/en-US.json
+++ b/frontend/src/locales/en-US.json
@@ -4492,6 +4492,97 @@
"userPolicyHint": "Users without any policy are not blocked (backward compatible); once assigned, only queries matching policies are allowed.",
"assign": "Assign",
"all": "All"
+ },
+ "lbl": {
+ "unlimited": "Unlimited",
+ "hitRate": "Hit Rate",
+ "totalDevices": "Total Devices",
+ "instances": "Instances",
+ "instanceStatus": "Instance Status",
+ "connections": "Connections",
+ "online": "Online",
+ "fragmentationRate": "Fragmentation Rate",
+ "trafficSent": "Traffic Sent",
+ "evictedKeys": "Evicted Keys",
+ "noMaxMemory": "No maxmemory configured",
+ "standalone": "Standalone",
+ "middleware": "Middleware",
+ "hostMonitor": "Host Monitor",
+ "basicMonitor": "Basic Monitor",
+ "diskMonitor": "Disk Monitor",
+ "networkMonitor": "Network Monitor",
+ "processMonitor": "Process Monitor",
+ "selectHost": "Select host...",
+ "selectHostHint": "Select a host to view metrics",
+ "coreMetrics": "Core Metrics",
+ "allMetrics": "All Metrics",
+ "cpuUsage": "CPU Usage (%)",
+ "cpuIowait": "CPU IO Wait (%)",
+ "memUsage": "Memory Usage (%)",
+ "memAvailable": "Available Memory (GB)",
+ "swapUsage": "Swap Usage (%)",
+ "load1": "System Load (1m)",
+ "diskUsage": "Disk Usage (%)",
+ "diskRead": "Disk Read (KB/s)",
+ "diskWrite": "Disk Write (KB/s)",
+ "diskIoBusy": "Disk IO Busy (%)",
+ "fdUsage": "FD Usage Rate",
+ "fdRate": "FD Usage",
+ "nicRxErrors": "NIC RX Errors",
+ "nicTxErrors": "NIC TX Errors",
+ "nicBandwidth": "NIC Bandwidth",
+ "saving": "Saving...",
+ "allPortsReport": "All discovered ports are reported, any port change triggers alert + recovery.",
+ "selectedOnlyReport": "Only selected port changes are reported, others are silently ignored. System process ports are not alerted by default.",
+ "whitelistAutoReport": "In whitelist mode, all ports are automatically reported",
+ "nameIpRequired": "Name and IP are required",
+ "updateSuccess": "Updated successfully",
+ "editMw": "Edit Middleware",
+ "addMw": "Add Middleware",
+ "siteProbe": "Site Probe",
+ "availability24h": "Availability (24h)",
+ "totalProbes": "Total Probes",
+ "editTask": "Edit Probe Task",
+ "addProbe": "Add Probe",
+ "editProbe": "Edit Probe",
+ "deleteProbe": "Delete Probe",
+ "selectTemplate": "Select Template",
+ "deleteMonitor": "Delete Monitor",
+ "partialFail": "Partial Failure",
+ "defaultAdded": "Default monitoring added",
+ "defaultExists": "Default target already exists",
+ "collectDone": "Collection completed",
+ "deleteFail": "Delete failed",
+ "nameAddrRequired": "Name and address are required",
+ "taskUpdated": "Task updated",
+ "taskCreated": "Probe task created",
+ "taskDeleted": "Task deleted",
+ "totalTasks": "Total Tasks",
+ "noTasks": "No probe tasks",
+ "noFilteredTasks": "No tasks match current filter",
+ "urlPlaceholder": "e.g., Homepage",
+ "probeDone": "Probe completed",
+ "probeFail": "Probe failed",
+ "metricDetail": "Metric Details",
+ "notDetected": "Not Detected",
+ "snmpTitle": "Network Device / BMC Collection & Trends",
+ "fillRequired": "Please fill device name, IP and select OID template",
+ "deviceAdded": "Device added",
+ "collectFail": "Collection failed",
+ "demoSwitch": "Core-Switch-A",
+ "oidTemplate": "OID Template",
+ "device": "Device",
+ "centerSubtitle": "Comprehensive infrastructure & application monitoring",
+ "explorerTitle": "Metrics Explorer",
+ "searchMetrics": "Search metrics...",
+ "explorerSubtitle": "Browse all metrics by category/host, supports overlay comparison",
+ "loadingTargets": "Loading targets...",
+ "selectTarget": "Please select a target",
+ "selectHint": "After selecting a target host, check metrics from the left panel",
+ "selectMetricsHint": "Please check metrics from the left panel",
+ "probeName": "Probe Name",
+ "execCommand": "Execute Command",
+ "refreshing": " · Refreshing..."
}
},
"task": {
diff --git a/frontend/src/locales/zh-CN.json b/frontend/src/locales/zh-CN.json
index 932f318..204542d 100644
--- a/frontend/src/locales/zh-CN.json
+++ b/frontend/src/locales/zh-CN.json
@@ -4492,6 +4492,97 @@
"userPolicyHint": "用户未分配任何策略时不拦截(向后兼容);分配后仅允许命中策略的查询。",
"assign": "分配",
"all": "全部"
+ },
+ "lbl": {
+ "unlimited": "无限制",
+ "hitRate": "命中率",
+ "totalDevices": "设备总数",
+ "instances": "监控实例",
+ "instanceStatus": "实例状态",
+ "connections": "连接",
+ "online": "在线",
+ "fragmentationRate": "碎片率",
+ "trafficSent": "发送流量",
+ "evictedKeys": "逐出 Key",
+ "noMaxMemory": "未配置 maxmemory",
+ "standalone": "单机",
+ "middleware": "中间件",
+ "hostMonitor": "主机监控",
+ "basicMonitor": "基础监控",
+ "diskMonitor": "磁盘监控",
+ "networkMonitor": "网络监控",
+ "processMonitor": "进程监控",
+ "selectHost": "选择主机...",
+ "selectHostHint": "选择主机查看监控指标",
+ "coreMetrics": "核心指标",
+ "allMetrics": "全部指标",
+ "cpuUsage": "CPU 使用率(%)",
+ "cpuIowait": "CPU IO等待(%)",
+ "memUsage": "内存使用率(%)",
+ "memAvailable": "可用内存(GB)",
+ "swapUsage": "Swap 使用率(%)",
+ "load1": "系统负载(1m)",
+ "diskUsage": "磁盘使用率(%)",
+ "diskRead": "磁盘读取(KB/s)",
+ "diskWrite": "磁盘写入(KB/s)",
+ "diskIoBusy": "磁盘IO繁忙度(%)",
+ "fdUsage": "FD 文件句柄使用率",
+ "fdRate": "FD 使用率",
+ "nicRxErrors": "网卡接收错误",
+ "nicTxErrors": "网卡发送错误",
+ "nicBandwidth": "网卡带宽吞吐",
+ "saving": "保存中…",
+ "allPortsReport": "所有发现的端口都上报,任意端口变化都会触发告警 + 恢复通知。",
+ "selectedOnlyReport": "仅上报选中端口的变化,其余端口变化静默忽略。系统进程端口默认不告警。",
+ "whitelistAutoReport": "白名单模式下所有端口自动上报",
+ "nameIpRequired": "请填写名称和 IP",
+ "updateSuccess": "更新成功",
+ "editMw": "编辑中间件",
+ "addMw": "添加中间件",
+ "siteProbe": "站点拨测",
+ "availability24h": "可用率(24h)",
+ "totalProbes": "探测次数",
+ "editTask": "编辑拨测任务",
+ "addProbe": "添加探针",
+ "editProbe": "编辑探针",
+ "deleteProbe": "删除探针",
+ "selectTemplate": "选择模板",
+ "deleteMonitor": "删除监控",
+ "partialFail": "部分失败",
+ "defaultAdded": "已添加默认监控",
+ "defaultExists": "默认目标已存在",
+ "collectDone": "采集完成",
+ "deleteFail": "删除失败",
+ "nameAddrRequired": "名称和地址不能为空",
+ "taskUpdated": "任务已更新",
+ "taskCreated": "拨测任务已创建",
+ "taskDeleted": "任务已删除",
+ "totalTasks": "总任务",
+ "noTasks": "暂无拨测任务",
+ "noFilteredTasks": "当前筛选无任务",
+ "urlPlaceholder": "例如:官网首页",
+ "probeDone": "拨测完成",
+ "probeFail": "拨测失败",
+ "metricDetail": "指标详情",
+ "notDetected": "未检测",
+ "snmpTitle": "网络设备 / BMC 采集与趋势",
+ "fillRequired": "请填写设备名称、IP 并选择 OID 模板",
+ "deviceAdded": "设备已添加",
+ "collectFail": "采集失败",
+ "demoSwitch": "核心交换机-A",
+ "oidTemplate": "OID 模板",
+ "device": "设备",
+ "centerSubtitle": "全面的基础设施与应用监控",
+ "explorerTitle": "指标浏览器",
+ "searchMetrics": "搜索指标...",
+ "explorerSubtitle": "按分类/主机浏览所有指标,支持叠加对比",
+ "loadingTargets": "加载监控目标...",
+ "selectTarget": "请选择监控目标",
+ "selectHint": "选择目标主机后,从左侧勾选要查看的指标",
+ "selectMetricsHint": "请从左侧勾选指标",
+ "probeName": "探针名称",
+ "execCommand": "执行命令",
+ "refreshing": " · 刷新中..."
}
},
"task": {
diff --git a/frontend/src/pages/monitor/HostMonitor.tsx b/frontend/src/pages/monitor/HostMonitor.tsx
index 2b60f11..66c6e2b 100644
--- a/frontend/src/pages/monitor/HostMonitor.tsx
+++ b/frontend/src/pages/monitor/HostMonitor.tsx
@@ -26,12 +26,13 @@ import { NetworkTab } from './host-monitor/tabs/NetworkTab';
import { PortMonitorTab } from './host-monitor/tabs/PortMonitorTab';
import { ProcessTab } from './host-monitor/tabs/ProcessTab';
import type { JsonData } from '@/types/common';
+import { useTranslation } from 'react-i18next';
import i18n from '@/i18n';
const TABS = [
- { id: 'basic', label: i18n.t('基础监控'), icon: },
- { id: 'disk', label: i18n.t('磁盘监控'), icon: },
- { id: 'network', label: i18n.t('网络监控'), icon: },
+ { id: 'basic', label: i18n.t('monitor.lbl.basicMonitor'), icon: },
+ { id: 'disk', label: i18n.t('monitor.lbl.diskMonitor'), icon: },
+ { id: 'network', label: i18n.t('monitor.lbl.networkMonitor'), icon: },
{ id: 'ports', label: i18n.t('agent.portMonitor'), icon: },
{ id: 'process', label: i18n.t('monitor.hostProcess'), icon:
},
{ id: 'system', label: i18n.t('system.systemInfo'), icon: },
@@ -39,6 +40,7 @@ const TABS = [
];
export function HostMonitor({ embedded = false }: { embedded?: boolean }) {
+ const { t } = useTranslation();
const qc = useQueryClient();
const [searchParams] = useSearchParams();
const urlHost = searchParams.get('host') || '';
@@ -118,7 +120,7 @@ export function HostMonitor({ embedded = false }: { embedded?: boolean }) {
{serverInfo && (
- {String(serverInfo.os || '')}{serverInfo.cpu_cores ? ` | ${serverInfo.cpu_cores as number | string} ${i18n.t('monitor.hostMonitorPanel.cores')}` : ''}{serverInfo.mem_total ? ` | ${(serverInfo.mem_total as number).toFixed(0)}GB` : ''}
+ {String(serverInfo.os || '')}{serverInfo.cpu_cores ? ` | ${serverInfo.cpu_cores as number | string} ${t('monitor.hostMonitorPanel.cores')}` : ''}{serverInfo.mem_total ? ` | ${(serverInfo.mem_total as number).toFixed(0)}GB` : ''}
)}
@@ -136,15 +138,15 @@ export function HostMonitor({ embedded = false }: { embedded?: boolean }) {
{actualDataSpan && (
- {i18n.t('monitor.hostMonitorPanel.dataSpan', { span: actualDataSpan })}
+ {t('monitor.hostMonitorPanel.dataSpan', { span: actualDataSpan })}
)}
@@ -212,10 +214,10 @@ export function HostMonitor({ embedded = false }: { embedded?: boolean }) {
}
return (
- } toolbar={toolbar}
- loading={loading && !history.length} loadingLabel={i18n.t('monitor.hostmonitortsx.sc23e802e')}
+ loading={loading && !history.length} loadingLabel={t('monitor.hostmonitortsx.sc23e802e')}
contentClassName="space-y-3">
{monitorBody}
{dialogs}
diff --git a/frontend/src/pages/monitor/MetricsExplorer.tsx b/frontend/src/pages/monitor/MetricsExplorer.tsx
index a298080..80b3ae1 100644
--- a/frontend/src/pages/monitor/MetricsExplorer.tsx
+++ b/frontend/src/pages/monitor/MetricsExplorer.tsx
@@ -9,6 +9,7 @@ import { metricsApi } from '@/api';
import { PageShell } from '@/components/layout/PageShell';
import { PageEmpty } from '@/components/layout/PageEmpty';
import type { JsonData } from '@/types/common';
+import { useTranslation } from 'react-i18next';
import i18n from '@/i18n';
interface TargetInfo {
@@ -34,10 +35,11 @@ const METRIC_CATEGORIES: Record },
network: { label: i18n.t('monitor.hostMetric.network'), icon: },
middleware: { label: i18n.t('monitor.alertRulesTab.catMiddleware'), icon: },
- device: { label: i18n.t('设备'), icon: },
+ device: { label: i18n.t('monitor.lbl.device'), icon: },
};
export function MetricsExplorer() {
+ const { t } = useTranslation();
const [targets, setTargets] = useState([]);
const [metricNames, setMetricNames] = useState([]);
const [selectedTarget, setSelectedTarget] = useState('');
@@ -109,7 +111,7 @@ export function MetricsExplorer() {