This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new c2bd8d169 feat(i18n): complete instance and query history translations 
(#2674)
c2bd8d169 is described below

commit c2bd8d16911d63d9fe98964e8f2aab433828032e
Author: aias00 <[email protected]>
AuthorDate: Tue Sep 8 11:35:34 2026 +0800

    feat(i18n): complete instance and query history translations (#2674)
    
    Route the instance management page and server query history drawer through 
the shared translation catalog while preserving the latest import failure and 
trace-topic behavior.
    
    Constraint: exclude all K8s certificate page and vendorOptions changes from 
this rework.
    
    Tested: NODE_ENV=test npm test -- 
src/components/__tests__/MessageQueryHistoryDrawer.test.tsx 
src/pages/instance/__tests__/InstancePage.test.tsx
    
    Tested: npm run lint
    
    Tested: npm run build
    
    Signed-off-by: liuhy <[email protected]>
---
 web/src/components/MessageQueryHistoryDrawer.tsx   |  71 ++--
 .../__tests__/MessageQueryHistoryDrawer.test.tsx   |  34 +-
 web/src/i18n/translations.ts                       | 230 ++++++++++++-
 .../pages/instance/__tests__/InstancePage.test.tsx |  14 +
 web/src/pages/instance/index.tsx                   | 362 ++++++++++++---------
 5 files changed, 531 insertions(+), 180 deletions(-)

diff --git a/web/src/components/MessageQueryHistoryDrawer.tsx 
b/web/src/components/MessageQueryHistoryDrawer.tsx
index fc25f3963..9c4b0e08e 100644
--- a/web/src/components/MessageQueryHistoryDrawer.tsx
+++ b/web/src/components/MessageQueryHistoryDrawer.tsx
@@ -15,6 +15,7 @@ import {
   type QueryHistorySummary,
   type TraceQueryHistory,
 } from '../api/messageHistory';
+import { useLang } from '../i18n/LangContext';
 
 interface Props {
   open: boolean;
@@ -38,6 +39,7 @@ const MessageQueryHistoryDrawer = ({
   onSelectMessage,
   onSelectTrace,
 }: Props) => {
+  const { t } = useLang();
   const [tab, setTab] = useState<'messages' | 'traces'>('messages');
   const [search, setSearch] = useState('');
   const [page, setPage] = useState(1);
@@ -82,12 +84,12 @@ const MessageQueryHistoryDrawer = ({
       else setTraceRows(result.items as TraceQueryHistory[]);
     } catch (loadError) {
       if (id === requestId.current) {
-        setError(loadError instanceof Error ? loadError.message : '查询历史加载失败');
+        setError(loadError instanceof Error ? loadError.message : 
t('messageHistory.loadFailed'));
       }
     } finally {
       if (id === requestId.current) setLoading(false);
     }
-  }, [clusterId, open, page, search, tab]);
+  }, [clusterId, open, page, search, t, tab]);
 
   useEffect(() => {
     // Loading is asynchronous; state updates happen after the history API 
resolves.
@@ -99,38 +101,65 @@ const MessageQueryHistoryDrawer = ({
   }, [load]);
 
   const messageColumns: ColumnsType<MessageQueryHistory> = [
-    { title: '类型', dataIndex: 'queryType', width: 90, render: (value) => 
<Tag>{value}</Tag> },
+    {
+      title: t('common.type'),
+      dataIndex: 'queryType',
+      width: 90,
+      render: (value) => <Tag>{value}</Tag>,
+    },
     { title: 'Topic', dataIndex: 'topic', ellipsis: true },
     { title: 'Message ID / Key', render: (_, row) => row.msgId || 
row.messageKey || '-' },
-    { title: '结果数', dataIndex: 'resultCount', width: 80 },
-    { title: '操作者', dataIndex: 'queriedBy', width: 110 },
-    { title: '查询时间', dataIndex: 'queriedAt', width: 180, render: formatTime },
+    { title: t('messageHistory.resultCount'), dataIndex: 'resultCount', width: 
80 },
+    { title: t('messageHistory.operator'), dataIndex: 'queriedBy', width: 110 
},
+    {
+      title: t('messageHistory.queryTime'),
+      dataIndex: 'queriedAt',
+      width: 180,
+      render: formatTime,
+    },
   ];
   const traceColumns: ColumnsType<TraceQueryHistory> = [
     { title: 'Message ID', dataIndex: 'msgId', ellipsis: true },
     { title: 'Topic', dataIndex: 'topic', ellipsis: true },
     {
-      title: '轨迹 Topic',
+      title: t('messageHistory.traceTopic'),
       dataIndex: 'traceTopic',
       ellipsis: true,
-      render: (value?: string) => value?.trim() || '默认',
+      render: (value?: string) => value?.trim() || t('common.default'),
+    },
+    { title: t('messageHistory.traceNodes'), dataIndex: 'nodeCount', width: 90 
},
+    { title: t('messageHistory.consumers'), dataIndex: 'consumerCount', width: 
90 },
+    { title: t('messageHistory.operator'), dataIndex: 'queriedBy', width: 110 
},
+    {
+      title: t('messageHistory.queryTime'),
+      dataIndex: 'queriedAt',
+      width: 180,
+      render: formatTime,
     },
-    { title: '轨迹节点', dataIndex: 'nodeCount', width: 90 },
-    { title: '消费者', dataIndex: 'consumerCount', width: 90 },
-    { title: '操作者', dataIndex: 'queriedBy', width: 110 },
-    { title: '查询时间', dataIndex: 'queriedAt', width: 180, render: formatTime },
   ];
 
   return (
-    <Drawer title="服务端查询历史" width={900} open={open} onClose={onClose} 
destroyOnHidden>
+    <Drawer
+      title={t('messageHistory.title')}
+      width={900}
+      open={open}
+      onClose={onClose}
+      destroyOnHidden
+    >
       <Flex gap={32} style={{ marginBottom: 16 }}>
-        <Statistic title="消息查询" value={summary?.messageQueries ?? 0} />
-        <Statistic title="轨迹查询" value={summary?.traceQueries ?? 0} />
-        <Statistic title="最近查询" value={formatTime(summary?.latestQueryAt)} />
+        <Statistic
+          title={t('messageHistory.messageQueries')}
+          value={summary?.messageQueries ?? 0}
+        />
+        <Statistic title={t('messageHistory.traceQueries')} 
value={summary?.traceQueries ?? 0} />
+        <Statistic
+          title={t('messageHistory.latestQuery')}
+          value={formatTime(summary?.latestQueryAt)}
+        />
       </Flex>
       <Input.Search
         allowClear
-        placeholder="搜索 Topic、轨迹 Topic、Message ID、Key 或操作者"
+        placeholder={t('messageHistory.searchPlaceholder')}
         onSearch={(value) => {
           setPage(1);
           setSearch(value.trim());
@@ -141,11 +170,11 @@ const MessageQueryHistoryDrawer = ({
         <Alert
           type="error"
           showIcon
-          message="查询历史加载失败"
+          message={t('messageHistory.loadFailed')}
           description={error}
           action={
             <Button size="small" onClick={() => void load()}>
-              重试
+              {t('common.retry')}
             </Button>
           }
           style={{ marginBottom: 12 }}
@@ -160,7 +189,7 @@ const MessageQueryHistoryDrawer = ({
         items={[
           {
             key: 'messages',
-            label: '消息查询',
+            label: t('messageHistory.messageQueries'),
             children: (
               <Table
                 rowKey="id"
@@ -181,7 +210,7 @@ const MessageQueryHistoryDrawer = ({
           },
           {
             key: 'traces',
-            label: '轨迹查询',
+            label: t('messageHistory.traceQueries'),
             children: (
               <Table
                 rowKey="id"
diff --git a/web/src/components/__tests__/MessageQueryHistoryDrawer.test.tsx 
b/web/src/components/__tests__/MessageQueryHistoryDrawer.test.tsx
index 474234be4..3de2391b1 100644
--- a/web/src/components/__tests__/MessageQueryHistoryDrawer.test.tsx
+++ b/web/src/components/__tests__/MessageQueryHistoryDrawer.test.tsx
@@ -9,6 +9,8 @@ import { render, screen, waitFor } from 
'@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import { App } from 'antd';
 import MessageQueryHistoryDrawer from '../MessageQueryHistoryDrawer';
+import { LangProvider } from '../../i18n/LangContext';
+import { LANGUAGE_STORAGE_KEY } from '../../i18n/languagePreference';
 import {
   getQueryHistorySummary,
   listMessageQueryHistory,
@@ -37,6 +39,7 @@ beforeAll(() => {
 describe('MessageQueryHistoryDrawer', () => {
   beforeEach(() => {
     vi.clearAllMocks();
+    localStorage.clear();
     vi.mocked(getQueryHistorySummary).mockResolvedValue({ messageQueries: 4, 
traceQueries: 2 });
     vi.mocked(listMessageQueryHistory).mockResolvedValue({
       items: [
@@ -77,7 +80,9 @@ describe('MessageQueryHistoryDrawer', () => {
     const user = userEvent.setup();
     render(
       <App>
-        <MessageQueryHistoryDrawer open clusterId="instance-a" 
onClose={vi.fn()} />
+        <LangProvider>
+          <MessageQueryHistoryDrawer open clusterId="instance-a" 
onClose={vi.fn()} />
+        </LangProvider>
       </App>,
     );
 
@@ -94,7 +99,9 @@ describe('MessageQueryHistoryDrawer', () => {
   it('clears stale rows and offers retry when a new instance load fails', 
async () => {
     const view = render(
       <App>
-        <MessageQueryHistoryDrawer open clusterId="instance-a" 
onClose={vi.fn()} />
+        <LangProvider>
+          <MessageQueryHistoryDrawer open clusterId="instance-a" 
onClose={vi.fn()} />
+        </LangProvider>
       </App>,
     );
     expect(await screen.findByText('order-1')).toBeInTheDocument();
@@ -102,7 +109,9 @@ describe('MessageQueryHistoryDrawer', () => {
 
     view.rerender(
       <App>
-        <MessageQueryHistoryDrawer open clusterId="instance-b" 
onClose={vi.fn()} />
+        <LangProvider>
+          <MessageQueryHistoryDrawer open clusterId="instance-b" 
onClose={vi.fn()} />
+        </LangProvider>
       </App>,
     );
 
@@ -110,4 +119,23 @@ describe('MessageQueryHistoryDrawer', () => {
     expect(screen.queryByText('order-1')).not.toBeInTheDocument();
     expect(screen.getByRole('button', { name: /重\s*试/ })).toBeEnabled();
   });
+
+  it('renders query history drawer copy in English mode', async () => {
+    localStorage.setItem(LANGUAGE_STORAGE_KEY, 'en');
+    render(
+      <App>
+        <LangProvider>
+          <MessageQueryHistoryDrawer open clusterId="instance-a" 
onClose={vi.fn()} />
+        </LangProvider>
+      </App>,
+    );
+
+    expect(await screen.findByText('order-1')).toBeInTheDocument();
+    expect(screen.getByText('Server Query History')).toBeInTheDocument();
+    expect(screen.getAllByText('Message Queries').length).toBeGreaterThan(1);
+    expect(
+      screen.getByPlaceholderText('Search Topic, trace Topic, Message ID, Key 
or operator'),
+    ).toBeInTheDocument();
+    expect(screen.queryByText('服务端查询历史')).not.toBeInTheDocument();
+  });
 });
diff --git a/web/src/i18n/translations.ts b/web/src/i18n/translations.ts
index 85c342f66..353df823b 100644
--- a/web/src/i18n/translations.ts
+++ b/web/src/i18n/translations.ts
@@ -74,6 +74,7 @@ const translations: Record<string, Record<Lang, string>> = {
   'common.yes': { zh: '是', en: 'Yes' },
   'common.no': { zh: '否', en: 'No' },
   'common.retry': { zh: '重试', en: 'Retry' },
+  'common.unavailable': { zh: '不可用', en: 'Unavailable' },
 
   // ─── Global layout controls ───
   'layout.skipToMain': { zh: '跳到主要内容', en: 'Skip to main content' },
@@ -204,11 +205,19 @@ const translations: Record<string, Record<Lang, string>> 
= {
   // ─── Instance / Topic / Group / ACL / Message ───
   'instance.title': { zh: '实例列表', en: 'Instance List' },
   'instance.subtitle': { zh: '管理 RocketMQ 集群连接', en: 'Manage RocketMQ cluster 
connections' },
+  'instance.managementSubtitle': {
+    zh: '接入并管理 RocketMQ 实例(开源自建 / 阿里云 / 腾讯云),当前显示 {count} 个实例',
+    en: 'Connect and manage RocketMQ instances (Apache / Aliyun / Tencent). 
Showing {count} instances.',
+  },
   'instance.count': { zh: '共 {n} 个实例', en: '{n} instances' },
   'instance.searchPlaceholder': { zh: '搜索实例 ID 或地址', en: 'Search instance ID 
or endpoint' },
   'instance.allTypes': { zh: '全部架构', en: 'All Types' },
+  'instance.cloudType': { zh: '云服务', en: 'Cloud Service' },
+  'instance.proxyLocalMode': { zh: 'Proxy Local 模式', en: 'Proxy Local Mode' },
+  'instance.proxyClusterMode': { zh: 'Proxy Cluster 模式', en: 'Proxy Cluster 
Mode' },
   'instance.directMode': { zh: 'Direct 模式', en: 'Direct Mode' },
   'instance.addInstance': { zh: '添加实例', en: 'Add Instance' },
+  'instance.editInstanceTitle': { zh: '编辑实例 — {name}', en: 'Edit Instance — 
{name}' },
   'instance.instanceName': { zh: '实例 ID', en: 'Instance ID' },
   'instance.namePlaceholder': { zh: '例:rocketmq-production', en: 'e.g. 
rocketmq-production' },
   'instance.accessType': { zh: '接入方式', en: 'Access Type' },
@@ -219,22 +228,241 @@ const translations: Record<string, Record<Lang, string>> 
= {
     en: 'e.g. proxy.example.com:8080',
   },
   'instance.remark': { zh: '备注', en: 'Remark' },
+  'instance.remarkPlaceholder': {
+    zh: '可选,描述实例用途',
+    en: 'Optional, describe the instance purpose',
+  },
+  'instance.remarkEditPlaceholder': { zh: '描述实例用途', en: 'Describe the instance 
purpose' },
   'instance.connect': { zh: '连接', en: 'Connect' },
   'instance.cancel': { zh: '取消', en: 'Cancel' },
   'instance.edit': { zh: '编辑', en: 'Edit' },
   'instance.delete': { zh: '删除', en: 'Delete' },
   'instance.confirmDelete': { zh: '确认删除 "{name}"?', en: 'Delete "{name}"?' },
+  'instance.confirmBatchDelete': {
+    zh: '确认删除选中的 {count} 个实例?',
+    en: 'Delete {count} selected instances?',
+  },
+  'instance.batchDeleteContent': {
+    zh: '将删除:{names}。{warning}',
+    en: 'Instances to delete: {names}. {warning}',
+  },
+  'instance.cloudBatchDeleteWarning': {
+    zh: '云厂商实例仅从 Studio 移除记录,不会释放云上的 RocketMQ 实例;仍有 Topic/Group 的开源实例无法删除。',
+    en: 'Cloud instances are only removed from Studio; the RocketMQ instances 
in the cloud are not released. Apache instances with Topic/Group resources 
still cannot be deleted.',
+  },
+  'instance.batchDeleteWarning': {
+    zh: '仍有 Topic/Group 的开源实例无法删除。',
+    en: 'Apache instances with Topic/Group resources still cannot be deleted.',
+  },
+  'instance.cloudDeleteWarning': {
+    zh: '仅从 Studio 移除该实例记录,不会释放云上的 RocketMQ 实例。',
+    en: 'Only removes this instance record from Studio. The RocketMQ instance 
in the cloud is not released.',
+  },
   'instance.deleteWarning': { zh: '此操作不可恢复。', en: 'This cannot be undone.' },
   'instance.deleted': { zh: '已删除', en: 'Deleted' },
-  'instance.added': { zh: '实例添加成功', en: 'Instance added' },
+  'instance.added': { zh: '实例「{name}」添加成功', en: 'Instance "{name}" added' },
+  'instance.updated': { zh: '实例「{name}」已更新', en: 'Instance "{name}" updated' },
   'instance.enter': { zh: '进入 {name}', en: 'Enter {name}' },
   'instance.createdAt': { zh: '创建时间', en: 'Created' },
   'instance.updatedAt': { zh: '修改时间', en: 'Updated' },
+  'instance.region': { zh: '地域', en: 'Region' },
+  'instance.vendor': { zh: '厂商', en: 'Vendor' },
+  'instance.aliyunEdition': { zh: 'Aliyun 版', en: 'Aliyun' },
+  'instance.tencentEdition': { zh: 'Tencent 版', en: 'Tencent' },
+  'instance.apacheDescription': {
+    zh: '接入自建 Apache RocketMQ 开源集群,支持 Proxy / Direct 两种接入方式',
+    en: 'Connect a self-managed Apache RocketMQ cluster through Proxy or 
Direct access',
+  },
+  'instance.aliyunDescription': {
+    zh: '选择已录入的云凭据与云上实例完成接入,接入点自动解析',
+    en: 'Select stored cloud credentials and a cloud instance; the endpoint is 
resolved automatically',
+  },
+  'instance.tencentDescription': {
+    zh: '接入腾讯云 TDMQ RocketMQ 版实例,接入地址填写实例的接入点',
+    en: 'Connect a Tencent Cloud TDMQ for RocketMQ instance using its 
endpoint',
+  },
+  'instance.openSourceEdition': { zh: '开源版', en: 'Apache' },
+  'instance.listLoadFailed': {
+    zh: '实例列表加载失败,请稍后重试',
+    en: 'Failed to load instances. Please try again later.',
+  },
+  'instance.cloudCredentialLoadFailed': {
+    zh: '云凭据列表加载失败',
+    en: 'Failed to load cloud credentials',
+  },
+  'instance.cloudRegionLoadFailed': {
+    zh: '云地域列表加载失败',
+    en: 'Failed to load cloud regions',
+  },
+  'instance.cloudInstanceLoadFailed': {
+    zh: '云实例列表加载失败',
+    en: 'Failed to load cloud instances',
+  },
+  'instance.createFailed': {
+    zh: '添加实例失败,请稍后重试',
+    en: 'Failed to add instance. Please try again later.',
+  },
+  'instance.updateFailed': {
+    zh: '更新实例失败,请稍后重试',
+    en: 'Failed to update instance. Please try again later.',
+  },
+  'instance.deleteFailed': {
+    zh: '删除实例失败,请稍后重试',
+    en: 'Failed to delete instance. Please try again later.',
+  },
+  'instance.batchDeleteFailed': {
+    zh: '批量删除失败,请稍后重试',
+    en: 'Failed to delete selected instances. Please try again later.',
+  },
+  'instance.selectCloudCredentialFirst': {
+    zh: '请先选择云凭据',
+    en: 'Select cloud credentials first',
+  },
+  'instance.importAll': { zh: '一键导入', en: 'Import All' },
+  'instance.importAllTooltip': {
+    zh: '遍历该凭据下全部地域,将所有云上实例导入(幂等,已存在的自动跳过),备注自动取自云上实例',
+    en: 'Scan all regions for this credential and import cloud instances. 
Existing instances are skipped and remarks come from the cloud instance.',
+  },
+  'instance.importSuccess': {
+    zh: '导入完成:共同步 {total} 个实例(新导入 {imported},已存在跳过 {skipped})',
+    en: 'Import complete: synced {total} instances ({imported} imported, 
{skipped} skipped)',
+  },
+  'instance.importAllSkipped': {
+    zh: '云上实例均已在 Studio 中(共 {skipped} 个),无需重复导入',
+    en: 'All cloud instances are already in Studio ({skipped} total). Nothing 
to import.',
+  },
+  'instance.importIncomplete': {
+    zh: '导入未完成:新导入 {imported} 个,已存在跳过 {skipped} 个',
+    en: 'Import incomplete: {imported} imported, {skipped} skipped',
+  },
+  'instance.importPartialFailure': {
+    zh: '{summary},失败 {count} 个{omitted}{details}',
+    en: '{summary}. {count} failed{omitted}{details}',
+  },
+  'instance.importFailureDetailsTruncated': {
+    zh: '(仅显示前 {count} 条)',
+    en: ' (showing the first {count})',
+  },
+  'instance.importFailed': {
+    zh: '一键导入失败,请稍后重试',
+    en: 'Failed to import cloud instances. Please try again later.',
+  },
+  'instance.deletedCount': { zh: '已删除 {count} 个', en: 'Deleted {count}' },
+  'instance.batchDeletePartialFailure': {
+    zh: '{summary},{count} 个未能删除:{failed}',
+    en: '{summary}. {count} failed to delete: {failed}',
+  },
+  'instance.cloudCredential': { zh: '云凭据', en: 'Cloud Credential' },
+  'instance.cloudCredentialRequired': { zh: '请选择云凭据', en: 'Select cloud 
credentials' },
+  'instance.cloudCredentialExtraPrefix': {
+    zh: '凭据为{vendor}账号的 AK/SK,',
+    en: 'Credentials are the AK/SK of the {vendor} account. ',
+  },
+  'instance.cloudCredentialSettingsLink': {
+    zh: '前往「设置 - 云凭据管理」添加',
+    en: 'Add them in Settings - Cloud Credentials',
+  },
+  'instance.selectStoredCredential': {
+    zh: '选择已录入的 AK/SK 凭据',
+    en: 'Select stored AK/SK credentials',
+  },
+  'instance.loading': { zh: '加载中…', en: 'Loading...' },
+  'instance.noCloudCredential': {
+    zh: '暂无{vendor}凭据,',
+    en: 'No {vendor} credentials. ',
+  },
+  'instance.addInSettings': { zh: '去设置中添加', en: 'Add in settings' },
+  'instance.regionRequired': { zh: '请选择地域', en: 'Select a region' },
+  'instance.selectRegion': { zh: '选择地域', en: 'Select a region' },
+  'instance.cloudInstance': { zh: '云上实例', en: 'Cloud Instance' },
+  'instance.cloudInstanceRequired': { zh: '请选择云上实例', en: 'Select a cloud 
instance' },
+  'instance.cloudInstanceExtra': {
+    zh: '商业版实例来自云端目录,无法手工创建',
+    en: 'Commercial instances come from the cloud catalog and cannot be 
created manually',
+  },
+  'instance.selectCloudInstance': { zh: '选择云上实例', en: 'Select a cloud 
instance' },
+  'instance.selectRegionFirst': { zh: '请先选择地域', en: 'Select a region first' },
+  'instance.nameRequired': { zh: '请输入实例 ID', en: 'Enter an instance ID' },
+  'instance.nameMax': {
+    zh: '实例 ID 不能超过 64 个字符',
+    en: 'Instance ID cannot exceed 64 characters',
+  },
+  'instance.cloudNamePlaceholder': {
+    zh: '默认取云上实例 ID',
+    en: 'Defaults to the cloud instance ID',
+  },
+  'instance.accessTypeRequired': { zh: '请选择接入方式', en: 'Select an access type' 
},
+  'instance.endpointRequired': { zh: '请输入接入地址', en: 'Enter an endpoint' },
+  'instance.endpointHelp': {
+    zh: '接入地址为客户端访问入口,会展示在 Topic 等页面供客户端配置使用。若客户端环境无法解析该地址(如 K8s 内部 Service 
域名),可自行配置 DNS 解析或在客户端 hosts 中映射。',
+    en: 'The endpoint is the client access entry and is shown on Topic pages 
for client configuration. If clients cannot resolve it, configure DNS or hosts 
mapping.',
+  },
+  'instance.directEndpointExtra': {
+    zh: 'Direct 模式请填写 NameServer SLB 地址(K8s 场景下一般为 NameServer Service 地址,如 
namesrv.mq.svc:9876)',
+    en: 'For Direct mode, enter the NameServer SLB address. In K8s this is 
usually the NameServer Service address, such as namesrv.mq.svc:9876.',
+  },
+  'instance.proxyLocalEndpointExtra': {
+    zh: 'Proxy Local 模式请填写与 Broker 同进程部署的 Proxy 接入地址(如 
broker-proxy.mq.svc:8080)',
+    en: 'For Proxy Local mode, enter the Proxy endpoint deployed with the 
Broker, such as broker-proxy.mq.svc:8080.',
+  },
+  'instance.proxyClusterEndpointExtra': {
+    zh: 'Proxy Cluster 模式请填写独立 Proxy 集群的 SLB 内网地址(如 proxy.mq.svc:8080)',
+    en: 'For Proxy Cluster mode, enter the internal SLB endpoint of the 
standalone Proxy cluster, such as proxy.mq.svc:8080.',
+  },
+  'instance.cloudEndpointExtra': {
+    zh: '云服务实例接入地址由云厂商目录解析,不支持手动修改',
+    en: 'Cloud instance endpoints are resolved from the cloud catalog and 
cannot be edited manually.',
+  },
+  'instance.selectAccessTypeFirst': {
+    zh: '请先选择接入方式',
+    en: 'Select an access type first',
+  },
+  'instance.directEndpointPlaceholder': {
+    zh: '例:namesrv.mq.svc.cluster.local:9876',
+    en: 'e.g. namesrv.mq.svc.cluster.local:9876',
+  },
+  'instance.proxyEndpointPlaceholder': {
+    zh: '例:proxy.mq.svc.cluster.local:8080',
+    en: 'e.g. proxy.mq.svc.cluster.local:8080',
+  },
+  'instance.adminCredentialRef': { zh: '管理凭据引用', en: 'Admin Credential Ref' },
+  'instance.adminCredentialRefExtra': {
+    zh: '可选。仅保存服务端配置中的凭据引用,不会保存或传输 AK/SK。',
+    en: 'Optional. Only stores the credential reference in server config; 
AK/SK is not stored or transferred.',
+  },
+  'instance.adminCredentialRefEditExtra': {
+    zh: '仅保存服务端配置中的引用,不会保存或传输 AK/SK。',
+    en: 'Only stores the reference in server config; AK/SK is not stored or 
transferred.',
+  },
+  'instance.adminCredentialRefPlaceholder': {
+    zh: '例:production-admin',
+    en: 'e.g. production-admin',
+  },
   'topic.title': { zh: 'Topic 管理', en: 'Topic Management' },
   'group.title': { zh: 'Group 管理', en: 'Group Management' },
   'acl.title': { zh: 'ACL 管理', en: 'ACL Management' },
   'message.title': { zh: '消息查询', en: 'Message Search' },
 
+  // ─── Message Query History ───
+  'messageHistory.title': { zh: '服务端查询历史', en: 'Server Query History' },
+  'messageHistory.messageQueries': { zh: '消息查询', en: 'Message Queries' },
+  'messageHistory.traceQueries': { zh: '轨迹查询', en: 'Trace Queries' },
+  'messageHistory.latestQuery': { zh: '最近查询', en: 'Latest Query' },
+  'messageHistory.searchPlaceholder': {
+    zh: '搜索 Topic、轨迹 Topic、Message ID、Key 或操作者',
+    en: 'Search Topic, trace Topic, Message ID, Key or operator',
+  },
+  'messageHistory.loadFailed': {
+    zh: '查询历史加载失败',
+    en: 'Failed to load query history',
+  },
+  'messageHistory.resultCount': { zh: '结果数', en: 'Results' },
+  'messageHistory.operator': { zh: '操作者', en: 'Operator' },
+  'messageHistory.queryTime': { zh: '查询时间', en: 'Query Time' },
+  'messageHistory.traceTopic': { zh: '轨迹 Topic', en: 'Trace Topic' },
+  'messageHistory.traceNodes': { zh: '轨迹节点', en: 'Trace Nodes' },
+  'messageHistory.consumers': { zh: '消费者', en: 'Consumers' },
+
   // ─── Dead Letter Queue ───
   'dlq.title': { zh: '死信队列', en: 'Dead Letter Queue' },
 
diff --git a/web/src/pages/instance/__tests__/InstancePage.test.tsx 
b/web/src/pages/instance/__tests__/InstancePage.test.tsx
index b0c7fed96..ec2494ef3 100644
--- a/web/src/pages/instance/__tests__/InstancePage.test.tsx
+++ b/web/src/pages/instance/__tests__/InstancePage.test.tsx
@@ -26,6 +26,7 @@ import * as tencentCatalogApi from 
'../../../api/tencentCatalog';
 import type { CloudCredential, CloudCredentialPage } from 
'../../../api/cloudCredential';
 import type { Instance } from '../../../api/instance';
 import { LangProvider } from '../../../i18n/LangContext';
+import { LANGUAGE_STORAGE_KEY } from '../../../i18n/languagePreference';
 import * as instanceService from '../../../services/instanceService';
 import InstancePage from '../index';
 
@@ -116,6 +117,7 @@ const deferred = <T,>() => {
 describe('InstancePage', () => {
   beforeEach(() => {
     vi.clearAllMocks();
+    localStorage.clear();
     
vi.mocked(cloudCredentialApi.listCloudCredentials).mockResolvedValue(cloudCredentialPage([]));
     vi.mocked(aliyunCatalogApi.listAliyunRegions).mockResolvedValue([]);
     vi.mocked(aliyunCatalogApi.listAliyunInstances).mockResolvedValue([]);
@@ -160,6 +162,18 @@ describe('InstancePage', () => {
     );
   });
 
+  it('renders instance management copy in English mode', async () => {
+    localStorage.setItem(LANGUAGE_STORAGE_KEY, 'en');
+    renderPage();
+
+    expect(await screen.findByText('production-proxy')).toBeInTheDocument();
+    expect(screen.getByText('Instance List')).toBeInTheDocument();
+    expect(screen.getByText(/Connect and manage RocketMQ 
instances/)).toBeInTheDocument();
+    expect(screen.getByPlaceholderText('Search instance ID or 
endpoint')).toBeInTheDocument();
+    expect(screen.getByRole('button', { name: /Add Instance/ 
})).toBeInTheDocument();
+    expect(screen.queryByText('添加实例')).not.toBeInTheDocument();
+  });
+
   it('keeps unavailable resource counts after available values in both sort 
directions', async () => {
     vi.mocked(instanceService.listInstances).mockResolvedValue([
       {
diff --git a/web/src/pages/instance/index.tsx b/web/src/pages/instance/index.tsx
index 5399cf97d..9b5e4155d 100644
--- a/web/src/pages/instance/index.tsx
+++ b/web/src/pages/instance/index.tsx
@@ -66,14 +66,32 @@ const DEFAULT_CLOUD_REGION_IDS: 
Partial<Record<InstanceVendor, string>> = {
   TENCENT: 'ap-chengdu',
 };
 
+const VENDOR_LABEL_KEYS: Record<InstanceVendor, string> = {
+  APACHE: 'instance.openSourceEdition',
+  ALIYUN: 'instance.aliyunEdition',
+  TENCENT: 'instance.tencentEdition',
+};
+
+const VENDOR_DESCRIPTION_KEYS: Record<InstanceVendor, string> = {
+  APACHE: 'instance.apacheDescription',
+  ALIYUN: 'instance.aliyunDescription',
+  TENCENT: 'instance.tencentDescription',
+};
+
 /* ─── Helpers ─── */
-const typeLabel: Record<string, { text: string; color: string }> = {
-  CLOUD: { text: '云服务', color: 'blue' },
-  PROXY_LOCAL: { text: 'Proxy Local', color: 'cyan' },
-  PROXY_CLUSTER: { text: 'Proxy Cluster', color: 'blue' },
-  DIRECT: { text: 'Direct', color: 'orange' },
+const typeLabel: Record<string, { labelKey: string; color: string }> = {
+  CLOUD: { labelKey: 'instance.cloudType', color: 'blue' },
+  PROXY_LOCAL: { labelKey: 'instance.proxyLocalMode', color: 'cyan' },
+  PROXY_CLUSTER: { labelKey: 'instance.proxyClusterMode', color: 'blue' },
+  DIRECT: { labelKey: 'instance.directMode', color: 'orange' },
 };
 
+const APACHE_ACCESS_TYPE_OPTIONS = [
+  { value: 'PROXY_LOCAL', labelKey: 'instance.proxyLocalMode' },
+  { value: 'PROXY_CLUSTER', labelKey: 'instance.proxyClusterMode' },
+  { value: 'DIRECT', labelKey: 'instance.directMode' },
+] as const;
+
 function describeApiError(error: unknown, fallback: string): string {
   const serverMessage = (error as { response?: { data?: { message?: unknown } 
} })?.response?.data
     ?.message;
@@ -104,7 +122,7 @@ function compareResourceCounts(
    InstancePage
    ═══════════════════════════════════════════ */
 const InstancePage = () => {
-  const { t } = useLang();
+  const { lang, t } = useLang();
   const navigate = useNavigate();
   const [instances, setInstances] = useState<Instance[]>([]);
   const [loading, setLoading] = useState(true);
@@ -153,14 +171,14 @@ const InstancePage = () => {
       }
     } catch {
       if (requestId === requestIdRef.current) {
-        message.error('实例列表加载失败,请稍后重试');
+        message.error(t('instance.listLoadFailed'));
       }
     } finally {
       if (requestId === requestIdRef.current) {
         setLoading(false);
       }
     }
-  }, []);
+  }, [t]);
 
   useEffect(() => {
     listQueryRef.current = {
@@ -193,7 +211,7 @@ const InstancePage = () => {
         })
         .catch(() => {
           if (active) {
-            message.error('云凭据列表加载失败');
+            message.error(t('instance.cloudCredentialLoadFailed'));
           }
         })
         .finally(() => {
@@ -206,7 +224,7 @@ const InstancePage = () => {
       active = false;
       window.clearTimeout(timer);
     };
-  }, [vendor, cloudVendor, addModalOpen]);
+  }, [vendor, cloudVendor, addModalOpen, t]);
 
   useEffect(() => {
     if (!cloudVendor || !addCredentialId) {
@@ -237,7 +255,7 @@ const InstancePage = () => {
         })
         .catch((error) => {
           if (active) {
-            message.error(describeApiError(error, '云地域列表加载失败'));
+            message.error(describeApiError(error, 
t('instance.cloudRegionLoadFailed')));
           }
         })
         .finally(() => {
@@ -250,7 +268,7 @@ const InstancePage = () => {
       active = false;
       window.clearTimeout(timer);
     };
-  }, [vendor, cloudVendor, addCredentialId, addForm]);
+  }, [vendor, cloudVendor, addCredentialId, addForm, t]);
 
   useEffect(() => {
     if (!cloudVendor || !addCredentialId || !addRegionId) {
@@ -272,7 +290,7 @@ const InstancePage = () => {
         })
         .catch((error) => {
           if (active) {
-            message.error(describeApiError(error, '云实例列表加载失败'));
+            message.error(describeApiError(error, 
t('instance.cloudInstanceLoadFailed')));
           }
         })
         .finally(() => {
@@ -285,7 +303,7 @@ const InstancePage = () => {
       active = false;
       window.clearTimeout(timer);
     };
-  }, [vendor, cloudVendor, addCredentialId, addRegionId]);
+  }, [vendor, cloudVendor, addCredentialId, addRegionId, t]);
 
   const handleVendorChange = (nextVendor: string) => {
     setVendor(nextVendor as InstanceVendor);
@@ -313,6 +331,24 @@ const InstancePage = () => {
     addForm.setFieldsValue({ cloudInstanceId: undefined });
   };
 
+  const getVendorLabel = (nextVendor: InstanceVendor) => {
+    return t(VENDOR_LABEL_KEYS[nextVendor]);
+  };
+
+  const getAccessTypeOptions = () =>
+    APACHE_ACCESS_TYPE_OPTIONS.map((option) => ({
+      value: option.value,
+      label: t(option.labelKey),
+    }));
+
+  const getEndpointExtra = (type?: Instance['type']) => {
+    if (type === 'DIRECT') return t('instance.directEndpointExtra');
+    if (type === 'PROXY_LOCAL') return t('instance.proxyLocalEndpointExtra');
+    if (type === 'PROXY_CLUSTER') return 
t('instance.proxyClusterEndpointExtra');
+    if (type === 'CLOUD') return t('instance.cloudEndpointExtra');
+    return t('instance.selectAccessTypeFirst');
+  };
+
   const handleCreate = async () => {
     if (mutationInFlightRef.current) return;
     mutationInFlightRef.current = true;
@@ -331,7 +367,7 @@ const InstancePage = () => {
         : values;
       const created = await createInstance(payload);
       await loadInstances();
-      message.success(`实例「${created.name}」添加成功`);
+      message.success(t('instance.added', { name: created.name }));
       setAddModalOpen(false);
       addForm.resetFields();
       setVendor(DEFAULT_VENDOR);
@@ -339,7 +375,7 @@ const InstancePage = () => {
       if (error && typeof error === 'object' && 'errorFields' in error) {
         return; // validation failure; antd already shows field-level errors
       }
-      message.error('添加实例失败,请稍后重试');
+      message.error(t('instance.createFailed'));
     } finally {
       mutationInFlightRef.current = false;
       setSubmitting(false);
@@ -350,7 +386,7 @@ const InstancePage = () => {
     if (importing || vendor === 'APACHE') return;
     const credentialId = addForm.getFieldValue('credentialId') as number | 
undefined;
     if (!credentialId) {
-      message.warning('请先选择云凭据');
+      message.warning(t('instance.selectCloudCredentialFirst'));
       return;
     }
     setImporting(true);
@@ -360,16 +396,33 @@ const InstancePage = () => {
       const failedCount = result.failedCount ?? result.failed.length;
       const summary =
         result.imported > 0
-          ? `导入完成:共同步 ${result.imported + result.skipped} 个实例(新导入 
${result.imported},已存在跳过 ${result.skipped})`
+          ? t('instance.importSuccess', {
+              total: result.imported + result.skipped,
+              imported: result.imported,
+              skipped: result.skipped,
+            })
           : failedCount > 0
-            ? `导入未完成:新导入 ${result.imported} 个,已存在跳过 ${result.skipped} 个`
-            : `云上实例均已在 Studio 中(共 ${result.skipped} 个),无需重复导入`;
+            ? t('instance.importIncomplete', {
+                imported: result.imported,
+                skipped: result.skipped,
+              })
+            : t('instance.importAllSkipped', { skipped: result.skipped });
       if (failedCount > 0) {
-        const details = result.failed.length > 0 ? 
`:${result.failed.join(';')}` : '';
+        const details =
+          result.failed.length > 0
+            ? `${lang === 'zh' ? ':' : ': '}${result.failed.join(lang === 'zh' 
? ';' : '; ')}`
+            : '';
         const omitted = result.failureDetailsTruncated
-          ? `(仅显示前 ${result.failed.length} 条)`
+          ? t('instance.importFailureDetailsTruncated', { count: 
result.failed.length })
           : '';
-        message.warning(`${summary},失败 ${failedCount} 个${omitted}${details}`);
+        message.warning(
+          t('instance.importPartialFailure', {
+            summary,
+            count: failedCount,
+            omitted,
+            details,
+          }),
+        );
       } else {
         message.success(summary);
       }
@@ -379,7 +432,7 @@ const InstancePage = () => {
       setRegions([]);
       setCloudInstances([]);
     } catch (error) {
-      message.error(describeApiError(error, '一键导入失败,请稍后重试'));
+      message.error(describeApiError(error, t('instance.importFailed')));
     } finally {
       setImporting(false);
     }
@@ -399,14 +452,14 @@ const InstancePage = () => {
         adminCredentialRef: values.adminCredentialRef,
       });
       await loadInstances();
-      message.success(`实例「${updated.name}」已更新`);
+      message.success(t('instance.updated', { name: updated.name }));
       setEditModalOpen(false);
       editForm.resetFields();
     } catch (error) {
       if (error && typeof error === 'object' && 'errorFields' in error) {
         return; // validation failure; antd already shows field-level errors
       }
-      message.error('更新实例失败,请稍后重试');
+      message.error(t('instance.updateFailed'));
     } finally {
       mutationInFlightRef.current = false;
       setSubmitting(false);
@@ -417,9 +470,9 @@ const InstancePage = () => {
     try {
       await deleteInstance(instance.name);
       await loadInstances();
-      message.success('已删除');
+      message.success(t('instance.deleted'));
     } catch (error) {
-      message.error(describeApiError(error, '删除实例失败,请稍后重试'));
+      message.error(describeApiError(error, t('instance.deleteFailed')));
     }
   };
 
@@ -435,28 +488,35 @@ const InstancePage = () => {
       (instance) => instance.vendor === 'ALIYUN' || instance.vendor === 
'TENCENT',
     );
     const warning = hasCloud
-      ? '云厂商实例仅从 Studio 移除记录,不会释放云上的 RocketMQ 实例;仍有 Topic/Group 的开源实例无法删除。'
-      : '仍有 Topic/Group 的开源实例无法删除。';
+      ? t('instance.cloudBatchDeleteWarning')
+      : t('instance.batchDeleteWarning');
     Modal.confirm({
-      title: `确认删除选中的 ${names.length} 个实例?`,
-      content: `将删除:${names.join('、')}。${warning}`,
-      okText: '删除',
+      title: t('instance.confirmBatchDelete', { count: names.length }),
+      content: t('instance.batchDeleteContent', {
+        names: names.join(lang === 'zh' ? '、' : ', '),
+        warning,
+      }),
+      okText: t('common.delete'),
       okButtonProps: { danger: true },
       onOk: async () => {
         try {
           const result = await deleteInstancesBatch(names);
           await loadInstances();
           setSelectedRowKeys([]);
-          const summary = `已删除 ${result.deleted} 个`;
+          const summary = t('instance.deletedCount', { count: result.deleted 
});
           if (result.failed.length > 0) {
             message.warning(
-              `${summary},${result.failed.length} 
个未能删除:${result.failed.join(';')}`,
+              t('instance.batchDeletePartialFailure', {
+                summary,
+                count: result.failed.length,
+                failed: result.failed.join(lang === 'zh' ? ';' : '; '),
+              }),
             );
           } else {
             message.success(summary);
           }
         } catch (error) {
-          message.error(describeApiError(error, '批量删除失败,请稍后重试'));
+          message.error(describeApiError(error, 
t('instance.batchDeleteFailed')));
         }
       },
     });
@@ -464,7 +524,7 @@ const InstancePage = () => {
 
   const columns: ColumnsType<Instance> = [
     {
-      title: '地域',
+      title: t('instance.region'),
       dataIndex: 'regionId',
       key: 'regionId',
       width: 130,
@@ -474,13 +534,13 @@ const InstancePage = () => {
       render: (regionId: string | undefined, record: Instance) => (
         <Text type="secondary" style={{ fontSize: 14 }}>
           {!record.vendor || record.vendor === 'APACHE'
-            ? '开源版'
+            ? t('instance.openSourceEdition')
             : record.regionName || regionId || '-'}
         </Text>
       ),
     },
     {
-      title: '实例 ID',
+      title: t('instance.instanceName'),
       dataIndex: 'name',
       key: 'name',
       ellipsis: true,
@@ -497,7 +557,7 @@ const InstancePage = () => {
       ),
     },
     {
-      title: '备注',
+      title: t('instance.remark'),
       dataIndex: 'remark',
       key: 'remark',
       ellipsis: { showTitle: false },
@@ -517,7 +577,7 @@ const InstancePage = () => {
         ),
     },
     {
-      title: '厂商',
+      title: t('instance.vendor'),
       dataIndex: 'vendor',
       key: 'vendor',
       width: 100,
@@ -529,22 +589,22 @@ const InstancePage = () => {
         }
         return (
           <Space size={6}>
-            <img src={option.logo} alt={option.label} style={{ height: 16 }} />
-            <Text style={{ fontSize: 14 }}>{option.label}</Text>
+            <img src={option.logo} alt={getVendorLabel(option.key)} style={{ 
height: 16 }} />
+            <Text style={{ fontSize: 14 }}>{getVendorLabel(option.key)}</Text>
           </Space>
         );
       },
     },
     {
-      title: '类型',
+      title: t('common.type'),
       dataIndex: 'type',
       key: 'type',
       width: 110,
       align: 'center' as const,
       sorter: (a, b) => a.type.localeCompare(b.type),
       render: (type: string) => {
-        const t = typeLabel[type] || { text: type, color: 'default' };
-        return <Tag color={t.color}>{t.text}</Tag>;
+        const config = typeLabel[type] || { labelKey: type, color: 'default' };
+        return <Tag color={config.color}>{typeLabel[type] ? t(config.labelKey) 
: type}</Tag>;
       },
     },
     {
@@ -555,7 +615,7 @@ const InstancePage = () => {
       align: 'center' as const,
       sorter: (a, b, sortOrder) => compareResourceCounts(a, b, 'topicCount', 
sortOrder),
       render: (count: number, record: Instance) =>
-        record.resourceCountsAvailable === false ? '不可用' : count,
+        record.resourceCountsAvailable === false ? t('common.unavailable') : 
count,
     },
     {
       title: 'Group',
@@ -565,10 +625,10 @@ const InstancePage = () => {
       align: 'center' as const,
       sorter: (a, b, sortOrder) => compareResourceCounts(a, b, 
'consumerGroupCount', sortOrder),
       render: (count: number, record: Instance) =>
-        record.resourceCountsAvailable === false ? '不可用' : count,
+        record.resourceCountsAvailable === false ? t('common.unavailable') : 
count,
     },
     {
-      title: '创建时间',
+      title: t('instance.createdAt'),
       dataIndex: 'gmtCreate',
       key: 'gmtCreate',
       width: 150,
@@ -580,7 +640,7 @@ const InstancePage = () => {
       ),
     },
     {
-      title: '修改时间',
+      title: t('instance.updatedAt'),
       dataIndex: 'gmtModified',
       key: 'gmtModified',
       width: 150,
@@ -592,7 +652,7 @@ const InstancePage = () => {
       ),
     },
     {
-      title: '操作',
+      title: t('common.actions'),
       key: 'actions',
       width: 150,
       render: (_: unknown, record: Instance) => (
@@ -612,7 +672,7 @@ const InstancePage = () => {
               setEditModalOpen(true);
             }}
           >
-            编辑
+            {t('common.edit')}
           </Button>
           <Button
             size="small"
@@ -621,17 +681,17 @@ const InstancePage = () => {
             onClick={() => {
               const isCloudInstance = record.vendor === 'ALIYUN' || 
record.vendor === 'TENCENT';
               Modal.confirm({
-                title: `确认删除 "${record.name}"?`,
+                title: t('instance.confirmDelete', { name: record.name }),
                 content: isCloudInstance
-                  ? '仅从 Studio 移除该实例记录,不会释放云上的 RocketMQ 实例。'
-                  : '此操作不可恢复。',
-                okText: '删除',
+                  ? t('instance.cloudDeleteWarning')
+                  : t('instance.deleteWarning'),
+                okText: t('common.delete'),
                 okButtonProps: { danger: true },
                 onOk: () => handleDelete(record),
               });
             }}
           >
-            删除
+            {t('common.delete')}
           </Button>
         </Flex>
       ),
@@ -644,7 +704,7 @@ const InstancePage = () => {
       <div style={{ marginBottom: 20 }}>
         <h2 style={{ margin: 0, fontSize: 20, fontWeight: 600 
}}>{t('instance.title')}</h2>
         <div style={{ marginTop: 6, fontSize: 14, color: '#9CA3AF' }}>
-          接入并管理 RocketMQ 实例(开源自建 / 阿里云 / 腾讯云),当前显示 {instances.length} 个实例
+          {t('instance.managementSubtitle', { count: instances.length })}
         </div>
       </div>
 
@@ -658,7 +718,7 @@ const InstancePage = () => {
       >
         <Space size={12} wrap>
           <Input
-            placeholder="搜索实例 ID 或地址"
+            placeholder={t('instance.searchPlaceholder')}
             prefix={<MagnifyingGlass size={14} color="#9CA3AF" />}
             value={search}
             onChange={(e) => setSearch(e.target.value)}
@@ -670,11 +730,11 @@ const InstancePage = () => {
             onChange={setTypeFilter}
             style={{ width: 140 }}
             options={[
-              { value: 'ALL', label: '全部架构' },
-              { value: 'CLOUD', label: '云服务' },
-              { value: 'PROXY_LOCAL', label: 'Proxy Local 模式' },
-              { value: 'PROXY_CLUSTER', label: 'Proxy Cluster 模式' },
-              { value: 'DIRECT', label: 'Direct 模式' },
+              { value: 'ALL', label: t('instance.allTypes') },
+              { value: 'CLOUD', label: t('instance.cloudType') },
+              { value: 'PROXY_LOCAL', label: t('instance.proxyLocalMode') },
+              { value: 'PROXY_CLUSTER', label: t('instance.proxyClusterMode') 
},
+              { value: 'DIRECT', label: t('instance.directMode') },
             ]}
           />
         </Space>
@@ -685,14 +745,14 @@ const InstancePage = () => {
             disabled={selectedRowKeys.length === 0}
             onClick={handleBatchDelete}
           >
-            删除
+            {t('common.delete')}
           </Button>
           <Button
             type="primary"
             icon={<Plus size={14} weight="bold" />}
             onClick={() => setAddModalOpen(true)}
           >
-            添加实例
+            {t('instance.addInstance')}
           </Button>
         </Space>
       </Flex>
@@ -718,7 +778,7 @@ const InstancePage = () => {
 
       {/* Add Instance Modal */}
       <Modal
-        title="添加实例"
+        title={t('instance.addInstance')}
         open={addModalOpen}
         onCancel={() => {
           setAddModalOpen(false);
@@ -731,13 +791,13 @@ const InstancePage = () => {
         footer={
           <Flex justify="flex-end" gap={8}>
             {cloudVendor && (
-              <Tooltip title="遍历该凭据下全部地域,将所有云上实例导入(幂等,已存在的自动跳过),备注自动取自云上实例">
+              <Tooltip title={t('instance.importAllTooltip')}>
                 <Button
                   loading={importing}
                   disabled={!addCredentialId}
                   onClick={() => void handleImportAll()}
                 >
-                  一键导入
+                  {t('instance.importAll')}
                 </Button>
               </Tooltip>
             )}
@@ -750,10 +810,10 @@ const InstancePage = () => {
                 setCloudInstances([]);
               }}
             >
-              取消
+              {t('common.cancel')}
             </Button>
             <Button type="primary" loading={submitting} onClick={() => void 
handleCreate()}>
-              连接
+              {t('instance.connect')}
             </Button>
           </Flex>
         }
@@ -767,40 +827,46 @@ const InstancePage = () => {
             key: option.key,
             label: (
               <span style={{ display: 'inline-flex', alignItems: 'center', 
gap: 8 }}>
-                <img src={option.logo} alt={option.label} style={{ height: 18, 
maxWidth: 80 }} />
-                {option.label}
+                <img
+                  src={option.logo}
+                  alt={getVendorLabel(option.key)}
+                  style={{ height: 18, maxWidth: 80 }}
+                />
+                {getVendorLabel(option.key)}
               </span>
             ),
           }))}
         />
         <Text type="secondary" style={{ display: 'block', fontSize: 14, 
marginBottom: 12 }}>
-          {VENDOR_OPTIONS.find((option) => option.key === vendor)?.description}
+          {t(VENDOR_DESCRIPTION_KEYS[vendor])}
         </Text>
         {cloudVendor ? (
           <>
             <Form form={addForm} layout="vertical">
               <Form.Item
-                label="云凭据"
+                label={t('instance.cloudCredential')}
                 name="credentialId"
-                rules={[{ required: true, message: '请选择云凭据' }]}
+                rules={[{ required: true, message: 
t('instance.cloudCredentialRequired') }]}
                 extra={
                   <span>
-                    凭据为{vendor === 'ALIYUN' ? '阿里云' : '腾讯云'}账号的 AK/SK,
-                    <Link to="/settings?tab=credential">前往「设置 - 云凭据管理」添加</Link>
+                    {t('instance.cloudCredentialExtraPrefix', { vendor: 
getVendorLabel(vendor) })}
+                    <Link to="/settings?tab=credential">
+                      {t('instance.cloudCredentialSettingsLink')}
+                    </Link>
                   </span>
                 }
               >
                 <Select
-                  placeholder="选择已录入的 AK/SK 凭据"
+                  placeholder={t('instance.selectStoredCredential')}
                   loading={credentialsLoading}
                   onChange={handleCredentialChange}
                   notFoundContent={
                     credentialsLoading ? (
-                      '加载中…'
+                      t('instance.loading')
                     ) : (
                       <span>
-                        暂无{vendor === 'ALIYUN' ? '阿里云' : '腾讯云'}凭据,
-                        <Link to="/settings?tab=credential">去设置中添加</Link>
+                        {t('instance.noCloudCredential', { vendor: 
getVendorLabel(vendor) })}
+                        <Link 
to="/settings?tab=credential">{t('instance.addInSettings')}</Link>
                       </span>
                     )
                   }
@@ -811,12 +877,16 @@ const InstancePage = () => {
                 />
               </Form.Item>
               <Form.Item
-                label="地域"
+                label={t('instance.region')}
                 name="regionId"
-                rules={[{ required: true, message: '请选择地域' }]}
+                rules={[{ required: true, message: 
t('instance.regionRequired') }]}
               >
                 <Select
-                  placeholder={addCredentialId ? '选择地域' : '请先选择云凭据'}
+                  placeholder={
+                    addCredentialId
+                      ? t('instance.selectRegion')
+                      : t('instance.selectCloudCredentialFirst')
+                  }
                   disabled={!addCredentialId}
                   loading={regionsLoading}
                   onChange={handleRegionChange}
@@ -827,15 +897,19 @@ const InstancePage = () => {
                 />
               </Form.Item>
               <Form.Item
-                label="云上实例"
+                label={t('instance.cloudInstance')}
                 name="cloudInstanceId"
-                rules={[{ required: true, message: '请选择云上实例' }]}
-                extra="商业版实例来自云端目录,无法手工创建"
+                rules={[{ required: true, message: 
t('instance.cloudInstanceRequired') }]}
+                extra={t('instance.cloudInstanceExtra')}
               >
                 <Select
                   showSearch
                   optionFilterProp="label"
-                  placeholder={addRegionId ? '选择云上实例' : '请先选择地域'}
+                  placeholder={
+                    addRegionId
+                      ? t('instance.selectCloudInstance')
+                      : t('instance.selectRegionFirst')
+                  }
                   disabled={!addRegionId}
                   loading={cloudInstancesLoading}
                   options={cloudInstances.map((item) => ({
@@ -851,84 +925,72 @@ const InstancePage = () => {
                 />
               </Form.Item>
               <Form.Item
-                label="实例 ID"
+                label={t('instance.instanceName')}
                 name="name"
                 rules={[
-                  { required: true, message: '请输入实例 ID' },
-                  { max: 64, message: '实例 ID 不能超过 64 个字符' },
+                  { required: true, message: t('instance.nameRequired') },
+                  { max: 64, message: t('instance.nameMax') },
                 ]}
               >
-                <Input placeholder="默认取云上实例 ID" />
+                <Input placeholder={t('instance.cloudNamePlaceholder')} />
               </Form.Item>
-              <Form.Item label="备注" name="remark">
-                <Input.TextArea rows={2} placeholder="可选,描述实例用途" />
+              <Form.Item label={t('instance.remark')} name="remark">
+                <Input.TextArea rows={2} 
placeholder={t('instance.remarkPlaceholder')} />
               </Form.Item>
             </Form>
           </>
         ) : (
           <Form form={addForm} layout="vertical">
             <Form.Item
-              label="实例 ID"
+              label={t('instance.instanceName')}
               name="name"
               rules={[
-                { required: true, message: '请输入实例 ID' },
-                { max: 64, message: '实例 ID 不能超过 64 个字符' },
+                { required: true, message: t('instance.nameRequired') },
+                { max: 64, message: t('instance.nameMax') },
               ]}
             >
-              <Input placeholder="例:rocketmq-production" />
+              <Input placeholder={t('instance.namePlaceholder')} />
             </Form.Item>
             <Form.Item
-              label="接入方式"
+              label={t('instance.accessType')}
               name="type"
-              rules={[{ required: true, message: '请选择接入方式' }]}
+              rules={[{ required: true, message: 
t('instance.accessTypeRequired') }]}
             >
               <Select
-                placeholder="选择接入方式"
-                options={[
-                  { value: 'PROXY_LOCAL', label: 'Proxy Local 模式' },
-                  { value: 'PROXY_CLUSTER', label: 'Proxy Cluster 模式' },
-                  { value: 'DIRECT', label: 'Direct 模式' },
-                ]}
+                placeholder={t('instance.selectAccessType')}
+                options={getAccessTypeOptions()}
               />
             </Form.Item>
             <Form.Item
               label={
                 <span>
-                  接入地址{' '}
-                  <Tooltip title="接入地址为客户端访问入口,会展示在 Topic 
等页面供客户端配置使用。若客户端环境无法解析该地址(如 K8s 内部 Service 域名),可自行配置 DNS 解析或在客户端 hosts 中映射。">
+                  {t('instance.endpoint')}{' '}
+                  <Tooltip title={t('instance.endpointHelp')}>
                     <QuestionCircleOutlined style={{ color: '#9CA3AF', cursor: 
'help' }} />
                   </Tooltip>
                 </span>
               }
               name="endpoint"
-              rules={[{ required: true, message: '请输入接入地址' }]}
-              extra={
-                addInstanceType === 'DIRECT'
-                  ? 'Direct 模式请填写 NameServer SLB 地址(K8s 场景下一般为 NameServer 
Service 地址,如 namesrv.mq.svc:9876)'
-                  : addInstanceType === 'PROXY_LOCAL'
-                    ? 'Proxy Local 模式请填写与 Broker 同进程部署的 Proxy 接入地址(如 
broker-proxy.mq.svc:8080)'
-                    : addInstanceType === 'PROXY_CLUSTER'
-                      ? 'Proxy Cluster 模式请填写独立 Proxy 集群的 SLB 内网地址(如 
proxy.mq.svc:8080)'
-                      : '请先选择接入方式'
-              }
+              rules={[{ required: true, message: 
t('instance.endpointRequired') }]}
+              extra={getEndpointExtra(addInstanceType)}
             >
               <Input
                 placeholder={
                   addInstanceType === 'DIRECT'
-                    ? '例:namesrv.mq.svc.cluster.local:9876'
-                    : '例:proxy.mq.svc.cluster.local:8080'
+                    ? t('instance.directEndpointPlaceholder')
+                    : t('instance.proxyEndpointPlaceholder')
                 }
               />
             </Form.Item>
             <Form.Item
-              label="管理凭据引用"
+              label={t('instance.adminCredentialRef')}
               name="adminCredentialRef"
-              extra="可选。仅保存服务端配置中的凭据引用,不会保存或传输 AK/SK。"
+              extra={t('instance.adminCredentialRefExtra')}
             >
-              <Input placeholder="例:production-admin" />
+              <Input placeholder={t('instance.adminCredentialRefPlaceholder')} 
/>
             </Form.Item>
-            <Form.Item label="备注" name="remark">
-              <Input.TextArea rows={2} placeholder="可选,描述实例用途" />
+            <Form.Item label={t('instance.remark')} name="remark">
+              <Input.TextArea rows={2} 
placeholder={t('instance.remarkPlaceholder')} />
             </Form.Item>
           </Form>
         )}
@@ -936,7 +998,7 @@ const InstancePage = () => {
 
       {/* Edit Instance Modal */}
       <Modal
-        title={`编辑实例 — ${editingInstance?.name || ''}`}
+        title={t('instance.editInstanceTitle', { name: editingInstance?.name 
|| '' })}
         open={editModalOpen}
         onCancel={() => {
           setEditModalOpen(false);
@@ -944,69 +1006,59 @@ const InstancePage = () => {
         }}
         onOk={() => void handleUpdate()}
         confirmLoading={submitting}
-        okText="保存"
-        cancelText="取消"
+        okText={t('common.save')}
+        cancelText={t('common.cancel')}
         width={520}
       >
         <Form form={editForm} layout="vertical" style={{ marginTop: 16 }}>
-          <Form.Item label="实例 ID">
+          <Form.Item label={t('instance.instanceName')}>
             <Input value={editingInstance?.name} disabled />
           </Form.Item>
           <Form.Item
-            label="接入方式"
+            label={t('instance.accessType')}
             name="type"
-            rules={[{ required: true, message: '请选择接入方式' }]}
+            rules={[{ required: true, message: 
t('instance.accessTypeRequired') }]}
           >
             <Select
               options={
                 editingInstance?.vendor && editingInstance.vendor !== 'APACHE'
-                  ? [{ value: 'CLOUD', label: '云服务' }]
-                  : [
-                      { value: 'PROXY_LOCAL', label: 'Proxy Local 模式' },
-                      { value: 'PROXY_CLUSTER', label: 'Proxy Cluster 模式' },
-                      { value: 'DIRECT', label: 'Direct 模式' },
-                    ]
+                  ? [{ value: 'CLOUD', label: t('instance.cloudType') }]
+                  : getAccessTypeOptions()
               }
             />
           </Form.Item>
           <Form.Item
             label={
               <span>
-                接入地址{' '}
-                <Tooltip title="接入地址为客户端访问入口,会展示在 Topic 
等页面供客户端配置使用。若客户端环境无法解析该地址(如 K8s 内部 Service 域名),可自行配置 DNS 解析或在客户端 hosts 中映射。">
+                {t('instance.endpoint')}{' '}
+                <Tooltip title={t('instance.endpointHelp')}>
                   <QuestionCircleOutlined style={{ color: '#9CA3AF', cursor: 
'help' }} />
                 </Tooltip>
               </span>
             }
             name="endpoint"
-            rules={[{ required: true, message: '请输入接入地址' }]}
-            extra={
-              editInstanceType === 'DIRECT'
-                ? 'Direct 模式请填写 NameServer SLB 地址(K8s 场景下一般为 NameServer 
Service 地址,如 namesrv.mq.svc:9876)'
-                : editInstanceType === 'CLOUD'
-                  ? '云服务实例接入地址由云厂商目录解析,不支持手动修改'
-                  : '请先选择接入方式'
-            }
+            rules={[{ required: true, message: t('instance.endpointRequired') 
}]}
+            extra={getEndpointExtra(editInstanceType)}
           >
             <Input
               placeholder={
                 editInstanceType === 'DIRECT'
-                  ? '例:namesrv.mq.svc.cluster.local:9876'
-                  : '例:proxy.mq.svc.cluster.local:8080'
+                  ? t('instance.directEndpointPlaceholder')
+                  : t('instance.proxyEndpointPlaceholder')
               }
             />
           </Form.Item>
           {editingInstance?.vendor === 'APACHE' && (
             <Form.Item
-              label="管理凭据引用"
+              label={t('instance.adminCredentialRef')}
               name="adminCredentialRef"
-              extra="仅保存服务端配置中的引用,不会保存或传输 AK/SK。"
+              extra={t('instance.adminCredentialRefEditExtra')}
             >
-              <Input placeholder="例:production-admin" />
+              <Input placeholder={t('instance.adminCredentialRefPlaceholder')} 
/>
             </Form.Item>
           )}
-          <Form.Item label="备注" name="remark">
-            <Input.TextArea rows={3} placeholder="描述实例用途" />
+          <Form.Item label={t('instance.remark')} name="remark">
+            <Input.TextArea rows={3} 
placeholder={t('instance.remarkEditPlaceholder')} />
           </Form.Item>
         </Form>
       </Modal>

Reply via email to