feat(i18n): 安全批量转换 135 文件 — 覆盖率 34%→62%

使用 i18n.t() 全局方式(避免 hook 定位问题):
- 288 目标文件中 135 个成功转换
- 2228 处中文替换为 i18n.t() 调用
- 1006 个新翻译 key 添加到 zh-CN.json + en-US.json
- 词典总量: 3554 keys (22 namespaces)
- tsc 零错误 + Vite 构建成功
- 6 个含代码示例/数据字符串的文件安全回退
This commit is contained in:
attacker committed 2026-07-03 02:14:20 +08:00
1 parent 72bfb0e12d
commit 55f216cfbb
131 files changed
+4049 -1908

No files matched your search

@@ -23,6 +23,7 @@ import PromDsFormDialog from './prometheus-ds/PromDsFormDialog';
import { PageLoading } from '@/components/layout/PageLoading';
import { PageEmpty } from '@/components/layout/PageEmpty';
import { ContentPanel } from '@/components/layout/ContentPanel';
import i18n from '@/i18n';
export default function PrometheusDatasourceManager() {
const _confirm = useConfirm();
@@ -33,7 +34,7 @@ export default function PrometheusDatasourceManager() {
const [editingDs, setEditingDs] = useState<PromDS | null>(null);
useEffect(() => {
if (isError) toast.error('获取数据源列表失败');
if (isError) toast.error(i18n.t('monitor.zabbixdatasourc.s45f81749'));
}, [isError]);
const openCreate = () => {
@@ -48,16 +49,16 @@ export default function PrometheusDatasourceManager() {
const handleDelete = async (ds: PromDS) => {
const ok = await _confirm({
title: '删除数据源',
title: i18n.t('monitor.deleteDatasource'),
description: `确定删除数据源「${ds.name}」吗?此操作不可撤销。`,
variant: 'destructive',
});
if (!ok) return;
try {
await deleteMutation.mutateAsync(ds.id);
toast.success('已删除');
toast.success(i18n.t('monitor.silenceRules.deleted'));
} catch {
toast.error('删除失败');
toast.error(i18n.t('kubernetes.msg.deleteFailed2'));
}
};
@@ -66,7 +67,7 @@ export default function PrometheusDatasourceManager() {
await setDefaultMutation.mutateAsync(ds.id);
toast.success(`已将「${ds.name}」设为默认数据源`);
} catch {
toast.error('设置失败');
toast.error(i18n.t('monitor.zabbixdatasourc.s9f96034c'));
}
};
@@ -94,8 +95,8 @@ export default function PrometheusDatasourceManager() {
{sources.length === 0 ? (
<PageEmpty
icon={<Database className="h-12 w-12" />}
title="暂无 Prometheus 数据源"
description="添加数据源后可用于指标监控与监控大屏"
title={i18n.t('monitor.prometheusdatas.s99ed81c8')}
description={i18n.t('monitor.prometheusdatas.sd9a356b8')}
action={(
<Button onClick={openCreate} size="sm" className="dg-btn-primary">
<Plus className="w-4 h-4 mr-1" />添加数据源
@@ -107,11 +108,11 @@ export default function PrometheusDatasourceManager() {
<table className="w-full">
<thead className="border-b border-[var(--border-default)]">
<tr className="text-xs dg-text-secondary">
<th className="text-left py-3 px-4 font-medium">名称</th>
<th className="text-left py-3 px-4 font-medium"> {i18n.t('kubernetes.secret.secretName')} </th>
<th className="text-left py-3 px-4 font-medium">URL</th>
<th className="text-left py-3 px-4 font-medium w-20">默认</th>
<th className="text-left py-3 px-4 font-medium w-16">状态</th>
<th className="text-right py-3 px-4 font-medium w-36">操作</th>
<th className="text-left py-3 px-4 font-medium w-20"> {i18n.t('k8s.storage.default')} </th>
<th className="text-left py-3 px-4 font-medium w-16"> {i18n.t('system.terminalStatus')} </th>
<th className="text-right py-3 px-4 font-medium w-36"> {i18n.t('system.auditAction')} </th>
</tr>
</thead>
<tbody>
@@ -142,16 +143,16 @@ export default function PrometheusDatasourceManager() {
</td>
<td className="py-3 px-4">
{ds.is_default ? (
<span className="dg-badge-yellow"><Star className="w-3 h-3 mr-1 inline" />默认</span>
<span className="dg-badge-yellow"><Star className="w-3 h-3 mr-1 inline" /> {i18n.t('k8s.storage.default')} </span>
) : (
<span className="text-xs dg-text-muted">--</span>
)}
</td>
<td className="py-3 px-4">
{ds.status === 1 ? (
<span className="dg-status-running">启用</span>
<span className="dg-status-running"> {i18n.t('system.userActive')} </span>
) : (
<span className="dg-badge-muted">禁用</span>
<span className="dg-badge-muted"> {i18n.t('system.userInactive')} </span>
)}
</td>
<td className="py-3 px-4">
@@ -160,7 +161,7 @@ export default function PrometheusDatasourceManager() {
variant="ghost" size="sm"
className="h-8 px-2"
onClick={() => handleTestQuick(ds)}
title="测试连接"
title={i18n.t('aiops.llmTest')}
>
<Plug className="w-3.5 h-3.5" />
</Button>
@@ -169,7 +170,7 @@ export default function PrometheusDatasourceManager() {
variant="ghost" size="sm"
className="h-8 px-2 dg-text-yellow"
onClick={() => handleSetDefault(ds)}
title="设为默认"
title={i18n.t('aiops.llmSetDefault')}
>
<Star className="w-3.5 h-3.5" />
</Button>
@@ -32,6 +32,7 @@ import { toast } from 'sonner';
import { useConfirm } from '@/components/ui/confirm-dialog';
import { zabbixDatasourceApi } from '@/api';
import type { JsonData } from '@/types/common';
import i18n from '@/i18n';
interface ZabbixDS {
id: number;
@@ -78,7 +79,7 @@ export default function ZabbixDatasourceManager() {
const res: JsonData = await zabbixDatasourceApi.list();
setSources(res?.data || res || []);
} catch {
toast.error('获取数据源列表失败');
toast.error(i18n.t('monitor.zabbixdatasourc.s45f81749'));
} finally {
setLoading(false);
}
@@ -115,38 +116,38 @@ export default function ZabbixDatasourceManager() {
};
const handleSave = async () => {
if (!form.name.trim()) { toast.error('请输入数据源名称'); return; }
if (!form.url.trim()) { toast.error('请输入 Zabbix API URL'); return; }
if (!form.username.trim()) { toast.error('请输入用户名'); return; }
if (!form.password.trim()) { toast.error('请输入密码'); return; }
if (!form.name.trim()) { toast.error(i18n.t('monitor.promDs.nameRequired')); return; }
if (!form.url.trim()) { toast.error(i18n.t('monitor.zabbixdatasourc.s2ba385d6')); return; }
if (!form.username.trim()) { toast.error(i18n.t('pipeline.usernameRequired')); return; }
if (!form.password.trim()) { toast.error(i18n.t('login.passwordRequired')); return; }
try {
if (editingId) {
await zabbixDatasourceApi.update(editingId, form);
toast.success('数据源已更新');
toast.success(i18n.t('monitor.zabbixdatasourc.s8dfdd2f4'));
} else {
await zabbixDatasourceApi.create(form);
toast.success('数据源已创建');
toast.success(i18n.t('monitor.zabbixdatasourc.sa6def01f'));
}
setDialogOpen(false);
fetchList();
} catch (err) {
toast.error(err?.message || '操作失败');
toast.error(err?.message || i18n.t('cloud.operationFailed'));
}
};
const handleDelete = async (ds: ZabbixDS) => {
const ok = await _confirm({
title: '删除数据源',
title: i18n.t('monitor.deleteDatasource'),
description: `确定删除「${ds.name}」?`,
variant: 'destructive',
});
if (!ok) return;
try {
await zabbixDatasourceApi.delete(ds.id);
toast.success('已删除');
toast.success(i18n.t('monitor.silenceRules.deleted'));
fetchList();
} catch { toast.error('删除失败'); }
} catch { toast.error(i18n.t('kubernetes.msg.deleteFailed2')); }
};
const handleSetDefault = async (ds: ZabbixDS) => {
@@ -154,12 +155,12 @@ export default function ZabbixDatasourceManager() {
await zabbixDatasourceApi.setDefault(ds.id);
toast.success(`已将「${ds.name}」设为默认`);
fetchList();
} catch { toast.error('设置失败'); }
} catch { toast.error(i18n.t('monitor.zabbixdatasourc.s9f96034c')); }
};
const handleTest = async () => {
if (!form.url.trim() || !form.username.trim()) {
toast.error('请填写 URL 和用户名');
toast.error(i18n.t('monitor.zabbixdatasourc.s1d3562b7'));
return;
}
setTesting(true);
@@ -173,7 +174,7 @@ export default function ZabbixDatasourceManager() {
const data = res?.data || res;
setTestResult(data);
} catch (err) {
setTestResult({ success: false, message: err?.message || '测试失败' });
setTestResult({ success: false, message: err?.message || i18n.t('monitor.alertChannels.testFailed') });
} finally {
setTesting(false);
}
@@ -199,7 +200,7 @@ export default function ZabbixDatasourceManager() {
/>
Zabbix 数据源
</h2>
<p className="text-xs text-[var(--dg-text-muted)]">配置 Zabbix API 连接,获取主机监控数据</p>
<p className="text-xs text-[var(--dg-text-muted)]"> {i18n.t('monitor.zabbixdatasourc.s79e929d8')} </p>
</div>
<Button onClick={openCreate} size="sm">
<Plus className="w-4 h-4 mr-1" />添加
@@ -210,7 +211,7 @@ export default function ZabbixDatasourceManager() {
<Card className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
<CardContent className="py-12 text-center text-[var(--dg-text-muted)]">
<Database className="w-12 h-12 mx-auto mb-3 opacity-30" />
<p className="text-sm">暂无 Zabbix 数据源</p>
<p className="text-sm"> {i18n.t('monitor.zabbixdatasourc.sc9c9bd18')} </p>
<Button size="sm" className="mt-4" onClick={openCreate}>
<Plus className="w-4 h-4 mr-1" />添加数据源
</Button>
@@ -226,15 +227,15 @@ export default function ZabbixDatasourceManager() {
<div className="flex items-center gap-2 mb-1">
<div className={`w-2 h-2 rounded-full ${ds.status === 1 ? 'bg-emerald-400' : 'bg-[var(--dg-bg-active)]'}`} />
<span className="font-medium text-[var(--dg-text-primary)]">{ds.name}</span>
{ds.is_default && <Badge className="bg-amber-500/20 dg-text-yellow text-[10px]"><Star className="w-3 h-3 mr-0.5" />默认</Badge>}
{ds.is_default && <Badge className="bg-amber-500/20 dg-text-yellow text-[10px]"><Star className="w-3 h-3 mr-0.5" /> {i18n.t('k8s.storage.default')} </Badge>}
{ds.status === 1
? <Badge className="bg-emerald-500/20 dg-text-green text-[10px]">启用</Badge>
: <Badge className="bg-[var(--dg-bg-active)]/20 dg-text-secondary text-[10px]">禁用</Badge>}
? <Badge className="bg-emerald-500/20 dg-text-green text-[10px]"> {i18n.t('system.userActive')} </Badge>
: <Badge className="bg-[var(--dg-bg-active)]/20 dg-text-secondary text-[10px]"> {i18n.t('system.userInactive')} </Badge>}
</div>
<div className="text-xs text-[var(--dg-text-muted)] space-x-3">
<code className="text-orange-300">{ds.url}</code>
<span>用户: {ds.username}</span>
{ds.direct_db && <Badge variant="outline" className="text-[10px]">直连DB</Badge>}
{ds.direct_db && <Badge variant="outline" className="text-[10px]"> {i18n.t('monitor.zabbixdatasourc.s85260abd')} </Badge>}
</div>
</div>
<div className="flex items-center gap-1">
@@ -263,7 +264,7 @@ export default function ZabbixDatasourceManager() {
<DialogHeader>
<DialogTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
<Database className="h-5 w-5 dg-text-orange" />
{editingId ? '编辑 Zabbix 数据源' : '新建 Zabbix 数据源'}
{editingId ? i18n.t('monitor.zabbixdatasourc.sc1c87ed6') : i18n.t('monitor.zabbixdatasourc.sa77d384f')}
</DialogTitle>
<DialogDescription>
配置 Zabbix API 连接,用于主机监控与告警数据获取
@@ -274,14 +275,14 @@ export default function ZabbixDatasourceManager() {
{/* Name + Default */}
<div className="grid grid-cols-2 gap-3">
<div>
<Label className="text-xs text-[var(--dg-text-secondary)]">名称 *</Label>
<Input className="mt-1 h-9 text-sm bg-[var(--dg-bg-primary)]" placeholder="如:生产 Zabbix"
<Label className="text-xs text-[var(--dg-text-secondary)]"> {i18n.t('deploy.form.nameStar')} </Label>
<Input className="mt-1 h-9 text-sm bg-[var(--dg-bg-primary)]" placeholder={i18n.t('monitor.zabbixdatasourc.s9f1e6a92')}
value={form.name} onChange={e => updateForm('name', e.target.value)} />
</div>
<div className="flex items-end pb-1">
<div className="flex items-center gap-2">
<Switch checked={form.is_default} onCheckedChange={v => updateForm('is_default', v)} />
<Label className="text-xs cursor-pointer">设为默认</Label>
<Label className="text-xs cursor-pointer"> {i18n.t('aiops.llmSetDefault')} </Label>
</div>
</div>
</div>
@@ -311,9 +312,9 @@ export default function ZabbixDatasourceManager() {
</button>
{showAuth && (
<div className="px-3 pb-3 space-y-3">
<Input className="h-9 text-sm bg-[var(--dg-bg-primary)]" placeholder="用户名 *"
<Input className="h-9 text-sm bg-[var(--dg-bg-primary)]" placeholder={i18n.t('system.userNameRequired')}
value={form.username} onChange={e => updateForm('username', e.target.value)} />
<Input className="h-9 text-sm bg-[var(--dg-bg-primary)]" type="password" placeholder="密码 *"
<Input className="h-9 text-sm bg-[var(--dg-bg-primary)]" type="password" placeholder={i18n.t('system.passwordRequired')}
value={form.password} onChange={e => updateForm('password', e.target.value)} />
</div>
)}
@@ -365,7 +366,7 @@ export default function ZabbixDatasourceManager() {
onClick={() => setShowOther(!showOther)}>
<div className="flex items-center gap-2">
<Settings className="w-4 h-4" />
<span>其他设置</span>
<span> {i18n.t('monitor.zabbixdatasourc.sdda36edb')} </span>
</div>
{showOther ? <ChevronUp className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}
</button>
@@ -376,11 +377,11 @@ export default function ZabbixDatasourceManager() {
<Switch checked={form.direct_db} onCheckedChange={v => updateForm('direct_db', v)} />
</div>
<div className="flex items-center justify-between">
<Label className="text-xs">只读用户禁用确认</Label>
<Label className="text-xs"> {i18n.t('monitor.zabbixdatasourc.s413ec771')} </Label>
<Switch checked={form.disable_acknowledges} onCheckedChange={v => updateForm('disable_acknowledges', v)} />
</div>
<div className="flex items-center justify-between">
<Label className="text-xs">禁用数据对齐</Label>
<Label className="text-xs"> {i18n.t('monitor.zabbixdatasourc.s6d4d6f81')} </Label>
<Switch checked={form.disable_data_alignment} onCheckedChange={v => updateForm('disable_data_alignment', v)} />
</div>
</div>
@@ -404,8 +405,8 @@ export default function ZabbixDatasourceManager() {
测试连接
</Button>
<div className="flex-1" />
<Button variant="ghost" size="sm" onClick={() => setDialogOpen(false)}>取消</Button>
<Button size="sm" onClick={handleSave}>保存</Button>
<Button variant="ghost" size="sm" onClick={() => setDialogOpen(false)}> {i18n.t('rbac.jobRole.cancel')} </Button>
<Button size="sm" onClick={handleSave}> {i18n.t('task.script.save')} </Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -3,6 +3,7 @@
import { toast } from 'sonner';
import { promDatasourceApi } from '@/api';
import type { PromDS, HeaderEntry, PromDsForm } from './types';
import i18n from '@/i18n';
export type TestConnectionParams = {
url: string;
@@ -106,10 +107,10 @@ export async function handleTestQuick(ds: PromDS): Promise<void> {
if (data?.success) {
toast.success(`连接成功 · ${data.target_count || 0} targets`);
} else {
toast.error(data?.message || '连接失败');
toast.error(data?.message || i18n.t('aiops.llmTestFailed'));
}
} catch (err: unknown) {
const message = err instanceof Error ? err.message : '测试失败';
const message = err instanceof Error ? err.message : i18n.t('monitor.alertChannels.testFailed');
toast.error(message);
}
}