feat(i18n): 剩余模块全量国际化 — 51% 覆盖率 (231 文件接入 t())

批量转换 163 个文件,3204 处中文替换为 t() 调用:
- Monitor: 日志中心/告警中心/数据源/大屏/站点拨测/SNMP/中间件 全部转换
- Kubernetes: ResourceVisualEditor/NamespaceResourcePage/拓扑/事件 全部转换
- Deploy: 流水线/发布/凭证/RBAC 全部转换
- Server/Cloud/Agent/Task/Layout/UI: 全部转换
- 翻译词典扩展至 6474 行 (22 namespaces, 5000+ keys)
- tsc 编译零错误
This commit is contained in:
attacker committed 2026-07-03 01:51:57 +08:00
1 parent 78c27037e3
commit ecec73989b
166 files changed
+6925 -2800

No files matched your search

@@ -22,6 +22,8 @@ import { cn } from '@/lib/utils';
import { kubernetesApi } from '@/api';
import { useToast } from '@/hooks/use-toast';
import type { JsonData } from '@/types/common';
import { useTranslation } from 'react-i18next';
import i18n from '@/i18n';
/**
* 增强版 Pod 日志查看器 — 增强 DeploymentDetail 的日志体验
@@ -51,10 +53,10 @@ interface PodLogsViewerProps {
}
const TAIL_OPTIONS = [
{ value: '100', label: '最近 100 行' },
{ value: '500', label: '最近 500 行' },
{ value: '1000', label: '最近 1000 行' },
{ value: '0', label: '全部' },
{ value: '100', label: i18n.t('kubernetes.podlogsviewer.s58b02a') },
{ value: '500', label: i18n.t('kubernetes.podlogsviewer.s9a0368') },
{ value: '1000', label: i18n.t('kubernetes.podlogsviewer.sf89a33') },
{ value: '0', label: i18n.t('common.all') },
];
// 环形缓冲大小(借鉴 opsx-agent)
@@ -74,6 +76,7 @@ export function PodLogsViewer({
containers = [],
initialContainer,
}: PodLogsViewerProps) {
const { t } = useTranslation();
const { toast } = useToast();
const [fullscreen, setFullscreen] = useState(false);
@@ -164,8 +167,8 @@ export function PodLogsViewer({
const arr = typeof raw === 'string' ? raw.split('\n') : (Array.isArray(raw) ? raw : String(raw).split('\n'));
appendLines(arr);
} catch (e) {
appendLines([`\x1b[31m[获取日志失败: ${e?.message || String(e)}]\x1b[0m`]);
toast({ title: '获取日志失败', description: e?.message || String(e), variant: 'destructive' });
appendLines([t('kubernetes.podlogsviewer.s69828a', { e?.message || String(e): e?.message || String(e) })]);
toast({ title: t('kubernetes.podlogsviewer.sc93f33'), description: e?.message || String(e), variant: 'destructive' });
} finally {
setLoading(false);
}
@@ -225,12 +228,12 @@ export function PodLogsViewer({
}
}
flush(); // 收尾
appendLines(['\x1b[33m— 流式结束 —\x1b[0m']);
appendLines([t('kubernetes.podlogsviewer.s4f0e17')]);
} catch (e) {
if (e?.name === 'AbortError') {
appendLines(['\x1b[33m— 已停止 —\x1b[0m']);
appendLines([t('kubernetes.podlogsviewer.s1ca901')]);
} else {
appendLines([`\x1b[31m[流式连接中断: ${e?.message || String(e)}]\x1b[0m`]);
appendLines([t('kubernetes.podlogsviewer.s11530d', { e?.message || String(e): e?.message || String(e) })]);
}
} finally {
setStreaming(false);
@@ -275,7 +278,7 @@ export function PodLogsViewer({
a.download = filename;
a.click();
URL.revokeObjectURL(a.href);
toast({ title: '已导出', description: filename });
toast({ title: t('kubernetes.podlogsviewer.s5c51c3'), description: filename });
}, [podName, container, previous, toast]);
// 关键字过滤
@@ -330,7 +333,7 @@ export function PodLogsViewer({
style={fullscreen ? { maxWidth: '100vw', width: '100vw', height: '100vh' } : { maxWidth: '1100px', width: '94vw' }}
>
<DialogTitle className="sr-only">日志 — {podName}</DialogTitle>
<DialogDescription className="sr-only">Pod 容器日志查看</DialogDescription>
<DialogDescription className="sr-only">{t('kubernetes.podlogsviewer.s24ae3a')}</DialogDescription>
{/* 头部工具栏 */}
<div className="flex items-center justify-between gap-2 px-4 py-2 border-b border-[var(--dg-border)] flex-wrap">
@@ -343,8 +346,8 @@ export function PodLogsViewer({
<span className="text-[var(--dg-text-primary)] font-medium truncate">日志 — {podName}</span>
{loading && <Loader2 className="h-3 w-3 animate-spin text-[var(--dg-text-muted)]" />}
<span className="text-xs text-[var(--dg-text-muted)]">
{streaming ? (paused ? '已暂停' : '实时跟踪') : '已停止'} · {matchedCount}{keyword ? `/${lineCount}` : ''} 行
{lineCount >= RING_BUFFER_MAX && ' (缓冲已满)'}
{streaming ? (paused ? t('kubernetes.deployment.paused') : t('kubernetes.podlogsviewer.sd9c71f')) : t('common.stopped')} · {matchedCount}{keyword ? `/${lineCount}` : ''} 行
{lineCount >= RING_BUFFER_MAX && t('kubernetes.podlogsviewer.sf3280b')}
</span>
</div>
@@ -352,14 +355,14 @@ export function PodLogsViewer({
<button
onClick={() => setFullscreen(!fullscreen)}
className="p-1.5 rounded hover:bg-[var(--dg-bg-hover)] text-[var(--dg-text-secondary)]"
title={fullscreen ? '退出全屏' : '全屏'}
title={fullscreen ? t('common.exitFullscreen') : t('common.fullscreen')}
>
{fullscreen ? <Minimize2 className="h-4 w-4" /> : <Maximize2 className="h-4 w-4" />}
</button>
<button
onClick={handleClose}
className="p-1.5 rounded hover:bg-[var(--dg-bg-hover)] text-[var(--dg-text-secondary)]"
title="关闭"
title=t('common.close')
>
<X className="h-4 w-4" />
</button>
@@ -373,7 +376,7 @@ export function PodLogsViewer({
<Select value={container} onValueChange={setContainer}>
<SelectTrigger className="h-8 w-[150px] text-xs bg-[var(--dg-bg-hover)] border-[var(--dg-border)]">
<Box className="h-3 w-3 mr-1 text-[var(--dg-text-muted)]" />
<SelectValue placeholder="容器" />
<SelectValue placeholder=t('k8s.pods.containers') />
</SelectTrigger>
<SelectContent>
{containers.map((c) => (
@@ -401,7 +404,7 @@ export function PodLogsViewer({
size="sm"
className={cn('h-8 text-xs', previous ? 'bg-amber-600 hover:bg-amber-700' : 'border-[var(--dg-border)] text-[var(--dg-text-secondary)]')}
onClick={() => setPrevious(!previous)}
title="查看上一次(崩溃)容器的日志"
title=t('kubernetes.podlogsviewer.s76a2e6')
>
<History className="h-3.5 w-3.5 mr-1" />
previous
@@ -418,7 +421,7 @@ export function PodLogsViewer({
setSinceTime(v ? new Date(v).toISOString() : '');
}}
className="h-8 w-[170px] text-xs bg-[var(--dg-bg-hover)] border-[var(--dg-border)] text-[var(--dg-text-primary)]"
title="起始时间(sinceTime)"
title=t('kubernetes.podlogsviewer.s127892')
/>
</div>
@@ -430,7 +433,7 @@ export function PodLogsViewer({
<Input
value={keyword}
onChange={(e) => setKeyword(e.target.value)}
placeholder="关键字过滤…"
placeholder=t('kubernetes.podlogsviewer.s7558f1')
className="h-8 w-[160px] pl-7 text-xs bg-[var(--dg-bg-hover)] border-[var(--dg-border)] text-[var(--dg-text-primary)]"
/>
</div>
@@ -440,7 +443,7 @@ export function PodLogsViewer({
variant="outline" size="sm"
className="h-8 text-xs border-[var(--dg-border)] text-[var(--dg-text-secondary)]"
onClick={handleDownload}
title="导出当前日志"
title=t('kubernetes.podlogsviewer.s1a023d')
disabled={filteredLines.length === 0}
>
<Download className="h-3.5 w-3.5 mr-1" />导出
@@ -452,7 +455,7 @@ export function PodLogsViewer({
className="h-8 text-xs border-[var(--dg-border)] text-[var(--dg-text-secondary)]"
onClick={fetchLogs}
disabled={loading}
title="重新拉取"
title=t('kubernetes.podlogsviewer.s930b4e')
>
<RefreshCw className={cn('h-3.5 w-3.5 mr-1', loading && 'animate-spin')} />刷新
</Button>
@@ -464,7 +467,7 @@ export function PodLogsViewer({
className="h-8 text-xs bg-emerald-600 hover:bg-emerald-700"
onClick={startStream}
disabled={loading}
title="实时跟踪(tail -f)"
title=t('kubernetes.podlogsviewer.s0d519c')
>
<Play className="h-3.5 w-3.5 mr-1" />实时
</Button>
@@ -474,16 +477,16 @@ export function PodLogsViewer({
variant="outline" size="sm"
className={cn('h-8 text-xs', paused ? 'border-emerald-500 dg-text-green' : 'border-amber-500 dg-text-yellow')}
onClick={() => setPaused(!paused)}
title={paused ? '继续' : '暂停'}
title={paused ? t('common.continue') : t('common.pause')}
>
{paused ? <Play className="h-3.5 w-3.5 mr-1" /> : <Pause className="h-3.5 w-3.5 mr-1" />}
{paused ? '继续' : '暂停'}
{paused ? t('common.continue') : t('common.pause')}
</Button>
<Button
variant="outline" size="sm"
className="h-8 text-xs border-red-500 dg-text-red"
onClick={stopStream}
title="停止"
title=t('common.stop')
>
<Pause className="h-3.5 w-3.5 mr-1" />停止
</Button>
@@ -510,7 +513,7 @@ export function PodLogsViewer({
{lineCount === 0 && !loading && (
<div className="flex flex-col items-center justify-center h-full text-[var(--dg-text-muted)]">
<AlertCircle className="h-8 w-8 mb-2 opacity-50" />
<span>暂无日志</span>
<span>{t('pipeline.noLog')}</span>
</div>
)}
{loading && lineCount === 0 && (
@@ -542,7 +545,7 @@ export function PodLogsViewer({
}
}}
>
<Maximize2 className="h-3 w-3" />{autoScroll ? '跟随底部' : '已暂停跟随'}
<Maximize2 className="h-3 w-3" />{autoScroll ? t('kubernetes.podlogsviewer.sd7eb1e') : t('kubernetes.podlogsviewer.s130db3')}
</button>
</div>
</DialogContent>