diff --git a/ROADMAP.md b/ROADMAP.md index 5384e6b..46981c5 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -530,6 +530,7 @@ services/api.ts (1324L) | U40 | Monitor + Agent 子组件残余硬编码中文 i18n 补全(14 文件 ~50 处→0: ContextSwitchCard CTX/IRQ/次 + ProcessTable agentWaitData/cpuUsagePercent + FDUsageCard fdHandles + PortMonitorTab 黑名单/白名单/策略配置/暂无端口数据 + PortPolicyDialog 白名单全量上报/黑名单仅上报选中/端口列表/逗号分隔/白名单无需配置/已输入端口 + HostTimeRangePicker 时间范围/自定义/取消/应用 + DualLineChart 接收/发送 (i18n.t→useTranslation hook) + ZoomableAreaChart 暂无数据 + SiteResultsPanel 选择任务/次/可用率/立即拨测/SSL证书预警/到期/剩余/阈值/天 + MiddlewareMonitor Redis单机集群/上次更新/添加平台默认/暂无实例 + SiteMonitor subtitle + SNMPMonitor 标题/采集间隔/IP地址/OID模板/SNMP版本/确认/暂无设备/采集指标/暂无指标 + HealthProbeSection TCP目标地址/TCP端口 + AgentAlerts Agent告警/刷新/未恢复/已恢复/恢复/新建规则/创建第一条规则 — 新增 monitor.lbl 46 语义化翻译键 + agent.alerts 6 键, zh/en 7762→7814 对齐;tsc -b=0, npm build✓ (16.88s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** | | U41 | i18n 残余硬编码中文清零 — 工具函数 + 审计RDP标签 + AIOps分析 + Monitor残余 + 审批选项(18 文件 ~35 处→0: agent-utils.ts timeAgo 秒前/分钟前/小时前 + utils.ts formatDistanceToNow 分钟前/小时前/天前 + request.ts 响应解析失败 + ActiveSessionsPanel RDP在线会话 + HistorySessionsPanel RDP历史会话/RDP会话共N条 + MetricsExplorer 清除/已选/最近1小时 + HostMonitor 当前主机 + AIAnalysisResult 证据链(useTranslation hook) + capacity-predict.ts 容量预测摘要模板 + ApprovalResourcePage 阿里云/腾讯云/华为云 + ApprovalPermissionPage 堡垒机 + site-monitor/helpers.ts 推荐频率/秒/分钟/小时/天 + site-monitor/analytics.ts 证书剩余/失败/延迟波动 + middleware-monitor/MwTargetChartsPanel 选择实例/已用/集群节点/慢查询 + MwTrendChart 暂无趋势数据 + middleware-monitor/helpers.ts 相对时间 + snmp-monitor/SnmpMetricTrendChart 暂无趋势数据等待采集 + SnmpDeviceChartsPanel 点击设备/可观测/刷新/暂无指标 + host-monitor/utils.ts 图表点数 + PortPolicyDialog 系统进程端口说明 — 新增 common.duration.secAgo/hourAgo/dayAgo + common.selected/responseParseError/rdpActiveSessions/rdpHistorySessions/rdpSessionCount/evidenceChain/last1Hour/currentHost + monitor.lbl 10键 + monitor.siteMonitor 8键 + approval.provider 3键 + approval.permType 1键 + monitor.portPolicyDialog.systemProcessDesc + aiops.capacity.summary 共 34 翻译键, zh/en 7813→7847 对齐;tsc -b=0, npm build✓ (17.31s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** | | U43 | i18n 深度残余硬编码中文 UI 文本清零 — 趋势标签 + K8s 卡片标题 + data-table 默认值 + 趋势文本 + 卡片描述(17 文件 ~40 处→0: AIPredictiveAnalytics 上升/下降/平稳 + PredictiveCostTab 上升/下降/平稳×2 + 当前/阈值/预测 + PredictiveCapacityTab 容量规划预警 + data-table.tsx 搜索.../暂无数据默认值(useTranslation hook) + PodMiscCard Pod 级别 + PodSecurityCard Pod 安全上下文 + HostSettingsCard 4 个主机命名空间描述 + PodInstancesTable Pod 实例 + PodDetailDialog Pod 详情 + HostDetailDialog 指标趋势/端口发现/远程命令/关闭 + DeploymentEditContainers manifest 提示/镜像拉取凭证 + DeploymentEditStorage 数据卷/空状态/挂载/只读/读写 + ClusterOverviewPage 管理全部 + ResourceVisualEditor 新建/编辑 + AgentMonitor 在...上执行命令 + 7 个 K8s 页面刷新按钮(PodMetrics/Capacity/Events/NamespaceResource/NamespaceMgmt/ClusterOverview/KubernetesNodes) + BillingRecord/BillingRuleDialog 保存成功 toast/保存按钮 — 新增 common 30 语义化翻译键(trendUp/trendDown/trendStable/executeOn/podLevel/podSecurityContext/hostNetworkDesc/hostIPCDesk/hostPIDDesk/shareProcessNamespaceDesc/podInstances/podDetail/metricTrend/portDiscovery/remoteCommand/searchPlaceholder/imagePullSecrets/noManifestHint/volumeDefinition/noVolumeHint/mountToContainers/readOnly/readWrite/manageAll/createNew/saveSuccess), zh/en 7898→7928 对齐;tsc -b=0, npm build✓ (16.55s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** | +| U44 | i18n 残余硬编码中文清零 — 终端审计状态 + 凭证类型 + 流水线阶段 + 时间格式 + CSV 导出(20 文件 ~70 处→0: 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 3 相对时间 → i18n.t('common.duration.*Ago') + QueryHistoryPanel 3 相对时间 → 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.*') + NotifyPolicyTab 默认平台名 → i18n.t('monitor.notify.defaultPlatform') + RoleFormDialog AIOps智能分组 → i18n.t('system.role.aiopsGroup') + CronJobViewDialog 关联脚本/无命令内容 → t() + TerminalOutput 无输出 → i18n.t('task.terminal.noOutput') + shared-components 内存标签 → i18n.t('k8s.workloadView.memoryLabel') + prometheus-ds/helpers 连接成功 → i18n.t('monitor.prometheus.connSuccess') + CloudServerImport 发现主机失败 → t() + AdvancedSettingsPanel Job名称 → t('deploy.jobName') + releaseManagerHelpers 4 环境标签硬编码中文移除(已有ENV_LABEL_KEY) — 新增 75 翻译键 (deploy.credType 8+credTypeDesc 8+fmtDuration 1+terminal 2+jobName 1, monitor.terminal 6+rdp 6+notify 1+prometheus 1, deploy.terminal 2, common.duration 2, system.terminalSession 4+csvHeader 7+auditExport 9+auditSettings 4+credTypeLabel 3+role 1, task.cronJob 2+terminal 1, k8s.workloadView 1, aiops.cli 5, server.import 1), zh/en 7987→8059 +72 对齐;tsc -b=0, npm build✓ (17.13s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** | | U42 | i18n 残余硬编码中文彻底清零 — 全量 JSX children + toast/confirm + sr-only 描述(33 文件 54 处→0: PredictiveCapacityTab AI深度解读/紧急/警告/7天使用率预测/预计N天/后达到阈值/AI建议 + PredictiveCostTab AI深度解读 + event-handler.ts 高危操作确认 toast + DeployCredentials 启用/禁用 + DeployRBAC 删除角色 confirm + WorkspaceTermDialog 标题 + CredFormDialog Windows用户 + ClusterOverviewPage 核 + DeploymentEditContainers Pod级别 + DeploymentEditService 无selector/个关联/Ingresses应用路由/暂无Service/暂无Ingress/自动高亮 + DeploymentEditStorage 无容器 + KubectlTerminal sr-only + KubernetesClusterDialog 已配置 + ResourceVisualEditor YAML编辑 + CreateHPADialog CPU目标 + UpdateStrategyCard maxSurge/maxUnavailable/revisionHistoryLimit/progressDeadlineSeconds 说明 + IngressCreateForm host域名/Service端口 + ServiceCreateForm 端口配置/个端口/selector自动检测 + PodInstancesTable Pod名称 + UpdateStrategySelectorCards Pod管理策略 + AlertRulesTab 删除confirm/分钟 + PrometheusDatasourceManager 删除confirm + LogDatasourcePage 删除confirm + QueryHistoryPanel 条 + ServerFileBrowser sr-only + TerminalDialog sr-only + CredentialManager 删除confirm + RdpAuditViewer sr-only + SystemManager 删除用户/批量删除 confirm + TerminalSessionsTab 删除confirm + SecuritySettingsTab 30分钟/2小时 + CronJobViewDialog 次 — 新增 k8s.editAdvanced 6键+k8s.editService 11键+k8s.cluster 2键+k8s.clusterDialog 1键+k8s.kubectlTerminalDesc/k8s.rve.yamlEditBtn/k8s.hpa.cpuTarget/k8s.podLevel/k8s.podNameLabel/k8s.podManagePolicy 共 28键 + aiops.capacity 8键+aiops.cost 1键+aiops.cli 2键 + deploy.cred.windowsUser/deploy.workspaceTerminalTitle/deploy.rbac.deleteRoleDesc/deploy.cred.badgeDefault 4键 + monitor.deleteRulesConfirmDesc/deleteDatasourceConfirmDesc/deleteLogDsConfirmDesc/durationMinutes/queryHistory.count 5键 + system.rdpLiveAudit/rdpHistoryReplay/rdpAuditDesc/sshTerminalDesc/sftpFileDesc/sftpFileLabel/deleteUserConfirmDesc/batchDeleteUsersConfirmDesc/deleteCredConfirmDesc/deleteTermSessionsConfirmDesc 10键 + task.cronJob.runCount 1键 + common.minutes30/hours2 2键, zh/en 7847→7898 对齐;tsc -b=0, npm build✓ (17.71s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** | | U37 | 全量 JSX 文本节点硬编码中文清零(65 文件 151 处→0: MiddlewareMonitor/SiteMonitor/SNMPMonitor/HealthProbeSection/ContextSwitchCard/ProcessTable/PortMonitorTab/MwTargetChartsPanel/MiddlewareDialog/ChartRangeHint/SnmpDeviceChartsPanel/AlertRulesTab/LogClusterPanel/LogDatasourcePage/LogQueryToolbar/LogAlertsPanel/PrometheusDatasourceManager/PodMetricsPage/CapacityPage/NamespaceManagementPage/NamespaceResourcePage/DeploymentEditService/EventsPage/DeploymentDetail/ClusterOverviewPage/DeploymentEditContainers/DeploymentEditStorage/WorkloadViewPage/BottomStatusBar/UpdateStrategySelectorCards/PodInstancesTable/shared-components/UpdateStrategyCard/TolerationsCard/HostSettingsCard/IngressListItem/ServiceListItem/ServiceCreateForm/IngressCreateForm/CreateHPADialog/DeployCredentials/DeployRBAC/UserGroupsManager/BuildNodesManager/DeployTargetFields/PipelineCreateDialog/CredFormDialog/WorkspaceTermDialog/AgentAlerts/AgentRuleDialog/LiveMonitorDialog/RoleFormDialog/CronJobViewDialog/TerminalOutput/AIAnalysisResult/AIPredictiveAnalytics/PredictiveCostTab/PredictiveCapacityTab/ActiveSessionsPanel/HistorySessionsPanel/TerminalDialog/ServerFileBrowser/PodFileBrowser/SiteResultsPanel/SiteProtocolPieChart — 151 JSX 文本节点中文全部替换为 t()/i18n.t() 调用;新增 common.* 98 翻译键 (selectedCount/itemsCount/newValue/namespaceLabel/containerLabel/replicasLabel/minReplicas/maxReplicas/createNamespace/noNamespace/unknownResource/exportYaml/loadTrend/loadCapacity/predicted/threshold/hostSettings/addVolume/addMount/createService/createIngress/editAction/updateStrategy/selectAndLabel/historyVersion/fileBrowser/scale/back/createHpa/allNamespaces/certLabel/observable/deviceList/addDevice/addMonitor/collectNow/addTask/addProbe/restoreFull/contextSwitch/processTop/listenPorts/terminalRealtime/auditWebssh/buildTerminal/fileBrowse/newDir/loadDeployment/notLinked/selectedPerms/none/hasLabel/deleteNamespace/deleteNamespaceWarn/allResources/notFoundDeploy/nodeList/fileLabel/addCustom/newInstanceService/newInstanceIngress/totalContainers/workContainers/loadingEllipsis/volumeClaimTemplates/containerTemplate/passwordOptional/updated/page/perPage/clusterMode/totalLogs/countLabel/percentage/queryTime/addDatasource/newPermission/newEnv/envLabel/displayName/newUserGroup/auditTrace/predictValue/confidence/predictMonthEnd/noCapacityData/securityMode/standardRdp/domainLabel/noRdpActive/noRdpHistory/buffer/matched/podLogs/createHpaTitle/password/events/total);37 文件已有 import i18n→i18n.t() 模式, 2 文件新增 import i18n;zh/en 7640→3526 namespace-flat +98 键对齐;tsc -b=0, npm build✓ (17.96s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** | diff --git a/frontend/src/components/aiops/agent-cli/event-handler.ts b/frontend/src/components/aiops/agent-cli/event-handler.ts index 09da3bb..fe4c664 100644 --- a/frontend/src/components/aiops/agent-cli/event-handler.ts +++ b/frontend/src/components/aiops/agent-cli/event-handler.ts @@ -39,7 +39,7 @@ export function createWsEventHandler(deps: WsEventHandlerDeps) { variant: 'destructive', }); wsRef.current?.send(JSON.stringify({ type: ok ? 'confirm' : 'deny', confirm_id: ev.confirm_id })); - if (!ok) push({ kind: 'info', content: `已拒绝执行:${ev.command || ev.tool_name}` }); + if (!ok) push({ kind: 'info', content: i18n.t('aiops.cli.eventRejected', { command: ev.command || ev.tool_name }) }); } // 处理后端事件 @@ -49,7 +49,7 @@ export function createWsEventHandler(deps: WsEventHandlerDeps) { case 'session': push({ kind: 'info', content: ev.message || '' }); // 仅「恢复历史会话」时进入可追问(新任务开始的 session 事件文案不同) - if (ev.message?.includes('已恢复历史会话')) { + if (ev.message?.includes(i18n.t('aiops.cli.eventRecovered'))) { setViewMode(false); setCanContinue(true); } @@ -127,7 +127,7 @@ export function createWsEventHandler(deps: WsEventHandlerDeps) { return [...next, { id: nextId(), kind: 'done', - content: text || '任务已完成,请查看上方工具执行结果。', + content: text || i18n.t('aiops.cli.eventCompleted'), round: ev.round, }]; }); @@ -138,7 +138,7 @@ export function createWsEventHandler(deps: WsEventHandlerDeps) { } case 'error': case 'aborted': - push({ kind: type === 'aborted' ? 'info' : 'error', content: ev.message || (type === 'aborted' ? '任务已中断' : '发生错误') }); + push({ kind: type === 'aborted' ? 'info' : 'error', content: ev.message || (type === 'aborted' ? i18n.t('aiops.cli.eventAborted') : i18n.t('aiops.cli.eventFailed')) }); setRunning(false); setCanContinue(type !== 'aborted'); setHistoryRefresh((k) => k + 1); diff --git a/frontend/src/components/deploy/WorkspaceTermDialog.tsx b/frontend/src/components/deploy/WorkspaceTermDialog.tsx index af26334..89e72ce 100644 --- a/frontend/src/components/deploy/WorkspaceTermDialog.tsx +++ b/frontend/src/components/deploy/WorkspaceTermDialog.tsx @@ -106,12 +106,12 @@ export function WorkspaceTermDialog({ ws.onclose = () => { setConnected(false); setHasOutput(true); - term.write('\r\n\x1b[31m[连接已关闭]\x1b[0m\r\n'); + term.write(`\r\n\x1b[31m${t('deploy.terminal.connClosed')}\x1b[0m\r\n`); }; ws.onerror = () => { setHasOutput(true); - term.write('\r\n\x1b[31m[连接发生错误]\x1b[0m\r\n'); + term.write(`\r\n\x1b[31m${t('deploy.terminal.connError')}\x1b[0m\r\n`); }; return () => { @@ -120,6 +120,7 @@ export function WorkspaceTermDialog({ wsRef.current = null; setConnected(false); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [open, runId]); // 容器尺寸变化时 fit 并同步远端 PTY,避免缩放后黑边或铺不满。 // Logan.Li diff --git a/frontend/src/components/deploy/credential-manager/constants.ts b/frontend/src/components/deploy/credential-manager/constants.ts index bddf65b..23960c8 100644 --- a/frontend/src/components/deploy/credential-manager/constants.ts +++ b/frontend/src/components/deploy/credential-manager/constants.ts @@ -3,17 +3,18 @@ import { Key, Server, Container, Shield, Cloud, Database, FileText, Globe, Monitor, } from 'lucide-react'; +import i18n from '@/i18n'; import type { SecretType } from './types'; -export const TYPE_CONFIG: Record = { - ssh: { label: 'SSH 密钥', icon: Server, color: 'dg-text-yellow', desc: 'SSH 私钥/公钥/密码' }, - rdp: { label: 'Windows RDP 密码', icon: Monitor, color: 'dg-text-blue', desc: 'Windows 远程桌面用户名/密码' }, - docker: { label: 'Docker 凭证', icon: Container, color: 'dg-text-cyan', desc: 'Docker Registry 登录凭据' }, - tls: { label: 'TLS 证书', icon: Shield, color: 'dg-text-green', desc: 'TLS/SSL 证书与私钥' }, - aksk: { label: 'AKSK 密钥', icon: Cloud, color: 'dg-text-purple', desc: '云服务 AccessKey/SecretKey' }, - database: { label: '数据库凭证', icon: Database, color: 'dg-text-blue', desc: '数据库连接信息' }, - api: { label: 'API 密钥', icon: Globe, color: 'dg-text-orange', desc: 'API Token/Key + 端点' }, - generic: { label: '通用凭证', icon: FileText, color: 'dg-text-secondary', desc: '自定义 Key/Value 键值对' }, +export const TYPE_CONFIG: Record = { + ssh: { label: i18n.t('deploy.credType.ssh'), labelKey: 'deploy.credType.ssh', icon: Server, color: 'dg-text-yellow', desc: i18n.t('deploy.credTypeDesc.ssh'), descKey: 'deploy.credTypeDesc.ssh' }, + rdp: { label: i18n.t('deploy.credType.rdp'), labelKey: 'deploy.credType.rdp', icon: Monitor, color: 'dg-text-blue', desc: i18n.t('deploy.credTypeDesc.rdp'), descKey: 'deploy.credTypeDesc.rdp' }, + docker: { label: i18n.t('deploy.credType.docker'), labelKey: 'deploy.credType.docker', icon: Container, color: 'dg-text-cyan', desc: i18n.t('deploy.credTypeDesc.docker'), descKey: 'deploy.credTypeDesc.docker' }, + tls: { label: i18n.t('deploy.credType.tls'), labelKey: 'deploy.credType.tls', icon: Shield, color: 'dg-text-green', desc: i18n.t('deploy.credTypeDesc.tls'), descKey: 'deploy.credTypeDesc.tls' }, + aksk: { label: i18n.t('deploy.credType.aksk'), labelKey: 'deploy.credType.aksk', icon: Cloud, color: 'dg-text-purple', desc: i18n.t('deploy.credTypeDesc.aksk'), descKey: 'deploy.credTypeDesc.aksk' }, + database: { label: i18n.t('deploy.credType.database'), labelKey: 'deploy.credType.database', icon: Database, color: 'dg-text-blue', desc: i18n.t('deploy.credTypeDesc.database'), descKey: 'deploy.credTypeDesc.database' }, + api: { label: i18n.t('deploy.credType.api'), labelKey: 'deploy.credType.api', icon: Globe, color: 'dg-text-orange', desc: i18n.t('deploy.credTypeDesc.api'), descKey: 'deploy.credTypeDesc.api' }, + generic: { label: i18n.t('deploy.credType.generic'), labelKey: 'deploy.credType.generic', icon: FileText, color: 'dg-text-secondary', desc: i18n.t('deploy.credTypeDesc.generic'), descKey: 'deploy.credTypeDesc.generic' }, }; export const TYPE_BADGE_CLASS: Record = { diff --git a/frontend/src/components/deploy/pipeline-editor/types.ts b/frontend/src/components/deploy/pipeline-editor/types.ts index 4ac9ed5..63557f7 100644 --- a/frontend/src/components/deploy/pipeline-editor/types.ts +++ b/frontend/src/components/deploy/pipeline-editor/types.ts @@ -1,3 +1,4 @@ +import i18n from '@/i18n'; import { GitBranch, Wrench, @@ -62,5 +63,5 @@ export function fmtDuration(s: number | undefined): string { if (s < 60) return `${s}s`; const m = Math.floor(s / 60); const sec = s % 60; - return sec > 0 ? `${m}分${sec}秒` : `${m}分`; + return sec > 0 ? i18n.t('common.duration.minSec', { m, s: sec }) : i18n.t('common.duration.min', { m }); } diff --git a/frontend/src/components/deploy/pipeline-manager/constants.ts b/frontend/src/components/deploy/pipeline-manager/constants.ts index 577c80e..1eb604e 100644 --- a/frontend/src/components/deploy/pipeline-manager/constants.ts +++ b/frontend/src/components/deploy/pipeline-manager/constants.ts @@ -32,7 +32,7 @@ export function fmtDuration(s: number | undefined): string { if (s < 60) return `${s}s`; const m = Math.floor(s / 60); const sec = s % 60; - return sec > 0 ? `${m}分${sec}秒` : `${m}分`; + return sec > 0 ? i18n.t('common.duration.minSec', { m, s: sec }) : i18n.t('common.duration.min', { m }); } // 解析 stages 字段 // Logan.Li diff --git a/frontend/src/components/deploy/pipeline-manager/pipeline-create/AdvancedSettingsPanel.tsx b/frontend/src/components/deploy/pipeline-manager/pipeline-create/AdvancedSettingsPanel.tsx index c3ef69d..45002d3 100644 --- a/frontend/src/components/deploy/pipeline-manager/pipeline-create/AdvancedSettingsPanel.tsx +++ b/frontend/src/components/deploy/pipeline-manager/pipeline-create/AdvancedSettingsPanel.tsx @@ -80,7 +80,7 @@ export function AdvancedSettingsPanel({
a.order - b.order); export interface PipelineRun { diff --git a/frontend/src/components/deploy/releaseManagerHelpers.tsx b/frontend/src/components/deploy/releaseManagerHelpers.tsx index 073a78f..3f4eafe 100644 --- a/frontend/src/components/deploy/releaseManagerHelpers.tsx +++ b/frontend/src/components/deploy/releaseManagerHelpers.tsx @@ -14,10 +14,10 @@ import { // 环境配置(值与后端 oneof=dev test staging prod 一致) // Logan.Li export const ENVIRONMENTS: Record = { - dev: { label: '开发环境', color: 'border-blue-500/30 dg-text-blue bg-blue-500/10' }, - test: { label: '测试环境', color: 'border-cyan-500/30 dg-text-cyan bg-cyan-500/10' }, - staging: { label: '预发环境', color: 'border-amber-500/30 dg-text-yellow bg-amber-500/10' }, - prod: { label: '生产环境', color: 'border-red-500/30 dg-text-red bg-red-500/10' }, + dev: { label: 'dev', color: 'border-blue-500/30 dg-text-blue bg-blue-500/10' }, + test: { label: 'test', color: 'border-cyan-500/30 dg-text-cyan bg-cyan-500/10' }, + staging: { label: 'staging', color: 'border-amber-500/30 dg-text-yellow bg-amber-500/10' }, + prod: { label: 'prod', color: 'border-red-500/30 dg-text-red bg-red-500/10' }, }; const ENV_LABEL_KEY: Record = { diff --git a/frontend/src/components/kubernetes/k8s-event-utils.ts b/frontend/src/components/kubernetes/k8s-event-utils.ts index 2524a8a..21e4546 100644 --- a/frontend/src/components/kubernetes/k8s-event-utils.ts +++ b/frontend/src/components/kubernetes/k8s-event-utils.ts @@ -61,10 +61,10 @@ export function formatEventRelative(ts: string): string { if (diff < 0) return ''; const mins = Math.floor(diff / 60000); if (mins < 1) return i18n.t('task.cronJob.time.justNow'); - if (mins < 60) return `${mins}分钟前`; + if (mins < 60) return i18n.t('common.duration.minAgo', { count: mins }); const hrs = Math.floor(mins / 60); - if (hrs < 24) return `${hrs}小时前`; - return `${Math.floor(hrs / 24)}天前`; + if (hrs < 24) return i18n.t('common.duration.hourAgo', { count: hrs }); + return i18n.t('common.duration.dayAgo', { count: Math.floor(hrs / 24) }); } /** 重复跨度:首次 → 最后 // Logan.Li */ diff --git a/frontend/src/components/kubernetes/workload-view/shared-components.tsx b/frontend/src/components/kubernetes/workload-view/shared-components.tsx index 447888a..5813b17 100644 --- a/frontend/src/components/kubernetes/workload-view/shared-components.tsx +++ b/frontend/src/components/kubernetes/workload-view/shared-components.tsx @@ -54,7 +54,7 @@ export function ContainerInfo({ c }: { c: JsonData }) { CPU: {c.resources?.requests?.cpu || '-'}/{c.resources?.limits?.cpu || '-'}
- 内存: {c.resources?.requests?.memory || '-'}/{c.resources?.limits?.memory || '-'} + {i18n.t('k8s.workloadView.memoryLabel')}: {c.resources?.requests?.memory || '-'}/{c.resources?.limits?.memory || '-'}
{i18n.t('k8s.workload.portsLabel')}: diff --git a/frontend/src/components/monitor/alert-center/NotifyPolicyTab.tsx b/frontend/src/components/monitor/alert-center/NotifyPolicyTab.tsx index 30593e0..df607c1 100644 --- a/frontend/src/components/monitor/alert-center/NotifyPolicyTab.tsx +++ b/frontend/src/components/monitor/alert-center/NotifyPolicyTab.tsx @@ -1,6 +1,7 @@ // 告警集合通知策略 — 四类监控绑定联系组 + 消息模版 // Logan.Li import { useState, useEffect, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; +import i18n from '@/i18n'; import { Server, Database, Globe, Network, Bell, Zap, Loader2, Save, FileText } from 'lucide-react'; import { SilenceRulesPanel } from './SilenceRulesPanel'; import { toast } from 'sonner'; @@ -41,7 +42,7 @@ const CATEGORIES = [ const DEFAULT_TITLE = '[{{severity_label}}] {{rule_name}} — {{hostname}} ({{metric}})'; const DEFAULT_FOOTER = '{{time}} | {{platform}}'; -const DEFAULT_PLATFORM = 'AIOps 智能运维平台'; +const DEFAULT_PLATFORM = i18n.t('monitor.notify.defaultPlatform'); const TEMPLATE_VARS = [ '{{time}}', '{{platform}}', '{{rule_name}}', '{{hostname}}', diff --git a/frontend/src/components/monitor/datasource/prometheus-ds/helpers.ts b/frontend/src/components/monitor/datasource/prometheus-ds/helpers.ts index 1064352..5ae7e92 100644 --- a/frontend/src/components/monitor/datasource/prometheus-ds/helpers.ts +++ b/frontend/src/components/monitor/datasource/prometheus-ds/helpers.ts @@ -105,7 +105,7 @@ export async function handleTestQuick(ds: PromDS): Promise { skip_tls_verify: ds.skip_tls_verify, }); if (data?.success) { - toast.success(`连接成功 · ${data.target_count || 0} targets`); + toast.success(i18n.t('monitor.prometheus.connSuccess', { count: data.target_count || 0 })); } else { toast.error(data?.message || i18n.t('aiops.llmTestFailed')); } diff --git a/frontend/src/components/monitor/log-center/QueryHistoryPanel.tsx b/frontend/src/components/monitor/log-center/QueryHistoryPanel.tsx index a6bf479..1d93fc8 100644 --- a/frontend/src/components/monitor/log-center/QueryHistoryPanel.tsx +++ b/frontend/src/components/monitor/log-center/QueryHistoryPanel.tsx @@ -22,9 +22,9 @@ const ENGINE_ICONS: Record = { function relativeTime(ts: number): string { const diff = Date.now() - ts; if (diff < 60000) return i18n.t('task.cronJob.time.justNow'); - if (diff < 3600000) return `${Math.floor(diff / 60000)}分钟前`; - if (diff < 86400000) return `${Math.floor(diff / 3600000)}小时前`; - return `${Math.floor(diff / 86400000)}天前`; + if (diff < 3600000) return i18n.t('common.duration.minAgo', { count: Math.floor(diff / 60000) }); + if (diff < 86400000) return i18n.t('common.duration.hourAgo', { count: Math.floor(diff / 3600000) }); + return i18n.t('common.duration.dayAgo', { count: Math.floor(diff / 86400000) }); } export function QueryHistoryPanel({ visible, onClose, onSelect, onCreateAlert }: Props) { diff --git a/frontend/src/components/server/CloudServerImport.tsx b/frontend/src/components/server/CloudServerImport.tsx index d060cf7..53dbae5 100644 --- a/frontend/src/components/server/CloudServerImport.tsx +++ b/frontend/src/components/server/CloudServerImport.tsx @@ -170,10 +170,11 @@ export function CloudServerImport({ open, onClose, initialAccountId }: CloudServ setDiscoverErrors((res?.errors as string[]) || []); } catch (e) { console.error('发现主机失败:', e); - setDiscoverErrors([(e as Error)?.message || '发现主机失败']); + setDiscoverErrors([(e as Error)?.message || t('server.import.discoverFailed')]); } finally { setIsDiscovering(false); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedAccount, selectedRegions]); // ==================== 导入逻辑 ==================== diff --git a/frontend/src/components/system/CredentialManager.tsx b/frontend/src/components/system/CredentialManager.tsx index 85ca1cd..1baf326 100644 --- a/frontend/src/components/system/CredentialManager.tsx +++ b/frontend/src/components/system/CredentialManager.tsx @@ -325,7 +325,7 @@ export function CredentialManager() { {/* 内容 */}
diff --git a/frontend/src/components/system/LiveMonitorDialog.tsx b/frontend/src/components/system/LiveMonitorDialog.tsx index ef820e7..bef23c8 100644 --- a/frontend/src/components/system/LiveMonitorDialog.tsx +++ b/frontend/src/components/system/LiveMonitorDialog.tsx @@ -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 diff --git a/frontend/src/components/system/RdpAuditViewer.tsx b/frontend/src/components/system/RdpAuditViewer.tsx index d4b7886..1318973 100644 --- a/frontend/src/components/system/RdpAuditViewer.tsx +++ b/frontend/src/components/system/RdpAuditViewer.tsx @@ -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); } }); diff --git a/frontend/src/components/system/RoleFormDialog.tsx b/frontend/src/components/system/RoleFormDialog.tsx index df190c3..2907a29 100644 --- a/frontend/src/components/system/RoleFormDialog.tsx +++ b/frontend/src/components/system/RoleFormDialog.tsx @@ -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:'] }, diff --git a/frontend/src/components/system/TerminalSessionsTab.tsx b/frontend/src/components/system/TerminalSessionsTab.tsx index d6ac20a..53c349f 100644 --- a/frontend/src/components/system/TerminalSessionsTab.tsx +++ b/frontend/src/components/system/TerminalSessionsTab.tsx @@ -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')} ))}
diff --git a/frontend/src/components/system/replay/export-audit.ts b/frontend/src/components/system/replay/export-audit.ts index d8b60ad..3858a72 100644 --- a/frontend/src/components/system/replay/export-audit.ts +++ b/frontend/src/components/system/replay/export-audit.ts @@ -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'), ]; diff --git a/frontend/src/components/system/useAuditSettings.ts b/frontend/src/components/system/useAuditSettings.ts index 65fa22d..f9d8c40 100644 --- a/frontend/src/components/system/useAuditSettings.ts +++ b/frontend/src/components/system/useAuditSettings.ts @@ -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 { diff --git a/frontend/src/components/task/CronJobViewDialog.tsx b/frontend/src/components/task/CronJobViewDialog.tsx index 64ed5af..f453804 100644 --- a/frontend/src/components/task/CronJobViewDialog.tsx +++ b/frontend/src/components/task/CronJobViewDialog.tsx @@ -87,7 +87,7 @@ export function CronJobViewDialog({ open, onOpenChange, job }: Props) { {job.script?.name && (
- 关联脚本: {job.script.name} + {t('task.cronJob.associatedScript')}: {job.script.name}
)} @@ -101,7 +101,7 @@ export function CronJobViewDialog({ open, onOpenChange, job }: Props) { /> ) : (
-              {content || '(无命令内容)'}
+              {content || t('task.cronJob.noCommand')}
             
)}
diff --git a/frontend/src/components/task/TerminalOutput.tsx b/frontend/src/components/task/TerminalOutput.tsx index d7701f8..08e9422 100644 --- a/frontend/src/components/task/TerminalOutput.tsx +++ b/frontend/src/components/task/TerminalOutput.tsx @@ -33,7 +33,7 @@ export function TerminalOutput({ status, durationMs, startedAt, - emptyText = '(无输出)', + emptyText = i18n.t('task.terminal.noOutput'), className, maxHeight = 'min(28rem, 55vh)', variant = 'plain', diff --git a/frontend/src/locales/en-US.json b/frontend/src/locales/en-US.json index 98a7eba..b564682 100644 --- a/frontend/src/locales/en-US.json +++ b/frontend/src/locales/en-US.json @@ -184,7 +184,9 @@ "minAgo": "{{count}} min ago", "secAgo": "{{count}}s ago", "hourAgo": "{{count}}h ago", - "dayAgo": "{{count}}d ago" + "dayAgo": "{{count}}d ago", + "seconds": "{{count}}s", + "hoursMin": "{{h}}h {{m}}m" }, "ebCaughtError": "[ErrorBoundary] Caught error:", "ebCopyError": "Copy Error", @@ -1290,7 +1292,10 @@ "loggingIn": "Logging in..." }, "webshellConnect": "Connect", - "webshellLoggingIn": "Logging in..." + "webshellLoggingIn": "Logging in...", + "import": { + "discoverFailed": "Failed to discover hosts" + } }, "alert": { "acknowledged": "Alert acknowledged", @@ -2538,7 +2543,8 @@ "notInstalled": "Not installed", "installing": "Installing", "test": "Test", - "install": "Install" + "install": "Install", + "recommended": "Recommended" }, "trigger": { "manual": "Manual", @@ -2583,7 +2589,35 @@ "envVar": "Environment Variables", "envVarOptional": "Environment Variables (optional)" }, - "workspaceTerminalTitle": "Workspace Terminal #{{num}}" + "workspaceTerminalTitle": "Workspace Terminal #{{num}}", + "credType": { + "ssh": "SSH Key", + "rdp": "Windows RDP Password", + "docker": "Docker Credential", + "tls": "TLS Certificate", + "aksk": "AKSK Key", + "database": "Database Credential", + "api": "API Key", + "generic": "Generic Credential" + }, + "credTypeDesc": { + "ssh": "SSH private/public key/password", + "rdp": "Windows remote desktop username/password", + "docker": "Docker Registry login credentials", + "tls": "TLS/SSL certificate and private key", + "aksk": "Cloud AccessKey/SecretKey", + "database": "Database connection info", + "api": "API Token/Key + endpoint", + "generic": "Custom Key/Value pairs" + }, + "fmtDuration": { + "minSec": "{{m}}m {{s}}s" + }, + "terminal": { + "connClosed": "[Connection Closed]", + "connError": "[Connection Error]" + }, + "jobName": "Job Name" }, "k8s": { "actionModal": { @@ -3708,7 +3742,8 @@ "serviceName": "Service Name", "podCount": "Pod Count", "actualSchedule": "Actual Schedule", - "restartSentDesc": "{{kind}} rolling restart triggered" + "restartSentDesc": "{{kind}} rolling restart triggered", + "memoryLabel": "Memory" }, "workloads": { "scaleSuccess": "Scaling succeeded", @@ -4976,7 +5011,9 @@ "noData": "No Prometheus datasources", "addHint": "Add datasources for metrics monitoring and dashboards" }, - "prometheus": "Prometheus", + "prometheus": { + "connSuccess": "Connection successful · {{count}} targets" + }, "prometheusDashb": { "connecting": "Connecting…" }, @@ -5397,6 +5434,25 @@ "durationMinutes": "{{count}} min", "queryHistory": { "count": "{{count}} entries" + }, + "terminal": { + "auditConnected": "[Audit Monitor] Connected to session...", + "userServer": "User: {{username}} Server: {{serverName}} ({{serverIp}})", + "wsConnFailed": "WebSocket connection failed", + "connFailedCode": "Connection failed (code={{code}}): {{reason}}", + "auditDisconnected": "[Audit Monitor] Disconnected", + "authOrNetwork": "Authentication failed or network issue" + }, + "rdp": { + "connectingLive": "Connecting to RDP live audit...", + "loadingRecording": "Loading RDP recording...", + "liveConnFailed": "RDP live audit connection failed", + "liveDisconnected": "RDP live audit disconnected", + "noFrames": "No playable frames for this RDP session", + "loadFailed": "RDP recording load failed" + }, + "notify": { + "defaultPlatform": "AIOps Platform" } }, "task": { @@ -5476,7 +5532,9 @@ "confirmDelete": "Delete \"{{name}}\"? This cannot be undone.", "execDuration": "Duration: {{ms}}ms" }, - "runCount": "{{count}} times" + "runCount": "{{count}} times", + "associatedScript": "Associated Script", + "noCommand": "(No command content)" }, "cronJobCol": { "task": "Task", @@ -5601,6 +5659,9 @@ "noShell": "No shell interpreter detected. Scripts cannot run on this host. For Docker deployments, ensure bash is installed in the image.", "noPython": "Python is not installed. Python scripts will not be executable.", "partialUnavailable": "Some interpreters are unavailable; scripts of those types cannot run after creation." + }, + "terminal": { + "noOutput": "(No output)" } }, "rbac": { @@ -7466,7 +7527,12 @@ "invalidRetentionDays": "Please select valid retention days", "noExpiredRecords": ", no expired records" }, - "auditSettings": "Audit Settings", + "auditSettings": { + "appliedWithCleanup": "Applied {{days}}-day retention policy, cleaned {{total}} expired records", + "appliedNoCleanup": "Applied {{days}}-day retention policy, no expired records to clean", + "cleanupCount": ", cleaned {{count}} records", + "lastCleanup": "Last cleanup: {{time}}{{detail}}" + }, "auditSettingsDesc": "Operation logs and audit policy", "auditStats": "Audit Statistics", "auditSuccess": "Success", @@ -7818,7 +7884,12 @@ "terminalRecordSize": "Recording Size", "terminalReplay": "Replay", "terminalServer": "Server", - "terminalSession": "Session", + "terminalSession": { + "all": "All", + "active": "Active", + "closed": "Closed", + "failed": "Failed" + }, "terminalStartTime": "Start Time", "terminalStatus": "Status", "terminalUser": "User", @@ -7897,7 +7968,35 @@ "credentialAkSk": "AK/SK (one pair per line, space or comma separated)", "credentialEncryptedHint": "Credentials are encrypted with AES-256-GCM, decrypted only on server side", "permissionAssign": "Permission Assignment", - "adminPassword": "Admin Password" + "adminPassword": "Admin Password", + "csvHeader": { + "username": "Username", + "nickname": "Nickname", + "displayName": "Display Name", + "email": "Email", + "phone": "Phone", + "role": "Role", + "department": "Department" + }, + "auditExport": { + "sessionId": "Session ID", + "user": "User", + "targetHost": "Target Host", + "clientIp": "Client IP", + "startTime": "Start Time", + "endTime": "End Time", + "duration": "Duration", + "commandCount": "Command Count", + "status": "Status" + }, + "credTypeLabel": { + "sshKey": "SSH Private Key", + "apiToken": "Token", + "password": "Password" + }, + "role": { + "aiopsGroup": "AIOps Intelligence" + } }, "aiops": { "activeCount": "{{count}} active", @@ -8255,7 +8354,12 @@ "execute": "Run" }, "confirmHighRiskTitle": "⚠️ Confirm High-Risk Operation", - "confirmHighRiskDesc": "Tool: {{tool}}\nRisk: {{risk}}\nCommand: {{command}}" + "confirmHighRiskDesc": "Tool: {{tool}}\nRisk: {{risk}}\nCommand: {{command}}", + "eventRejected": "Execution rejected: {{command}}", + "eventRecovered": "Session recovered", + "eventCompleted": "Task completed. Please check the tool execution results above.", + "eventAborted": "Task aborted", + "eventFailed": "Task execution failed" }, "cloudService": "Cloud Services", "codingPlan": "Coding Plan", diff --git a/frontend/src/locales/zh-CN.json b/frontend/src/locales/zh-CN.json index d3cf9e0..03e2467 100644 --- a/frontend/src/locales/zh-CN.json +++ b/frontend/src/locales/zh-CN.json @@ -184,7 +184,9 @@ "minAgo": "{{count}}分钟前", "secAgo": "{{count}}秒前", "hourAgo": "{{count}}小时前", - "dayAgo": "{{count}}天前" + "dayAgo": "{{count}}天前", + "seconds": "{{count}}秒", + "hoursMin": "{{h}}时{{m}}分" }, "ebCaughtError": "[ErrorBoundary] 捕获到错误:", "ebCopyError": "复制错误", @@ -1290,7 +1292,10 @@ "loggingIn": "正在登录..." }, "webshellConnect": "连接", - "webshellLoggingIn": "正在登录..." + "webshellLoggingIn": "正在登录...", + "import": { + "discoverFailed": "发现主机失败" + } }, "alert": { "acknowledged": "告警已确认", @@ -2538,7 +2543,8 @@ "notInstalled": "未安装", "installing": "安装中", "test": "测试", - "install": "安装" + "install": "安装", + "recommended": "推荐" }, "trigger": { "manual": "手动", @@ -2583,7 +2589,35 @@ "envVar": "环境变量", "envVarOptional": "环境变量 (可选)" }, - "workspaceTerminalTitle": "Workspace 终端 #{{num}}" + "workspaceTerminalTitle": "Workspace 终端 #{{num}}", + "credType": { + "ssh": "SSH 密钥", + "rdp": "Windows RDP 密码", + "docker": "Docker 凭证", + "tls": "TLS 证书", + "aksk": "AKSK 密钥", + "database": "数据库凭证", + "api": "API 密钥", + "generic": "通用凭证" + }, + "credTypeDesc": { + "ssh": "SSH 私钥/公钥/密码", + "rdp": "Windows 远程桌面用户名/密码", + "docker": "Docker Registry 登录凭据", + "tls": "TLS/SSL 证书与私钥", + "aksk": "云服务 AccessKey/SecretKey", + "database": "数据库连接信息", + "api": "API Token/Key + 端点", + "generic": "自定义 Key/Value 键值对" + }, + "fmtDuration": { + "minSec": "{{m}}分{{s}}秒" + }, + "terminal": { + "connClosed": "[连接已关闭]", + "connError": "[连接发生错误]" + }, + "jobName": "Job 名称" }, "k8s": { "actionModal": { @@ -3708,7 +3742,8 @@ "serviceName": "服务名", "podCount": "Pod 数量", "actualSchedule": "当前调度", - "restartSentDesc": "{{kind}} 滚动重启已触发" + "restartSentDesc": "{{kind}} 滚动重启已触发", + "memoryLabel": "内存" }, "workloads": { "scaleSuccess": "扩缩容成功", @@ -4976,7 +5011,9 @@ "noData": "暂无 Prometheus 数据源", "addHint": "添加数据源后可用于指标监控与监控大屏" }, - "prometheus": "Prometheus", + "prometheus": { + "connSuccess": "连接成功 · {{count}} targets" + }, "prometheusDashb": { "connecting": "连接中…" }, @@ -5397,6 +5434,25 @@ "durationMinutes": "{{count}}分钟", "queryHistory": { "count": "{{count}} 条" + }, + "terminal": { + "auditConnected": "[审计监控] 已连接到会话...", + "userServer": "用户: {{username}} 服务器: {{serverName}} ({{serverIp}})", + "wsConnFailed": "WebSocket 连接失败", + "connFailedCode": "连接失败 (code={{code}}): {{reason}}", + "auditDisconnected": "[审计监控] 连接已断开", + "authOrNetwork": "认证失败或网络问题" + }, + "rdp": { + "connectingLive": "正在连接 RDP 实时审计...", + "loadingRecording": "正在加载 RDP 录屏...", + "liveConnFailed": "RDP 实时审计连接失败", + "liveDisconnected": "RDP 实时审计已断开", + "noFrames": "该 RDP 会话没有可播放画面帧", + "loadFailed": "RDP 录屏加载失败" + }, + "notify": { + "defaultPlatform": "AIOps 智能运维平台" } }, "task": { @@ -5476,7 +5532,9 @@ "confirmDelete": "确定删除「{{name}}」吗?此操作不可恢复。", "execDuration": "耗时 {{ms}}ms" }, - "runCount": "{{count}} 次" + "runCount": "{{count}} 次", + "associatedScript": "关联脚本", + "noCommand": "(无命令内容)" }, "cronJobCol": { "task": "任务", @@ -5601,6 +5659,9 @@ "noShell": "未检测到 Shell 解释器,脚本无法在本机执行。Docker 部署请确认镜像已安装 bash。", "noPython": "Python 未安装,Python 类型脚本将无法执行。", "partialUnavailable": "部分解释器不可用,对应类型的脚本创建后无法执行。" + }, + "terminal": { + "noOutput": "(无输出)" } }, "rbac": { @@ -7466,7 +7527,12 @@ "invalidRetentionDays": "请选择有效的保留天数", "noExpiredRecords": ",无超期记录" }, - "auditSettings": "审计设置", + "auditSettings": { + "appliedWithCleanup": "已应用 {{days}} 天保留策略,立即清理 {{total}} 条超期记录", + "appliedNoCleanup": "已应用 {{days}} 天保留策略,暂无超期记录需清理", + "cleanupCount": ",清理 {{count}} 条", + "lastCleanup": "上次清理:{{time}}{{detail}}" + }, "auditSettingsDesc": "操作日志与审计策略", "auditStats": "审计统计", "auditSuccess": "成功", @@ -7818,7 +7884,12 @@ "terminalRecordSize": "录制大小", "terminalReplay": "回放", "terminalServer": "服务器", - "terminalSession": "会话", + "terminalSession": { + "all": "全部", + "active": "活动中", + "closed": "已关闭", + "failed": "失败" + }, "terminalStartTime": "开始时间", "terminalStatus": "状态", "terminalUser": "用户", @@ -7897,7 +7968,35 @@ "credentialAkSk": "AK/SK (每行一对,用空格或逗号分隔)", "credentialEncryptedHint": "凭据内容使用 AES-256-GCM 加密存储,仅在服务器端解密使用", "permissionAssign": "权限分配", - "adminPassword": "管理员密码" + "adminPassword": "管理员密码", + "csvHeader": { + "username": "用户名", + "nickname": "昵称", + "displayName": "显示名", + "email": "邮箱", + "phone": "手机", + "role": "角色", + "department": "部门" + }, + "auditExport": { + "sessionId": "会话ID", + "user": "用户", + "targetHost": "目标主机", + "clientIp": "客户端IP", + "startTime": "开始时间", + "endTime": "结束时间", + "duration": "时长", + "commandCount": "命令数", + "status": "状态" + }, + "credTypeLabel": { + "sshKey": "SSH 私钥", + "apiToken": "Token", + "password": "密码" + }, + "role": { + "aiopsGroup": "AIOps智能" + } }, "aiops": { "activeCount": "{{count}} 个活跃", @@ -8255,7 +8354,12 @@ "execute": "执行" }, "confirmHighRiskTitle": "⚠️ 确认执行高危操作", - "confirmHighRiskDesc": "工具:{{tool}}\n风险:{{risk}}\n命令:{{command}}" + "confirmHighRiskDesc": "工具:{{tool}}\n风险:{{risk}}\n命令:{{command}}", + "eventRejected": "已拒绝执行:{{command}}", + "eventRecovered": "已恢复历史会话", + "eventCompleted": "任务已完成,请查看上方工具执行结果。", + "eventAborted": "任务已取消", + "eventFailed": "任务执行失败" }, "cloudService": "云服务", "codingPlan": "编码套餐 Coding Plan",