feat(i18n): 剩余模块全量国际化 — 51% 覆盖率 (231 文件接入 t())

批量转换 163 个文件,3204 处中文替换为 t() 调用:
- Monitor: 日志中心/告警中心/数据源/大屏/站点拨测/SNMP/中间件 全部转换
- Kubernetes: ResourceVisualEditor/NamespaceResourcePage/拓扑/事件 全部转换
- Deploy: 流水线/发布/凭证/RBAC 全部转换
- Server/Cloud/Agent/Task/Layout/UI: 全部转换
- 翻译词典扩展至 6474 行 (22 namespaces, 5000+ keys)
- tsc 编译零错误
This commit is contained in:
attacker committed 2026-07-03 01:51:57 +08:00
1 parent 78c27037e3
commit ecec73989b
166 files changed
+6925 -2800

No files matched your search

@@ -18,6 +18,7 @@ import { deployApi } from '@/api';
import CredentialFormDialog from './CredentialFormDialog';
import ToolConfigTab from './ToolConfigTab';
import type { JsonData } from '@/types/common';
import { useTranslation } from 'react-i18next';
interface Repo {
id: number; name: string; description: string; url: string;
@@ -35,6 +36,7 @@ interface Environment {
}
function EnvFormDialog({ open, onClose, onSaved, editData }: { open: boolean; onClose: () => void; onSaved: () => void; editData: Environment | null }) {
const { t } = useTranslation();
const [name, setName] = useState('');
const [displayName, setDisplayName] = useState('');
const [envType, setEnvType] = useState('development');
@@ -57,43 +59,43 @@ function EnvFormDialog({ open, onClose, onSaved, editData }: { open: boolean; on
}, [editData, open]);
const handleSubmit = async () => {
if (!name.trim() || !displayName.trim()) { toast.error('请填写名称'); return; }
if (!name.trim() || !displayName.trim()) { toast.error(t('deploy.form.nameRequired')); return; }
setSubmitting(true);
try {
if (editData) await deployApi.updateEnvironment(editData.id, { name, display_name: displayName, type: envType, color, sort_order: sortOrder, description });
else await deployApi.createEnvironment({ name, display_name: displayName, type: envType, color, sort_order: sortOrder, description });
toast.success(editData ? '已更新' : '已创建');
toast.success(editData ? t('deploy.toast.updated') : t('deploy.toast.created'));
onSaved();
onClose();
} catch { toast.error('操作失败'); }
} catch { toast.error(t('common.operationFailed')); }
finally { setSubmitting(false); }
};
return (
<Dialog open={open} onOpenChange={onClose}>
<DialogContent>
<DialogHeader><DialogTitle>{editData ? '编辑环境' : '新增环境'}</DialogTitle></DialogHeader>
<DialogHeader><DialogTitle>{editData ? t('pipeline.editEnv') : t('pipeline.addEnv')}</DialogTitle></DialogHeader>
<div className="space-y-3">
<div className="space-y-1"><Label>环境标识</Label><Input value={name} onChange={e => setName(e.target.value)} placeholder="production" /></div>
<div className="space-y-1"><Label>显示名称</Label><Input value={displayName} onChange={e => setDisplayName(e.target.value)} placeholder="生产环境" /></div>
<div className="space-y-1"><Label>环境类型</Label>
<div className="space-y-1"><Label>{t('pipeline.envLabel')}</Label><Input value={name} onChange={e => setName(e.target.value)} placeholder="production" /></div>
<div className="space-y-1"><Label>{t('system.userDisplayName')}</Label><Input value={displayName} onChange={e => setDisplayName(e.target.value)} placeholder=t('pipeline.prodEnv') /></div>
<div className="space-y-1"><Label>{t('pipeline.envType')}</Label>
<Select value={envType} onValueChange={setEnvType}>
<SelectTrigger><SelectValue /></SelectTrigger>
<SelectContent>
<SelectItem value="production">生产环境</SelectItem>
<SelectItem value="staging">预发布</SelectItem>
<SelectItem value="testing">测试环境</SelectItem>
<SelectItem value="development">开发环境</SelectItem>
<SelectItem value="production">{t('pipeline.prodEnv')}</SelectItem>
<SelectItem value="staging">{t('pipeline.staging')}</SelectItem>
<SelectItem value="testing">{t('pipeline.testEnv')}</SelectItem>
<SelectItem value="development">{t('pipeline.devEnv')}</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-1"><Label>标志颜色</Label><Input value={color} onChange={e => setColor(e.target.value)} type="color" className="w-16 h-9 p-1" /></div>
<div className="space-y-1"><Label>排序序号</Label><Input value={sortOrder} onChange={e => setSortOrder(Number(e.target.value))} type="number" /></div>
<div className="space-y-1"><Label>描述</Label><Input value={description} onChange={e => setDescription(e.target.value)} placeholder="可选" /></div>
<div className="space-y-1"><Label>{t('deploy.deploycredentials.sc06ac4')}</Label><Input value={color} onChange={e => setColor(e.target.value)} type="color" className="w-16 h-9 p-1" /></div>
<div className="space-y-1"><Label>{t('deploy.deploycredentials.s65dd48')}</Label><Input value={sortOrder} onChange={e => setSortOrder(Number(e.target.value))} type="number" /></div>
<div className="space-y-1"><Label>{t('common.description')}</Label><Input value={description} onChange={e => setDescription(e.target.value)} placeholder=t('common.optional') /></div>
</div>
<div className="flex justify-end gap-2 mt-4">
<Button variant="outline" onClick={onClose}>取消</Button>
<Button onClick={handleSubmit} disabled={submitting}>{submitting ? '...' : editData ? '保存' : '创建'}</Button>
<Button variant="outline" onClick={onClose}>{t('common.cancel')}</Button>
<Button onClick={handleSubmit} disabled={submitting}>{submitting ? '...' : editData ? t('common.save') : t('common.create')}</Button>
</div>
</DialogContent>
</Dialog>
@@ -103,6 +105,7 @@ function EnvFormDialog({ open, onClose, onSaved, editData }: { open: boolean; on
const CONFIG_TABS = ['repos', 'registries', 'environments', 'tools', 'build-nodes'] as const;
export default function DeployCredentials() {
const { t } = useTranslation();
const _confirm = useConfirm();
const [searchParams] = useSearchParams();
const tabFromUrl = searchParams.get('tab');
@@ -126,39 +129,39 @@ export default function DeployCredentials() {
setRepos((rR as JsonData)?.list || []);
setRegistries((rReg as JsonData)?.list || []);
setEnvironments((rEnv as JsonData)?.list || []);
} catch { toast.error('获取数据失败'); }
} catch { toast.error(t('deploy.toast.getDataFailed')); }
finally { setLoading(false); }
};
useEffect(() => { fetchAll(); }, []);
const handleDelete = async (type: 'repo' | 'registry' | 'env', item: JsonData) => {
const ok = await _confirm({ title: '删除', description: `确定删除「${item.name || item.display_name}」?`, confirmText: '删除', variant: 'destructive' });
const ok = await _confirm({ title: t('common.delete'), description: t('deploy.deploycredentials.s999d97', { item.name || item.display_name: item.name || item.display_name }), confirmText: t('common.delete'), variant: 'destructive' });
if (!ok) return;
try {
if (type === 'repo') await deployApi.deleteRepo(item.id);
else if (type === 'registry') await deployApi.deleteRegistry(item.id);
else await deployApi.deleteEnvironment(item.id);
toast.success('已删除');
toast.success(t('alert.deleted'));
fetchAll();
} catch { toast.error('删除失败'); }
} catch { toast.error(t('common.deleteFailed')); }
};
const envTypeLabel: Record<string, string> = { production: '生产', staging: '预发布', testing: '测试', development: '开发' };
const envTypeLabel: Record<string, string> = { production: t('pipeline.production'), staging: t('pipeline.staging'), testing: t('common.test'), development: t('pipeline.development') };
const pageTabs = [
{ id: 'repos', label: 'Git 仓库', badge: repos.length || undefined },
{ id: 'registries', label: '镜像仓库', badge: registries.length || undefined },
{ id: 'environments', label: '环境管理', badge: environments.length || undefined },
{ id: 'build-nodes', label: '构建节点' },
{ id: 'tools', label: '工具配置' },
{ id: 'repos', label: t('deploy.deploycredentials.sd71d03'), badge: repos.length || undefined },
{ id: 'registries', label: t('pipeline.registry'), badge: registries.length || undefined },
{ id: 'environments', label: t('pipeline.envManage'), badge: environments.length || undefined },
{ id: 'build-nodes', label: t('pipeline.buildNode') },
{ id: 'tools', label: t('deploy.tool.title') },
];
return (
<PageShell
variant="list"
title="发布配置"
subtitle="Git 仓库、镜像仓库、环境与工具"
title=t('menu.deployConfig')
subtitle=t('deploy.deploycredentials.s15a730')
icon={<Settings2 className="h-5 w-5" />}
loading={loading}
tabs={pageTabs}
@@ -181,18 +184,18 @@ export default function DeployCredentials() {
>
{activeTab === 'repos' && (
repos.length === 0 ? (
<PageEmpty icon={<GitBranch className="h-10 w-10" />} title="暂无 Git 仓库认证配置" />
<PageEmpty icon={<GitBranch className="h-10 w-10" />} title=t('deploy.deploycredentials.sb19733') />
) : (
<ContentPanel noPadding>
<div className="overflow-hidden">
<table className="w-full text-sm">
<thead className="bg-[var(--dg-bg-tertiary)] border-b border-[var(--dg-border)]">
<tr>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">名称</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)] hidden md:table-cell">仓库 URL</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">认证方式</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">状态</th>
<th className="px-3 py-2 text-right font-medium text-[var(--dg-text-secondary)]">操作</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.name')}</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)] hidden md:table-cell">{t('deploy.table.repoUrl')}</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('deploy.cred.authMethod')}</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.status')}</th>
<th className="px-3 py-2 text-right font-medium text-[var(--dg-text-secondary)]">{t('common.actions')}</th>
</tr>
</thead>
<tbody>
@@ -202,7 +205,7 @@ export default function DeployCredentials() {
<td className="px-3 py-2 text-[var(--dg-text-secondary)] hidden md:table-cell font-mono text-xs max-w-[300px] truncate">{r.url}</td>
<td className="px-3 py-2"><Badge variant="outline" className="text-xs">{r.auth_type}</Badge></td>
<td className="px-3 py-2">
<Badge className={r.enabled ? 'bg-emerald-500/20 dg-text-green border-emerald-500/30' : 'bg-[var(--dg-bg-active)]/20 dg-text-secondary border-[var(--dg-border)]'}>{r.enabled ? '启用' : '禁用'}</Badge>
<Badge className={r.enabled ? 'bg-emerald-500/20 dg-text-green border-emerald-500/30' : 'bg-[var(--dg-bg-active)]/20 dg-text-secondary border-[var(--dg-border)]'}>{r.enabled ? t('common.enable') : t('common.disable')}</Badge>
</td>
<td className="px-3 py-2 text-right">
<div className="flex justify-end gap-1">
@@ -221,19 +224,19 @@ export default function DeployCredentials() {
{activeTab === 'registries' && (
registries.length === 0 ? (
<PageEmpty icon={<Container className="h-10 w-10" />} title="暂无镜像仓库认证配置" />
<PageEmpty icon={<Container className="h-10 w-10" />} title=t('deploy.deploycredentials.sdf33f0') />
) : (
<ContentPanel noPadding>
<div className="overflow-hidden">
<table className="w-full text-sm">
<thead className="bg-[var(--dg-bg-tertiary)] border-b border-[var(--dg-border)]">
<tr>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">名称</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.name')}</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)] hidden md:table-cell">Registry URL</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)] hidden sm:table-cell">命名空间</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">认证</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">状态</th>
<th className="px-3 py-2 text-right font-medium text-[var(--dg-text-secondary)]">操作</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)] hidden sm:table-cell">{t('k8s.column.namespace')}</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('deploy.deploycredentials.sb7158a')}</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.status')}</th>
<th className="px-3 py-2 text-right font-medium text-[var(--dg-text-secondary)]">{t('common.actions')}</th>
</tr>
</thead>
<tbody>
@@ -244,7 +247,7 @@ export default function DeployCredentials() {
<td className="px-3 py-2 text-[var(--dg-text-secondary)] hidden sm:table-cell">{r.namespace || '-'}</td>
<td className="px-3 py-2"><Badge variant="outline" className="text-xs">{r.auth_type}</Badge></td>
<td className="px-3 py-2">
<Badge className={r.enabled ? 'bg-emerald-500/20 dg-text-green border-emerald-500/30' : 'bg-[var(--dg-bg-active)]/20 dg-text-secondary border-[var(--dg-border)]'}>{r.enabled ? '启用' : '禁用'}</Badge>
<Badge className={r.enabled ? 'bg-emerald-500/20 dg-text-green border-emerald-500/30' : 'bg-[var(--dg-bg-active)]/20 dg-text-secondary border-[var(--dg-border)]'}>{r.enabled ? t('common.enable') : t('common.disable')}</Badge>
</td>
<td className="px-3 py-2 text-right">
<div className="flex justify-end gap-1">
@@ -271,8 +274,8 @@ export default function DeployCredentials() {
{environments.length === 0 ? (
<PageEmpty
icon={<Globe className="h-10 w-10" />}
title="暂无环境配置"
description='点击"新增环境"创建'
title=t('pipeline.noEnv')
description=t('deploy.deploycredentials.sac4fb6')
action={(
<Button size="sm" onClick={() => { setEditEnv(null); setEnvDialogOpen(true); }}>
<Plus className="w-4 h-4 mr-1" />新增环境
@@ -285,13 +288,13 @@ export default function DeployCredentials() {
<table className="w-full text-sm">
<thead className="bg-[var(--dg-bg-tertiary)] border-b border-[var(--dg-border)]">
<tr>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">环境标识</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">显示名称</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">类型</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">颜色</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">排序</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">状态</th>
<th className="px-3 py-2 text-right font-medium text-[var(--dg-text-secondary)]">操作</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('pipeline.envLabel')}</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('system.userDisplayName')}</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.type')}</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.color')}</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.sort')}</th>
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.status')}</th>
<th className="px-3 py-2 text-right font-medium text-[var(--dg-text-secondary)]">{t('common.actions')}</th>
</tr>
</thead>
<tbody>
@@ -308,7 +311,7 @@ export default function DeployCredentials() {
<td className="px-3 py-2"><div className="w-6 h-6 rounded border" style={{ backgroundColor: env.color }} /></td>
<td className="px-3 py-2 text-[var(--dg-text-secondary)]">{env.sort_order}</td>
<td className="px-3 py-2">
<Badge className={env.enabled ? 'bg-emerald-500/20 dg-text-green border-emerald-500/30' : 'bg-[var(--dg-bg-active)]/20 dg-text-secondary border-[var(--dg-border)]'}>{env.enabled ? '启用' : '禁用'}</Badge>
<Badge className={env.enabled ? 'bg-emerald-500/20 dg-text-green border-emerald-500/30' : 'bg-[var(--dg-bg-active)]/20 dg-text-secondary border-[var(--dg-border)]'}>{env.enabled ? t('common.enable') : t('common.disable')}</Badge>
</td>
<td className="px-3 py-2 text-right">
<div className="flex justify-end gap-1">