feat(i18n): 全量中英文国际化改造
- 翻译 en-US.json 中 1006 条未翻译的中文条目为英文 - 提取 30+ 组件文件的硬编码中文到 locale JSON - 新增 900+ 翻译键覆盖所有业务模块: - Layout (Sidebar, Header, Breadcrumb) - Server (ServerForm, CloudServerImport, WebShell, RdpTools) - Deploy (ReleaseManager, PipelineCreate, AppRelease) - Kubernetes (DeploymentEdit, PodExec, PodLogs, ResourceEditor) - Monitor (UnifiedQueryPanel, AlertCenter, Prometheus/Grafana Dashboard) - AIOps (predictUtils, PredictiveCostTab, AIPredictive) - System (useLdapManagement, AgentMonitor, AgentWizard) - tsc --noEmit 类型检查通过
This commit is contained in:
1 parent
76ec9387f0
commit
a9513c2056
44 files changed
+4342
-1792
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { readFromClipboard } from '@/utils/clipboard';
|
||||
import { rdpFilesApi, type RdpFileItem } from '@/api/server/rdp-files';
|
||||
@@ -29,6 +30,7 @@ export function RdpToolsPanel({
|
||||
onSyncToRemote,
|
||||
onAutoExec,
|
||||
}: RdpToolsPanelProps) {
|
||||
const { t } = useTranslation();
|
||||
const [tab, setTab] = useState<ToolsTab>('general');
|
||||
const [localClipDraft, setLocalClipDraft] = useState('');
|
||||
const [files, setFiles] = useState<RdpFileItem[]>([]);
|
||||
@@ -43,7 +45,7 @@ export function RdpToolsPanel({
|
||||
setFiles(data?.list ?? []);
|
||||
} catch (err) {
|
||||
setFiles([]);
|
||||
toast.error(err instanceof Error ? err.message : '无法列出远端文件(SMB 445 可能未开放)');
|
||||
toast.error(err instanceof Error ? err.message : t('server.listFileError'));
|
||||
} finally {
|
||||
setLoadingFiles(false);
|
||||
}
|
||||
@@ -59,17 +61,17 @@ export function RdpToolsPanel({
|
||||
setLocalClipDraft(text);
|
||||
return;
|
||||
}
|
||||
toast.info('无法自动读取剪贴板,请 Ctrl+V 粘贴(HTTPS 下可自动读取)');
|
||||
toast.info(t('server.clipboardHint'));
|
||||
};
|
||||
|
||||
const syncLocalClip = () => {
|
||||
const trimmed = localClipDraft.trim();
|
||||
if (!trimmed) {
|
||||
toast.info('内容为空');
|
||||
toast.info(t('server.emptyContent'));
|
||||
return;
|
||||
}
|
||||
onSyncToRemote(trimmed);
|
||||
toast.success('已同步到远端');
|
||||
toast.success(t('server.syncedToRemote'));
|
||||
};
|
||||
|
||||
const uploadWithFallback = async (file: File) => {
|
||||
@@ -77,7 +79,7 @@ export function RdpToolsPanel({
|
||||
try {
|
||||
try {
|
||||
await rdpFilesApi.upload(serverId, file);
|
||||
toast.success(`${file.name} 已上传到 Download`);
|
||||
toast.success(t('server.uploadedToDownload', { name: file.name }));
|
||||
void refreshFiles();
|
||||
return;
|
||||
} catch {
|
||||
@@ -85,9 +87,9 @@ export function RdpToolsPanel({
|
||||
}
|
||||
const staged = await rdpFilesApi.stage(serverId, file);
|
||||
onAutoExec(staged.deploy_command);
|
||||
toast.success(`${file.name} 已自动下发(SMB 不可用时的回退模式)`);
|
||||
toast.success(t('server.autoSent', { name: file.name }));
|
||||
} catch (err) {
|
||||
toast.error(err instanceof Error ? err.message : '上传失败');
|
||||
toast.error(err instanceof Error ? err.message : t('server.rdpUploadFailed'));
|
||||
} finally {
|
||||
setUploading(false);
|
||||
}
|
||||
@@ -102,9 +104,9 @@ export function RdpToolsPanel({
|
||||
const handleDownload = async (name: string) => {
|
||||
try {
|
||||
await rdpFilesApi.download(serverId, name);
|
||||
toast.success(`已开始下载 ${name}`);
|
||||
toast.success(t('server.downloadStarted', { name }));
|
||||
} catch (err) {
|
||||
toast.error(err instanceof Error ? err.message : '下载失败');
|
||||
toast.error(err instanceof Error ? err.message : t('server.rdpDownloadFailed'));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -122,7 +124,7 @@ export function RdpToolsPanel({
|
||||
)}
|
||||
>
|
||||
<Settings2 className="h-3.5 w-3.5" />
|
||||
通用
|
||||
{t('server.general')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -135,24 +137,24 @@ export function RdpToolsPanel({
|
||||
)}
|
||||
>
|
||||
<FolderOpen className="h-3.5 w-3.5" />
|
||||
文件
|
||||
{t('server.rdpFiles')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{tab === 'general' && (
|
||||
<div className="p-3 space-y-3">
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs text-[var(--dg-text-muted)]">远端剪贴板</label>
|
||||
<label className="text-xs text-[var(--dg-text-muted)]">{t('server.remoteClipboard')}</label>
|
||||
<textarea
|
||||
readOnly
|
||||
value={remoteClipboard}
|
||||
rows={3}
|
||||
placeholder="远端复制内容将显示在此"
|
||||
placeholder={t('server.remoteClipPlaceholder')}
|
||||
className="w-full resize-none rounded border border-[var(--dg-border)] bg-[var(--dg-bg-primary)] px-2 py-1.5 text-xs text-[var(--dg-text-secondary)] outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs text-[var(--dg-text-muted)]">同步到远端</label>
|
||||
<label className="text-xs text-[var(--dg-text-muted)]">{t('server.syncToRemote')}</label>
|
||||
<textarea
|
||||
value={localClipDraft}
|
||||
onChange={(e) => setLocalClipDraft(e.target.value)}
|
||||
@@ -162,11 +164,11 @@ export function RdpToolsPanel({
|
||||
if (pasted) setLocalClipDraft(pasted);
|
||||
}}
|
||||
rows={3}
|
||||
placeholder="点击输入框自动粘贴本地剪贴板"
|
||||
placeholder={t('server.syncPlaceholder')}
|
||||
className="w-full resize-none rounded border border-[var(--dg-border)] bg-[var(--dg-bg-secondary)] px-2 py-1.5 text-xs text-[var(--dg-text-primary)] outline-none"
|
||||
/>
|
||||
<Button type="button" size="sm" className="w-full" onClick={syncLocalClip}>
|
||||
同步到远端
|
||||
{t('server.syncButton')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -194,12 +196,12 @@ export function RdpToolsPanel({
|
||||
/>
|
||||
<Button type="button" size="sm" className="w-full" disabled={uploading} onClick={() => fileInputRef.current?.click()}>
|
||||
<Upload className="h-3.5 w-3.5 mr-1.5" />
|
||||
{uploading ? '上传中...' : '上传文件'}
|
||||
{uploading ? t('server.rdpUploading') : t('server.uploadFile')}
|
||||
</Button>
|
||||
<div className="max-h-40 overflow-y-auto rounded border border-[var(--dg-border)]">
|
||||
{files.length === 0 ? (
|
||||
<p className="px-2 py-3 text-[10px] text-[var(--dg-text-muted)] text-center">
|
||||
{loadingFiles ? '加载中...' : '暂无文件(需 SMB 445 可达才能列出)'}
|
||||
{loadingFiles ? t('server.rdpLoading') : t('server.noRdpFiles')}
|
||||
</p>
|
||||
) : (
|
||||
files.map((f) => (
|
||||
@@ -216,7 +218,7 @@ export function RdpToolsPanel({
|
||||
)}
|
||||
</div>
|
||||
<p className="text-[10px] text-[var(--dg-text-muted)] leading-relaxed">
|
||||
优先 SMB 直传(一键);若 445 不通则自动暂存到 AIOps 并由 RDP 执行下载命令。
|
||||
{t('server.smbHint')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in new issue
Block a user