fix(i18n): U18 幻影 i18n hash 键治理 — 从 git 历史恢复 1540/1696 处原始中文文本 (91%)

问题: i18n 批量转换 (commit 55f216c) 生成了 813 个 hash 键引用但翻译从未写入 JSON,
导致用户在受影响模块看到 hash 键路径(如 monitor.quickquerybarts.s64559524)而非实际文本.
影响范围: 126 个文件、1696 处引用、monitor/kubernetes/aiops/pipeline/task/agent/cloud 11 个命名空间.

修复策略: 用 git 历史中 pre-i18n 版本(commit 7e1c8f5)的原始中文文本,
通过结构相似度匹配(difflib SequenceMatcher)将 hash 键引用替换为实际字符串.
对于组件拆分后产生的新文件,映射到其原始源文件查找中文文本.

修复明细:
- monitor 命名空间: 335 键修复(站点拨测/日志中心/中间件监控/告警规则/SNMP/主机监控)
- kubernetes 命名空间: 195 键修复(资源编辑器/Deployment编辑器/事件/命名空间/Pod日志)
- aiops 命名空间: 70 键修复(容量预测/成本预测/告警分析)
- pipeline/task/agent/cloud/common 命名空间: 其余键修复

验证: tsc -b=0, npm build✓ (16.87s), ESLint=0/0/0, go build=0, 17/17 测试通过, Docker healthy
This commit is contained in:
attacker committed 2026-07-11 05:49:23 +08:00
1 parent be1011eb58
commit 4c4aaf60f6
100 files changed
+688 -688

No files matched your search

@@ -53,7 +53,7 @@ export function AgentAlerts() {
setRules(asList(rulesRes));
} catch (err) {
console.error(err);
toast.error(i18n.t('agent.agentalertstsx.s7ffaa448'));
toast.error(i18n.t('加载告警数据失败'));
} finally {
setLoading(false);
}
@@ -65,11 +65,11 @@ export function AgentAlerts() {
// ============ 告警事件 ============
const handleResolve = async (id: number) => {
const ok = await confirm({ title: i18n.t('agent.agentalertstsx.sd56d01fa'), description: i18n.t('agent.agentalertstsx.s99f0fb65'), confirmText: i18n.t('kubernetes.deployment.resume') });
const ok = await confirm({ title: i18n.t('恢复告警'), description: i18n.t('确定将此告警标记为已恢复?'), confirmText: i18n.t('kubernetes.deployment.resume') });
if (!ok) return;
try {
await agentApi.resolveAlert(id);
toast.success(i18n.t('agent.agentalertstsx.s0e23522e'));
toast.success(i18n.t('告警已恢复'));
loadData();
} catch (err) {
toast.error(err?.message || i18n.t('cloud.operationFailed'));
@@ -88,11 +88,11 @@ export function AgentAlerts() {
};
const handleDeleteRule = async (id: number) => {
const ok = await confirm({ title: i18n.t('monitor.deleteRule'), description: i18n.t('monitor.alertrulestabts.sd301558d'), confirmText: i18n.t('kubernetes.storage.delete2'), variant: 'destructive' });
const ok = await confirm({ title: i18n.t('monitor.deleteRule'), description: i18n.t('删除规则'), confirmText: i18n.t('kubernetes.storage.delete2'), variant: 'destructive' });
if (!ok) return;
try {
await agentApi.deleteRule(id);
toast.success(i18n.t('agent.agentalertstsx.s8b2798c4'));
toast.success(i18n.t('告警已恢复'));
loadData();
} catch (err) {
toast.error(err?.message || i18n.t('kubernetes.msg.deleteFailed2'));
@@ -114,7 +114,7 @@ export function AgentAlerts() {
<div className="flex items-center justify-between">
<div>
<h2 className="text-xl font-semibold text-[var(--dg-text-primary)]">Agent 告警</h2>
<p className="text-sm dg-text-secondary mt-0.5"> {i18n.t('agent.agentalertstsx.s03a08cd6')} </p>
<p className="text-sm dg-text-secondary mt-0.5"> {i18n.t('触发告警阈值')} </p>
</div>
<Button variant="outline" size="sm" onClick={loadData} disabled={loading} className="dg-input text-[var(--dg-text-secondary)] hover:bg-[var(--dg-bg-hover)]">
<RefreshCw className={`h-4 w-4 mr-1.5 ${loading ? 'animate-spin' : ''}`} />
@@ -160,7 +160,7 @@ export function AgentAlerts() {
<Card className="dg-card">
<CardContent className="flex flex-col items-center justify-center py-16">
<CheckCircle className="h-10 w-10 text-emerald-500 mb-3" />
<p className="dg-text-secondary">{resolvedView ? i18n.t('agent.agentalertstsx.se459f480') : i18n.t('agent.agentalertstsx.s778455b9')}</p>
<p className="dg-text-secondary">{resolvedView ? i18n.t('暂无已恢复的告警') : i18n.t('当前无活动告警,一切正常')}</p>
</CardContent>
</Card>
) : (
@@ -178,7 +178,7 @@ export function AgentAlerts() {
{severityBadge(alert.severity)}
<span className="font-medium text-[var(--dg-text-primary)]">{alert.rule_name || alert.name || alert.title || i18n.t('monitor.hostDashboard.alert')}</span>
</div>
<p className="text-sm dg-text-secondary mt-1">{alert.message || alert.description || i18n.t('agent.agentalertstsx.sddab4a17')}</p>
<p className="text-sm dg-text-secondary mt-1">{alert.message || alert.description || i18n.t('触发告警阈值')}</p>
<div className="flex items-center gap-4 mt-2 text-xs dg-text-muted flex-wrap">
<span className="inline-flex items-center gap-1">
<Cpu className="h-3 w-3" />
@@ -71,7 +71,7 @@ export function AgentMonitor() {
if (fresh) setSelectedHost(fresh);
}
} catch (err) {
if (!silent) toast.error(i18n.t('agent.agentmonitortsx.s5760f667'));
if (!silent) toast.error(i18n.t('加载主机列表失败'));
console.error(err);
} finally {
setLoading(false);
@@ -100,7 +100,7 @@ export function AgentMonitor() {
// 提交远程命令(直连 SSH 即时返回)
const submitCommand = async () => {
if (!cmdCommand.trim()) {
toast.error(i18n.t('agent.agentmonitortsx.s9358aada'));
toast.error(i18n.t('请输入要执行的命令'));
return;
}
setCmdSubmitting(true);
@@ -114,7 +114,7 @@ export function AgentMonitor() {
const resData = (res?.data ?? {}) as Record<string, unknown>;
setCmdResult({
status: res?.code === 200 ? 'completed' : 'failed',
result: (resData.output as string) || (res?.message as string) || i18n.t('agent.agentmonitortsx.s26d45bea'),
result: (resData.output as string) || (res?.message as string) || i18n.t('无输出'),
error: resData.error as string | undefined,
});
} catch (err) {
@@ -154,7 +154,7 @@ export function AgentMonitor() {
className="dg-input text-[var(--dg-text-secondary)] hover:bg-[var(--dg-bg-hover)] hover:text-[var(--dg-text-primary)]"
>
<RefreshCw className={`h-4 w-4 mr-1.5 ${refreshing ? 'animate-spin' : ''}`} />
{t('agent.agentmonitortsx.s2b3c4d5e')}
{t('例如:free -m && df -h')}
</Button>
<Button
size="sm"
@@ -162,7 +162,7 @@ export function AgentMonitor() {
className="bg-blue-600 hover:bg-blue-700 text-white"
>
<Rocket className="h-4 w-4 mr-1.5" />
{t('agent.agentmonitortsx.s3c4d5e6f')}
{t('例如:free -m && df -h')}
</Button>
</div>
</div>
@@ -325,7 +325,7 @@ export function AgentMonitor() {
<Textarea
value={cmdCommand}
onChange={(e) => setCmdCommand(e.target.value)}
placeholder={i18n.t('agent.agentmonitortsx.s6e62a5b0')}
placeholder={i18n.t('例如:free -m && df -h')}
rows={3}
className="bg-[var(--dg-bg-primary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] font-mono text-sm resize-none"
/>
@@ -359,7 +359,7 @@ export function AgentMonitor() {
</Badge>
</div>
<pre className="text-xs text-[var(--dg-text-secondary)] font-mono whitespace-pre-wrap break-all bg-[var(--dg-bg-primary)] border border-[var(--dg-border)] rounded-lg p-3 max-h-48 overflow-auto">
{cmdResult.result || cmdResult.output || cmdResult.error || i18n.t('agent.agentmonitortsx.s26d45bea')}
{cmdResult.result || cmdResult.output || cmdResult.error || i18n.t('无输出')}
</pre>
</div>
)}
@@ -70,7 +70,7 @@ export function AgentRuleDialog({ open, onOpenChange, editingRule, onSuccess }:
const handleSave = async () => {
if (!ruleForm.name.trim()) {
toast.error(i18n.t('agent.agentruledialog.s40f3f17d'));
toast.error(i18n.t('请输入规则名称'));
return;
}
setSaving(true);
@@ -107,8 +107,8 @@ export function AgentRuleDialog({ open, onOpenChange, editingRule, onSuccess }:
<Dialog open={open} onOpenChange={(v) => { if (!v) onOpenChange(false); }}>
<DialogContent className="max-w-md dg-card text-[var(--dg-text-primary)]">
<DialogHeader>
<DialogTitle className="text-[var(--dg-text-primary)]">{editingRule ? i18n.t('monitor.editRule') : i18n.t('agent.agentruledialog.sf10ed468')}</DialogTitle>
<DialogDescription className="dg-text-secondary"> {i18n.t('agent.agentruledialog.s0cc0f608')} </DialogDescription>
<DialogTitle className="text-[var(--dg-text-primary)]">{editingRule ? i18n.t('monitor.editRule') : i18n.t('编辑规则')}</DialogTitle>
<DialogDescription className="dg-text-secondary"> {i18n.t('>阈值 {ruleForm.metric !== ')} </DialogDescription>
</DialogHeader>
<div className="space-y-3">
@@ -117,7 +117,7 @@ export function AgentRuleDialog({ open, onOpenChange, editingRule, onSuccess }:
<Input
value={ruleForm.name}
onChange={(e) => setRuleForm({ ...ruleForm, name: e.target.value })}
placeholder={i18n.t('agent.agentruledialog.s5a0f7e3e')}
placeholder={i18n.t('例如:CPU 使用率告警')}
className="h-9 dg-input"
/>
</div>
@@ -154,7 +154,7 @@ export function AgentRuleDialog({ open, onOpenChange, editingRule, onSuccess }:
{ruleForm.metric !== 'offline' && (
<div className="grid grid-cols-2 gap-3">
<div className="space-y-1.5">
<Label className="text-[var(--dg-text-secondary)] text-xs"> {i18n.t('agent.agentruledialog.sd52f2cb3')} </Label>
<Label className="text-[var(--dg-text-secondary)] text-xs"> {i18n.t('>阈值 {ruleForm.metric !== ')} </Label>
<Select value={ruleForm.operator} onValueChange={(v) => setRuleForm({ ...ruleForm, operator: v })}>
<SelectTrigger className="h-9 dg-input">
<SelectValue />
@@ -180,24 +180,24 @@ export function AgentRuleDialog({ open, onOpenChange, editingRule, onSuccess }:
{ruleForm.metric === 'port_down' && (
<div className="space-y-1.5">
<Label className="text-[var(--dg-text-secondary)] text-xs"> {i18n.t('agent.agentruledialog.s4d134841')} </Label>
<Label className="text-[var(--dg-text-secondary)] text-xs"> {i18n.t('>阈值 {ruleForm.metric !== ')} </Label>
<Input
type="number"
value={ruleForm.port}
onChange={(e) => setRuleForm({ ...ruleForm, port: e.target.value })}
placeholder={i18n.t('agent.agentruledialog.s77565e5d')}
placeholder={i18n.t('例如:8080')}
className="h-9 dg-input"
/>
</div>
)}
<div className="space-y-1.5">
<Label className="text-[var(--dg-text-secondary)] text-xs"> {i18n.t('agent.agentruledialog.sb1551d7f')} </Label>
<Label className="text-[var(--dg-text-secondary)] text-xs"> {i18n.t('>阈值 {ruleForm.metric !== ')} </Label>
<Input
type="number"
value={ruleForm.duration}
onChange={(e) => setRuleForm({ ...ruleForm, duration: e.target.value })}
placeholder={i18n.t('agent.agentruledialog.sd140c78d')}
placeholder={i18n.t('例如:CPU 使用率告警')}
className="h-9 dg-input"
/>
</div>
@@ -94,7 +94,7 @@ export function HostDetailDialog({
<InfoCell label={i18n.t('agent.agentIp')} value={host.ip || '--'} />
<InfoCell label={i18n.t('agent.agentOs')} value={host.os || host.platform || '--'} />
<InfoCell label={i18n.t('agent.agentLastSeen')} value={timeAgo(host.last_report || host.last_reported_at || host.updated_at)} />
<InfoCell label={i18n.t('agent.hostdetaildialo.s6ad4fc6e')} value={String(ports.length)} />
<InfoCell label={i18n.t('端口数')} value={String(ports.length)} />
</div>
{/* 趋势图 */}
@@ -10,23 +10,23 @@ import i18n from '@/i18n';
// 主机监控指标(与后端 alert_engine 对齐)// Logan.Li
export const METRIC_OPTIONS = [
{ value: 'cpu', label: i18n.t('kubernetes.cluster.cpuUsage'), icon: Cpu },
{ value: 'cpu_iowait', label: i18n.t('agent.agentalerthelpe.sc1eec3e5'), icon: Cpu },
{ value: 'cpu_iowait', label: i18n.t('入网带宽'), icon: Cpu },
{ value: 'mem', label: i18n.t('kubernetes.cluster.memoryUsage'), icon: MemoryStick },
{ value: 'mem_available', label: i18n.t('monitor.hostmonitortsx.sa23fcda0'), icon: MemoryStick },
{ value: 'swap', label: i18n.t('agent.agentalerthelpe.sa2f9101c'), icon: MemoryStick },
{ value: 'load1', label: i18n.t('agent.agentalerthelpe.sf23ce82f'), icon: Gauge },
{ value: 'mem_available', label: i18n.t('可用内存(GB)'), icon: MemoryStick },
{ value: 'swap', label: i18n.t('Swap 使用率'), icon: MemoryStick },
{ value: 'load1', label: i18n.t('1分钟负载'), icon: Gauge },
{ value: 'disk', label: i18n.t('monitor.hostDisk'), icon: HardDrive },
{ value: 'disk_inode', label: i18n.t('agent.agentalerthelpe.sf7eadeca'), icon: HardDrive },
{ value: 'disk_io_util', label: i18n.t('agent.agentalerthelpe.s565a0e4d'), icon: HardDrive },
{ value: 'tcp_established', label: i18n.t('agent.agentalerthelpe.s6d9639e8'), icon: Network },
{ value: 'disk_inode', label: i18n.t('Inode 使用率'), icon: HardDrive },
{ value: 'disk_io_util', label: i18n.t('磁盘 IO 利用率'), icon: HardDrive },
{ value: 'tcp_established', label: i18n.t('TCP 已建立'), icon: Network },
{ value: 'tcp_time_wait', label: 'TCP TIME_WAIT', icon: Network },
{ value: 'tcp_close_wait', label: 'TCP CLOSE_WAIT', icon: Network },
{ value: 'net_rx_bps', label: i18n.t('monitor.hostNetIn'), icon: Network },
{ value: 'net_tx_bps', label: i18n.t('monitor.hostNetOut'), icon: Network },
{ value: 'net_rx_errors', label: i18n.t('agent.agentalerthelpe.s8d73bfe3'), icon: Network },
{ value: 'net_rx_errors', label: i18n.t('入网错误'), icon: Network },
{ value: 'fd', label: i18n.t('monitor.hostFileDescriptor'), icon: Activity },
{ value: 'offline', label: i18n.t('agent.agentalerthelpe.s8ed49aa6'), icon: WifiOff },
{ value: 'port_down', label: i18n.t('agent.agentalerthelpe.sf62ce662'), icon: Network },
{ value: 'offline', label: i18n.t('主机离线'), icon: WifiOff },
{ value: 'port_down', label: i18n.t('端口不通'), icon: Network },
{ value: 'health_probe', label: i18n.t('kubernetes.container.probes'), icon: Timer },
];