From de6f9454fcb06af7710bd9866749049179d63ef3 Mon Sep 17 00:00:00 2001 From: attacker Date: Sat, 11 Jul 2026 17:48:04 +0800 Subject: [PATCH] =?UTF-8?q?refactor(i18n):=20U23=20Task=20=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=20i18n=20=E6=B2=BB=E7=90=86=20=E2=80=94=204=20?= =?UTF-8?q?=E6=96=87=E4=BB=B6=20phantom=20key=20+=20hash=20key=20+=20?= =?UTF-8?q?=E7=A1=AC=E7=BC=96=E7=A0=81=E4=B8=AD=E6=96=87=E6=B8=85=E9=9B=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CronJobManager/CronJobFormDialog/ScriptManager/RemoteExecPage 从 import i18n 全局调用改为 useTranslation() hook - 42 处 phantom key (i18n.t('Chinese text') → 语义化键) - 28 个孤儿 hash key 清理 (cronjobformdial.s*/remoteexecpaget.s*) - 50+ 处硬编码 JSX 中文 → t() 调用 - 新增 task.cronJob.*/task.scriptList.*/task.remoteExec.* 子命名空间 - zh/en 6825→6886 keys 对齐 - tsc -b=0, npm build✓ (17.46s), ESLint=0/45/0, go build=0 - 17/17 集成回归测试通过 --- ROADMAP.md | 1 + .../src/components/task/CronJobFormDialog.tsx | 105 +++++++-------- .../src/components/task/CronJobManager.tsx | 89 +++++++------ .../src/components/task/RemoteExecPage.tsx | 77 +++++------ .../src/components/task/ScriptManager.tsx | 68 +++++----- frontend/src/locales/en-US.json | 125 ++++++++++++++---- frontend/src/locales/zh-CN.json | 125 ++++++++++++++---- 7 files changed, 361 insertions(+), 229 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index c33d07a..c0c6654 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -514,6 +514,7 @@ services/api.ts (1324L) | U17 | K8s 残余组件 i18n 补全(NodeDetailPage 16 处硬编码中文清零 + 8 个 hash 键替换为语义化 k8s.nodeDetail.* 键 + DeploymentWorkload 12 处 toast/confirm 硬编码中文清零,zh/en 7564→7597 +33 键对齐) | P3 | **done** | | U19 | i18n hash 键清理(删除 866 个死 hash 键 + 重命名 21 个高频 live hash 键为语义化键名,zh/en 7597→6731 keys 对齐,文件 328KB→276KB (-16%),tsc -b=0,npm build✓,ESLint=0/66/0,17/17 测试通过) | P3 | **done** | | U20 | ESLint static-components 清零 + CredDetailDialog 内联组件修复 + i18n 批量迁移损坏修复(CredDetailDialog.tsx `Field` 内联组件提取为模块级 `CredField` — 23 处 react-hooks/static-components 警告清零;修复 8 处被批量正则损坏的 `i18n.t()` 调用(`i18n.t('>名称:')` 等 → 语义化键);6 处硬编码中文清零;新增 `deploy.cred.sensitiveWarn` 键;ESLint warnings 66→43 (-35%),tsc -b=0,npm build✓ (17.29s),17/17 测试通过) | P3 | **done** | +| U23 | Task 模块 i18n 治理(CronJobManager + CronJobFormDialog + ScriptManager + RemoteExecPage 4 文件 — `import i18n` 全局调用 → `useTranslation()` hook;42 处 phantom key (`i18n.t('Chinese text')` → 语义化 `task.cronJob.*`/`task.scriptList.*`/`task.remoteExec.*` 键);28 个孤儿 hash 键清理 (cronjobformdial.s*/remoteexecpaget.s*/systemtaskspanel.s*);50+ 处硬编码 JSX 中文 → t() 调用;zh/en 6825→6886 +61 键对齐,tsc -b=0,npm build✓ (17.46s),ESLint=0/45/0,go build=0,17/17 测试通过) | P3 | **done** | --- diff --git a/frontend/src/components/task/CronJobFormDialog.tsx b/frontend/src/components/task/CronJobFormDialog.tsx index f4bee08..247ed70 100644 --- a/frontend/src/components/task/CronJobFormDialog.tsx +++ b/frontend/src/components/task/CronJobFormDialog.tsx @@ -1,4 +1,5 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { @@ -22,15 +23,6 @@ import { Badge } from '@/components/ui/badge'; import { toast } from 'sonner'; import { cronJobApi, scriptApi } from '@/api'; import type { JsonData } from '@/types/common'; -import i18n from '@/i18n'; - -// 定时任务类型定义 // Logan.Li -const jobTypes = [ - { value: 'shell', label: 'Shell', desc: i18n.t('关联脚本库中的 Shell 脚本') }, - { value: 'python', label: 'Python', desc: i18n.t('关联脚本库中的 Python 脚本') }, - { value: 'powershell', label: 'PowerShell', desc: i18n.t('关联脚本库中的 PowerShell 脚本') }, - { value: 'command', label: i18n.t('自定义命令'), desc: i18n.t('手动输入命令或脚本路径') }, -]; const scriptJobTypes = ['shell', 'python', 'powershell']; @@ -51,6 +43,7 @@ export function CronJobFormDialog({ editJob: JsonData | null; onSuccess: () => void; }) { + const { t } = useTranslation(); const [form, setForm] = useState({ name: '', description: '', @@ -63,10 +56,15 @@ export function CronJobFormDialog({ const [selectedScript, setSelectedScript] = useState(null); const [submitting, setSubmitting] = useState(false); - // 弹窗打开时:加载脚本库 + 初始化表单 // Logan.Li + const jobTypes = useMemo(() => [ + { value: 'shell', label: 'Shell', desc: t('task.cronJob.typeShell') }, + { value: 'python', label: 'Python', desc: t('task.cronJob.typePython') }, + { value: 'powershell', label: 'PowerShell', desc: t('task.cronJob.typePowershell') }, + { value: 'command', label: t('task.cronJob.typeCommandLabel'), desc: t('task.cronJob.typeCommandDesc') }, + ], [t]); + useEffect(() => { if (!open) return; - // 拉取脚本库 scriptApi.getScripts({ page_size: 200 }).then((res: JsonData) => { setScripts(res?.list || []); }).catch(() => setScripts([])); @@ -80,7 +78,6 @@ export function CronJobFormDialog({ content: editJob.content || '', script_id: editJob.script_id || null, }); - // 如果关联了脚本,拉取脚本详情 if (editJob.script_id) { scriptApi.getScript(editJob.script_id).then((res: JsonData) => { setSelectedScript(res); @@ -94,12 +91,10 @@ export function CronJobFormDialog({ } }, [open, editJob]); - // 按类型过滤脚本库 // Logan.Li const filteredScripts = scriptJobTypes.includes(form.type) ? scripts.filter(s => s.type === form.type) : []; - // 选中脚本时更新关联 const handleSelectScript = (scriptId: string) => { const sc = scripts.find(s => String(s.id) === scriptId); if (sc) { @@ -108,7 +103,6 @@ export function CronJobFormDialog({ } }; - // 切换类型时重置脚本关联 const handleTypeChange = (type: string) => { setForm(prev => ({ ...prev, @@ -121,12 +115,11 @@ export function CronJobFormDialog({ const handleSave = async () => { if (!form.name || !form.cron_expr) { - toast.error(i18n.t('请填写任务名称和 Cron 表达式')); + toast.error(t('task.cronJob.form.toastNameRequired')); return; } - // 脚本类型必须选关联脚本 // Logan.Li if (scriptJobTypes.includes(form.type) && !form.script_id) { - toast.error(i18n.t('请填写任务名称和 Cron 表达式')); + toast.error(t('task.cronJob.form.toastNameRequired')); return; } try { @@ -141,16 +134,16 @@ export function CronJobFormDialog({ }; if (editJob) { await cronJobApi.updateJob(editJob.id, payload); - toast.success(i18n.t('任务更新成功')); + toast.success(t('task.cronJob.form.toastSaved')); } else { await cronJobApi.createJob(payload); - toast.success(i18n.t('任务更新成功')); + toast.success(t('task.cronJob.form.toastSaved')); } onOpenChange(false); onSuccess(); } catch (error) { console.error('Failed to save cron job:', error); - toast.error(editJob ? i18n.t('kubernetes.deployment.imageUpdateFailed') : i18n.t('monitor.dashboard.custom.toastCreateFailed')); + toast.error(editJob ? t('kubernetes.deployment.imageUpdateFailed') : t('monitor.dashboard.custom.toastCreateFailed')); } finally { setSubmitting(false); } @@ -160,36 +153,33 @@ export function CronJobFormDialog({ - {editJob ? i18n.t('automation.editCronJob') : i18n.t('编辑定时任务')} - {i18n.t('task.cronjobformdial.s2e10ee70')} + {editJob ? t('task.cronJob.form.titleEdit') : t('task.cronJob.form.titleCreate')} + {t('task.cronJob.form.desc')}
- {/* 任务名称 */}
- + setForm({ ...form, name: e.target.value })} - placeholder={i18n.t('例如: 数据库备份')} + placeholder={t('task.cronJob.form.placeholderName')} className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] mt-1" />
- {/* 描述 */}
- +