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

@@ -59,20 +59,20 @@ export const MYSQL_PRIMARY_KEYS = ['mysql_qps', 'mysql_connections', 'mysql_buff
export const REDIS_CHARTS: MwChartDef[] = [
{ key: 'redis_qps', label: 'QPS', color: 'var(--dg-blue)', unit: 'ops/s' },
{ key: 'redis_used_memory', label: i18n.t('内存占用'), color: 'var(--dg-red)', formatter: fmtMemory },
{ key: 'redis_used_memory', label: i18n.t('monitor.lbl.mwMemUsage'), color: 'var(--dg-red)', formatter: fmtMemory },
{ key: 'redis_hit_rate', label: i18n.t('monitor.lbl.hitRate'), color: 'var(--dg-green)', percent: true },
{ key: 'redis_connected_clients', label: i18n.t('kubernetes.topology.connections'), color: 'var(--dg-cyan)' },
{ key: 'redis_db_size', label: i18n.t('慢查询速率'), color: 'var(--dg-purple)' },
{ key: 'redis_blocked_clients', label: i18n.t('阻塞客户端'), color: 'var(--dg-orange)' },
{ key: 'redis_db_size', label: i18n.t('monitor.lbl.mwSlowQueryRate'), color: 'var(--dg-purple)' },
{ key: 'redis_blocked_clients', label: i18n.t('monitor.lbl.mwBlockedClients'), color: 'var(--dg-orange)' },
];
export const MYSQL_CHARTS: MwChartDef[] = [
{ key: 'mysql_qps', label: 'QPS', color: 'var(--dg-blue)', unit: 'q/s' },
{ key: 'mysql_connections', label: i18n.t('kubernetes.topology.connections'), color: 'var(--dg-cyan)' },
{ key: 'mysql_threads_running', label: i18n.t('活跃线程'), color: 'var(--dg-purple)' },
{ key: 'mysql_buffer_hit_rate', label: i18n.t('缓冲池命中率'), color: 'var(--dg-green)', percent: true },
{ key: 'mysql_slow_queries', label: i18n.t('慢查询速率'), color: 'var(--dg-orange)', unit: i18n.t('次/周期'), counterDelta: true },
{ key: 'mysql_bytes_sent', label: i18n.t('缓冲池命中率'), color: 'var(--dg-amber)', formatter: fmtMemory },
{ key: 'mysql_threads_running', label: i18n.t('monitor.lbl.mwActiveThreads'), color: 'var(--dg-purple)' },
{ key: 'mysql_buffer_hit_rate', label: i18n.t('monitor.lbl.mwBufferHitRate'), color: 'var(--dg-green)', percent: true },
{ key: 'mysql_slow_queries', label: i18n.t('monitor.lbl.mwSlowQueryRate'), color: 'var(--dg-orange)', unit: i18n.t('monitor.lbl.mwPerCycle'), counterDelta: true },
{ key: 'mysql_bytes_sent', label: i18n.t('monitor.lbl.mwBufferHitRate'), color: 'var(--dg-amber)', formatter: fmtMemory },
];
export function fmtMemory(bytes: number): string {
@@ -139,7 +139,7 @@ export function statusBg(status: string): string {
}
export function redisModeLabel(mode?: string): string {
return mode === 'cluster' ? i18n.t('k8s.topology.typeCluster') : i18n.t('集群');
return mode === 'cluster' ? i18n.t('k8s.topology.typeCluster') : i18n.t('monitor.lbl.mwCluster');
}
export function redisMemoryPct(metrics: Record<string, number>): number | null {
@@ -209,27 +209,27 @@ export function evalMwHealth(target: MwTarget): MwHealthIssue[] {
const m = target.latest_metrics || {};
const issues: MwHealthIssue[] = [];
if (target.status !== 'online') {
issues.push({ level: 'crit', message: i18n.t('实例离线') });
issues.push({ level: 'crit', message: i18n.t('monitor.lbl.mwInstanceOffline') });
return issues;
}
if (target.description === 'redis') {
if (m.redis_hit_rate > 0 && m.redis_hit_rate < 0.8) issues.push({ level: 'crit', message: i18n.t('命中率 < 80%') });
else if (m.redis_hit_rate > 0 && m.redis_hit_rate < 0.9) issues.push({ level: 'warn', message: i18n.t('命中率 < 90%') });
if (m.redis_hit_rate > 0 && m.redis_hit_rate < 0.8) issues.push({ level: 'crit', message: i18n.t('monitor.lbl.mwHitRateBelow80') });
else if (m.redis_hit_rate > 0 && m.redis_hit_rate < 0.9) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwHitRateBelow90') });
const memPct = redisMemoryPct(m);
if (memPct != null && memPct > 90) issues.push({ level: 'crit', message: i18n.t('内存 > 90%') });
else if (memPct != null && memPct > 80) issues.push({ level: 'warn', message: i18n.t('内存 > 80%') });
if (m.redis_blocked_clients > 0) issues.push({ level: 'warn', message: i18n.t('阻塞客户端') });
if (m.redis_evicted_keys > 0) issues.push({ level: 'warn', message: i18n.t('Key 逐出') });
if (memPct != null && memPct > 90) issues.push({ level: 'crit', message: i18n.t('monitor.lbl.mwMemAbove90') });
else if (memPct != null && memPct > 80) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwMemAbove80') });
if (m.redis_blocked_clients > 0) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwBlockedClients') });
if (m.redis_evicted_keys > 0) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwKeyEviction') });
} else if (target.description === 'mysql') {
if (m.mysql_buffer_hit_rate > 0 && m.mysql_buffer_hit_rate < 0.9) {
issues.push({ level: 'crit', message: i18n.t('缓冲池命中 < 90%') });
issues.push({ level: 'crit', message: i18n.t('monitor.lbl.mwBufferHitBelow90') });
} else if (m.mysql_buffer_hit_rate > 0 && m.mysql_buffer_hit_rate < 0.95) {
issues.push({ level: 'warn', message: i18n.t('缓冲池命中 < 95%') });
issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwBufferHitBelow95') });
}
const connPct = mysqlConnPct(m);
if (connPct != null && connPct > 90) issues.push({ level: 'crit', message: i18n.t('连接 > 90% 上限') });
else if (connPct != null && connPct > 80) issues.push({ level: 'warn', message: i18n.t('连接 > 80% 上限') });
if (m.mysql_threads_running > 20) issues.push({ level: 'warn', message: i18n.t('活跃线程偏多') });
if (connPct != null && connPct > 90) issues.push({ level: 'crit', message: i18n.t('monitor.lbl.mwConnAbove90') });
else if (connPct != null && connPct > 80) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwConnAbove80') });
if (m.mysql_threads_running > 20) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwTooManyThreads') });
}
return issues;
}
@@ -57,10 +57,10 @@ export const SITE_TIME_RANGE_HOURS: Record<SiteTimeRange, number> = {
};
export const SITE_TIME_RANGE_LABELS: Record<SiteTimeRange, string> = {
'1h': i18n.t('近 1 小时'),
'1h': i18n.t('monitor.lbl.siteRecentHour'),
'6h': i18n.t('monitor.siteProtocol.rangeDefault'),
'24h': i18n.t('近 24 小时'),
'7d': i18n.t('近 7 天'),
'24h': i18n.t('monitor.lbl.siteRecent24h'),
'7d': i18n.t('monitor.lbl.siteRecent7d'),
};
/** 各协议推荐默认拨测间隔(秒)// Logan.Li */
@@ -86,11 +86,11 @@ export function defaultProbeFrequency(type: ProbeType): number {
}
export const probeTypeMeta: Record<ProbeType, { label: string; placeholder: string; hint: string }> = {
HTTP: { label: i18n.t('目标 URL'), placeholder: 'https://example.com/health', hint: i18n.t('Web 请求(支持 http/https),检测状态码与响应时间') },
SSL: { label: i18n.t('SSL 地址'), placeholder: i18n.t('example.com:443 或 https://example.com'), hint: i18n.t('TLS 握手检测证书(支持 host:port / https:// 域名,不发起 HTTP 请求)') },
TCP: { label: i18n.t('主机:端口'), placeholder: i18n.t('192.168.1.1:8080 或 example.com:443'), hint: i18n.t('TCP 端口连通性') },
HTTP: { label: i18n.t('monitor.lbl.siteTargetUrl'), placeholder: 'https://example.com/health', hint: i18n.t('monitor.lbl.siteHttpHint') },
SSL: { label: i18n.t('monitor.lbl.siteSslAddr'), placeholder: i18n.t('monitor.lbl.siteSslPlaceholder'), hint: i18n.t('monitor.lbl.siteSslHint') },
TCP: { label: i18n.t('monitor.lbl.siteHostPort'), placeholder: i18n.t('monitor.lbl.siteTcpPlaceholder'), hint: i18n.t('monitor.lbl.siteTcpHint') },
DNS: { label: i18n.t('cloud.domainName'), placeholder: 'example.com', hint: i18n.t('monitor.helpersts.sd3fd8f1d') },
PING: { label: i18n.t('主机地址'), placeholder: i18n.t('192.168.1.1 或 example.com'), hint: i18n.t('ICMP 连通性与延迟(默认 2 分钟/次)') },
PING: { label: i18n.t('monitor.lbl.siteHostAddr'), placeholder: i18n.t('monitor.lbl.sitePingPlaceholder'), hint: i18n.t('monitor.lbl.sitePingHint') },
};
export function probeFrequencyHint(type: ProbeType): string {
@@ -93,16 +93,16 @@ export function analyzeHttpResults(results: SiteResult[], task: SiteTask): HttpO
}
if (code >= 500) {
err5xx++;
pushEvent(events, r, `HTTP ${code}`, 'error', r.error_message || i18n.t('服务端错误'));
pushEvent(events, r, `HTTP ${code}`, 'error', r.error_message || i18n.t('monitor.lbl.siteServerError'));
} else if (code >= 400) {
err4xx++;
pushEvent(events, r, `HTTP ${code}`, 'warn', r.error_message || i18n.t('客户端/鉴权错误'));
pushEvent(events, r, `HTTP ${code}`, 'warn', r.error_message || i18n.t('monitor.lbl.siteClientError'));
} else if (r.status === 'timeout') {
otherErr++;
pushEvent(events, r, i18n.t('common.timeoutError'), 'error', r.error_message);
} else {
otherErr++;
pushEvent(events, r, code > 0 ? `HTTP ${code}` : i18n.t('请求失败'), 'error', r.error_message);
pushEvent(events, r, code > 0 ? `HTTP ${code}` : i18n.t('monitor.lbl.siteRequestFailed'), 'error', r.error_message);
}
}
const latest = results[0];
@@ -128,7 +128,7 @@ export function analyzeSslResults(results: SiteResult[], task: SiteTask): SslObs
const events: ProbeEvent[] = [];
for (const r of results) {
if (r.status !== 'success') {
pushEvent(events, r, i18n.t('请求超时'), 'error', r.error_message);
pushEvent(events, r, i18n.t('monitor.lbl.siteRequestTimeout'), 'error', r.error_message);
} else if (r.ssl_days_remaining != null && r.ssl_days_remaining < 30) {
pushEvent(events, r, `证书剩余 ${r.ssl_days_remaining} 天`, r.ssl_days_remaining <= 7 ? 'error' : 'warn', expiry);
}
@@ -186,7 +186,7 @@ export function analyzeTcpResults(results: SiteResult[]): ConnectivityObsSummary
const failed = r.status !== 'success';
if (failed) {
lastFailAt = r.checked_at;
pushEvent(events, r, i18n.t('连接失败'), 'error', r.error_message || i18n.t('aiops.llmTestFailed'));
pushEvent(events, r, i18n.t('monitor.lbl.siteConnFailed'), 'error', r.error_message || i18n.t('aiops.llmTestFailed'));
}
return { time: fmtTime(r.checked_at).slice(-5), up: failed ? 0 : 100, failed };
});