From be1011eb58e1e55f2280e0980b8fa9788e2683a0 Mon Sep 17 00:00:00 2001 From: attacker Date: Sat, 11 Jul 2026 03:33:31 +0800 Subject: [PATCH] =?UTF-8?q?refactor(i18n):=20U17=20K8s=20=E6=AE=8B?= =?UTF-8?q?=E4=BD=99=E7=BB=84=E4=BB=B6=20i18n=20=E8=A1=A5=E5=85=A8=20?= =?UTF-8?q?=E2=80=94=20NodeDetailPage=2016=20=E5=A4=84=E7=A1=AC=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E4=B8=AD=E6=96=87=E6=B8=85=E9=9B=B6=20+=208=20?= =?UTF-8?q?=E4=B8=AA=20hash=20=E9=94=AE=E6=9B=BF=E6=8D=A2=E4=B8=BA?= =?UTF-8?q?=E8=AF=AD=E4=B9=89=E5=8C=96=20k8s.nodeDetail.*=20+=20Deployment?= =?UTF-8?q?Workload=2012=20=E5=A4=84=20toast/confirm=20=E7=A1=AC=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E4=B8=AD=E6=96=87=E6=B8=85=E9=9B=B6.=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20k8s.nodeDetail=20=E5=91=BD=E5=90=8D=E7=A9=BA?= =?UTF-8?q?=E9=97=B4=2021=20=E9=94=AE=20+=20k8s.deploymentDetail=20?= =?UTF-8?q?=E6=89=A9=E5=B1=95=2012=20=E9=94=AE(=E5=90=AB=E6=8F=92=E5=80=BC?= =?UTF-8?q?).=20zh/en=207564=E2=86=927597=20=E5=AF=B9=E9=BD=90.=20?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E4=BB=8E=20i18n.t()=20=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=20useTranslation()=20hook.=20tsc=20-b=3D0,?= =?UTF-8?q?=20npm=20build=E2=9C=93,=20ESLint=3D0,=2017/17=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ROADMAP.md | 1 + .../kubernetes/DeploymentWorkload.tsx | 24 ++--- .../components/kubernetes/NodeDetailPage.tsx | 87 ++++++++++--------- frontend/src/locales/en-US.json | 37 +++++++- frontend/src/locales/zh-CN.json | 37 +++++++- 5 files changed, 129 insertions(+), 57 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index e4ebd6e..c3f5b35 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -511,6 +511,7 @@ services/api.ts (1324L) | U15 | ApiAccessKeySection i18n 迁移(清理 56 个 apiaccesskey.s{hash} 乱码键为语义化 user.apiKey.* 键 + 组件全量接入 useTranslation,UI 中文 57→0,zh/en 7556=7556 对齐,零 hash 键残留) | P3 | **done** | | Q37 | 前端巨型工具文件拆分(k8s-yaml-utils.ts 504L→451L + k8s-helpers.ts 67L 新文件,提取 7 个通用工具函数 parseScalar/STATUS_COLORS/statusColor/aggregateByImage/formatK8sTime/elapsedSeconds/formatDuration,barrel re-export 保持 8 个消费者零修改) | P0 | **done** | | Q38 | 前端巨型组件拆分(UnifiedQueryPanel 529L→353L (-33%),提取 unified-query/useLogQueryEngine.ts 295L 查询执行引擎 Hook + useLogExport.ts 62L 导出/复制 Hook,全项目最后一个 ≥500L 业务组件清零) | P0 | **done** | +| U17 | K8s 残余组件 i18n 补全(NodeDetailPage 16 处硬编码中文清零 + 8 个 hash 键替换为语义化 k8s.nodeDetail.* 键 + DeploymentWorkload 12 处 toast/confirm 硬编码中文清零,zh/en 7564→7597 +33 键对齐) | P3 | **done** | --- diff --git a/frontend/src/components/kubernetes/DeploymentWorkload.tsx b/frontend/src/components/kubernetes/DeploymentWorkload.tsx index cf41c96..d8e625b 100644 --- a/frontend/src/components/kubernetes/DeploymentWorkload.tsx +++ b/frontend/src/components/kubernetes/DeploymentWorkload.tsx @@ -162,7 +162,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod setActionLoading('scale'); try { await kubernetesApi.scaleDeployment(clusterCode, namespace, deploymentName, newReplicas); - toast({ title: i18n.t('k8s.workloads.scaleSuccess'), description: `副本数已设置为 ${newReplicas}` }); + toast({ title: i18n.t('k8s.workloads.scaleSuccess'), description: i18n.t('k8s.deploymentDetail.replicasSetTo', { count: newReplicas }) }); loadData(); } catch (e) { toast({ title: i18n.t('cloud.operationFailed'), description: e?.message || String(e), variant: 'destructive' }); @@ -173,7 +173,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod setActionLoading('scale'); try { await kubernetesApi.scaleDeployment(clusterCode, namespace, deploymentName, scaleValue); - toast({ title: i18n.t('kubernetes.msg.scaleSuccess'), description: `副本数已设置为 ${scaleValue}` }); + toast({ title: i18n.t('kubernetes.msg.scaleSuccess'), description: i18n.t('k8s.deploymentDetail.replicasSetTo', { count: scaleValue }) }); setModal(null); loadData(); } catch (e) { @@ -184,7 +184,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod const handleRestart = async () => { const ok = await confirm({ title: i18n.t('kubernetes.deployment.restart'), - description: `确认滚动重启 Deployment "${deploymentName}"?`, + description: i18n.t('k8s.deploymentDetail.confirmRestart', { name: deploymentName }), confirmText: i18n.t('agent.agentServiceRestart'), }); if (!ok) return; @@ -202,8 +202,8 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod const isPaused = !!deployment?.paused; const action = isPaused ? i18n.t('kubernetes.deployment.resume') : i18n.t('kubernetes.job.suspend'); const ok = await confirm({ - title: `${action}滚动更新`, - description: `确认${action} Deployment "${deploymentName}" 的滚动更新?`, + title: i18n.t('k8s.deploymentDetail.rollingUpdate', { action }), + description: i18n.t('k8s.deploymentDetail.confirmRollingUpdate', { action, name: deploymentName }), confirmText: action, }); if (!ok) return; @@ -214,10 +214,10 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod } else { await kubernetesApi.pauseDeployment(clusterCode, namespace, deploymentName); } - toast({ title: `${action}成功`, description: `Deployment 滚动更新已${action}` }); + toast({ title: i18n.t('k8s.deploymentDetail.actionSuccess', { action }), description: i18n.t('k8s.deploymentDetail.rollingUpdated', { action }) }); setTimeout(loadData, 1000); } catch (e) { - toast({ title: `${action}失败`, description: e?.message || String(e), variant: 'destructive' }); + toast({ title: i18n.t('k8s.deploymentDetail.actionFailed', { action }), description: e?.message || String(e), variant: 'destructive' }); } finally { setActionLoading(''); } }; @@ -234,7 +234,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod await kubernetesApi.updateDeploymentImage( clusterCode, namespace, deploymentName, newImage, cicdContainerName || undefined, ); - toast({ title: i18n.t('kubernetes.deploymentdetai.s6df3c303'), description: `正在滚动更新为 ${newImage}` }); + toast({ title: i18n.t('kubernetes.deploymentdetai.s6df3c303'), description: i18n.t('k8s.deploymentDetail.rollingUpdateImage', { image: newImage }) }); setModal(null); loadData(); } catch (e) { @@ -251,7 +251,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod const url = `${baseUrl}/api/v1/kubernetes/${clusterCode}/namespace/${namespace}/deployments/${deploymentName}`; const resp = await fetch(url, { method: 'DELETE', headers: { Authorization: `Bearer ${tk}` } }); if (!resp.ok) throw new Error(`HTTP ${resp.status}`); - toast({ title: i18n.t('kubernetes.msg.deleteSuccess'), description: `${deploymentName} 已删除` }); + toast({ title: i18n.t('kubernetes.msg.deleteSuccess'), description: i18n.t('k8s.deploymentDetail.deploymentDeleted', { name: deploymentName }) }); setModal(null); setTimeout(() => navigate(`/kubernetes/${clusterCode}/namespace/${namespace}/deployments`), 800); } catch (e) { @@ -272,7 +272,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod const handleDeletePod = async (pod: any) => { const ok = await confirm({ title: i18n.t('kubernetes.pod.deletePod'), - description: `确认删除 Pod "${pod.name}"?操作不可恢复。`, + description: i18n.t('k8s.deploymentDetail.confirmDeletePod', { name: pod.name }), confirmText: i18n.t('kubernetes.storage.delete2'), }); if (!ok) return; @@ -297,7 +297,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod if (!deployment && !isCreate) { return ( {i18n.t('common.back')} }> -

未找到 Deployment: {deploymentName}

+

{i18n.t('k8s.deploymentDetail.deploymentNotFound', { name: deploymentName })}

); } @@ -330,7 +330,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod diff --git a/frontend/src/components/kubernetes/NodeDetailPage.tsx b/frontend/src/components/kubernetes/NodeDetailPage.tsx index 0a03838..3ebdfa0 100644 --- a/frontend/src/components/kubernetes/NodeDetailPage.tsx +++ b/frontend/src/components/kubernetes/NodeDetailPage.tsx @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { useState, useEffect, useCallback } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; @@ -8,7 +9,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { - + RefreshCw, Server, Activity, @@ -22,9 +23,9 @@ import { import { kubernetesApi } from '@/api'; import { PageShell } from '@/components/layout/PageShell'; -import i18n from '@/i18n'; export default function NodeDetailPage() { + const { t } = useTranslation(); const { clusterCode, nodeName } = useParams<{ clusterCode: string; nodeName: string }>(); const navigate = useNavigate(); const [data, setData] = useState(null); @@ -96,20 +97,20 @@ export default function NodeDetailPage() { return ( } loading={loading && !data} - loadingLabel={i18n.t('kubernetes.nodedetailpaget.sfdff6194')} + loadingLabel={t('k8s.nodeDetail.loadingNode')} actions={( <> )} @@ -129,7 +130,7 @@ export default function NodeDetailPage() { - 无法加载节点详情 + {t('k8s.nodeDetail.loadFailed')} ) : data ? ( @@ -140,11 +141,11 @@ export default function NodeDetailPage() {

- 系统信息 + {t('k8s.nodeDetail.systemInfo')}

- {i18n.t('kubernetes.node.containerRuntime')} + {t('kubernetes.node.containerRuntime')} {data.container_runtime || '-'}
@@ -152,19 +153,19 @@ export default function NodeDetailPage() { {data.kubelet_version || '-'}
- {i18n.t('agent.agentOs')} + {t('agent.agentOs')} {data.os_image || '-'}
- {i18n.t('kubernetes.node.kernelVersion')} + {t('kubernetes.node.kernelVersion')} {data.kernel_version || '-'}
- {i18n.t('agent.agentArch')} + {t('agent.agentArch')} {data.architecture || '-'}
- {i18n.t('system.userCreatedAt')} + {t('system.userCreatedAt')} {data.creation_time ? new Date(data.creation_time).toLocaleString('zh-CN') : '-'}
@@ -179,14 +180,14 @@ export default function NodeDetailPage() {

- 资源分配率 + {t('k8s.nodeDetail.resourceAllocation')}

{/* CPU allocation (requested vs allocatable) */}
- CPU 容量 / 可分配 - {data.cpu_capacity} / {data.cpu_allocatable} 核 + {t('k8s.nodeDetail.cpuCapacityAlloc')} + {data.cpu_capacity} / {data.cpu_allocatable} {t('k8s.nodeDetail.coreUnit')}
- {i18n.t('kubernetes.nodedetailpaget.s5038523b')} + {t('k8s.nodeDetail.memCapacityAlloc')} {data.mem_capacity_mb} / {data.mem_allocatable_mb} Mi
- Pod 容量 / 可分配 + {t('k8s.nodeDetail.podCapacityAlloc')} {data.pod_capacity} / {data.pod_allocatable}
@@ -257,10 +258,10 @@ export default function NodeDetailPage() {

- 节点条件 + {t('k8s.nodeDetail.conditions')}

{(!data.conditions || data.conditions.length === 0) ? ( -

{i18n.t('kubernetes.nodedetailpaget.s0f03f9da')}

+

{t('k8s.nodeDetail.noConditions')}

) : (
{data.conditions.map(( cond: any, i: number) => ( @@ -284,17 +285,17 @@ export default function NodeDetailPage() {

- 污点 (Taints) + {t('k8s.nodeDetail.taints')}

{(!data.taints || data.taints.length === 0) ? ( -

{i18n.t('kubernetes.node.noTaint')}

+

{t('kubernetes.node.noTaint')}

) : (
- {data.taints.map(( t: any, i: number) => ( + {data.taints.map(( tnt: any, i: number) => (
- {t.effect} - {t.key} - {t.value && = {t.value}} + {tnt.effect} + {tnt.key} + {tnt.value && = {tnt.value}}
))}
@@ -308,7 +309,7 @@ export default function NodeDetailPage() {

- 标签 ({data.labels.length}) + {t('k8s.nodeDetail.labels', { count: data.labels.length })}

{data.labels.map(( l: any, i: number) => ( @@ -329,23 +330,23 @@ export default function NodeDetailPage() {

- 节点上的 Pod + {t('k8s.nodeDetail.podsOnNode')} {data.pods?.length || 0}

{(!data.pods || data.pods.length === 0) ? ( -

{i18n.t('kubernetes.nodedetailpaget.s86d276f5')}

+

{t('k8s.nodeDetail.noPodsOnNode')}

) : ( - {i18n.t('kubernetes.namespace.title')} - {i18n.t('kubernetes.secret.secretName')} - {i18n.t('system.terminalStatus')} + {t('kubernetes.namespace.title')} + {t('kubernetes.secret.secretName')} + {t('system.terminalStatus')} IP - CPU 请求 - {i18n.t('kubernetes.container.memoryRequest')} - {i18n.t('kubernetes.pod.restartCount')} + {t('k8s.nodeDetail.cpuRequest')} + {t('kubernetes.container.memoryRequest')} + {t('kubernetes.pod.restartCount')} diff --git a/frontend/src/locales/en-US.json b/frontend/src/locales/en-US.json index 2eb5c87..3a3ad53 100644 --- a/frontend/src/locales/en-US.json +++ b/frontend/src/locales/en-US.json @@ -2771,7 +2771,19 @@ "notFound": "Deployment not found", "podList": "Pod List", "logs": "Logs", - "confirmDeleteHpa": "Confirm Delete HPA" + "confirmDeleteHpa": "Confirm Delete HPA", + "replicasSetTo": "Replicas set to {{count}}", + "confirmRestart": "Confirm rolling restart of Deployment \"{{name}}\"?", + "rollingUpdate": "{{action}} Rolling Update", + "confirmRollingUpdate": "Confirm {{action}} rolling update of Deployment \"{{name}}\"?", + "actionSuccess": "{{action}} Succeeded", + "actionFailed": "{{action}} Failed", + "rollingUpdated": "Deployment rolling update {{action}}d", + "rollingUpdateImage": "Rolling updating to {{image}}", + "deploymentDeleted": "{{name}} deleted", + "confirmDeletePod": "Confirm delete Pod \"{{name}}\"? This action cannot be undone.", + "deploymentNotFound": "Deployment not found: {{name}}", + "imageLabel": "Image" }, "podLogs": { "noLogs": "No logs", @@ -3234,6 +3246,29 @@ "configured": "Configured (leave empty to keep)", "kubeconfigHint": "API Server address will be auto-parsed after pasting kubeconfig content", "cancel": "Cancel" + }, + "nodeDetail": { + "nodeTitle": "Node Details", + "loadingNode": "Loading node details...", + "loadFailed": "Failed to load node details", + "systemInfo": "System Info", + "resourceAllocation": "Resource Allocation", + "cpuAllocated": "CPU Allocated", + "cpuRealtimeUsage": "CPU Real-time Usage", + "memAllocated": "Memory Allocated", + "memRealtimeUsage": "Memory Real-time Usage", + "podCount": "Pod Count", + "cpuCapacityAlloc": "CPU Capacity / Allocatable", + "memCapacityAlloc": "Memory Capacity / Allocatable", + "podCapacityAlloc": "Pod Capacity / Allocatable", + "coreUnit": "cores", + "conditions": "Conditions", + "noConditions": "No condition data", + "taints": "Taints", + "labels": "Labels ({{count}})", + "podsOnNode": "Pods on Node", + "noPodsOnNode": "No pods on this node", + "cpuRequest": "CPU Request" } }, "monitor": { diff --git a/frontend/src/locales/zh-CN.json b/frontend/src/locales/zh-CN.json index 13cf2e0..7882379 100644 --- a/frontend/src/locales/zh-CN.json +++ b/frontend/src/locales/zh-CN.json @@ -2771,7 +2771,19 @@ "notFound": "未找到 Deployment", "podList": "Pod 列表", "logs": "日志", - "confirmDeleteHpa": "确定删除 HPA" + "confirmDeleteHpa": "确定删除 HPA", + "replicasSetTo": "副本数已设置为 {{count}}", + "confirmRestart": "确认滚动重启 Deployment \"{{name}}\"?", + "rollingUpdate": "{{action}}滚动更新", + "confirmRollingUpdate": "确认{{action}} Deployment \"{{name}}\" 的滚动更新?", + "actionSuccess": "{{action}}成功", + "actionFailed": "{{action}}失败", + "rollingUpdated": "Deployment 滚动更新已{{action}}", + "rollingUpdateImage": "正在滚动更新为 {{image}}", + "deploymentDeleted": "{{name}} 已删除", + "confirmDeletePod": "确认删除 Pod \"{{name}}\"?操作不可恢复。", + "deploymentNotFound": "未找到 Deployment: {{name}}", + "imageLabel": "镜像" }, "podLogs": { "noLogs": "无日志", @@ -3234,6 +3246,29 @@ "configured": "已配置(留空不修改)", "kubeconfigHint": "粘贴 kubeconfig 内容后将自动解析 API Server 地址", "cancel": "取消" + }, + "nodeDetail": { + "nodeTitle": "节点详情", + "loadingNode": "加载节点详情...", + "loadFailed": "无法加载节点详情", + "systemInfo": "系统信息", + "resourceAllocation": "资源分配率", + "cpuAllocated": "CPU 已分配", + "cpuRealtimeUsage": "CPU 实时使用", + "memAllocated": "内存已分配", + "memRealtimeUsage": "内存实时使用", + "podCount": "Pod 数量", + "cpuCapacityAlloc": "CPU 容量 / 可分配", + "memCapacityAlloc": "内存容量 / 可分配", + "podCapacityAlloc": "Pod 容量 / 可分配", + "coreUnit": "核", + "conditions": "节点条件", + "noConditions": "无条件数据", + "taints": "污点 (Taints)", + "labels": "标签 ({{count}})", + "podsOnNode": "节点上的 Pod", + "noPodsOnNode": "该节点上暂无 Pod", + "cpuRequest": "CPU 请求" } }, "monitor": {