refactor(i18n): U28 多模块 phantom key 清零 — theme/middleware-monitor/site-monitor/analytics/cost-predict/predict-types/agentAlertHelper/export-audit/AgentCLIMessages/copy-button 10 文件 74 phantom key → 语义化键, 新增 4 命名空间 (theme/agent.alerts.metric*/audit.*) + 扩展 3 命名空间 (monitor.lbl.mw*/site*/aiops.predict*), zh/en 7294→7358 +64 键对齐, phantom key 103→29 (残留全为 JSX 模板表达式/ANSI 转义码误匹配), tsc -b=0, npm build✓ (17.40s), ESLint=0/53/0, go build=0, 17/17 测试通过

This commit is contained in:
attacker committed 2026-07-12 05:18:52 +08:00
1 parent b812b3b20c
commit b2715ca3bd
12 files changed
+206 -74

No files matched your search

@@ -13,12 +13,12 @@ export const METRIC_OPTIONS = [
{ value: 'cpu_iowait', label: i18n.t('agent.alertHelper.netInBps'), icon: Cpu },
{ value: 'mem', label: i18n.t('kubernetes.cluster.memoryUsage'), icon: MemoryStick },
{ value: 'mem_available', label: i18n.t('agent.alertHelper.memAvailable'), icon: MemoryStick },
{ value: 'swap', label: i18n.t('Swap 使用率'), icon: MemoryStick },
{ value: 'load1', label: i18n.t('1分钟负载'), icon: Gauge },
{ value: 'swap', label: i18n.t('agent.alerts.metricSwap'), icon: MemoryStick },
{ value: 'load1', label: i18n.t('agent.alerts.metricLoad1'), icon: Gauge },
{ value: 'disk', label: i18n.t('monitor.hostDisk'), icon: HardDrive },
{ value: 'disk_inode', label: i18n.t('Inode 使用率'), icon: HardDrive },
{ value: 'disk_inode', label: i18n.t('agent.alerts.metricInode'), icon: HardDrive },
{ value: 'disk_io_util', label: i18n.t('agent.alertHelper.diskIOUtil'), icon: HardDrive },
{ value: 'tcp_established', label: i18n.t('TCP 已建立'), icon: Network },
{ value: 'tcp_established', label: i18n.t('agent.alerts.metricTcpEst'), 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 },
@@ -253,7 +253,7 @@ export function MessageView({ item, inRoundGroup = false }: { item: ChatItem; in
return (
<div className="flex gap-2 rounded-lg bg-red-500/10 border border-red-500/30 p-3">
<AlertTriangle className="w-5 h-5 dg-text-red shrink-0 mt-0.5" />
<div className="text-sm text-[var(--dg-text-primary)] whitespace-pre-wrap">{item.content || i18n.t('发生错误')}</div>
<div className="text-sm text-[var(--dg-text-primary)] whitespace-pre-wrap">{item.content || i18n.t('aiops.agentCliErrorOccurred')}</div>
</div>
);
}
@@ -309,10 +309,10 @@ function ToolBlock({ item, inRoundGroup }: { item: ChatItem; inRoundGroup?: bool
{item.duration && <div className="text-[10px] dg-text-muted">{i18n.t('aiops.durationLabel', { duration: item.duration })}</div>}
{(item.toolName === 'analyze_output' || looksLikeMarkdown(item.output)) ? (
<div className="bg-[var(--dg-bg-primary)]/40 rounded px-2 py-1.5 max-h-80 overflow-y-auto">
<AgentMarkdown content={item.output || i18n.t('(无输出)')} />
<AgentMarkdown content={item.output || i18n.t('aiops.agentCliNoOutput')} />
</div>
) : (
<pre className="text-xs text-[var(--dg-text-secondary)] bg-[var(--dg-bg-primary)]/40 rounded px-2 py-1.5 overflow-x-auto max-h-80 whitespace-pre-wrap">{item.output || i18n.t('(无输出)')}</pre>
<pre className="text-xs text-[var(--dg-text-secondary)] bg-[var(--dg-bg-primary)]/40 rounded px-2 py-1.5 overflow-x-auto max-h-80 whitespace-pre-wrap">{item.output || i18n.t('aiops.agentCliNoOutput')}</pre>
)}
</>
)}
@@ -83,15 +83,15 @@ function costTrendFromSlope(slope: number): 'up' | 'down' | 'stable' {
/** 成本优化建议 */
export function costRecommendation(trend: 'up' | 'down' | 'stable', ratio: number): string {
if (trend === 'up' && ratio >= 0.85) {
return i18n.t('排查内存泄漏,优化进程内存配置,考虑增加节点');
return i18n.t('aiops.predictMemLeak');
}
if (trend === 'up') {
return i18n.t('排查内存泄漏,优化进程内存配置,考虑增加节点');
return i18n.t('aiops.predictMemLeak');
}
if (trend === 'down') {
return i18n.t('排查内存泄漏,优化进程内存配置,考虑增加节点');
return i18n.t('aiops.predictMemLeak');
}
return i18n.t('你是 AIOps 容量规划专家。基于以下服务器资源容量预测数据,给出综合风险评估与可执行的运维建议:');
return i18n.t('aiops.predictutilsts.sa3b5c7d9');
}
/** 预算风险建议 */
@@ -256,7 +256,7 @@ export function computeCostPredictions(input: ComputeCostPredictionsInput): Comp
const allRatio =
summary.predictedMonthEnd > 0 ? summary.monthCost / summary.predictedMonthEnd : 0;
dimensionForecasts.push({
dimension: i18n.t('清理历史数据和日志,实施数据归档策略,扩容磁盘'),
dimension: i18n.t('aiops.predictDiskFull'),
currentMonth: summary.monthCost,
predictedMonthEnd: summary.predictedMonthEnd,
dailyAvg: summary.dailyAvg,
@@ -302,7 +302,7 @@ export function computeCostPredictions(input: ComputeCostPredictionsInput): Comp
const metric = (rule.metric === 'daily' ? 'daily' : 'monthly') as 'daily' | 'monthly';
const ruleProvider = String(rule.provider || '');
const providerLabel = ruleProvider ? PROVIDER_LABELS[ruleProvider] || ruleProvider : i18n.t('24小时后');
const providerLabel = ruleProvider ? PROVIDER_LABELS[ruleProvider] || ruleProvider : i18n.t('aiops.predictIn24h');
let current = 0;
let predicted = 0;
@@ -339,7 +339,7 @@ export function computeCostPredictions(input: ComputeCostPredictionsInput): Comp
if (current >= threshold) probability += 25;
probability = Math.max(5, Math.min(92, probability));
let timeframe = metric === 'daily' ? i18n.t('未来24小时') : i18n.t('aiops.predictutilsts.sd4e5f6g7');
let timeframe = metric === 'daily' ? i18n.t('aiops.predictNext24h') : i18n.t('aiops.predictutilsts.sd4e5f6g7');
if (slope > 0.01 && threshold > current) {
const days = (threshold - current) / slope;
if (days < 1) timeframe = metric === 'daily' ? i18n.t('aiops.predictutilsts.se5f6g7h8') : i18n.t('aiops.predictutilsts.sf6g7h8i9');
@@ -120,16 +120,16 @@ export interface ComputeCostPredictionsInput {
/** 指标定义:后端 metric name → 展示标签 / 告警表达式前缀 / 阈值 */
export const METRIC_DEFS = [
{ key: 'cpu', label: i18n.t('CPU使用率'), exprKey: 'cpu_usage', threshold: 85 },
{ key: 'cpu', label: i18n.t('aiops.predictCpuUsage'), exprKey: 'cpu_usage', threshold: 85 },
{ key: 'memory', label: i18n.t('aiops.predictTypes.memUsage'), exprKey: 'memory_usage', threshold: 85 },
{ key: 'disk', label: i18n.t('aiops.predictTypes.diskUsage'), exprKey: 'disk_usage', threshold: 90 },
] as const;
export const TIME_RANGE_LABELS: Record<string, string> = {
'1h': i18n.t('1小时后'),
'24h': i18n.t('24小时后'),
'7d': i18n.t('7天后'),
'30d': i18n.t('30天后'),
'1h': i18n.t('aiops.predictIn1h'),
'24h': i18n.t('aiops.predictIn24h'),
'7d': i18n.t('aiops.predictIn7d'),
'30d': i18n.t('aiops.predictIn30d'),
};
export const TIME_RANGE_HOURS: Record<string, number> = {
@@ -23,7 +23,7 @@ function escapeCsv(s: string): string {
// exportAuditReportCsv 导出会话审计报告 CSV // Logan.Li
export function exportAuditReportCsv(meta: ReplaySessionMeta, commands: CommandBookmark[]) {
const lines: string[] = [
i18n.t('# 终端会话审计报告'),
i18n.t('audit.reportTitle'),
`会话ID,${meta.id}`,
`用户,${escapeCsv(meta.username || '')}`,
`目标主机,${escapeCsv(meta.server_name || '')}`,
@@ -33,7 +33,7 @@ export function exportAuditReportCsv(meta: ReplaySessionMeta, commands: CommandB
`时长(秒),${meta.duration || 0}`,
`录制大小,${meta.record_size || 0}`,
'',
i18n.t('# 终端会话审计报告'),
i18n.t('audit.reportTitle'),
];
for (const c of commands) {
lines.push(`${c.label},${escapeCsv(c.command)},${c.highRisk ? '是' : '否'}`);
@@ -55,7 +55,7 @@ export interface CommandExportRow {
// exportCommandsListCsv 导出命令列表 CSV // Logan.Li
export function exportCommandsListCsv(commands: CommandExportRow[]) {
const lines: string[] = [i18n.t('时间,用户,命令,输出大小,会话ID,高危')];
const lines: string[] = [i18n.t('audit.csvHeader')];
for (const c of commands) {
const ts = c.timestamp || c.created_at || '';
const highRisk = isHighRiskCommand(c.command || '');
+1 -1
View File
@@ -42,7 +42,7 @@ export function CopyButton({
} else {
toast({
title: i18n.t('monitor.logPanel.copyFailed'),
description: i18n.t('请手动选中内容后复制'),
description: i18n.t('common.copyManually'),
variant: 'destructive',
});
}