fix(i18n): 回退到稳定的 32% 覆盖率状态 (tsc + Vite 构建通过)

批量转换脚本引入的语法错误已回退,保留稳定的 i18n 转换:
- 翻译词典: 22 namespaces, 3600+ keys
- 已接入: 145+ 文件 (Dashboard/Login/K8s 主页面/Monitor/System/Deploy)
- 语言切换器在 Header 中可用 (🇨🇳/🇺🇸)
- tsc 零错误, Vite 构建成功
This commit is contained in:
attacker committed 2026-07-03 02:02:29 +08:00
1 parent ecec73989b
commit 72bfb0e12d
191 files changed
+5057 -7592

No files matched your search

@@ -57,22 +57,19 @@ export function CICDWebhookContent({
const restartUrl = `${apiBase}/kubernetes/${clusterCode}/namespace/${namespace}/deployments/${deploymentName}/restart`;
const updateBody = useMemo(() => {
const body: Record<string, string> = { image: image || t('kubernetes.cicdwebhookcontent.sc4be9c') };
const body: Record<string, string> = { image: image || t('k8s.cicd.newImagePlaceholder') };
if (containerName) body.container_name = containerName;
return JSON.stringify(body);
}, [image, containerName]);
const accessKeyPlaceholder = t('k8s.cicd.accessKeyPlaceholder');
const updateCurl = accessKey
? `curl -X POST '${updateUrl}' \\
-H 'X-AIOps-Access-Key: ${accessKey}' \\
-H 'Content-Type: application/json' \\
-d '${updateBody}'`
: t('kubernetes.cicdwebhookcontent.s1976d2', { updateUrl: updateUrl, updateBody: updateBody });
? `curl -X POST '${updateUrl}' \\\n -H 'X-AIOps-Access-Key: ${accessKey}' \\\n -H 'Content-Type: application/json' \\\n -d '${updateBody}'`
: `curl -X POST '${updateUrl}' \\\n -H 'X-AIOps-Access-Key: ${accessKeyPlaceholder}' \\\n -H 'Content-Type: application/json' \\\n -d '${updateBody}'`;
const restartCurl = accessKey
? `curl -X POST '${restartUrl}' \\
-H 'X-AIOps-Access-Key: ${accessKey}'`
: t('kubernetes.cicdwebhookcontent.s0e3668', { restartUrl: restartUrl });
? `curl -X POST '${restartUrl}' \\\n -H 'X-AIOps-Access-Key: ${accessKey}'`
: `curl -X POST '${restartUrl}' \\\n -H 'X-AIOps-Access-Key: ${accessKeyPlaceholder}'`;
const canCopy = !!accessKey && !keyExpired;
@@ -81,53 +78,53 @@ export function CICDWebhookContent({
<div className="rounded-md bg-[var(--dg-bg-tertiary)]/50 px-3 py-2 text-xs text-[var(--dg-text-muted)] leading-relaxed">
{keyLoading ? (
<span className="inline-flex items-center gap-1.5">
<Loader2 className="h-3 w-3 animate-spin" />正在读取 API 密钥…
<Loader2 className="h-3 w-3 animate-spin" />{t('k8s.cicd.readingKey')}
</span>
) : keyExpired ? (
<>
访问凭证已过期,请前往
<Link to="/profile" className="text-[var(--dg-blue)] hover:underline mx-1">{t('header.profile')}</Link>
调整有效期或轮换凭证后再复制 curl。
{t('k8s.cicd.expiredPrefix')}
<Link to="/profile" className="text-[var(--dg-blue)] hover:underline mx-1">{t('k8s.cicd.profileCenter')}</Link>
{t('k8s.cicd.expiredSuffix')}
</>
) : accessKey ? (
<>{t('kubernetes.cicdwebhookcontent.scd2b7d')}</>
<>{t('k8s.cicd.cachedHint')}</>
) : hasKey ? (
<>
已检测到访问凭证,但本机未缓存明文。请前往
<Link to="/profile" className="text-[var(--dg-blue)] hover:underline mx-1">{t('header.profile')}</Link>
轮换凭证一次,之后 curl 将自动填入。
{t('k8s.cicd.detectedPrefix')}
<Link to="/profile" className="text-[var(--dg-blue)] hover:underline mx-1">{t('k8s.cicd.profileCenter')}</Link>
{t('k8s.cicd.detectedSuffix')}
</>
) : (
<>
请先在
<Link to="/profile" className="text-[var(--dg-blue)] hover:underline mx-1">{t('header.profile')}</Link>
签发 CI/CD 访问凭证,curl 将自动填入。
{t('k8s.cicd.noKeyPrefix')}
<Link to="/profile" className="text-[var(--dg-blue)] hover:underline mx-1">{t('k8s.cicd.profileCenter')}</Link>
{t('k8s.cicd.noKeySuffix')}
</>
)}
</div>
<CodeSnippetBlock
label=t('kubernetes.deployment.updateImage')
label={t('k8s.editImage.updateImage')}
code={updateCurl}
copyLabel=t('kubernetes.cicdwebhookcontent.s25a990')
copyLabel={t('k8s.cicd.copyLabel')}
copyDisabled={!canCopy}
copyDisabledTitle=t('kubernetes.cicdwebhookcontent.sc3bc41')
copyDisabledTitle={t('k8s.cicd.copyDisabledTitle')}
/>
<CodeSnippetBlock
label=t('kubernetes.deployment.restart')
label={t('k8s.cicd.rollingRestart')}
code={restartCurl}
copyLabel=t('kubernetes.cicdwebhookcontent.s25a990')
copyLabel={t('k8s.cicd.copyLabel')}
copyDisabled={!canCopy}
copyDisabledTitle=t('kubernetes.cicdwebhookcontent.sc3bc41')
copyDisabledTitle={t('k8s.cicd.copyDisabledTitle')}
/>
<div className="text-xs text-[var(--dg-text-muted)] space-y-1">
<p>{t('kubernetes.cicdwebhookcontent.s1bdaf4')}<code className="text-[var(--dg-text-secondary)]">{image || '—'}</code>
{containerName ? <> {t('kubernetes.cicdwebhookcontent.s9b07e8')} <code className="text-[var(--dg-text-secondary)]">{containerName}</code></> : null}
<p>{t('k8s.cicd.sampleImage')}<code className="text-[var(--dg-text-secondary)]">{image || '—'}</code>
{containerName ? <>{t('k8s.cicd.container')}<code className="text-[var(--dg-text-secondary)]">{containerName}</code></> : null}
</p>
<p>{t('kubernetes.cicdwebhookcontent.se067d1')}</p>
<p>{t('kubernetes.cicdwebhookcontent.s311998')} <code className="text-[var(--dg-text-secondary)]">image</code> {t('kubernetes.cicdwebhookcontent.s55260c')}</p>
<p>{t('kubernetes.cicdwebhookcontent.s4e20ba')} <code className="text-[var(--dg-text-secondary)]">{t('kubernetes.cicdwebhookcontent.s67cc60')}</code></p>
<p>{t('k8s.cicd.tipLongTermKey')}</p>
<p>{t('k8s.cicd.tipEditImagePrefix')}<code className="text-[var(--dg-text-secondary)]">image</code>{t('k8s.cicd.tipEditImageSuffix')}</p>
<p>{t('k8s.cicd.tipBearerPrefix')}<code className="text-[var(--dg-text-secondary)]">Authorization: Bearer &lt;{t('k8s.cicd.tipBearerKey')}&gt;</code>{t('k8s.cicd.tipBearerSuffix')}</p>
</div>
</div>
);
@@ -1,13 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
// EditModeContainer.tsx — 编辑模式 Tab 容器,共享 manifest 状态 // Logan.Li
import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { Container, Settings, Database, Network } from 'lucide-react';
import { DeploymentEditBasic } from '../DeploymentEditBasic';
import { DeploymentEditContainers } from '../DeploymentEditContainers';
import { DeploymentEditStorage } from '../DeploymentEditStorage';
import { DeploymentEditAdvanced } from '../DeploymentEditAdvanced';
import { DeploymentEditService } from '../DeploymentEditService';
import { useTranslation } from 'react-i18next';
export interface EditModeContainerProps {
clusterCode: string;
@@ -36,11 +36,11 @@ export function EditModeContainer({ clusterCode, namespace, deploymentName, mani
};
const tabs: Array<{ key: EditTab; label: string; icon: typeof Settings }> = [
{ key: 'basic', label: t('deploy.label.basicInfo'), icon: Settings },
{ key: 'containers', label: t('kubernetes.editmodecontainer.sd58c2e'), icon: Container },
{ key: 'storage', label: t('kubernetes.editmodecontainer.s9ffdac'), icon: Database },
{ key: 'advanced', label: t('kubernetes.editmodecontainer.se37075'), icon: Settings },
{ key: 'service', label: t('kubernetes.editmodecontainer.s8bdc2d'), icon: Network },
{ key: 'basic', label: t('k8s.editMode.basic'), icon: Settings },
{ key: 'containers', label: t('k8s.editMode.containers'), icon: Container },
{ key: 'storage', label: t('k8s.editMode.storage'), icon: Database },
{ key: 'advanced', label: t('k8s.editMode.advanced'), icon: Settings },
{ key: 'service', label: t('k8s.editMode.service'), icon: Network },
];
const commonProps = {
@@ -8,8 +8,8 @@ import { FileText, RefreshCw, Loader2, X } from 'lucide-react';
import { kubernetesApi } from '@/api';
import { useToast } from '@/hooks/use-toast';
import { useUserStore } from '@/store';
import type { JsonData } from '@/types/common';
import { useTranslation } from 'react-i18next';
import type { JsonData } from '@/types/common';
export interface PodLogsModalProps {
clusterCode: string;
@@ -32,9 +32,9 @@ export function PodLogsModal({ clusterCode, namespace, podName, containers, onCl
setLoading(true);
try {
const res: JsonData = await kubernetesApi.getPodLogs(clusterCode, namespace, podName, tail, container || undefined);
setLogs(res?.data?.logs || res?.logs || res || t('kubernetes.podlogsmodal.s4ff3b4'));
setLogs(res?.data?.logs || res?.logs || res || t('k8s.podLogs.noLogs'));
} catch {
setLogs(t('kubernetes.podlogsmodal.sc93f33'));
setLogs(t('k8s.podLogs.loadFailed'));
} finally { setLoading(false); }
};
@@ -59,7 +59,7 @@ export function PodLogsModal({ clusterCode, namespace, podName, containers, onCl
setLogs(buf);
}
} catch {
toast({ title: t('kubernetes.podlogsmodal.s6273c9'), variant: 'destructive' });
toast({ title: t('k8s.podLogs.streamInterrupted'), variant: 'destructive' });
} finally { setStreaming(false); }
};
@@ -87,14 +87,14 @@ export function PodLogsModal({ clusterCode, namespace, podName, containers, onCl
{loading ? <Loader2 className="h-3 w-3 animate-spin" /> : <RefreshCw className="h-3 w-3" />}
</Button>
<Button size="sm" variant="outline" className="h-7 border-[var(--dg-border)] dg-text-green text-xs" onClick={startStream} disabled={streaming}>
{streaming ? t('kubernetes.podlogsmodal.s2d4fb3') : t('monitor.logStreaming')}
{streaming ? t('k8s.podLogs.streaming') : t('k8s.podLogs.liveStream')}
</Button>
<Button variant="ghost" size="icon" className="h-7 w-7 dg-text-secondary" onClick={onClose}><X className="h-4 w-4" /></Button>
</div>
</div>
<div className="flex-1 overflow-auto p-3">
<pre className="bg-[var(--dg-bg-primary)] rounded p-3 text-xs text-[var(--dg-text-secondary)] font-mono whitespace-pre-wrap max-h-[60vh] overflow-auto">
{logs || t('kubernetes.podlogsmodal.s99eac0')}
{logs || t('k8s.podLogs.noLogContent')}
</pre>
</div>
</div>
@@ -4,9 +4,9 @@ import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { ArrowRight, Loader2 } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { joinImageRef, parseImageRef } from '../image-ref-utils';
import { ModalShell } from './ModalShell';
import { useTranslation } from 'react-i18next';
export interface UpdateImageModalProps {
deployment: any;
@@ -48,14 +48,14 @@ export function UpdateImageModal({
};
return (
<ModalShell title=t('kubernetes.updateimagemodal.s22a2ed') onClose={onClose} size="xl">
<ModalShell title={t('k8s.editImage.title')} onClose={onClose} size="xl">
<div className="space-y-5">
{/* 当前镜像:只读展示完整地址与 Tag // Logan.Li */}
<div className="rounded-lg border border-[var(--dg-border)]/80 bg-[var(--dg-bg-tertiary)]/40 p-4 space-y-3">
<p className="text-xs font-medium dg-text-secondary">{t('kubernetes.deployment.currentImage')}</p>
<p className="text-xs font-medium dg-text-secondary">{t('k8s.editImage.currentImage')}</p>
<div className="grid grid-cols-[1fr_180px] gap-3">
<div>
<Label className="dg-text-muted text-xs">{t('kubernetes.updateimagemodal.sdbe6a6')}</Label>
<Label className="dg-text-muted text-xs">{t('k8s.editImage.imageAddress')}</Label>
<p
className="mt-1.5 text-sm text-[var(--dg-text-primary)] font-mono break-all leading-relaxed bg-[var(--dg-bg-secondary)]/60 rounded-md px-3 py-2.5 min-h-[42px]"
title={current.repository || '-'}
@@ -64,7 +64,7 @@ export function UpdateImageModal({
</p>
</div>
<div>
<Label className="dg-text-muted text-xs">{t('kubernetes.updateimagemodal.sf08c71')}</Label>
<Label className="dg-text-muted text-xs">{t('k8s.editImage.currentTag')}</Label>
<p
className="mt-1.5 text-sm text-cyan-300 font-mono break-all leading-relaxed bg-[var(--dg-bg-secondary)]/60 rounded-md px-3 py-2.5 min-h-[42px]"
title={current.tag || '-'}
@@ -74,7 +74,7 @@ export function UpdateImageModal({
</div>
</div>
<p className="text-[11px] dg-text-muted font-mono break-all" title={currentImage}>
完整引用:<span className="dg-text-secondary">{currentImage || '-'}</span>
{t('k8s.editImage.fullRef')}<span className="dg-text-secondary">{currentImage || '-'}</span>
</p>
</div>
@@ -84,10 +84,10 @@ export function UpdateImageModal({
{/* 新镜像:地址与 Tag 分栏编辑 // Logan.Li */}
<div className="rounded-lg border border-blue-500/30 bg-blue-500/5 p-4 space-y-3">
<p className="text-xs font-medium text-blue-300/90">{t('kubernetes.deployment.newImage')}</p>
<p className="text-xs font-medium text-blue-300/90">{t('k8s.editImage.newImage')}</p>
<div className="grid grid-cols-[1fr_180px] gap-3">
<div>
<Label className="dg-text-secondary text-xs">{t('kubernetes.updateimagemodal.sdbe6a6')}</Label>
<Label className="dg-text-secondary text-xs">{t('k8s.editImage.imageAddress')}</Label>
<Input
value={newRepo}
onChange={e => {
@@ -100,7 +100,7 @@ export function UpdateImageModal({
/>
</div>
<div>
<Label className="dg-text-secondary text-xs">{t('kubernetes.updateimagemodal.s6a38a8')}</Label>
<Label className="dg-text-secondary text-xs">{t('k8s.editImage.newTag')}</Label>
<Input
value={newTag}
onChange={e => {
@@ -115,7 +115,7 @@ export function UpdateImageModal({
</div>
<div className="flex flex-wrap items-center gap-2 text-xs">
<span className="dg-text-muted">{t('kubernetes.updateimagemodal.sec74e0')}</span>
<span className="dg-text-muted">{t('k8s.editImage.tagChange')}</span>
<code className="px-2 py-0.5 rounded bg-[var(--dg-bg-tertiary)] dg-text-secondary font-mono">{current.tag}</code>
<ArrowRight className="h-3 w-3 dg-text-muted" />
<code
@@ -126,28 +126,28 @@ export function UpdateImageModal({
{newTag.trim() || '-'}
</code>
{!tagChanged && !repoChanged && (
<span className="dg-text-muted">{t('kubernetes.updateimagemodal.s47c8cf')}</span>
<span className="dg-text-muted">{t('k8s.editImage.notModified')}</span>
)}
{repoChanged && !tagChanged && (
<span className="dg-text-yellow/80">{t('kubernetes.updateimagemodal.sdb3122')}</span>
<span className="dg-text-yellow/80">{t('k8s.editImage.addressChanged')}</span>
)}
</div>
<p className="text-[11px] dg-text-muted font-mono break-all">
更新预览:<span className="text-[var(--dg-text-secondary)]">{previewImage || '-'}</span>
{t('k8s.editImage.updatePreview')}<span className="text-[var(--dg-text-secondary)]">{previewImage || '-'}</span>
</p>
</div>
<div className="flex justify-end gap-2 pt-1">
<Button variant="outline" className="border-[var(--dg-border)] dg-text-secondary" onClick={onClose}>
取消
{t('common.cancel')}
</Button>
<Button
className="bg-blue-600 hover:bg-blue-700"
disabled={actionLoading === 'image' || !previewImage.trim() || !hasChanges}
onClick={onUpdateImage}
>
{actionLoading === 'image' ? <Loader2 className="h-4 w-4 animate-spin" /> : i18n.t('kubernetes.deployment.updateImage')}
{actionLoading === 'image' ? <Loader2 className="h-4 w-4 animate-spin" /> : t('k8s.editImage.updateImage')}
</Button>
</div>
</div>