refactor(i18n): U37 全量 JSX 文本节点硬编码中文清零 — 65 文件 151 处→0, 新增 common.* 98 翻译键, zh/en 对齐, tsc -b=0, npm build✓ (17.96s), ESLint=0/43/any=0, go build=0, 17/17 测试通过

This commit is contained in:
attacker committed 2026-07-13 06:39:08 +08:00
1 parent e274ba7b9b
commit 7c80e35411
68 files changed
+11819 -11622

No files matched your search

@@ -325,7 +325,7 @@ export function ActiveSessionsPanel({ userToggledOff, onUserToggledOff }: Active
) : rdpSessions.length === 0 ? (
<div className="flex flex-col items-center justify-center py-10 dg-text-muted">
<Activity className="h-7 w-7 mb-2 opacity-40" />
<p className="text-sm">暂无 RDP 在线会话</p>
<p className="text-sm">{t("common.noRdpActive")}</p>
</div>
) : (
<Table>
@@ -256,7 +256,7 @@ export function HistorySessionsPanel() {
) : rdpSessions.length === 0 ? (
<div className="flex flex-col items-center justify-center py-12 dg-text-muted">
<Monitor className="h-7 w-7 mb-2 opacity-40" />
<p className="text-sm">暂无 RDP 历史会话</p>
<p className="text-sm">{t("common.noRdpHistory")}</p>
</div>
) : (
<>
@@ -164,10 +164,10 @@ export function MiddlewareMonitor() {
</div>
<div className="flex items-center gap-2">
<Button variant="outline" size="sm" onClick={handleCollectNow} className="gap-1.5">
<Zap className="h-4 w-4" />立即采集
<Zap className="h-4 w-4" />{t("common.collectNow")}
</Button>
<Button variant="outline" size="sm" onClick={() => loadTargets(true)} disabled={refreshing} className="gap-1.5">
<RefreshCw className={`h-4 w-4 ${refreshing ? 'animate-spin' : ''}`} />刷新
<RefreshCw className={`h-4 w-4 ${refreshing ? 'animate-spin' : ''}`} />{t("common.refresh")}
</Button>
{targets.length === 0 && (
<Button variant="outline" size="sm" onClick={handleSeedDefaults} disabled={seeding} className="gap-1.5">
@@ -176,14 +176,14 @@ export function MiddlewareMonitor() {
</Button>
)}
<Button size="sm" onClick={() => openCreate()} className="gap-1.5">
<Plus className="h-4 w-4" />添加监控
<Plus className="h-4 w-4" />{t("common.addMonitor")}
</Button>
</div>
</div>
{loading && (
<div className="flex items-center justify-center py-12 text-sm text-[var(--dg-text-muted)]">
<Loader2 className="h-5 w-5 animate-spin mr-2" />加载中...
<Loader2 className="h-5 w-5 animate-spin mr-2" />{t("common.loading")}
</div>
)}
+5 -5
View File
@@ -188,12 +188,12 @@ export function SNMPMonitor() {
</div>
<div className="flex gap-2">
<Button size="sm" variant="outline" onClick={refresh} className="h-8">
<RefreshCw className="h-3.5 w-3.5 mr-1" />刷新
<RefreshCw className="h-3.5 w-3.5 mr-1" />{t("common.refresh")}
</Button>
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
<DialogTrigger asChild>
<Button size="sm" className="bg-cyan-500/10 dg-text-cyan border border-cyan-500/30 h-8">
<Plus className="h-3.5 w-3.5 mr-1" />添加设备
<Plus className="h-3.5 w-3.5 mr-1" />{t("common.addDevice")}
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-md bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
@@ -272,7 +272,7 @@ export function SNMPMonitor() {
{loading ? (
<div className="py-16 text-center text-sm text-[var(--dg-text-muted)]">
<Loader2 className="h-5 w-5 animate-spin mx-auto mb-2" />加载中...
<Loader2 className="h-5 w-5 animate-spin mx-auto mb-2" />{t("common.loading")}
</div>
) : devices.length === 0 ? (
<Card className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
@@ -289,7 +289,7 @@ export function SNMPMonitor() {
<div className="grid grid-cols-1 xl:grid-cols-12 gap-4 items-start">
<Card className="xl:col-span-5 bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
<CardContent className="p-3">
<h3 className="text-sm font-medium mb-3">设备列表 ({devices.length})</h3>
<h3 className="text-sm font-medium mb-3">{t('common.deviceList')} ({devices.length})</h3>
<div className="overflow-x-auto">
<Table>
<TableHeader>
@@ -373,7 +373,7 @@ export function SNMPMonitor() {
<Table>
<TableHeader>
<TableRow>
<TableHead> {t('cloud.colMetric')} </TableHead><TableHead> {t('monitor.logIndex')} </TableHead><TableHead>值</TableHead><TableHead>OID</TableHead>
<TableHead> {t('cloud.colMetric')} </TableHead><TableHead> {t('monitor.logIndex')} </TableHead><TableHead> {t('common.newValue')} </TableHead><TableHead>OID</TableHead>
</TableRow>
</TableHeader>
<TableBody>
+4 -4
View File
@@ -217,10 +217,10 @@ export function SiteMonitor() {
</div>
<div className="flex gap-2">
<Button size="sm" variant="outline" className="h-8" onClick={() => { loadStats(); loadTasks(); }} disabled={refreshing}>
<RefreshCw className={`h-3.5 w-3.5 mr-1 ${refreshing ? 'animate-spin' : ''}`} />刷新
<RefreshCw className={`h-3.5 w-3.5 mr-1 ${refreshing ? 'animate-spin' : ''}`} />{t("common.refresh")}
</Button>
<Button size="sm" className="h-8 gap-1.5" onClick={() => openCreate()}>
<Plus className="h-3.5 w-3.5" />添加任务
<Plus className="h-3.5 w-3.5" />{t("common.addTask")}
</Button>
</div>
</div>
@@ -302,7 +302,7 @@ export function SiteMonitor() {
<span className="text-sm font-medium truncate">{task.name}</span>
{isSslProbeTask(task) && isSslExpiringSoon(task.ssl_days_remaining) && (
<Badge className="bg-amber-500/15 dg-text-yellow border-amber-500/30 text-[10px] shrink-0 gap-0.5">
<ShieldAlert className="h-3 w-3" />证书
<ShieldAlert className="h-3 w-3" />{t("common.certLabel")}
</Badge>
)}
</div>
@@ -321,7 +321,7 @@ export function SiteMonitor() {
<TableCell className="py-2">
<div className="flex items-center justify-end gap-0.5">
<Button variant="outline" size="sm" className="h-7 text-xs" onClick={() => openDetail(task)}>
<LineChart className="h-3 w-3 mr-1" />可观测
<LineChart className="h-3 w-3 mr-1" />{t("common.observable")}
</Button>
<Button variant="ghost" size="icon-sm" onClick={() => openEdit(task)}><Pencil className="h-3.5 w-3.5" /></Button>
<Button variant="ghost" size="icon-sm" className="dg-text-red" onClick={() => handleDelete(task)}><Trash2 className="h-3.5 w-3.5" /></Button>
@@ -94,10 +94,10 @@ export function HealthProbeSection({ selectedHost }: HealthProbeSectionProps) {
<h3 className="text-xs font-medium text-[var(--dg-text-primary)]"> {t('monitor.lbl.unlimited')} </h3>
<div className="flex gap-2">
<Button size="sm" variant="outline" className="h-7 text-[11px]" onClick={() => refetch()} disabled={isFetching}>
<RefreshCw className={cn('w-3 h-3 mr-1', isFetching && 'animate-spin')} />刷新
<RefreshCw className={cn('w-3 h-3 mr-1', isFetching && 'animate-spin')} />{t("common.refresh")}
</Button>
<Button size="sm" className="h-7 text-[11px] bg-blue-600 hover:bg-blue-500" onClick={openCreateDialog}>
<Plus className="w-3 h-3 mr-1" />添加探针
<Plus className="w-3 h-3 mr-1" />{t("common.addProbe")}
</Button>
</div>
</div>
@@ -145,8 +145,8 @@ export function HealthProbeSection({ selectedHost }: HealthProbeSectionProps) {
<span> {t('monitor.lbl.unlimited')} <span className={p.last_status === 'up' ? 'dg-text-green' : p.last_status === 'down' ? 'dg-text-red' : 'dg-text-secondary'}>
{p.last_status ? String(p.last_status).toUpperCase() : t('monitor.lbl.notDetected')}
</span></span>
{Number(p.last_latency_ms) > 0 && <span>延迟: {String(p.last_latency_ms)}ms</span>}
{Number(p.fail_count) > 0 && <span className="dg-text-red">连续失败: {String(p.fail_count)}次</span>}
{Number(p.last_latency_ms) > 0 && <span>{t('common.latency')}: {String(p.last_latency_ms)}ms</span>}
{Number(p.fail_count) > 0 && <span className="dg-text-red">{t('common.consecutiveFail')}: {String(p.fail_count)}</span>}
{p.last_checked_at && <span className="text-[10px]">{new Date(String(p.last_checked_at)).toLocaleString('zh-CN')}</span>}
</div>
</div>
@@ -10,7 +10,7 @@ export function ContextSwitchCard({ csInfo }: { csInfo: JsonData }) {
<Card className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
<CardContent className="p-4">
<h3 className="text-xs font-medium text-[var(--dg-text-primary)] mb-3 flex items-center gap-2">
<RefreshCw className="h-4 w-4 dg-text-green" />上下文切换
<RefreshCw className="h-4 w-4 dg-text-green" />{t("common.contextSwitch")}
</h3>
{csInfo?.ctx_per_sec != null ? (
<div className="space-y-4">
@@ -19,7 +19,7 @@ export function PortMonitorTab({ portInfo, portPolicyMode, portWhitelist, onOpen
<Card className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
<CardContent className="p-4">
<h3 className="text-xs font-medium text-[var(--dg-text-primary)] mb-3 flex items-center gap-2">
<Server className="h-4 w-4 dg-text-green" />监听端口 {portInfo.length}
<Server className="h-4 w-4 dg-text-green" />{t("common.listenPorts")} {portInfo.length}
<span className="ml-auto flex items-center gap-2">
{portPolicyMode === 'blacklist' && portWhitelist.length > 0 && (
<Badge variant="outline" className="text-[10px] dg-text-yellow border-amber-500/30">
@@ -10,7 +10,7 @@ export function ProcessTable({ processTop }: { processTop: JsonData[] }) {
<Card className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
<CardContent className="p-4">
<h3 className="text-xs font-medium text-[var(--dg-text-primary)] mb-3 flex items-center gap-2">
<List className="h-4 w-4 dg-text-cyan" />进程 TOP {processTop.length}
<List className="h-4 w-4 dg-text-cyan" />{t("common.processTop")} {processTop.length}
</h3>
{processTop.length === 0 ? (
<div className="text-center py-6 text-xs text-[var(--dg-text-muted)] border border-dashed border-[var(--dg-border)] rounded-lg">
@@ -125,7 +125,7 @@ export function MiddlewareDialog({ open, onOpenChange, editTarget, onSuccess }:
</div>
</div>
<div className="space-y-2">
<Label>密码 {editTarget && <span className="text-xs text-muted-foreground">(留空不修改)</span>}</Label>
<Label>{t('common.password')} {editTarget && <span className="text-xs text-muted-foreground">{t('common.passwordOptional')}</span>}</Label>
<Input type="password" value={form.password} onChange={(e) => setForm((f) => ({ ...f, password: e.target.value }))} />
</div>
{form.type === 'mysql' && (
@@ -84,12 +84,12 @@ export function MwTargetChartsPanel({ target, chartDefs, accent }: Props) {
<div className="flex items-center justify-between gap-2 mb-3 flex-wrap">
<div className="flex items-center gap-2 min-w-0">
<Activity className="h-4 w-4 text-[var(--dg-text-muted)] shrink-0" />
<h3 className="text-sm font-medium truncate">可观测 · {target.name}</h3>
<h3 className="text-sm font-medium truncate">{t('common.observable')} · {target.name}</h3>
<Badge variant="outline" className="text-[10px] shrink-0">{target.ip}:{target.port}</Badge>
{accent === 'redis' && (
<Badge variant="outline" className="text-[10px] shrink-0">{redisModeLabel(target.config_public?.redis_mode)}</Badge>
)}
<span className="text-[10px] text-[var(--dg-text-muted)] shrink-0">更新 {fmtLastSeen(target.last_seen_at)}</span>
<span className="text-[10px] text-[var(--dg-text-muted)] shrink-0">{t('common.updated')} {fmtLastSeen(target.last_seen_at)}</span>
</div>
<div className="flex items-center gap-1.5">
<Button variant="ghost" size="sm" className="h-7 text-xs" onClick={() => setShowAll((v) => !v)}>
@@ -105,7 +105,7 @@ export function MwTargetChartsPanel({ target, chartDefs, accent }: Props) {
</SelectContent>
</Select>
<Button variant="outline" size="sm" className="h-7 text-xs" onClick={loadCharts} disabled={loading}>
<RefreshCw className={`h-3 w-3 mr-1 ${loading ? 'animate-spin' : ''}`} />刷新
<RefreshCw className={`h-3 w-3 mr-1 ${loading ? 'animate-spin' : ''}`} />{t("common.refresh")}
</Button>
</div>
</div>
@@ -184,7 +184,7 @@ export function MwTargetChartsPanel({ target, chartDefs, accent }: Props) {
{loading ? (
<div className="py-10 flex items-center justify-center text-sm text-[var(--dg-text-muted)]">
<Loader2 className="h-4 w-4 animate-spin mr-2" />加载趋势...
<Loader2 className="h-4 w-4 animate-spin mr-2" />{t("common.loadTrend")}
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
@@ -16,7 +16,7 @@ export function ChartRangeHint({ label, zoomed, onReset }: Props) {
<div className="flex items-center justify-between text-[10px] text-[var(--dg-text-muted)] mt-1 px-0.5">
<span> {t('monitor.chartRangeHint.selectedRange')} <span className="text-[var(--dg-text-primary)] font-mono">{label}</span></span>
<Button type="button" variant="ghost" size="sm" className="h-6 text-[10px] px-2" onClick={onReset}>
<ZoomOut className="h-3 w-3 mr-1" />恢复全量
<ZoomOut className="h-3 w-3 mr-1" />{t("common.restoreFull")}
</Button>
</div>
);
@@ -48,7 +48,7 @@ export function SiteProtocolPieChart({ tasks }: Props) {
<div className="flex items-center gap-2 mb-2">
<PieChartIcon className="h-4 w-4 text-[var(--dg-text-muted)]" />
<h3 className="text-sm font-medium text-[var(--dg-text-primary)]"> {t('monitor.lbl.availability24h')} </h3>
<span className="text-[10px] text-[var(--dg-text-muted)]">共 {tasks.length} 个任务</span>
<span className="text-[10px] text-[var(--dg-text-muted)]">{t('common.itemsCount', { count: tasks.length })}</span>
</div>
<ResponsiveContainer width="100%" height={200}>
<PieChart>
@@ -213,7 +213,7 @@ export function SiteResultsPanel({ task, onProbed, fullPage = false }: Props) {
{!fullPage && (
<>
<Activity className="h-4 w-4 text-[var(--dg-text-muted)] shrink-0" />
<h3 className="text-sm font-medium text-[var(--dg-text-primary)] truncate">可观测 · {task.name}</h3>
<h3 className="text-sm font-medium text-[var(--dg-text-primary)] truncate">{t('common.observable')} · {task.name}</h3>
<Badge variant="outline" className="text-[10px] border-[var(--dg-border)] shrink-0">{probeType}</Badge>
</>
)}
@@ -232,7 +232,7 @@ export function SiteResultsPanel({ task, onProbed, fullPage = false }: Props) {
</SelectContent>
</Select>
<Button variant="outline" size="sm" className="h-7 text-xs" onClick={loadResults} disabled={loading}>
<RefreshCw className={`h-3 w-3 mr-1 ${loading ? 'animate-spin' : ''}`} />刷新
<RefreshCw className={`h-3 w-3 mr-1 ${loading ? 'animate-spin' : ''}`} />{t("common.refresh")}
</Button>
<Button size="sm" className="h-7 text-xs" onClick={handleProbeNow} disabled={probing}>
{probing ? <Loader2 className="h-3 w-3 mr-1 animate-spin" /> : <Zap className="h-3 w-3 mr-1" />}立即拨测
@@ -143,7 +143,7 @@ export function SnmpDeviceChartsPanel({ device, templateName }: Props) {
{loading ? (
<div className="py-12 flex items-center justify-center text-sm text-[var(--dg-text-muted)]">
<Loader2 className="h-4 w-4 animate-spin mr-2" />加载趋势...
<Loader2 className="h-4 w-4 animate-spin mr-2" />{t("common.loadTrend")}
</div>
) : charts.length === 0 ? (
<div className="py-12 text-center text-sm text-[var(--dg-text-muted)]">