diff --git a/frontend/src/components/aiops/PredictiveCapacityTab.tsx b/frontend/src/components/aiops/PredictiveCapacityTab.tsx
index 66dd09c..3a54461 100644
--- a/frontend/src/components/aiops/PredictiveCapacityTab.tsx
+++ b/frontend/src/components/aiops/PredictiveCapacityTab.tsx
@@ -4,6 +4,7 @@ import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { toast } from 'sonner';
+import { useTranslation } from 'react-i18next';
import { aiApi } from '@/api';
import { buildCapacityInsightPrompt, type CapacityForecast } from './predictUtils';
import { AgentMarkdown, looksLikeMarkdown } from './AgentMarkdown';
@@ -15,6 +16,7 @@ export function PredictiveCapacityTab({
forecasts: CapacityForecast[];
loading: boolean;
}) {
+ const { t } = useTranslation();
const [insight, setInsight] = useState('');
const [analyzing, setAnalyzing] = useState(false);
@@ -28,7 +30,7 @@ export function PredictiveCapacityTab({
const res = await aiApi.chat([{ role: 'user', content: prompt }]);
setInsight(res?.content || '');
} catch {
- toast.error('AI 解读失败,请检查大模型配置或稍后重试');
+ toast.error(t('aiops.aiAnalysisFailedToast'));
} finally {
setAnalyzing(false);
}
diff --git a/frontend/src/components/common/TerminalLoadingOverlay.tsx b/frontend/src/components/common/TerminalLoadingOverlay.tsx
index 9c54fb3..14deed8 100644
--- a/frontend/src/components/common/TerminalLoadingOverlay.tsx
+++ b/frontend/src/components/common/TerminalLoadingOverlay.tsx
@@ -1,5 +1,6 @@
import { Loader2 } from 'lucide-react';
import { cn } from '@/lib/utils';
+import { useTranslation } from 'react-i18next';
interface TerminalLoadingOverlayProps {
show: boolean;
@@ -7,14 +8,15 @@ interface TerminalLoadingOverlayProps {
className?: string;
}
-export function TerminalLoadingOverlay({ show, label = '连接中...', className }: TerminalLoadingOverlayProps) {
+export function TerminalLoadingOverlay({ show, label, className }: TerminalLoadingOverlayProps) {
+ const { t } = useTranslation();
if (!show) return null;
return (
- {label && {label}}
+ {label && {label || t('common.connectingEllipsis')}}
);
diff --git a/frontend/src/components/deploy/AppRelease.tsx b/frontend/src/components/deploy/AppRelease.tsx
index 034d3cd..f5d79f8 100644
--- a/frontend/src/components/deploy/AppRelease.tsx
+++ b/frontend/src/components/deploy/AppRelease.tsx
@@ -100,7 +100,7 @@ export function AppReleaseManager() {
{/* 用户名(左上)与密码(左下)同列上下行,安全模式/域归右列 // Logan.Li */}
-
+
- setRdpDomain(e.target.value)} placeholder="可选"
+ setRdpDomain(e.target.value)} placeholder={t('common.optional')}
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
diff --git a/frontend/src/components/deploy/deploy-rbac/JobRoleCreateDialog.tsx b/frontend/src/components/deploy/deploy-rbac/JobRoleCreateDialog.tsx
index 13a6bbd..ffc7dbc 100644
--- a/frontend/src/components/deploy/deploy-rbac/JobRoleCreateDialog.tsx
+++ b/frontend/src/components/deploy/deploy-rbac/JobRoleCreateDialog.tsx
@@ -89,7 +89,7 @@ export function JobRoleCreateDialog({
onPatternChange(e.target.value)}
- placeholder="^cex-.* 或 ^api-server$"
+ placeholder={t('deploy.jobNamePatternHint')}
className="h-8 text-sm font-mono dg-input"
/>
{patternHint}
diff --git a/frontend/src/components/deploy/pipeline-manager/PipelineCreateDialog.tsx b/frontend/src/components/deploy/pipeline-manager/PipelineCreateDialog.tsx
index 0f142c4..66e6d1a 100644
--- a/frontend/src/components/deploy/pipeline-manager/PipelineCreateDialog.tsx
+++ b/frontend/src/components/deploy/pipeline-manager/PipelineCreateDialog.tsx
@@ -371,7 +371,7 @@ export function PipelineCreateDialog({ open, onOpenChange, onCreated }: Pipeline
onValueChange={(v) => setNewGitCredentialId(v === '__none' ? '' : v)}
>
-
+
{t('deploy.notLinked')}
@@ -396,7 +396,7 @@ export function PipelineCreateDialog({ open, onOpenChange, onCreated }: Pipeline
onValueChange={(v) => setNewRegistryCredentialId(v === '__none' ? '' : v)}
>
-
+
不关联
diff --git a/frontend/src/components/deploy/pipeline-manager/pipeline-create/AdvancedSettingsPanel.tsx b/frontend/src/components/deploy/pipeline-manager/pipeline-create/AdvancedSettingsPanel.tsx
index 215262d..c3ef69d 100644
--- a/frontend/src/components/deploy/pipeline-manager/pipeline-create/AdvancedSettingsPanel.tsx
+++ b/frontend/src/components/deploy/pipeline-manager/pipeline-create/AdvancedSettingsPanel.tsx
@@ -106,7 +106,7 @@ export function AdvancedSettingsPanel({
onWatchBranchesChange(e.target.value)}
- placeholder="监听分支,如 main, release/*"
+ placeholder={t('deploy.branchListenPlaceholder')}
className="h-8 text-xs font-mono dg-input"
/>
)}
diff --git a/frontend/src/components/monitor/AlertRulesTab.tsx b/frontend/src/components/monitor/AlertRulesTab.tsx
index f609369..e14a00f 100644
--- a/frontend/src/components/monitor/AlertRulesTab.tsx
+++ b/frontend/src/components/monitor/AlertRulesTab.tsx
@@ -82,7 +82,7 @@ export function AlertRulesTab({
if (!ok) return;
try {
await alertApi.batchDeleteRules(selectedIds);
- toast.success(`已删除 ${selectedIds.length} 条告警规则`);
+ toast.success(i18n.t('monitor.deletedRules', { count: selectedIds.length }));
setSelectedIds([]);
onReload();
} catch (error) {
diff --git a/frontend/src/components/monitor/datasource/PrometheusDatasourceManager.tsx b/frontend/src/components/monitor/datasource/PrometheusDatasourceManager.tsx
index 52415ea..6db3904 100644
--- a/frontend/src/components/monitor/datasource/PrometheusDatasourceManager.tsx
+++ b/frontend/src/components/monitor/datasource/PrometheusDatasourceManager.tsx
@@ -65,7 +65,7 @@ export default function PrometheusDatasourceManager() {
const handleSetDefault = async (ds: PromDS) => {
try {
await setDefaultMutation.mutateAsync(ds.id);
- toast.success(`已将「${ds.name}」设为默认数据源`);
+ toast.success(i18n.t('monitor.setDefaultDsSuccess', { name: ds.name }));
} catch {
toast.error(i18n.t('monitor.promDs2.deleteFailed'));
}
diff --git a/frontend/src/components/server/ServerForm.tsx b/frontend/src/components/server/ServerForm.tsx
index fdbcaf8..ffd0186 100644
--- a/frontend/src/components/server/ServerForm.tsx
+++ b/frontend/src/components/server/ServerForm.tsx
@@ -396,7 +396,7 @@ export function ServerForm({
setFormData({ ...formData, tags: e.target.value })}
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] placeholder:text-[var(--dg-text-muted)] font-mono text-sm"
diff --git a/frontend/src/components/system/LdapManagementSection.tsx b/frontend/src/components/system/LdapManagementSection.tsx
index ff9a1c8..ffe7720 100644
--- a/frontend/src/components/system/LdapManagementSection.tsx
+++ b/frontend/src/components/system/LdapManagementSection.tsx
@@ -288,7 +288,7 @@ export function LdapManagementSection(props: LdapManagementSectionProps) {
- setNewUser({ ...newUser, display_name: e.target.value })} placeholder="张三" className="dg-input" />
+ setNewUser({ ...newUser, display_name: e.target.value })} placeholder={t('system.namePlaceholder')} className="dg-input" />
@@ -450,7 +450,7 @@ export function LdapManagementSection(props: LdapManagementSectionProps) {
- setEditLdapForm({ ...editLdapForm, title: e.target.value })} placeholder="运维工程师" className="dg-input" />
+ setEditLdapForm({ ...editLdapForm, title: e.target.value })} placeholder={t('system.roleTitlePlaceholder')} className="dg-input" />
)}
diff --git a/frontend/src/components/system/LiveMonitorDialog.tsx b/frontend/src/components/system/LiveMonitorDialog.tsx
index 84401e8..59fdf08 100644
--- a/frontend/src/components/system/LiveMonitorDialog.tsx
+++ b/frontend/src/components/system/LiveMonitorDialog.tsx
@@ -1,5 +1,6 @@
// 终端审计实时监控 Dialog — 与 WebSSH 终端弹框一致的布局与适配 // Logan.Li
import { useEffect, useRef, useState } from 'react';
+import { useTranslation } from 'react-i18next';
import { Terminal as XTerm } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
import 'xterm/css/xterm.css';
@@ -33,6 +34,7 @@ interface LiveMonitorProps {
}
export function LiveMonitorDialog({ open, onOpenChange, sessionId, sessionInfo }: LiveMonitorProps) {
+ const { t } = useTranslation();
const containerRef = useRef(null);
const termRef = useRef(null);
const fitRef = useRef(null);
@@ -250,7 +252,7 @@ export function LiveMonitorDialog({ open, onOpenChange, sessionId, sessionInfo }
diff --git a/frontend/src/components/system/SystemManager.tsx b/frontend/src/components/system/SystemManager.tsx
index 448db0d..2ca03de 100644
--- a/frontend/src/components/system/SystemManager.tsx
+++ b/frontend/src/components/system/SystemManager.tsx
@@ -237,7 +237,7 @@ export function SystemManager() {
const res = (await userApi.batchDelete(selectedUserIds)) as {
message?: string;
};
- toast.success(res?.message || `已删除 ${selectedUserIds.length} 个用户`);
+ toast.success(res?.message || t('system.batchDeleteUsers', { count: selectedUserIds.length }));
setSelectedUserIds([]);
await loadUsers();
} catch (error: unknown) {
diff --git a/frontend/src/components/ui/copy-button.tsx b/frontend/src/components/ui/copy-button.tsx
index 5b9256c..4252aa6 100644
--- a/frontend/src/components/ui/copy-button.tsx
+++ b/frontend/src/components/ui/copy-button.tsx
@@ -5,7 +5,7 @@ import { Button } from '@/components/ui/button';
import { useToast } from '@/hooks/use-toast';
import { copyToClipboard } from '@/utils/clipboard';
import { cn } from '@/lib/utils';
-import i18n from '@/i18n';
+import { useTranslation } from 'react-i18next';
export interface CopyButtonProps {
text: string;
@@ -22,14 +22,17 @@ export interface CopyButtonProps {
export function CopyButton({
text,
- label = '已复制',
+ label,
children,
className,
size = 'sm',
variant = 'outline',
disabled,
- title = '复制',
+ title,
}: CopyButtonProps) {
+ const { t } = useTranslation();
+ const resolvedLabel = label ?? t('common.copied');
+ const resolvedTitle = title ?? t('common.copy');
const { toast } = useToast();
const [copied, setCopied] = useState(false);
@@ -37,12 +40,12 @@ export function CopyButton({
const ok = await copyToClipboard(text);
if (ok) {
setCopied(true);
- toast({ title: label });
+ toast({ title: resolvedLabel });
setTimeout(() => setCopied(false), 2000);
} else {
toast({
- title: i18n.t('monitor.logPanel.copyFailed'),
- description: i18n.t('common.copyManually'),
+ title: t('monitor.logPanel.copyFailed'),
+ description: t('common.copyManually'),
variant: 'destructive',
});
}
@@ -61,8 +64,8 @@ export function CopyButton({
)}
onClick={handleCopy}
disabled={disabled || !text}
- title={title}
- aria-label={title}
+ title={resolvedTitle}
+ aria-label={resolvedTitle}
>
{copied ? (
diff --git a/frontend/src/locales/en-US.json b/frontend/src/locales/en-US.json
index 4c420b3..beeff2b 100644
--- a/frontend/src/locales/en-US.json
+++ b/frontend/src/locales/en-US.json
@@ -516,7 +516,10 @@
"seconds": "sec",
"copyManually": "Please manually select and copy",
"scrollToTop": "Scroll to top",
- "scrollToBottom": "Scroll to bottom"
+ "scrollToBottom": "Scroll to bottom",
+ "connectingEllipsis": "Connecting...",
+ "enteringWorkspace": "Entering workspace...",
+ "connectingMonitor": "Connecting to monitor..."
},
"menu": {
"dashboard": "Dashboard",
@@ -1142,7 +1145,8 @@
"loadDirFailed": "Failed to load directory",
"downloadFailed": "Download failed: ",
"directory": "Directory"
- }
+ },
+ "jsonFormatPlaceholder": "JSON format, e.g. {\"key\":\"value\"}"
},
"alert": {
"stat": {
@@ -1510,7 +1514,9 @@
}
},
"reportTitle": "Terminal Session Audit Report",
- "csvHeader": "Time,User,Command,Output Size,Session ID,Critical"
+ "csvHeader": "Time,User,Command,Output Size,Session ID,Critical",
+ "rdpRealtimeAudit": "RDP Real-time Audit",
+ "rdpHistoryReplay": "RDP History Replay"
},
"deploy": {
"pipeline": {
@@ -2408,7 +2414,19 @@
"copyRef": "Copy Reference ID",
"testConn": "Test Connection",
"noTags": "No tags"
- }
+ },
+ "placeholderEnv": "Environment",
+ "placeholderStatus": "Status",
+ "noEnvConfig": "No environment configuration",
+ "clickEnvConfigHint": "Click \"Add Environment\" to create",
+ "rdpPassword": "Windows Password",
+ "rdpPasswordPlaceholder": "Windows login password",
+ "selectCredentialPlaceholder": "Select credential",
+ "dockerCredPlaceholder": "Docker credential",
+ "branchListenPlaceholder": "Listen branches, e.g. main, release/*",
+ "rdpUserRequired": "Please fill in RDP username",
+ "rdpPasswordRequired": "Please fill in RDP password",
+ "jobNamePatternHint": "^cex-.* or ^api-server$"
},
"k8s": {
"cluster": {
@@ -5075,7 +5093,10 @@
"configDesc": "Configure Zabbix API connection to get host monitoring data",
"directDb": "Direct DB Connection",
"emptyDatasource": "No Zabbix data sources"
- }
+ },
+ "deletedRules": "Deleted {{count}} alert rules",
+ "setDefaultDsSuccess": "Set \"{{name}}\" as default datasource",
+ "collectSuccess": "{{name}} collection success"
},
"task": {
"cronJob": {
@@ -6134,7 +6155,7 @@
},
"pipeline": {
"title": "Pipelines",
- "subtitle": "CI/CD Build · Deploy · Release All-in-One",
+ "subtitle": "CI/CD build, image packaging & dual-channel deployment",
"pipelines": "Pipelines",
"addPipeline": "New Pipeline",
"editPipeline": "Edit Pipeline",
@@ -7374,7 +7395,7 @@
"savingDot": "Saving...",
"recordAllOps": "Record All Operations",
"searchFilterHint": "Search filter (optional, use %s for username)",
- "batchDeleteUsers": "Batch Delete Users",
+ "batchDeleteUsers": "Deleted {{count}} users",
"forcePasswordComplexity": "Enforce Password Complexity",
"systemVersion": "System Version",
"saveConfig": "Save Configuration",
@@ -7530,7 +7551,9 @@
"importSelected": "Import ({{count}})",
"importAll": "Import All ({{count}})",
"editLdapUserDesc": "Modify attributes of {{uid}}",
- "permEffectTrailing": ", changes take effect after user re-login."
+ "permEffectTrailing": ", changes take effect after user re-login.",
+ "namePlaceholder": "John Doe",
+ "roleTitlePlaceholder": "DevOps Engineer"
},
"aiops": {
"title": "AIOps",
@@ -8238,7 +8261,8 @@
"predictUtils": {
"dailyCostHint": "Review {{scope}}today's high-cost services, pause non-essential resources or adjust auto-scaling",
"monthlyBillHint": "Review {{scope}}this month's bill composition, optimize storage/CDN/compute, reduce over-budget quotas"
- }
+ },
+ "aiAnalysisFailedToast": "AI analysis failed, please check LLM config or try again later"
},
"breadcrumb": {
"dashboard": "Dashboard",
diff --git a/frontend/src/locales/zh-CN.json b/frontend/src/locales/zh-CN.json
index b186e63..f171d05 100644
--- a/frontend/src/locales/zh-CN.json
+++ b/frontend/src/locales/zh-CN.json
@@ -516,7 +516,10 @@
"seconds": "秒",
"copyManually": "请手动选中内容后复制",
"scrollToTop": "回到顶部",
- "scrollToBottom": "回到底部"
+ "scrollToBottom": "回到底部",
+ "connectingEllipsis": "连接中...",
+ "enteringWorkspace": "正在进入工作区...",
+ "connectingMonitor": "正在连接监控..."
},
"menu": {
"dashboard": "仪表盘",
@@ -1142,7 +1145,8 @@
"loadDirFailed": "加载目录失败",
"downloadFailed": "下载失败: ",
"directory": "目录"
- }
+ },
+ "jsonFormatPlaceholder": "JSON 格式,如 {\"key\":\"value\"}"
},
"alert": {
"stat": {
@@ -1510,7 +1514,9 @@
}
},
"reportTitle": "终端会话审计报告",
- "csvHeader": "时间,用户,命令,输出大小,会话ID,高危"
+ "csvHeader": "时间,用户,命令,输出大小,会话ID,高危",
+ "rdpRealtimeAudit": "RDP 实时审计",
+ "rdpHistoryReplay": "RDP 历史回放"
},
"deploy": {
"pipeline": {
@@ -2408,7 +2414,19 @@
"copyRef": "复制引用ID",
"testConn": "测试连接",
"noTags": "无标签"
- }
+ },
+ "placeholderEnv": "环境",
+ "placeholderStatus": "状态",
+ "noEnvConfig": "暂无环境配置",
+ "clickEnvConfigHint": "点击\"新增环境\"创建",
+ "rdpPassword": "Windows 密码",
+ "rdpPasswordPlaceholder": "Windows 登录密码",
+ "selectCredentialPlaceholder": "选择凭证",
+ "dockerCredPlaceholder": "Docker 凭证",
+ "branchListenPlaceholder": "监听分支,如 main, release/*",
+ "rdpUserRequired": "请填写 RDP 用户",
+ "rdpPasswordRequired": "请填写 RDP 密码",
+ "jobNamePatternHint": "^cex-.* 或 ^api-server$"
},
"k8s": {
"cluster": {
@@ -5075,7 +5093,10 @@
"configDesc": "配置 Zabbix API 连接,获取主机监控数据",
"directDb": "直连DB",
"emptyDatasource": "暂无 Zabbix 数据源"
- }
+ },
+ "deletedRules": "已删除 {{count}} 条告警规则",
+ "setDefaultDsSuccess": "已将「{{name}}」设为默认数据源",
+ "collectSuccess": "{{name}} 采集成功"
},
"task": {
"cronJob": {
@@ -6134,7 +6155,7 @@
},
"pipeline": {
"title": "流水线",
- "subtitle": "CI/CD 构建 · 部署 · 发布一体化",
+ "subtitle": "CI/CD 构建、镜像打包与双通道部署",
"pipelines": "流水线列表",
"addPipeline": "新建流水线",
"editPipeline": "编辑流水线",
@@ -7374,7 +7395,7 @@
"savingDot": "保存中...",
"recordAllOps": "记录所有操作",
"searchFilterHint": "搜索过滤器(可选,用 %s 代表用户名)",
- "batchDeleteUsers": "批量删除用户",
+ "batchDeleteUsers": "已删除 {{count}} 个用户",
"forcePasswordComplexity": "强制密码复杂度",
"systemVersion": "系统版本",
"saveConfig": "保存配置",
@@ -7530,7 +7551,9 @@
"importSelected": "导入 ({{count}})",
"importAll": "导入全部 ({{count}})",
"editLdapUserDesc": "修改 {{uid}} 的属性",
- "permEffectTrailing": ",修改后用户需重新登录生效。"
+ "permEffectTrailing": ",修改后用户需重新登录生效。",
+ "namePlaceholder": "张三",
+ "roleTitlePlaceholder": "运维工程师"
},
"aiops": {
"title": "AIOps 智能",
@@ -8238,7 +8261,8 @@
"predictUtils": {
"dailyCostHint": "检查{{scope}}今日高消费服务,暂停非必要资源或调整弹性伸缩策略",
"monthlyBillHint": "复盘{{scope}}本月账单构成,优化存储/CDN/计算规格,必要时下调预算外资源配额"
- }
+ },
+ "aiAnalysisFailedToast": "AI 解读失败,请检查大模型配置或稍后重试"
},
"breadcrumb": {
"dashboard": "仪表盘",
diff --git a/frontend/src/pages/audit/terminal-audit/ActiveSessionsPanel.tsx b/frontend/src/pages/audit/terminal-audit/ActiveSessionsPanel.tsx
index ce3b644..b14d9c8 100644
--- a/frontend/src/pages/audit/terminal-audit/ActiveSessionsPanel.tsx
+++ b/frontend/src/pages/audit/terminal-audit/ActiveSessionsPanel.tsx
@@ -138,7 +138,7 @@ function RdpActiveSessionRow({
-