@@ -142,16 +143,16 @@ export default function PrometheusDatasourceManager() {
|
{ds.is_default ? (
- 默认
+ {i18n.t('k8s.storage.default')}
) : (
--
)}
|
{ds.status === 1 ? (
- 启用
+ {i18n.t('system.userActive')}
) : (
- 禁用
+ {i18n.t('system.userInactive')}
)}
|
@@ -160,7 +161,7 @@ export default function PrometheusDatasourceManager() {
variant="ghost" size="sm"
className="h-8 px-2"
onClick={() => handleTestQuick(ds)}
- title="测试连接"
+ title={i18n.t('aiops.llmTest')}
>
@@ -169,7 +170,7 @@ export default function PrometheusDatasourceManager() {
variant="ghost" size="sm"
className="h-8 px-2 dg-text-yellow"
onClick={() => handleSetDefault(ds)}
- title="设为默认"
+ title={i18n.t('aiops.llmSetDefault')}
>
diff --git a/frontend/src/components/monitor/datasource/ZabbixDatasourceManager.tsx b/frontend/src/components/monitor/datasource/ZabbixDatasourceManager.tsx
index 8103a56..ee9904d 100644
--- a/frontend/src/components/monitor/datasource/ZabbixDatasourceManager.tsx
+++ b/frontend/src/components/monitor/datasource/ZabbixDatasourceManager.tsx
@@ -32,6 +32,7 @@ import { toast } from 'sonner';
import { useConfirm } from '@/components/ui/confirm-dialog';
import { zabbixDatasourceApi } from '@/api';
import type { JsonData } from '@/types/common';
+import i18n from '@/i18n';
interface ZabbixDS {
id: number;
@@ -78,7 +79,7 @@ export default function ZabbixDatasourceManager() {
const res: JsonData = await zabbixDatasourceApi.list();
setSources(res?.data || res || []);
} catch {
- toast.error('获取数据源列表失败');
+ toast.error(i18n.t('monitor.zabbixdatasourc.s45f81749'));
} finally {
setLoading(false);
}
@@ -115,38 +116,38 @@ export default function ZabbixDatasourceManager() {
};
const handleSave = async () => {
- if (!form.name.trim()) { toast.error('请输入数据源名称'); return; }
- if (!form.url.trim()) { toast.error('请输入 Zabbix API URL'); return; }
- if (!form.username.trim()) { toast.error('请输入用户名'); return; }
- if (!form.password.trim()) { toast.error('请输入密码'); return; }
+ if (!form.name.trim()) { toast.error(i18n.t('monitor.promDs.nameRequired')); return; }
+ if (!form.url.trim()) { toast.error(i18n.t('monitor.zabbixdatasourc.s2ba385d6')); return; }
+ if (!form.username.trim()) { toast.error(i18n.t('pipeline.usernameRequired')); return; }
+ if (!form.password.trim()) { toast.error(i18n.t('login.passwordRequired')); return; }
try {
if (editingId) {
await zabbixDatasourceApi.update(editingId, form);
- toast.success('数据源已更新');
+ toast.success(i18n.t('monitor.zabbixdatasourc.s8dfdd2f4'));
} else {
await zabbixDatasourceApi.create(form);
- toast.success('数据源已创建');
+ toast.success(i18n.t('monitor.zabbixdatasourc.sa6def01f'));
}
setDialogOpen(false);
fetchList();
} catch (err) {
- toast.error(err?.message || '操作失败');
+ toast.error(err?.message || i18n.t('cloud.operationFailed'));
}
};
const handleDelete = async (ds: ZabbixDS) => {
const ok = await _confirm({
- title: '删除数据源',
+ title: i18n.t('monitor.deleteDatasource'),
description: `确定删除「${ds.name}」?`,
variant: 'destructive',
});
if (!ok) return;
try {
await zabbixDatasourceApi.delete(ds.id);
- toast.success('已删除');
+ toast.success(i18n.t('monitor.silenceRules.deleted'));
fetchList();
- } catch { toast.error('删除失败'); }
+ } catch { toast.error(i18n.t('kubernetes.msg.deleteFailed2')); }
};
const handleSetDefault = async (ds: ZabbixDS) => {
@@ -154,12 +155,12 @@ export default function ZabbixDatasourceManager() {
await zabbixDatasourceApi.setDefault(ds.id);
toast.success(`已将「${ds.name}」设为默认`);
fetchList();
- } catch { toast.error('设置失败'); }
+ } catch { toast.error(i18n.t('monitor.zabbixdatasourc.s9f96034c')); }
};
const handleTest = async () => {
if (!form.url.trim() || !form.username.trim()) {
- toast.error('请填写 URL 和用户名');
+ toast.error(i18n.t('monitor.zabbixdatasourc.s1d3562b7'));
return;
}
setTesting(true);
@@ -173,7 +174,7 @@ export default function ZabbixDatasourceManager() {
const data = res?.data || res;
setTestResult(data);
} catch (err) {
- setTestResult({ success: false, message: err?.message || '测试失败' });
+ setTestResult({ success: false, message: err?.message || i18n.t('monitor.alertChannels.testFailed') });
} finally {
setTesting(false);
}
@@ -199,7 +200,7 @@ export default function ZabbixDatasourceManager() {
/>
Zabbix 数据源
- 配置 Zabbix API 连接,获取主机监控数据
+ {i18n.t('monitor.zabbixdatasourc.s79e929d8')}
- setDialogOpen(false)}>取消
- 保存
+ setDialogOpen(false)}> {i18n.t('rbac.jobRole.cancel')}
+ {i18n.t('task.script.save')}
diff --git a/frontend/src/components/monitor/datasource/prometheus-ds/helpers.ts b/frontend/src/components/monitor/datasource/prometheus-ds/helpers.ts
index 10542ee..1064352 100644
--- a/frontend/src/components/monitor/datasource/prometheus-ds/helpers.ts
+++ b/frontend/src/components/monitor/datasource/prometheus-ds/helpers.ts
@@ -3,6 +3,7 @@
import { toast } from 'sonner';
import { promDatasourceApi } from '@/api';
import type { PromDS, HeaderEntry, PromDsForm } from './types';
+import i18n from '@/i18n';
export type TestConnectionParams = {
url: string;
@@ -106,10 +107,10 @@ export async function handleTestQuick(ds: PromDS): Promise {
if (data?.success) {
toast.success(`连接成功 · ${data.target_count || 0} targets`);
} else {
- toast.error(data?.message || '连接失败');
+ toast.error(data?.message || i18n.t('aiops.llmTestFailed'));
}
} catch (err: unknown) {
- const message = err instanceof Error ? err.message : '测试失败';
+ const message = err instanceof Error ? err.message : i18n.t('monitor.alertChannels.testFailed');
toast.error(message);
}
}
\ No newline at end of file
diff --git a/frontend/src/components/monitor/log-center/EsIndexPicker.tsx b/frontend/src/components/monitor/log-center/EsIndexPicker.tsx
index dec4f62..baad76b 100644
--- a/frontend/src/components/monitor/log-center/EsIndexPicker.tsx
+++ b/frontend/src/components/monitor/log-center/EsIndexPicker.tsx
@@ -1,6 +1,7 @@
import { useState, useEffect, useMemo } from 'react';
import { ChevronDown, Loader2, Search } from 'lucide-react';
import { logCenterApi } from '@/api/log/log-center';
+import i18n from '@/i18n';
interface Props {
datasourceId?: number;
@@ -40,9 +41,9 @@ export function EsIndexPicker({ datasourceId, value, onChange }: Props) {
onClick={() => setOpen(!open)}
className="h-10 px-2 text-xs rounded flex items-center gap-1 font-mono min-w-[150px] max-w-[220px]"
style={{ background: 'var(--dg-bg-tertiary)', border: '1px solid var(--dg-border)', color: 'var(--dg-text-primary)' }}
- title="选择或搜索 ES 索引"
+ title={i18n.t('monitor.esindexpickerts.sa0eff8ea')}
>
- {value || '选择索引'}
+ {value || i18n.t('monitor.selectIndex')}
{loading ? : }
{open && (
@@ -58,7 +59,7 @@ export function EsIndexPicker({ datasourceId, value, onChange }: Props) {
setSearch(e.target.value)}
- placeholder="搜索索引..."
+ placeholder={i18n.t('monitor.esindexpickerts.s9ae0c004')}
className="flex-1 bg-transparent text-xs outline-none font-mono"
style={{ color: 'var(--dg-text-primary)' }}
/>
@@ -88,7 +89,7 @@ export function EsIndexPicker({ datasourceId, value, onChange }: Props) {
))}
{!loading && filtered.length === 0 && (
- 无匹配索引
+ {i18n.t('monitor.esindexpickerts.saf5cc132')}
)}
diff --git a/frontend/src/components/monitor/log-center/LogAlertFromQueryDialog.tsx b/frontend/src/components/monitor/log-center/LogAlertFromQueryDialog.tsx
index 49418f7..aadd1b1 100644
--- a/frontend/src/components/monitor/log-center/LogAlertFromQueryDialog.tsx
+++ b/frontend/src/components/monitor/log-center/LogAlertFromQueryDialog.tsx
@@ -4,6 +4,7 @@ import { X, BellRing, Loader2, Flame, Database, Cloud } from 'lucide-react';
import { alertApi } from '@/api';
import { useToast } from '@/hooks/use-toast';
import type { LogEngine } from './types-v3';
+import i18n from '@/i18n';
interface LogQueryContext {
engine: LogEngine;
@@ -73,11 +74,11 @@ export function LogAlertFromQueryDialog({ open, onOpenChange, ctx, onSaved }: Pr
notify_channels: [],
});
setSaved(true);
- toast({ title: '告警规则已创建' });
+ toast({ title: i18n.t('monitor.savequerydialog.sd3dbea92') });
onSaved?.();
setTimeout(() => onOpenChange(false), 800);
} catch (e: any) {
- toast({ title: '创建失败', description: e?.message || String(e), variant: 'destructive' });
+ toast({ title: i18n.t('monitor.dashboard.custom.toastCreateFailed'), description: e?.message || String(e), variant: 'destructive' });
} finally {
setSaving(false);
}
@@ -94,7 +95,7 @@ export function LogAlertFromQueryDialog({ open, onOpenChange, ctx, onSaved }: Pr
- 创建告警规则
+ {i18n.t('monitor.logalertfromque.s5f470749')}
onOpenChange(false)}
@@ -112,12 +113,12 @@ export function LogAlertFromQueryDialog({ open, onOpenChange, ctx, onSaved }: Pr
{meta.name}
- {ctx.datasourceName || '默认数据源'}
+ {ctx.datasourceName || i18n.t('monitor.savequerydialog.sddb4ca92')}
{ctx.timeRange || '1h'}
-
+
setName(e.target.value)}
@@ -127,7 +128,7 @@ export function LogAlertFromQueryDialog({ open, onOpenChange, ctx, onSaved }: Pr
-
+
-
+
diff --git a/frontend/src/components/monitor/log-center/LogAlertsPanel.tsx b/frontend/src/components/monitor/log-center/LogAlertsPanel.tsx
index 7df9cf4..e92e3e5 100644
--- a/frontend/src/components/monitor/log-center/LogAlertsPanel.tsx
+++ b/frontend/src/components/monitor/log-center/LogAlertsPanel.tsx
@@ -9,6 +9,7 @@ import { useToast } from '@/hooks/use-toast';
import { useConfirm } from '@/components/ui/confirm-dialog';
import { alertApi } from '@/api';
import { AlertRuleDialog } from '@/components/monitor/AlertRuleDialog';
+import i18n from '@/i18n';
export function LogAlertsPanel() {
const { toast } = useToast();
@@ -37,14 +38,14 @@ export function LogAlertsPanel() {
useEffect(() => { load(); }, [load]);
const handleDelete = async (rule: any) => {
- const ok = await confirm({ title: '删除规则', description: `删除「${rule.name}」?`, variant: 'destructive', confirmText: '删除' });
+ const ok = await confirm({ title: i18n.t('monitor.deleteRule'), description: `删除「${rule.name}」?`, variant: 'destructive', confirmText: i18n.t('kubernetes.storage.delete2') });
if (!ok) return;
try {
await alertApi.deleteRule(rule.id);
- toast({ title: '已删除' });
+ toast({ title: i18n.t('monitor.silenceRules.deleted') });
load();
} catch (e: any) {
- toast({ title: '删除失败', description: e?.message || String(e), variant: 'destructive' });
+ toast({ title: i18n.t('kubernetes.msg.deleteFailed2'), description: e?.message || String(e), variant: 'destructive' });
}
};
@@ -57,7 +58,7 @@ export function LogAlertsPanel() {
return (
- 仅保存告警策略(LogQL / Lucene),日志数据仍在外部 Loki / ES
+ {i18n.t('monitor.logalertspanelt.s5bc514d8')}
刷新
@@ -87,7 +88,7 @@ export function LogAlertsPanel() {
{rule.source || 'log'}
{rule.severity}
{!rule.enabled && rule.enabled !== undefined && (
- 已禁用
+ {i18n.t('aiops.llmDisabled')}
)}
{rule.expression}
diff --git a/frontend/src/components/monitor/log-center/LogClusterPanel.tsx b/frontend/src/components/monitor/log-center/LogClusterPanel.tsx
index 1d01303..b8db324 100644
--- a/frontend/src/components/monitor/log-center/LogClusterPanel.tsx
+++ b/frontend/src/components/monitor/log-center/LogClusterPanel.tsx
@@ -2,6 +2,7 @@
import { useState } from 'react';
import { ChevronDown, ChevronRight, Copy, Check } from 'lucide-react';
import type { LogCluster } from './types-v3';
+import i18n from '@/i18n';
interface Props {
clusters: LogCluster[];
@@ -41,7 +42,7 @@ export function LogClusterPanel({ clusters }: Props) {
{/* 头部 */}
共 {clusters.length} 个聚类模式,总计 {total.toLocaleString()} 条日志
- 基于日志相似度自动聚类
+ {i18n.t('monitor.logclusterpanel.s38112792')}
{/* 聚类列表 */}
@@ -90,7 +91,7 @@ export function LogClusterPanel({ clusters }: Props) {
{/* 展开详情 */}
{expanded[i] && (
- 样例日志:
+ {i18n.t('monitor.logclusterpanel.se909e426')}
{cluster.sample}
diff --git a/frontend/src/components/monitor/log-center/LogDatasourceDialog.tsx b/frontend/src/components/monitor/log-center/LogDatasourceDialog.tsx
index 55ca7ab..66459a2 100644
--- a/frontend/src/components/monitor/log-center/LogDatasourceDialog.tsx
+++ b/frontend/src/components/monitor/log-center/LogDatasourceDialog.tsx
@@ -14,6 +14,7 @@ import { Loader2, Plug, RefreshCw } from 'lucide-react';
import { useToast } from '@/hooks/use-toast';
import { logCenterApi, type LogDataSource, type TestConnectionResult } from '@/api';
import type { LogEngine } from './log-center-types';
+import i18n from '@/i18n';
export function LogDatasourceDialog({
open, onOpenChange, engine, editing, onSaved,
@@ -127,12 +128,12 @@ export function LogDatasourceDialog({
: payload();
const result: TestConnectionResult = await logCenterApi.testDatasource(data);
if (result.status === 'ok') {
- toast({ title: '连接成功' });
+ toast({ title: i18n.t('aiops.llmTestSuccess') });
} else {
- toast({ title: '连接失败', description: result.error || '未知错误', variant: 'destructive' });
+ toast({ title: i18n.t('aiops.llmTestFailed'), description: result.error || i18n.t('monitor.dashboard.agent.toast.unknownError'), variant: 'destructive' });
}
} catch (e: any) {
- toast({ title: '连接失败', description: e?.message || String(e), variant: 'destructive' });
+ toast({ title: i18n.t('aiops.llmTestFailed'), description: e?.message || String(e), variant: 'destructive' });
} finally {
setTesting(false);
}
@@ -147,11 +148,11 @@ export function LogDatasourceDialog({
} else {
await logCenterApi.createDatasource(payload());
}
- toast({ title: '已保存' });
+ toast({ title: i18n.t('deploy.toast.saved') });
onOpenChange(false);
onSaved();
} catch (e: any) {
- toast({ title: '保存失败', description: e?.message || String(e), variant: 'destructive' });
+ toast({ title: i18n.t('kubernetes.msg.saveFailed'), description: e?.message || String(e), variant: 'destructive' });
} finally {
setSaving(false);
}
@@ -162,7 +163,7 @@ export function LogDatasourceDialog({
- {editing ? '编辑' : '添加'}{engine === 'loki' ? ' Loki' : ' Elasticsearch'} 数据源
+ {editing ? i18n.t('common.edit') : i18n.t('monitor.dashboard.custom.addBtn')}{engine === 'loki' ? ' Loki' : ' Elasticsearch'} 数据源
仅保存连接信息,日志本体存储在您的 Loki / ES 集群
@@ -170,17 +171,17 @@ export function LogDatasourceDialog({
)}
-
+
-
+
diff --git a/frontend/src/components/monitor/log-center/LogDatasourcePage.tsx b/frontend/src/components/monitor/log-center/LogDatasourcePage.tsx
index 63560e0..b0fe45d 100644
--- a/frontend/src/components/monitor/log-center/LogDatasourcePage.tsx
+++ b/frontend/src/components/monitor/log-center/LogDatasourcePage.tsx
@@ -11,6 +11,7 @@ import { useConfirm } from '@/components/ui/confirm-dialog';
import { logCenterApi, type LogDataSource, type TestConnectionResult } from '@/api';
import { LogDatasourceDialog } from './LogDatasourceDialog';
import type { LogEngine } from './log-center-types';
+import i18n from '@/i18n';
export function LogDatasourcePage() {
const { toast } = useToast();
@@ -46,18 +47,18 @@ export function LogDatasourcePage() {
const handleDelete = async (ds: LogDataSource) => {
const ok = await confirm({
- title: '删除数据源',
+ title: i18n.t('monitor.deleteDatasource'),
description: `确认删除「${ds.name}」?`,
variant: 'destructive',
- confirmText: '删除',
+ confirmText: i18n.t('kubernetes.storage.delete2'),
});
if (!ok) return;
try {
await logCenterApi.deleteDatasource(ds.id);
- toast({ title: '已删除' });
+ toast({ title: i18n.t('monitor.silenceRules.deleted') });
load();
} catch (e) {
- toast({ title: '删除失败', description: e?.message || String(e), variant: 'destructive' });
+ toast({ title: i18n.t('kubernetes.msg.deleteFailed2'), description: e?.message || String(e), variant: 'destructive' });
}
};
@@ -66,22 +67,22 @@ export function LogDatasourcePage() {
// 已保存数据源通过 datasource_id 测试,避免密码丢失或前端暴露密码。// Logan.Li
const result: TestConnectionResult = await logCenterApi.testDatasource({ datasource_id: ds.id });
if (result.status === 'ok') {
- toast({ title: '连接成功', description: `${ds.name} 可达` });
+ toast({ title: i18n.t('aiops.llmTestSuccess'), description: `${ds.name} 可达` });
} else {
- toast({ title: '连接失败', description: result.error || '未知错误', variant: 'destructive' });
+ toast({ title: i18n.t('aiops.llmTestFailed'), description: result.error || i18n.t('monitor.dashboard.agent.toast.unknownError'), variant: 'destructive' });
}
} catch (e) {
- toast({ title: '连接失败', description: e?.message || String(e), variant: 'destructive' });
+ toast({ title: i18n.t('aiops.llmTestFailed'), description: e?.message || String(e), variant: 'destructive' });
}
};
const handleSetDefault = async (ds: LogDataSource) => {
try {
await logCenterApi.setDefaultDatasource(ds.id);
- toast({ title: '已设为默认' });
+ toast({ title: i18n.t('approval.msg.setDefaultSuccess') });
load();
} catch (e) {
- toast({ title: '操作失败', description: e?.message || String(e), variant: 'destructive' });
+ toast({ title: i18n.t('cloud.operationFailed'), description: e?.message || String(e), variant: 'destructive' });
}
};
@@ -92,39 +93,39 @@ export function LogDatasourcePage() {
// DataTable 列定义
const columns: DataTableColumn [] = [
- { key: 'name', header: '名称', sortable: true, render: (ds) => {ds.name} },
+ { key: 'name', header: i18n.t('kubernetes.secret.secretName'), sortable: true, render: (ds) => {ds.name} },
{
- key: 'type', header: '类型', sortable: true, width: 120,
+ key: 'type', header: i18n.t('system.credentialType'), sortable: true, width: 120,
render: (ds) => {engineLabel(ds.type)},
},
{
- key: 'url', header: '地址',
+ key: 'url', header: i18n.t('monitor.datasourceUrl'),
render: (ds) => {ds.url},
},
{
- key: 'is_default', header: '默认', width: 60, align: 'center', sortable: true,
+ key: 'is_default', header: i18n.t('k8s.storage.default'), width: 60, align: 'center', sortable: true,
render: (ds) => ds.is_default ? : —,
},
{
- key: 'actions', header: '操作', align: 'right', hideable: false,
+ key: 'actions', header: i18n.t('system.auditAction'), align: 'right', hideable: false,
render: (ds) => (
handleTest(ds)}>
+ title={i18n.t('aiops.llmTest')} onClick={() => handleTest(ds)}>
{!ds.is_default && (
handleSetDefault(ds)}>
+ title={i18n.t('aiops.llmSetDefault')} onClick={() => handleSetDefault(ds)}>
)}
handleEdit(ds)}>
+ title={i18n.t('common.edit')} onClick={() => handleEdit(ds)}>
handleDelete(ds)}>
+ title={i18n.t('kubernetes.storage.delete2')} onClick={() => handleDelete(ds)}>
@@ -146,10 +147,10 @@ export function LogDatasourcePage() {
rowKey={(ds) => ds.id}
loading={loading}
searchable
- searchPlaceholder="搜索数据源名称或地址..."
+ searchPlaceholder={i18n.t('monitor.logdatasourcepa.seb5e4d30')}
searchKeys={['name', 'url']}
sortable
- emptyText="暂无数据源,点击上方按钮添加"
+ emptyText={i18n.t('monitor.logdatasourcepa.sc8a96073')}
toolbarExtra={
<>
diff --git a/frontend/src/components/monitor/log-center/LogDingAssistant.tsx b/frontend/src/components/monitor/log-center/LogDingAssistant.tsx
index 4a98d7d..c82d07d 100644
--- a/frontend/src/components/monitor/log-center/LogDingAssistant.tsx
+++ b/frontend/src/components/monitor/log-center/LogDingAssistant.tsx
@@ -4,6 +4,7 @@ import { Sparkles } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useLogQueryContext } from './LogQueryContext';
import { LogAlertFromQueryDialog } from './LogAlertFromQueryDialog';
+import i18n from '@/i18n';
export function LogDingAssistant({ onRuleCreated }: { onRuleCreated?: () => void }) {
const { context } = useLogQueryContext();
@@ -19,10 +20,10 @@ export function LogDingAssistant({ onRuleCreated }: { onRuleCreated?: () => void
size="lg"
className="h-12 rounded-full shadow-lg bg-gradient-to-r from-amber-500 to-orange-500 hover:from-amber-400 hover:to-orange-400 text-white gap-2 px-5"
onClick={() => setOpen(true)}
- title="叮当 · 添加告警"
+ title={i18n.t('monitor.logdingassistan.s26b79b6b')}
>
- 叮当
+ {i18n.t('monitor.logdingassistan.s1a663141')}
setSearch(e.target.value)}
- placeholder="搜索字段"
+ placeholder={i18n.t('monitor.logfieldsidebar.s2d3013c3')}
className="w-full h-7 pl-7 pr-2 text-xs rounded-md dg-input"
style={{ background: 'var(--dg-bg-tertiary)', border: '1px solid var(--dg-border)', color: 'var(--dg-text-primary)' }}
/>
diff --git a/frontend/src/components/monitor/log-center/LogNav.tsx b/frontend/src/components/monitor/log-center/LogNav.tsx
index f92a773..230c9ea 100644
--- a/frontend/src/components/monitor/log-center/LogNav.tsx
+++ b/frontend/src/components/monitor/log-center/LogNav.tsx
@@ -1,13 +1,14 @@
import { NavLink } from 'react-router-dom';
import { FileSearch, Database, HardDrive, AlertTriangle, Shield } from 'lucide-react';
import { cn } from '@/lib/utils';
+import i18n from '@/i18n';
const NAV_ITEMS = [
- { path: '/log-center/loki', label: 'Loki 查询', icon: FileSearch },
- { path: '/log-center/es', label: 'ES 查询', icon: Database },
- { path: '/log-center/datasources', label: '日志库', icon: HardDrive },
- { path: '/log-center/alerts', label: '日志告警', icon: AlertTriangle },
- { path: '/log-center/rbac', label: '日志权限', icon: Shield },
+ { path: '/log-center/loki', label: i18n.t('monitor.lokiQuery'), icon: FileSearch },
+ { path: '/log-center/es', label: i18n.t('monitor.esQuery'), icon: Database },
+ { path: '/log-center/datasources', label: i18n.t('monitor.logLibrary'), icon: HardDrive },
+ { path: '/log-center/alerts', label: i18n.t('monitor.alertHelper.srcLog'), icon: AlertTriangle },
+ { path: '/log-center/rbac', label: i18n.t('monitor.logCenter.rbac'), icon: Shield },
];
// 日志中心二级导航 // Logan.Li
diff --git a/frontend/src/components/monitor/log-center/LogQueryToolbar.tsx b/frontend/src/components/monitor/log-center/LogQueryToolbar.tsx
index e8dcfa4..02661ea 100644
--- a/frontend/src/components/monitor/log-center/LogQueryToolbar.tsx
+++ b/frontend/src/components/monitor/log-center/LogQueryToolbar.tsx
@@ -1,6 +1,7 @@
// LogQueryToolbar.tsx — 查询工具栏(统计条 + 分页 + 操作)// Logan.Li
import { ArrowUpDown, Bell, Download, Copy, ChevronLeft, ChevronRight, ChevronsDown } from 'lucide-react';
import { useState } from 'react';
+import i18n from '@/i18n';
interface Props {
total: number;
@@ -23,9 +24,9 @@ interface Props {
}
const STATUS_LABEL: Record = {
- precise: { text: '结果精确', color: '#22c55e' },
- partial: { text: '部分命中', color: '#f59e0b' },
- failed: { text: '查询失败', color: '#ef4444' },
+ precise: { text: i18n.t('monitor.logquerytoolbar.sd0368470'), color: '#22c55e' },
+ partial: { text: i18n.t('monitor.logquerytoolbar.s8b09f4fe'), color: '#f59e0b' },
+ failed: { text: i18n.t('monitor.logPanel.queryFailed'), color: '#ef4444' },
};
export function LogQueryToolbar({
@@ -121,7 +122,7 @@ export function LogQueryToolbar({
- 到第
+ {i18n.t('monitor.logquerytoolbar.s8b76adb2')}
@@ -160,7 +161,7 @@ export function LogQueryToolbar({
onClick={onExport}
className="h-7 w-7 flex items-center justify-center rounded border transition-colors"
style={{ borderColor: 'var(--dg-border)', color: 'var(--dg-text-muted)', background: 'var(--dg-bg-tertiary)' }}
- title="导出"
+ title={i18n.t('common.export2')}
>
@@ -168,7 +169,7 @@ export function LogQueryToolbar({
onClick={onCopy}
className="h-7 w-7 flex items-center justify-center rounded border transition-colors"
style={{ borderColor: 'var(--dg-border)', color: 'var(--dg-text-muted)', background: 'var(--dg-bg-tertiary)' }}
- title="复制"
+ title={i18n.t('aiops.copyMessage')}
>
@@ -176,7 +177,7 @@ export function LogQueryToolbar({
onClick={onBellClick}
className="relative h-7 w-7 flex items-center justify-center rounded border transition-colors"
style={{ borderColor: 'var(--dg-border)', color: 'var(--dg-text-muted)', background: 'var(--dg-bg-tertiary)' }}
- title="关联告警"
+ title={i18n.t('aiops.alertAnalysisRelated')}
>
{hasAlertRule && (
diff --git a/frontend/src/components/monitor/log-center/LogRBAC.tsx b/frontend/src/components/monitor/log-center/LogRBAC.tsx
index 3586489..677a87c 100644
--- a/frontend/src/components/monitor/log-center/LogRBAC.tsx
+++ b/frontend/src/components/monitor/log-center/LogRBAC.tsx
@@ -18,20 +18,21 @@ import { LogRoleCreateDialog } from './log-rbac/LogRoleCreateDialog';
import { matchSampleScopes, SAMPLE_SCOPES, scopeDisplayLabel } from './log-rbac/matchLogScope';
import type { LogDataSource } from '@/api/log/log-center';
import type { JsonData } from '@/types/common';
+import i18n from '@/i18n';
const ROLE_LABEL: Record = {
- viewer: '查看者',
- analyst: '分析者',
+ viewer: i18n.t('pipeline.viewer'),
+ analyst: i18n.t('monitor.logrbactsx.sa72dec16'),
};
const ENGINE_LABEL: Record = {
- '*': '全部',
+ '*': i18n.t('system.auditAll'),
loki: 'Loki',
elasticsearch: 'ES',
};
const FIELD_LABEL: Record = {
- index: '索引',
+ index: i18n.t('monitor.logIndex'),
app: 'app',
namespace: 'namespace',
job: 'job',
@@ -106,7 +107,7 @@ export default function LogRBAC() {
const handleCreate = async () => {
if (!newName.trim() || !newCode.trim() || !newPattern.trim()) {
- toast.error('请填写名称、标识与正则'); return;
+ toast.error(i18n.t('monitor.logrbactsx.sf6e80bf0')); return;
}
setSaving(true);
try {
@@ -120,83 +121,83 @@ export default function LogRBAC() {
description: newDesc,
...(newDatasourceId ? { datasource_id: Number(newDatasourceId) } : {}),
});
- toast.success('已创建');
+ toast.success(i18n.t('kubernetes.event.created'));
setCreateOpen(false);
setNewName(''); setNewCode(''); setNewEngine('*'); setNewMatchField('app');
setNewPattern(''); setNewRole('viewer'); setNewDatasourceId(''); setNewDesc('');
loadData();
} catch (e: unknown) {
- toast.error((e as Error)?.message || '创建失败');
+ toast.error((e as Error)?.message || i18n.t('monitor.dashboard.custom.toastCreateFailed'));
} finally { setSaving(false); }
};
const handleUpdate = async (id: number) => {
- if (!editPattern.trim()) { toast.error('正则不能为空'); return; }
+ if (!editPattern.trim()) { toast.error(i18n.t('pipeline.regexEmpty')); return; }
setSaving(true);
try {
await logRbacApi.updateRole(id, { pattern: editPattern, role: editRole });
- toast.success('已更新');
+ toast.success(i18n.t('deploy.toast.updated'));
setEditing(null);
loadData();
} catch (e: unknown) {
- toast.error((e as Error)?.message || '更新失败');
+ toast.error((e as Error)?.message || i18n.t('kubernetes.deployment.imageUpdateFailed'));
} finally { setSaving(false); }
};
const handleDelete = async (role: LogScopeRole) => {
const ok = await _confirm({
- title: '删除权限',
+ title: i18n.t('monitor.logrbactsx.s5d79e436'),
description: `确定删除「${role.name}」?将影响 ${matchCount[role.id]?.length || 0} 个示例范围`,
variant: 'destructive',
});
if (!ok) return;
- try { await logRbacApi.deleteRole(role.id); toast.success('已删除'); loadData(); }
- catch { toast.error('删除失败'); }
+ try { await logRbacApi.deleteRole(role.id); toast.success(i18n.t('monitor.silenceRules.deleted')); loadData(); }
+ catch { toast.error(i18n.t('kubernetes.msg.deleteFailed2')); }
};
const handleToggleStatus = async (role: LogScopeRole) => {
try {
await logRbacApi.updateRole(role.id, { status: role.status ? 0 : 1 });
- toast.success(role.status ? '已禁用' : '已启用');
+ toast.success(role.status ? i18n.t('aiops.llmDisabled') : i18n.t('aiops.llmEnabled'));
loadData();
- } catch { toast.error('操作失败'); }
+ } catch { toast.error(i18n.t('cloud.operationFailed')); }
};
const handleAssign = async () => {
- if (!selectedUserId || !assignRoleId) { toast.error('请选择用户和权限'); return; }
+ if (!selectedUserId || !assignRoleId) { toast.error(i18n.t('monitor.logrbactsx.s0fc53985')); return; }
setAssignLoading(true);
try {
await logRbacApi.assignRole(Number(selectedUserId), {
log_scope_role_id: Number(assignRoleId),
});
- toast.success('已分配');
+ toast.success(i18n.t('deploy.toast.assigned'));
setAssignRoleId('');
loadAssignments();
} catch (e: unknown) {
- toast.error((e as Error)?.message || '分配失败');
+ toast.error((e as Error)?.message || i18n.t('deploy.toast.assignFailed'));
} finally { setAssignLoading(false); }
};
const handleRevoke = async (id: number) => {
try {
await logRbacApi.removeRole(Number(selectedUserId), id);
- toast.success('已撤销');
+ toast.success(i18n.t('deploy.toast.revoked'));
loadAssignments();
- } catch { toast.error('撤销失败'); }
+ } catch { toast.error(i18n.t('deploy.toast.revokeFailed')); }
};
const selectedUser = users.find((u) => String(u.id) === selectedUserId);
const pageTabs = [
- { id: 'roles', label: '权限策略', badge: roles.length || undefined },
- { id: 'users', label: '用户授权' },
- { id: 'preview', label: '命中预览' },
+ { id: 'roles', label: i18n.t('monitor.logrbactsx.s93ef07cd'), badge: roles.length || undefined },
+ { id: 'users', label: i18n.t('monitor.logrbactsx.s2de89571') },
+ { id: 'preview', label: i18n.t('pipeline.matchPreview') },
];
return (
}
loading={loading}
tabs={pageTabs}
@@ -213,9 +214,9 @@ export default function LogRBAC() {
roles.length === 0 ? (
}
- title="暂无日志权限策略"
- description="创建策略并分配给用户后,将按正则限制可查询的索引与 Label 范围"
- action={ setCreateOpen(true)}>新建权限}
+ title={i18n.t('monitor.logrbactsx.s4a00d253')}
+ description={i18n.t('monitor.logrbactsx.sd11b7407')}
+ action={ setCreateOpen(true)}> {i18n.t('monitor.logrbactsx.s6058845c')} }
/>
) : (
@@ -235,7 +236,7 @@ export default function LogRBAC() {
{FIELD_LABEL[role.match_field] || role.match_field}
- {role.status === 0 && 已禁用}
+ {role.status === 0 && {i18n.t('aiops.llmDisabled')} }
- 查看者
- 分析者
+ {i18n.t('pipeline.viewer')}
+ {i18n.t('monitor.logrbactsx.sa72dec16')}
handleUpdate(role.id)}>
@@ -265,8 +266,8 @@ export default function LogRBAC() {
>
) : (
<>
- { setEditing(role.id); setEditPattern(role.pattern); setEditRole(role.role); }}>编辑
- handleToggleStatus(role)}>{role.status ? '禁用' : '启用'}
+ { setEditing(role.id); setEditPattern(role.pattern); setEditRole(role.role); }}> {i18n.t('common.edit')}
+ handleToggleStatus(role)}>{role.status ? i18n.t('system.userInactive') : i18n.t('system.userActive')}
handleDelete(role)}>
>
)}
@@ -287,9 +288,9 @@ export default function LogRBAC() {
-
+
-
+
{selectedUser ? (
assignments.length === 0 ? (
- 该用户尚未分配日志权限
+ {i18n.t('monitor.logrbactsx.sa120fc78')}
) : (
{assignments.map((a) => {
@@ -338,7 +339,7 @@ export default function LogRBAC() {
)
) : (
- 选择用户后查看已分配权限
+ {i18n.t('monitor.logrbactsx.s9be00c95')}
)}
@@ -371,7 +372,7 @@ export default function LogRBAC() {
))}
{previewRoleId !== null && previewMatches.length === 0 && (
- 无匹配 — 请调整正则
+ {i18n.t('monitor.logrbactsx.s64096f4d')}
)}
diff --git a/frontend/src/components/monitor/log-center/LokiLabelBrowser.tsx b/frontend/src/components/monitor/log-center/LokiLabelBrowser.tsx
index 1f891e3..d9ec05f 100644
--- a/frontend/src/components/monitor/log-center/LokiLabelBrowser.tsx
+++ b/frontend/src/components/monitor/log-center/LokiLabelBrowser.tsx
@@ -3,6 +3,7 @@ import { ChevronDown, ChevronRight, Loader2, Tags } from 'lucide-react';
import { logCenterApi } from '@/api/log/log-center';
import { extractLokiSelector, mergeLokiSelector } from './query-builder';
import type { TimeRange } from './types-v3';
+import i18n from '@/i18n';
interface Props {
datasourceId?: number;
@@ -95,7 +96,7 @@ export function LokiLabelBrowser({ datasourceId, query, timeRange, onQueryChange
))}
- {!activeLabel && 选择左侧标签 }
+ {!activeLabel && {i18n.t('monitor.lokilabelbrowse.s088b9477')} }
{loadingValues &&
}
{!loadingValues && activeLabel && values.map((v) => (
= {
function relativeTime(ts: number): string {
const diff = Date.now() - ts;
- if (diff < 60000) return '刚刚';
+ if (diff < 60000) return i18n.t('task.cronJob.time.justNow');
if (diff < 3600000) return `${Math.floor(diff / 60000)}分钟前`;
if (diff < 86400000) return `${Math.floor(diff / 3600000)}小时前`;
return `${Math.floor(diff / 86400000)}天前`;
@@ -59,7 +60,7 @@ export function QueryHistoryPanel({ visible, onClose, onSelect, onCreateAlert }:
- 查询历史
+ {i18n.t('monitor.logPanel.history')}
{history.length} 条
@@ -69,7 +70,7 @@ export function QueryHistoryPanel({ visible, onClose, onSelect, onCreateAlert }:
onClick={handleClear}
className="h-7 w-7 flex items-center justify-center rounded transition-colors"
style={{ color: 'var(--dg-text-muted)' }}
- title="清空"
+ title={i18n.t('common.clear')}
>
@@ -88,8 +89,8 @@ export function QueryHistoryPanel({ visible, onClose, onSelect, onCreateAlert }:
{history.length === 0 ? (
- 暂无查询记录
- 执行查询后将自动记录
+ {i18n.t('monitor.queryhistorypan.s1e60bc17')}
+ {i18n.t('monitor.queryhistorypan.s3895021f')}
) : (
@@ -137,7 +138,7 @@ export function QueryHistoryPanel({ visible, onClose, onSelect, onCreateAlert }:
onClick={() => onSelect(item)}
className="h-6 w-6 flex items-center justify-center rounded transition-colors"
style={{ background: 'var(--dg-bg-tertiary)', color: 'var(--dg-green)' }}
- title="执行查询"
+ title={i18n.t('monitor.queryhistorypan.s4fb36a61')}
>
diff --git a/frontend/src/components/monitor/log-center/QuickQueryBar.tsx b/frontend/src/components/monitor/log-center/QuickQueryBar.tsx
index 4ba9d64..c622660 100644
--- a/frontend/src/components/monitor/log-center/QuickQueryBar.tsx
+++ b/frontend/src/components/monitor/log-center/QuickQueryBar.tsx
@@ -1,38 +1,39 @@
import { useState } from 'react';
import { ChevronDown } from 'lucide-react';
+import i18n from '@/i18n';
const ALL_TEMPLATES: Record<'loki' | 'elasticsearch', { label: string; query: string }[]> = {
loki: [
- { label: 'Nginx 错误', query: '{job="nginx"} |= "error"' },
- { label: 'JSON 过滤', query: '{namespace="prod"} | json | level="warn"' },
- { label: '超时搜索', query: '{app="api"} |= "timeout"' },
- { label: '级别统计', query: 'sum by(level) (count_over_time({job="app"}[5m]))' },
- { label: '正则多级别', query: '{container="frontend"} |~ "ERROR|WARN|FATAL"' },
- { label: '慢请求>1s', query: '{job="api"} | json | response_time > 1000' },
- { label: '错误率统计', query: 'sum by(level) (count_over_time({app="cex-admin-api"} |= "error" [5m]))' },
- { label: '追踪ID查询', query: '{app="cex-admin-api"} |= "trace_id" | json' },
- { label: '服务聚合', query: 'sum by(service_name) (count_over_time({namespace="astralx"}[5m]))' },
- { label: '高延迟筛选', query: '{app="cex-admin-api"} | json | response_time > 500' },
- { label: '异常堆栈', query: '{app="cex-admin-api"} |= "Exception"' },
- { label: '日志趋势', query: 'sum(count_over_time({app="cex-admin-api"}[1h]))' },
- { label: '正则提取', query: '{app="cex-admin-api"} | regexp "(?P [A-Za-z0-9_]+) (?P[^ ]+)"' },
- { label: '格式输出', query: '{app="cex-admin-api"} | json | line_format "{{.level}} {{.message}}"' },
+ { label: i18n.t('monitor.quickquerybarts.s64559524'), query: '{job="nginx"} |= "error"' },
+ { label: i18n.t('monitor.quickquerybarts.s315990ac'), query: '{namespace="prod"} | json | level="warn"' },
+ { label: i18n.t('monitor.quickquerybarts.sfc6d4276'), query: '{app="api"} |= "timeout"' },
+ { label: i18n.t('monitor.quickquerybarts.s0ce3d219'), query: 'sum by(level) (count_over_time({job="app"}[5m]))' },
+ { label: i18n.t('monitor.quickquerybarts.s6209b154'), query: '{container="frontend"} |~ "ERROR|WARN|FATAL"' },
+ { label: i18n.t('monitor.quickquerybarts.sf839efd6'), query: '{job="api"} | json | response_time > 1000' },
+ { label: i18n.t('monitor.quickquerybarts.s386c7580'), query: 'sum by(level) (count_over_time({app="cex-admin-api"} |= "error" [5m]))' },
+ { label: i18n.t('monitor.quickquerybarts.sf94f3fdb'), query: '{app="cex-admin-api"} |= "trace_id" | json' },
+ { label: i18n.t('monitor.quickquerybarts.s7f0fa5fa'), query: 'sum by(service_name) (count_over_time({namespace="astralx"}[5m]))' },
+ { label: i18n.t('monitor.quickquerybarts.s49c7620d'), query: '{app="cex-admin-api"} | json | response_time > 500' },
+ { label: i18n.t('monitor.quickquerybarts.sb8edf48d'), query: '{app="cex-admin-api"} |= "Exception"' },
+ { label: i18n.t('monitor.logTrend'), query: 'sum(count_over_time({app="cex-admin-api"}[1h]))' },
+ { label: i18n.t('monitor.quickquerybarts.s1ace0c03'), query: '{app="cex-admin-api"} | regexp "(?P[A-Za-z0-9_]+) (?P[^ ]+)"' },
+ { label: i18n.t('monitor.quickquerybarts.s20b34227'), query: '{app="cex-admin-api"} | json | line_format "{{.level}} {{.message}}"' },
],
elasticsearch: [
{ label: 'API 5xx', query: 'status:500 AND path:"/api/*"' },
- { label: '错误超时', query: '(level:error OR log.level:error) AND message:*timeout*' },
- { label: '排除调试', query: 'host.name:server-* AND NOT level:debug' },
- { label: '慢请求', query: 'response_time:>1000 AND method:POST' },
- { label: '严重错误', query: '@timestamp:[now-1h TO now] AND (level:critical OR log.level:critical)' },
- { label: '服务错误', query: 'service:nginx AND (level:(error OR fatal) OR log.level:(error OR fatal))' },
- { label: '组合查询', query: 'app:cex-admin-api AND (level:(error OR warn) OR log.level:(error OR warn))' },
- { label: '模糊匹配', query: 'message:*timeout* AND app:cex-admin-api' },
- { label: '范围查询', query: 'response_time:[1000 TO *] AND method:POST' },
- { label: '排除路径', query: 'app:cex-admin-api AND NOT path:/health' },
- { label: '时间过滤', query: '@timestamp:[now-1h TO now] AND level:error' },
- { label: 'IP段过滤', query: 'client_ip:172.36.* AND app:cex-admin-api' },
- { label: '多级别筛选', query: 'app:cex-admin-api AND (level:(error OR warn OR info) OR log.level:(error OR warn OR info))' },
- { label: '嵌套字段', query: 'labels.orgId:10001 AND app:cex-admin-api' },
+ { label: i18n.t('monitor.quickquerybarts.sa1eb8196'), query: '(level:error OR log.level:error) AND message:*timeout*' },
+ { label: i18n.t('monitor.quickquerybarts.s0235c6eb'), query: 'host.name:server-* AND NOT level:debug' },
+ { label: i18n.t('monitor.quickquerybarts.s0876c43d'), query: 'response_time:>1000 AND method:POST' },
+ { label: i18n.t('monitor.quickquerybarts.se31850bf'), query: '@timestamp:[now-1h TO now] AND (level:critical OR log.level:critical)' },
+ { label: i18n.t('monitor.quickquerybarts.s6241b884'), query: 'service:nginx AND (level:(error OR fatal) OR log.level:(error OR fatal))' },
+ { label: i18n.t('monitor.quickquerybarts.s04adb0fd'), query: 'app:cex-admin-api AND (level:(error OR warn) OR log.level:(error OR warn))' },
+ { label: i18n.t('monitor.quickquerybarts.sc579cfbb'), query: 'message:*timeout* AND app:cex-admin-api' },
+ { label: i18n.t('monitor.quickquerybarts.s0c9d7886'), query: 'response_time:[1000 TO *] AND method:POST' },
+ { label: i18n.t('monitor.quickquerybarts.se11dceb4'), query: 'app:cex-admin-api AND NOT path:/health' },
+ { label: i18n.t('monitor.quickquerybarts.s00f6f739'), query: '@timestamp:[now-1h TO now] AND level:error' },
+ { label: i18n.t('monitor.quickquerybarts.s8a1879ae'), query: 'client_ip:172.36.* AND app:cex-admin-api' },
+ { label: i18n.t('monitor.quickquerybarts.s6f401985'), query: 'app:cex-admin-api AND (level:(error OR warn OR info) OR log.level:(error OR warn OR info))' },
+ { label: i18n.t('monitor.quickquerybarts.sf09e007f'), query: 'labels.orgId:10001 AND app:cex-admin-api' },
],
};
diff --git a/frontend/src/components/monitor/log-center/SaveQueryDialog.tsx b/frontend/src/components/monitor/log-center/SaveQueryDialog.tsx
index 62e3f0e..ffa17e7 100644
--- a/frontend/src/components/monitor/log-center/SaveQueryDialog.tsx
+++ b/frontend/src/components/monitor/log-center/SaveQueryDialog.tsx
@@ -5,6 +5,7 @@ import { alertApi } from '@/api';
import { useToast } from '@/hooks/use-toast';
import type { LogEngine, TimeRange } from './types-v3';
import { ENGINE_META, savedQueryStorage } from './types-v3';
+import i18n from '@/i18n';
interface SaveQueryProps {
open: boolean;
@@ -46,24 +47,24 @@ export function SaveQueryDialog({ open, onClose, engine, query, timeRange, datas
- 另存为查询
+ {i18n.t('monitor.statChart.saveAsQuery')}
- 取消
+ {i18n.t('rbac.jobRole.cancel')}
- {saving && }{saved ? '已保存' : '保存'}
+ {saving && }{saved ? i18n.t('deploy.toast.saved') : i18n.t('task.script.save')}
@@ -100,7 +101,7 @@ export function SaveAlertDialog({ open, onClose, engine, query, datasourceId, da
try {
await alertApi.createRule({
name: name.trim(),
- description: `从查询页创建: ${datasourceName || '默认数据源'}`,
+ description: `从查询页创建: ${datasourceName || i18n.t('monitor.savequerydialog.sddb4ca92')}`,
type: 'log',
source: engine === 'sls' ? 'loki' : engine,
expression: query.trim(),
@@ -110,11 +111,11 @@ export function SaveAlertDialog({ open, onClose, engine, query, datasourceId, da
notify_channels: [],
});
setSaved(true);
- toast({ title: '告警规则已创建' });
+ toast({ title: i18n.t('monitor.savequerydialog.sd3dbea92') });
onSave?.();
setTimeout(() => { setSaved(false); onClose(); }, 800);
} catch (e: any) {
- toast({ title: '创建失败', description: e?.message || String(e), variant: 'destructive' });
+ toast({ title: i18n.t('monitor.dashboard.custom.toastCreateFailed'), description: e?.message || String(e), variant: 'destructive' });
} finally {
setSaving(false);
}
@@ -125,35 +126,35 @@ export function SaveAlertDialog({ open, onClose, engine, query, datasourceId, da
- 另存为告警
+ {i18n.t('monitor.logSaveAsAlert')}
- 取消
+ {i18n.t('rbac.jobRole.cancel')}
- {saving && }{saved ? '已创建' : '创建告警'}
+ {saving && }{saved ? i18n.t('kubernetes.event.created') : i18n.t('monitor.savequerydialog.sbc1d9937')}
diff --git a/frontend/src/components/monitor/log-center/SavedQueriesPanel.tsx b/frontend/src/components/monitor/log-center/SavedQueriesPanel.tsx
index 3644a57..3b351de 100644
--- a/frontend/src/components/monitor/log-center/SavedQueriesPanel.tsx
+++ b/frontend/src/components/monitor/log-center/SavedQueriesPanel.tsx
@@ -3,6 +3,7 @@ import { X, Trash2, Play, Bookmark, Clock } from 'lucide-react';
import type { SavedQuery } from './types-v3';
import { savedQueryStorage } from './types-v3';
import { ENGINE_META } from './types-v3';
+import i18n from '@/i18n';
interface Props {
visible: boolean;
@@ -30,7 +31,7 @@ export function SavedQueriesPanel({ visible, onClose, onSelect }: Props) {
- 已保存查询
+ {i18n.t('monitor.logPanel.savedQueries')}
{items.length}
@@ -41,7 +42,7 @@ export function SavedQueriesPanel({ visible, onClose, onSelect }: Props) {
{items.length === 0 ? (
- 暂无保存的查询
+ {i18n.t('monitor.savedqueriespan.s9c8dc62b')}
) : items.map((item) => (
{ onSelect(item); onClose(); }}
className="h-7 w-7 flex items-center justify-center rounded border"
style={{ borderColor: 'var(--dg-border)', color: '#22c55e' }}
- title="应用"
+ title={i18n.t('kubernetes.yaml.apply')}
>
@@ -73,7 +74,7 @@ export function SavedQueriesPanel({ visible, onClose, onSelect }: Props) {
onClick={() => { savedQueryStorage.remove(item.id); setItems(savedQueryStorage.getAll()); }}
className="h-7 w-7 flex items-center justify-center rounded border"
style={{ borderColor: 'var(--dg-border)', color: 'var(--dg-text-muted)' }}
- title="删除"
+ title={i18n.t('kubernetes.storage.delete2')}
>
diff --git a/frontend/src/components/monitor/log-center/TimeRangePicker.tsx b/frontend/src/components/monitor/log-center/TimeRangePicker.tsx
index 7b4f4db..c6653f0 100644
--- a/frontend/src/components/monitor/log-center/TimeRangePicker.tsx
+++ b/frontend/src/components/monitor/log-center/TimeRangePicker.tsx
@@ -2,30 +2,31 @@
import { useState, useRef, useEffect } from 'react';
import { ChevronDown, ChevronUp, Calendar } from 'lucide-react';
import type { TimeRange } from './types-v3';
+import i18n from '@/i18n';
// 相对时间预设:最近N... 每次点击时计算 start = now - N // Logan.Li
const RELATIVE_PRESETS = [
- { label: '最近1分钟', value: '1m' },
- { label: '最近5分钟', value: '5m' },
- { label: '最近15分钟', value: '15m' },
- { label: '最近1小时', value: '1h' },
- { label: '最近4小时', value: '4h' },
- { label: '最近1天', value: '24h' },
- { label: '最近1周', value: '7d' },
- { label: '最近30天', value: '30d' },
+ { label: i18n.t('monitor.timerangepicker.s6b3f2ecb'), value: '1m' },
+ { label: i18n.t('monitor.logPanel.last5min'), value: '5m' },
+ { label: i18n.t('monitor.timerangepicker.sd4962f4b'), value: '15m' },
+ { label: i18n.t('monitor.timerangepicker.sd8a81545'), value: '1h' },
+ { label: i18n.t('monitor.timerangepicker.s0823ad83'), value: '4h' },
+ { label: i18n.t('monitor.timerangepicker.s77be0dba'), value: '24h' },
+ { label: i18n.t('monitor.timerangepicker.s2ba41ef4'), value: '7d' },
+ { label: i18n.t('monitor.timerangepicker.s63f66f1f'), value: '30d' },
];
// 绝对时间预设:固定的自然日/周/月/季/年 // Logan.Li
const ABSOLUTE_PRESETS = [
- { label: '今天', value: 'today' },
- { label: '昨天', value: 'yesterday' },
- { label: '前天', value: 'day_before_yesterday' },
- { label: '本周', value: 'this_week' },
- { label: '上周', value: 'last_week' },
- { label: '本月', value: 'this_month' },
- { label: '上月', value: 'last_month' },
- { label: '本季度', value: 'this_quarter' },
- { label: '本年度', value: 'this_year' },
+ { label: i18n.t('audit.terminal.presetToday'), value: 'today' },
+ { label: i18n.t('common.yesterday'), value: 'yesterday' },
+ { label: i18n.t('monitor.timerangepicker.s94995c31'), value: 'day_before_yesterday' },
+ { label: i18n.t('common.thisWeek'), value: 'this_week' },
+ { label: i18n.t('common.lastWeek'), value: 'last_week' },
+ { label: i18n.t('cloud.thisMonth'), value: 'this_month' },
+ { label: i18n.t('common.lastMonth'), value: 'last_month' },
+ { label: i18n.t('monitor.timerangepicker.s0477ce74'), value: 'this_quarter' },
+ { label: i18n.t('monitor.timerangepicker.s77df6c8e'), value: 'this_year' },
];
function getPresetRange(value: string): { start: Date; end: Date; label: string } {
@@ -94,7 +95,7 @@ export function TimeRangePicker({ value, onChange }: Props) {
onChange({
start: customStart,
end: customEnd,
- label: '自定义',
+ label: i18n.t('aiops.providerCustom'),
type: 'absolute',
});
setActivePreset('custom');
@@ -135,7 +136,7 @@ export function TimeRangePicker({ value, onChange }: Props) {
{/* 头部 */}
- 时间选择
+ {i18n.t('monitor.timerangepicker.sc2c8fb23')}
{/* 相对时间 — 最近... */}
- 相对时间(滚动窗口)
+ {i18n.t('monitor.timerangepicker.s8ead0af2')}
{RELATIVE_PRESETS.map(p => (
{/* 绝对时间 — 固定日历范围 */}
- 绝对时间(日历范围)
+ {i18n.t('monitor.timerangepicker.s714f6cdd')}
{ABSOLUTE_PRESETS.map(p => (
- 自定义时间范围
+ {i18n.t('monitor.hosttimerangepi.s0122e022')}
)}
diff --git a/frontend/src/components/monitor/log-center/query-url-state.ts b/frontend/src/components/monitor/log-center/query-url-state.ts
index fb013a6..2e666db 100644
--- a/frontend/src/components/monitor/log-center/query-url-state.ts
+++ b/frontend/src/components/monitor/log-center/query-url-state.ts
@@ -1,6 +1,7 @@
// 日志查询 URL 状态编解码 — 可分享链接 // Logan.Li
import type { TimeRange } from './types-v3';
+import i18n from '@/i18n';
export interface LogQueryUrlState {
query?: string;
@@ -16,7 +17,7 @@ export function parseLogQueryUrl(params: URLSearchParams): LogQueryUrlState {
const index = params.get('index') || undefined;
const start = params.get('from') || undefined;
const end = params.get('to') || undefined;
- const timeLabel = params.get('tr') || '自定义';
+ const timeLabel = params.get('tr') || i18n.t('aiops.providerCustom');
const autoRun = params.get('run') === '1';
const state: LogQueryUrlState = { query, datasourceId, index, autoRun };
if (start && end) {
diff --git a/frontend/src/components/monitor/log-center/types-v3.ts b/frontend/src/components/monitor/log-center/types-v3.ts
index 62c52ce..ac935f4 100644
--- a/frontend/src/components/monitor/log-center/types-v3.ts
+++ b/frontend/src/components/monitor/log-center/types-v3.ts
@@ -1,3 +1,4 @@
+import i18n from '@/i18n';
// types-v3.ts — v3 统一日志中心类型定义 // Logan.Li
export type LogEngine = 'loki' | 'elasticsearch' | 'sls';
@@ -132,7 +133,7 @@ export const ENGINE_META: Record = {
loki: [
- { label: 'Nginx 错误日志', query: '{job="nginx"} |= "error"' },
- { label: 'JSON 解析过滤', query: '{namespace="prod"} | json | level="warn"' },
- { label: '超时搜索', query: '{app="api"} |= "timeout"' },
- { label: '按级别统计', query: 'sum by (level) (count_over_time({job="app"}[5m]))' },
- { label: '正则匹配多级别', query: '{container="frontend"} |~ "ERROR|WARN|FATAL"' },
- { label: '慢请求 >1s', query: '{job="api"} | json | response_time > 1000' },
+ { label: i18n.t('monitor.typesv3ts.s70d6c24a'), query: '{job="nginx"} |= "error"' },
+ { label: i18n.t('monitor.typesv3ts.saf1cb054'), query: '{namespace="prod"} | json | level="warn"' },
+ { label: i18n.t('monitor.quickquerybarts.sfc6d4276'), query: '{app="api"} |= "timeout"' },
+ { label: i18n.t('monitor.typesv3ts.s475a42fe'), query: 'sum by (level) (count_over_time({job="app"}[5m]))' },
+ { label: i18n.t('monitor.typesv3ts.sac8a5c83'), query: '{container="frontend"} |~ "ERROR|WARN|FATAL"' },
+ { label: i18n.t('monitor.typesv3ts.s4dc793a9'), query: '{job="api"} | json | response_time > 1000' },
],
elasticsearch: [
- { label: 'API 5xx 错误', query: 'status:500 AND path:"/api/*"' },
- { label: '错误超时日志', query: '(level:error OR log.level:error) AND message:*timeout*' },
- { label: '排除调试日志', query: 'host.name:server-* AND NOT level:debug AND NOT log.level:debug' },
- { label: '慢请求检测', query: 'response_time:>1000 AND method:POST' },
- { label: '最近1小时严重错误', query: '@timestamp:[now-1h TO now] AND (level:critical OR log.level:critical)' },
- { label: '特定服务错误', query: 'service:nginx AND (level:(error OR fatal) OR log.level:(error OR fatal))' },
+ { label: i18n.t('monitor.typesv3ts.sd81428f4'), query: 'status:500 AND path:"/api/*"' },
+ { label: i18n.t('monitor.typesv3ts.s6624c787'), query: '(level:error OR log.level:error) AND message:*timeout*' },
+ { label: i18n.t('monitor.typesv3ts.s98b327ac'), query: 'host.name:server-* AND NOT level:debug AND NOT log.level:debug' },
+ { label: i18n.t('monitor.typesv3ts.s95d72fa1'), query: 'response_time:>1000 AND method:POST' },
+ { label: i18n.t('monitor.typesv3ts.s9a0d4c8c'), query: '@timestamp:[now-1h TO now] AND (level:critical OR log.level:critical)' },
+ { label: i18n.t('monitor.typesv3ts.s68f58cc0'), query: 'service:nginx AND (level:(error OR fatal) OR log.level:(error OR fatal))' },
],
sls: [
- { label: '错误日志筛选', query: "* | select * where level = 'error'" },
- { label: '按级别统计', query: "* | select count(*) as cnt, level group by level" },
- { label: '时间聚合', query: "* | select date_trunc('minute', __time__) as t, count(*) group by t order by t" },
- { label: 'Top 方法统计', query: "* | select method, count(*) as cnt, avg(response_time) group by method order by cnt desc" },
- { label: '慢请求分析', query: "* | select * where response_time > 1000 order by response_time desc limit 100" },
- { label: '状态码分布', query: "* | select status_code, count(*) as cnt, count(*) * 100.0 / sum(count(*)) over() as pct group by status_code" },
+ { label: i18n.t('monitor.typesv3ts.sf8889aa4'), query: "* | select * where level = 'error'" },
+ { label: i18n.t('monitor.typesv3ts.s475a42fe'), query: "* | select count(*) as cnt, level group by level" },
+ { label: i18n.t('monitor.typesv3ts.s27ee0975'), query: "* | select date_trunc('minute', __time__) as t, count(*) group by t order by t" },
+ { label: i18n.t('monitor.typesv3ts.sa5ad7487'), query: "* | select method, count(*) as cnt, avg(response_time) group by method order by cnt desc" },
+ { label: i18n.t('monitor.typesv3ts.s80428bd5'), query: "* | select * where response_time > 1000 order by response_time desc limit 100" },
+ { label: i18n.t('monitor.typesv3ts.s63c5c72e'), query: "* | select status_code, count(*) as cnt, count(*) * 100.0 / sum(count(*)) over() as pct group by status_code" },
],
};
diff --git a/frontend/src/components/server/CloudServerImport.tsx b/frontend/src/components/server/CloudServerImport.tsx
index d57c893..9a88ed1 100644
--- a/frontend/src/components/server/CloudServerImport.tsx
+++ b/frontend/src/components/server/CloudServerImport.tsx
@@ -27,6 +27,7 @@ import {
AlertCircle,
} from 'lucide-react';
import { cloudApi } from '@/api';
+import i18n from '@/i18n';
interface CloudServerImportProps {
open: boolean;
@@ -35,9 +36,9 @@ interface CloudServerImportProps {
const cloudProviders = [
{ id: 'aws', name: 'AWS', color: 'bg-orange-500', icon: 'AWS' },
- { id: 'aliyun', name: '阿里云', color: 'bg-orange-600', icon: 'AL' },
- { id: 'tencent', name: '腾讯云', color: 'bg-blue-500', icon: 'TX' },
- { id: 'huawei', name: '华为云', color: 'bg-red-500', icon: 'HW' },
+ { id: 'aliyun', name: i18n.t('cloud.aliyun'), color: 'bg-orange-600', icon: 'AL' },
+ { id: 'tencent', name: i18n.t('cloud.tencent'), color: 'bg-blue-500', icon: 'TX' },
+ { id: 'huawei', name: i18n.t('cloud.huawei'), color: 'bg-red-500', icon: 'HW' },
{ id: 'azure', name: 'Azure', color: 'bg-blue-600', icon: 'AZ' },
];
@@ -67,7 +68,7 @@ export function CloudServerImport({ open, onClose }: CloudServerImportProps) {
const res: Record = await cloudApi.getAccounts();
setCloudAccounts(res?.list || []);
} catch (e) {
- console.error('加载云账号失败:', e);
+ console.error(i18n.t('server.cloudserverimpo.sddeee730'), e);
}
};
@@ -102,7 +103,7 @@ export function CloudServerImport({ open, onClose }: CloudServerImportProps) {
const list = await loadRegions(accountId);
setRegions(list);
} catch (e) {
- console.error('同步区域失败:', e);
+ console.error(i18n.t('server.cloudserverimpo.s1d65993d'), e);
throw e;
} finally {
setIsSyncingRegions(false);
@@ -137,8 +138,8 @@ export function CloudServerImport({ open, onClose }: CloudServerImportProps) {
setCloudServers(res?.list || []);
setDiscoverErrors(res?.errors || []);
} catch (e) {
- console.error('发现主机失败:', e);
- setDiscoverErrors([e?.message || '发现主机失败']);
+ console.error(i18n.t('server.cloudserverimpo.s5e749a34'), e);
+ setDiscoverErrors([e?.message || i18n.t('server.cloudserverimpo.s7d43dcbe')]);
} finally {
setIsDiscovering(false);
}
@@ -156,7 +157,7 @@ export function CloudServerImport({ open, onClose }: CloudServerImportProps) {
});
setImportResult((res as any) || { imported: 0, skipped: 0 });
} catch (e) {
- console.error('导入失败:', e);
+ console.error(i18n.t('server.cloudserverimpo.s1b122554'), e);
} finally {
setIsImporting(false);
}
@@ -223,18 +224,18 @@ export function CloudServerImport({ open, onClose }: CloudServerImportProps) {
);
const steps = [
- { id: 1, title: '公有云', icon: Cloud },
- { id: 2, title: '访问凭据', icon: Key },
- { id: 3, title: '选择区域', icon: MapPin },
- { id: 4, title: '导入确认', icon: CheckCircle },
+ { id: 1, title: i18n.t('server.cloudserverimpo.s7ef31abb'), icon: Cloud },
+ { id: 2, title: i18n.t('server.cloudserverimpo.s02badc25'), icon: Key },
+ { id: 3, title: i18n.t('server.cloudserverimpo.s97d03d46'), icon: MapPin },
+ { id: 4, title: i18n.t('server.cloudserverimpo.s81eea51a'), icon: CheckCircle },
];
return (
|