refactor(i18n): U44 残余硬编码中文清零 — 终端审计状态+凭证类型+流水线阶段+时间格式+CSV导出
20 文件 ~70 处 UI 硬编码中文清零:
- credential-manager/constants.ts: 8 凭证类型 label/desc → labelKey/descKey + i18n.t()
- pipeline-run-detail/types.ts: 6 阶段 label → i18n.t('deploy.stage.*') + labelKey
- pipeline-manager/constants.ts + pipeline-editor/types.ts: 分秒 duration → i18n.t('common.duration.minSec')
- LiveMonitorDialog: 6 终端状态消息 → t()
- RdpAuditViewer: 6 RDP审计状态 → i18n.t('monitor.rdp.*')
- WorkspaceTermDialog: 2 终端连接状态 → t()
- TerminalSessionsTab: 4 时长格式+状态标签 → i18n.t()/t()
- k8s-event-utils + QueryHistoryPanel: 6 相对时间 → i18n.t('common.duration.*Ago')
- export-audit.ts: 9 CSV导出表头 → i18n.t('system.auditExport.*')
- useAuditSettings: 4 审计保留策略消息 → i18n.t('system.auditSettings.*')
- event-handler.ts: 4 AgentCLI事件消息 → i18n.t('aiops.cli.*')
- 其他 9 文件: NotifyPolicyTab/RoleFormDialog/CronJobViewDialog/TerminalOutput/shared-components/prometheus-ds/helpers/CloudServerImport/AdvancedSettingsPanel/releaseManagerHelpers
新增 75 翻译键, zh/en 7987→8059 对齐
tsc -b=0, npm build✓ (17.13s), ESLint=0/43/any=0, go build=0, 17/17 测试通过
This commit is contained in:
1 parent
bd1ccefa7f
commit
05ee051879
26 files changed
+307
-93
No files matched your search
@@ -325,7 +325,7 @@ export function CredentialManager() {
|
||||
{/* 内容 */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--dg-text-secondary)] mb-1">
|
||||
{formData.type === 'ssh_key' ? 'SSH 私钥' : formData.type === 'api_token' ? 'Token' : formData.type === 'access_key' ? 'AK/SK (每行一对,用空格或逗号分隔)' : '密码'}
|
||||
{formData.type === 'ssh_key' ? t('system.credTypeLabel.sshKey') : formData.type === 'api_token' ? t('system.credTypeLabel.apiToken') : formData.type === 'access_key' ? 'AK/SK (每行一对,用空格或逗号分隔)' : t('system.credTypeLabel.password')}
|
||||
{!editingId && <span className="dg-text-red"> *</span>}
|
||||
{editingId && <span className="text-xs text-[var(--dg-text-muted)] ml-1">{t('system.leaveBlankNoUpdate')}</span>}
|
||||
</label>
|
||||
|
||||
@@ -102,7 +102,7 @@ export function LiveMonitorDialog({ open, onOpenChange, sessionId, sessionInfo }
|
||||
setConnected(true);
|
||||
setConnectError('');
|
||||
mountXterm(term, fitAddon, () => containerRef.current);
|
||||
term.writeln('\x1b[36m[审计监控] 已连接到会话...\x1b[0m');
|
||||
term.writeln(`\x1b[36m${t('monitor.terminal.auditConnected')}\x1b[0m`);
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
@@ -112,7 +112,7 @@ export function LiveMonitorDialog({ open, onOpenChange, sessionId, sessionInfo }
|
||||
case 'session_info':
|
||||
setMeta(msg.payload);
|
||||
term.writeln(
|
||||
`\x1b[36m用户: ${msg.payload.username} 服务器: ${msg.payload.server_name} (${msg.payload.server_ip})\x1b[0m`,
|
||||
`\x1b[36m${t('monitor.terminal.userServer', { username: msg.payload.username, serverName: msg.payload.server_name, serverIp: msg.payload.server_ip })}\x1b[0m`,
|
||||
);
|
||||
break;
|
||||
case 'history':
|
||||
@@ -127,14 +127,14 @@ export function LiveMonitorDialog({ open, onOpenChange, sessionId, sessionInfo }
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = () => setConnectError('WebSocket 连接失败');
|
||||
ws.onerror = () => setConnectError(t('monitor.terminal.wsConnFailed'));
|
||||
|
||||
ws.onclose = (e) => {
|
||||
if (!didOpen) {
|
||||
setConnectError(`连接失败 (code=${e.code}): ${e.reason || '认证失败或网络问题'}`);
|
||||
setConnectError(t('monitor.terminal.connFailedCode', { code: e.code, reason: e.reason || t('monitor.terminal.authOrNetwork') }));
|
||||
}
|
||||
setConnected(false);
|
||||
term.writeln('\r\n\x1b[33m[审计监控] 连接已断开\x1b[0m');
|
||||
term.writeln(`\r\n\x1b[33m${t('monitor.terminal.auditDisconnected')}\x1b[0m`);
|
||||
};
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
@@ -153,6 +153,7 @@ export function LiveMonitorDialog({ open, onOpenChange, sessionId, sessionInfo }
|
||||
wsRef.current = null;
|
||||
setConnected(false);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open, sessionId]);
|
||||
|
||||
// 容器尺寸变化时持续 fit // Logan.Li
|
||||
|
||||
@@ -126,7 +126,7 @@ export function RdpAuditViewer({ open, onOpenChange, sessionId, mode }: RdpAudit
|
||||
|
||||
useEffect(() => {
|
||||
if (!open || !sessionId) return;
|
||||
setStatus(mode === 'live' ? '正在连接 RDP 实时审计...' : '正在加载 RDP 录屏...');
|
||||
setStatus(mode === 'live' ? i18n.t('monitor.rdp.connectingLive') : i18n.t('monitor.rdp.loadingRecording'));
|
||||
setLoading(true);
|
||||
setFrames([]);
|
||||
setIndex(0);
|
||||
@@ -161,8 +161,8 @@ export function RdpAuditViewer({ open, onOpenChange, sessionId, mode }: RdpAudit
|
||||
/* ignore */
|
||||
}
|
||||
};
|
||||
ws.onerror = () => { setLoading(false); setStatus('RDP 实时审计连接失败'); };
|
||||
ws.onclose = () => setStatus((prev) => prev || 'RDP 实时审计已断开');
|
||||
ws.onerror = () => { setLoading(false); setStatus(i18n.t('monitor.rdp.liveConnFailed')); };
|
||||
ws.onclose = () => setStatus((prev) => prev || i18n.t('monitor.rdp.liveDisconnected'));
|
||||
return () => {
|
||||
ws.close();
|
||||
wsRef.current = null;
|
||||
@@ -182,13 +182,13 @@ export function RdpAuditViewer({ open, onOpenChange, sessionId, mode }: RdpAudit
|
||||
setCanvasSize({ width: sizeFrame.width, height: sizeFrame.height });
|
||||
}
|
||||
setFrames(list);
|
||||
setStatus(list.length ? '' : '该 RDP 会话没有可播放画面帧');
|
||||
setStatus(list.length ? '' : i18n.t('monitor.rdp.noFrames'));
|
||||
setPlaying(list.length > 0);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) {
|
||||
setStatus('RDP 录屏加载失败');
|
||||
setStatus(i18n.t('monitor.rdp.loadFailed'));
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -45,7 +45,7 @@ const MODULE_GROUPS: { key: string; label: string; prefixes: string[] }[] = [
|
||||
{ key: 'deploy', label: i18n.t('common.menuApp'), prefixes: ['deploy:'] },
|
||||
{ key: 'monitor', label: i18n.t('common.menuMonitoring'), prefixes: ['monitor:', 'agent:'] },
|
||||
{ key: 'auto', label: i18n.t('common.menuAutomation'), prefixes: ['auto:'] },
|
||||
{ key: 'aiops', label: '🤖 AIOps智能', prefixes: ['aiops:'] },
|
||||
{ key: 'aiops', label: i18n.t('system.role.aiopsGroup'), prefixes: ['aiops:'] },
|
||||
{ key: 'approval', label: i18n.t('common.menuApproval'), prefixes: ['approval:'] },
|
||||
{ key: 'audit', label: i18n.t('common.menuAudit'), prefixes: ['audit:'] },
|
||||
{ key: 'system', label: i18n.t('common.menuSystem'), prefixes: ['system:'] },
|
||||
|
||||
@@ -17,16 +17,17 @@ import { useTerminalSessions, useTerminalSessionMutations } from '@/hooks/api/us
|
||||
import { useConfirm } from '@/components/ui/confirm-dialog';
|
||||
import { ReplayDialog } from './ReplayDialog';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import i18n from '@/i18n';
|
||||
|
||||
function formatDuration(sec: number): string {
|
||||
if (!sec || sec < 0) return '--';
|
||||
if (sec < 60) return `${sec}秒`;
|
||||
if (sec < 60) return i18n.t('common.duration.seconds', { count: sec });
|
||||
const m = Math.floor(sec / 60);
|
||||
const s = sec % 60;
|
||||
if (m < 60) return `${m}分${s > 0 ? `${s}秒` : ''}`;
|
||||
if (m < 60) return s > 0 ? i18n.t('common.duration.minSec', { m, s }) : i18n.t('common.duration.min', { m });
|
||||
const h = Math.floor(m / 60);
|
||||
const rm = m % 60;
|
||||
return `${h}时${rm > 0 ? `${rm}分` : ''}`;
|
||||
return rm > 0 ? i18n.t('common.duration.hoursMin', { h, m: rm }) : i18n.t('common.duration.hour', { count: h });
|
||||
}
|
||||
|
||||
function formatSize(bytes: number): string {
|
||||
@@ -170,7 +171,7 @@ export function TerminalSessionsTab() {
|
||||
}
|
||||
onClick={() => setStatusFilter(st)}
|
||||
>
|
||||
{st === '' ? '全部' : st === 'active' ? '活动中' : st === 'closed' ? '已关闭' : '失败'}
|
||||
{st === '' ? t('system.terminalSession.all') : st === 'active' ? t('system.terminalSession.active') : st === 'closed' ? t('system.terminalSession.closed') : t('system.terminalSession.failed')}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -24,14 +24,14 @@ function escapeCsv(s: string): string {
|
||||
export function exportAuditReportCsv(meta: ReplaySessionMeta, commands: CommandBookmark[]) {
|
||||
const lines: string[] = [
|
||||
i18n.t('audit.reportTitle'),
|
||||
`会话ID,${meta.id}`,
|
||||
`用户,${escapeCsv(meta.username || '')}`,
|
||||
`目标主机,${escapeCsv(meta.server_name || '')}`,
|
||||
`${i18n.t('system.auditExport.sessionId')},${meta.id}`,
|
||||
`${i18n.t('system.auditExport.user')},${escapeCsv(meta.username || '')}`,
|
||||
`${i18n.t('system.auditExport.targetHost')},${escapeCsv(meta.server_name || '')}`,
|
||||
`IP,${meta.server_ip}:${meta.server_port}`,
|
||||
`客户端IP,${meta.client_ip || ''}`,
|
||||
`开始时间,${meta.start_time || ''}`,
|
||||
`时长(秒),${meta.duration || 0}`,
|
||||
`录制大小,${meta.record_size || 0}`,
|
||||
`${i18n.t('system.auditExport.clientIp')},${meta.client_ip || ''}`,
|
||||
`${i18n.t('system.auditExport.startTime')},${meta.start_time || ''}`,
|
||||
`${i18n.t('system.auditExport.duration')},${meta.duration || 0}`,
|
||||
`${i18n.t('system.auditExport.status')},${meta.record_size || 0}`,
|
||||
'',
|
||||
i18n.t('audit.reportTitle'),
|
||||
];
|
||||
|
||||
@@ -107,8 +107,8 @@ export function useAuditSettings() {
|
||||
const total = res.cleanup?.total ?? 0;
|
||||
toast.success(
|
||||
total > 0
|
||||
? `已应用 ${days} 天保留策略,立即清理 ${total} 条超期记录`
|
||||
: `已应用 ${days} 天保留策略,暂无超期记录需清理`,
|
||||
? i18n.t('system.auditSettings.appliedWithCleanup', { days, total })
|
||||
: i18n.t('system.auditSettings.appliedNoCleanup', { days }),
|
||||
);
|
||||
} catch (e: unknown) {
|
||||
toast.error(
|
||||
@@ -131,16 +131,13 @@ export function useAuditSettings() {
|
||||
total?: number;
|
||||
};
|
||||
if (typeof s.total === "number") {
|
||||
detail =
|
||||
s.total > 0
|
||||
? `,清理 ${s.total} 条`
|
||||
: i18n.t("system.auditSetting.noExpiredRecords");
|
||||
detail = s.total > 0 ? i18n.t('system.auditSettings.cleanupCount', { count: s.total }) : i18n.t("system.auditSetting.noExpiredRecords");
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return `上次清理:${t}${detail}`;
|
||||
return i18n.t('system.auditSettings.lastCleanup', { time: t, detail });
|
||||
})();
|
||||
|
||||
return {
|
||||
|
||||
Reference in new issue
Block a user