feat(i18n): 安全批量转换 135 文件 — 覆盖率 34%→62%

使用 i18n.t() 全局方式(避免 hook 定位问题):
- 288 目标文件中 135 个成功转换
- 2228 处中文替换为 i18n.t() 调用
- 1006 个新翻译 key 添加到 zh-CN.json + en-US.json
- 词典总量: 3554 keys (22 namespaces)
- tsc 零错误 + Vite 构建成功
- 6 个含代码示例/数据字符串的文件安全回退
This commit is contained in:
attacker committed 2026-07-03 02:14:20 +08:00
1 parent 72bfb0e12d
commit 55f216cfbb
131 files changed
+4049 -1908

No files matched your search

@@ -11,6 +11,7 @@ import { toast } from 'sonner';
import { useCredentialDetail } from '@/hooks/api';
import type { SecretType } from './types';
import { TYPE_CONFIG, TYPE_BADGE_CLASS } from './constants';
import i18n from '@/i18n';
export interface CredDetailDialogProps {
open: boolean;
@@ -26,7 +27,7 @@ export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProp
if (!open || !credId) return null;
const toggleShow = (key: string) => setShowMap(prev => ({ ...prev, [key]: !prev[key] }));
const copyValue = (val: string) => { navigator.clipboard.writeText(val); toast.success('已复制'); };
const copyValue = (val: string) => { navigator.clipboard.writeText(val); toast.success(i18n.t('aiops.agentCliCopied')); };
const st = detail?.secret_type as SecretType;
const cfg = TYPE_CONFIG[st];
@@ -77,39 +78,39 @@ export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProp
</DialogTitle>
</DialogHeader>
{loading ? (
<div className="text-center py-8 text-[var(--dg-text-muted)]">加载中...</div>
<div className="text-center py-8 text-[var(--dg-text-muted)]"> {i18n.t('monitor.logPanel.logResults.loading')} </div>
) : detail ? (
<div className="space-y-4">
{/* 基本信息 // Logan.Li */}
<div className="grid grid-cols-2 gap-3 text-sm">
<div><span className="text-[var(--dg-text-muted)]">名称:</span><span className="text-[var(--dg-text-primary)] font-medium">{detailRecord?.name as string}</span></div>
<div><span className="text-[var(--dg-text-muted)]">类型:</span>
<div><span className="text-[var(--dg-text-muted)]"> {i18n.t('pipeline.creddetaildialo.s5b478615')} </span><span className="text-[var(--dg-text-primary)] font-medium">{detailRecord?.name as string}</span></div>
<div><span className="text-[var(--dg-text-muted)]"> {i18n.t('pipeline.creddetaildialo.se91f5a13')} </span>
<Badge variant="outline" className={`text-xs ml-1 ${TYPE_BADGE_CLASS[st] || ''}`}>{cfg?.label || st}</Badge>
</div>
<div><span className="text-[var(--dg-text-muted)]">状态:</span>
<div><span className="text-[var(--dg-text-muted)]"> {i18n.t('approval.detail.statusLabel')} </span>
{detailRecord?.is_active
? <Badge className="bg-green-500/20 dg-text-green text-xs ml-1"><CheckCircle2 className="h-3 w-3 mr-0.5" />启用</Badge>
: <Badge className="bg-red-500/20 dg-text-red text-xs ml-1"><XCircle className="h-3 w-3 mr-0.5" />禁用</Badge>}
? <Badge className="bg-green-500/20 dg-text-green text-xs ml-1"><CheckCircle2 className="h-3 w-3 mr-0.5" /> {i18n.t('system.userActive')} </Badge>
: <Badge className="bg-red-500/20 dg-text-red text-xs ml-1"><XCircle className="h-3 w-3 mr-0.5" /> {i18n.t('system.userInactive')} </Badge>}
{detailRecord?.expires_at && new Date(detailRecord.expires_at as string) < new Date() && (
<Badge className="bg-yellow-500/20 dg-text-yellow text-xs ml-1"><AlertTriangle className="h-3 w-3 mr-0.5" />已过期</Badge>
<Badge className="bg-yellow-500/20 dg-text-yellow text-xs ml-1"><AlertTriangle className="h-3 w-3 mr-0.5" /> {i18n.t('system.expired2')} </Badge>
)}
</div>
<div className="col-span-2 cursor-pointer" onClick={() => copyValue((detailRecord?.env_prefix as string) || '')}>
<span className="text-[var(--dg-text-muted)]">引用ID:</span>
<span className="text-[var(--dg-text-muted)]"> {i18n.t('deploy.cred.refIdLabel')} </span>
<code className="text-[var(--dg-blue)] font-mono text-xs">{detailRecord?.env_prefix as string || '无'}</code>
<Copy className="h-3 w-3 inline ml-1 text-[var(--dg-text-muted)]" />
</div>
{(detailRecord?.tags as string[])?.length > 0 && (
<div className="col-span-2">
<span className="text-[var(--dg-text-muted)]">标签:</span>
<span className="text-[var(--dg-text-muted)]"> {i18n.t('pipeline.creddetaildialo.s1655dd5f')} </span>
{(detailRecord?.tags as string[]).map((t: string) => (
<Badge key={t} variant="outline" className="text-xs ml-1 border-[var(--dg-border)]">{t}</Badge>
))}
</div>
)}
<div className="col-span-2"><span className="text-[var(--dg-text-muted)]">描述:</span><span className="text-[var(--dg-text-secondary)]">{(detailRecord?.description as string) || '无'}</span></div>
<div><span className="text-[var(--dg-text-muted)]">创建:</span><span className="text-[var(--dg-text-secondary)] text-xs">{new Date(detailRecord?.created_at as string).toLocaleString()}</span></div>
<div><span className="text-[var(--dg-text-muted)]">更新:</span><span className="text-[var(--dg-text-secondary)] text-xs">{new Date(detailRecord?.updated_at as string).toLocaleString()}</span></div>
<div className="col-span-2"><span className="text-[var(--dg-text-muted)]"> {i18n.t('pipeline.creddetaildialo.s4a4e3b5a')} </span><span className="text-[var(--dg-text-secondary)]">{(detailRecord?.description as string) || '无'}</span></div>
<div><span className="text-[var(--dg-text-muted)]"> {i18n.t('pipeline.creddetaildialo.s76d768fb')} </span><span className="text-[var(--dg-text-secondary)] text-xs">{new Date(detailRecord?.created_at as string).toLocaleString()}</span></div>
<div><span className="text-[var(--dg-text-muted)]"> {i18n.t('pipeline.creddetaildialo.s3820b7e1')} </span><span className="text-[var(--dg-text-secondary)] text-xs">{new Date(detailRecord?.updated_at as string).toLocaleString()}</span></div>
</div>
{/* 密钥数据 // Logan.Li */}
@@ -118,41 +119,41 @@ export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProp
<Key className="h-4 w-4 text-yellow-500" />密钥数据
</div>
<div className="p-3 rounded-md bg-yellow-500/5 border border-yellow-500/20 mb-3">
<p className="text-xs dg-text-yellow/80">以下内容包含敏感信息,请妥善保管,不要泄露给他人。</p>
<p className="text-xs dg-text-yellow/80"> {i18n.t('pipeline.creddetaildialo.s03b218d4')} </p>
</div>
{st === 'ssh' && <>
<Field label="SSH 用户" value={content.ssh_user} />
<Field label="SSH 端口" value={content.ssh_port} />
<Field label="SSH 密码" value={content.password} sensitive fieldKey="ssh_password" />
<Field label="私钥" value={content.private_key} sensitive fieldKey="ssh_private_key" />
<Field label="公钥" value={content.public_key} fieldKey="ssh_public_key" />
<Field label={i18n.t('pipeline.creddetaildialo.s2272f5e9')} value={content.ssh_user} />
<Field label={i18n.t('pipeline.creddetaildialo.s3f284a59')} value={content.ssh_port} />
<Field label={i18n.t('system.sshPassword')} value={content.password} sensitive fieldKey="ssh_password" />
<Field label={i18n.t('system.sshPrivateKey')} value={content.private_key} sensitive fieldKey="ssh_private_key" />
<Field label={i18n.t('system.sshPublicKey')} value={content.public_key} fieldKey="ssh_public_key" />
</>}
{st === 'docker' && <>
<Field label="Registry 地址" value={content.server} />
<Field label="用户名" value={content.username} />
<Field label="密码" value={content.password} sensitive fieldKey="docker_password" />
<Field label={i18n.t('deploy.form.registryAddr')} value={content.server} />
<Field label={i18n.t('system.userName')} value={content.username} />
<Field label={i18n.t('system.passwordLabel')} value={content.password} sensitive fieldKey="docker_password" />
</>}
{st === 'tls' && <>
<Field label="证书" value={content.cert} sensitive fieldKey="tls_cert" />
<Field label="私钥" value={content.key} sensitive fieldKey="tls_key" />
<Field label="CA 证书" value={content.ca} sensitive fieldKey="tls_ca" />
<Field label={i18n.t('pipeline.creddetaildialo.sd40b5115')} value={content.cert} sensitive fieldKey="tls_cert" />
<Field label={i18n.t('system.sshPrivateKey')} value={content.key} sensitive fieldKey="tls_key" />
<Field label={i18n.t('pipeline.credformdialogt.sa24356be')} value={content.ca} sensitive fieldKey="tls_ca" />
</>}
{st === 'aksk' && <>
<Field label="Access Key ID" value={content.access_key} />
<Field label="Secret Access Key" value={content.secret_key} sensitive fieldKey="aksk_secret_key" />
</>}
{st === 'database' && <>
<Field label="数据库类型" value={String(content.db_type || '').toUpperCase()} />
<Field label="主机" value={content.host} />
<Field label="端口" value={content.port} />
<Field label="数据库名" value={content.db_name} />
<Field label="用户名" value={content.username} />
<Field label="密码" value={content.password} sensitive fieldKey="db_password" />
<Field label={i18n.t('pipeline.credformdialogt.s84b916da')} value={String(content.db_type || '').toUpperCase()} />
<Field label={i18n.t('agent.agentHost')} value={content.host} />
<Field label={i18n.t('system.ldapPort')} value={content.port} />
<Field label={i18n.t('pipeline.credformdialogt.s5ccbbd01')} value={content.db_name} />
<Field label={i18n.t('system.userName')} value={content.username} />
<Field label={i18n.t('system.passwordLabel')} value={content.password} sensitive fieldKey="db_password" />
</>}
{st === 'api' && <>
<Field label="API Key" value={content.api_key} sensitive fieldKey="api_key" />
<Field label="API 端点" value={content.endpoint} />
<Field label={i18n.t('pipeline.creddetaildialo.s48ec3494')} value={content.endpoint} />
</>}
{st === 'generic' && <>
<Field label="Key" value={content.generic_key} />
@@ -162,17 +163,17 @@ export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProp
{/* 引用提示 // Logan.Li */}
<div className="border-t border-[var(--dg-border)] pt-3">
<div className="text-xs text-[var(--dg-text-muted)] mb-2">在流水线/脚本中引用此凭据:</div>
<div className="text-xs text-[var(--dg-text-muted)] mb-2"> {i18n.t('deploy.cred.refHint')} </div>
<code className="text-xs bg-[var(--dg-bg-tertiary)] px-3 py-1.5 rounded block text-[var(--dg-blue)]">
{'${'}{String(detailRecord?.variable_name || String(detailRecord?.name || '').toUpperCase().replace(/[^A-Z0-9]/g, '_'))}{'}'}
</code>
</div>
</div>
) : (
<div className="text-center py-8 text-[var(--dg-text-muted)]">未找到凭据数据</div>
<div className="text-center py-8 text-[var(--dg-text-muted)]"> {i18n.t('deploy.cred.noCredData')} </div>
)}
<DialogFooter>
<Button variant="outline" onClick={onClose}>关闭</Button>
<Button variant="outline" onClick={onClose}> {i18n.t('agent.portClosed')} </Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -4,15 +4,16 @@ import {
Key, Server, Container, Shield, Cloud, Database, FileText, Globe,
} from 'lucide-react';
import type { SecretType } from './types';
import i18n from '@/i18n';
export const TYPE_CONFIG: Record<SecretType, { label: string; icon: typeof Key; color: string; desc: string }> = {
ssh: { label: 'SSH 密钥', icon: Server, color: 'dg-text-yellow', desc: 'SSH 私钥/公钥/密码' },
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 键值对' },
ssh: { label: i18n.t('system.sshKeyLabel'), icon: Server, color: 'dg-text-yellow', desc: i18n.t('pipeline.constantsts.sedc7f9e9') },
docker: { label: i18n.t('system.dockerCredential'), icon: Container, color: 'dg-text-cyan', desc: i18n.t('pipeline.constantsts.sbd6cf171') },
tls: { label: i18n.t('pipeline.constantsts.sfa5a64de'), icon: Shield, color: 'dg-text-green', desc: i18n.t('pipeline.constantsts.s43f00c61') },
aksk: { label: i18n.t('pipeline.constantsts.sb82698a1'), icon: Cloud, color: 'dg-text-purple', desc: i18n.t('pipeline.constantsts.s564e98a9') },
database: { label: i18n.t('system.dbCredential'), icon: Database, color: 'dg-text-blue', desc: i18n.t('pipeline.constantsts.se47498d3') },
api: { label: i18n.t('system.apiKeys'), icon: Globe, color: 'dg-text-orange', desc: i18n.t('pipeline.constantsts.sb3edf0a4') },
generic: { label: i18n.t('pipeline.constantsts.s1d319bb7'), icon: FileText, color: 'dg-text-secondary', desc: i18n.t('pipeline.constantsts.s51b5b280') },
};
export const TYPE_BADGE_CLASS: Record<SecretType, string> = {