fix: 修复网络管理国际化解析错误

This commit is contained in:
sunlei 2026-07-23 14:06:43 +08:00
parent f94a98c09c
commit 66283903d5
5 changed files with 44 additions and 2 deletions

View File

@ -51,6 +51,7 @@ pnpm run build:antdv-next
- 系统管理 / 菜单管理维护后端 `admin_menu.sort` 排序字段;`/menu/all` caller 会把后端 `sort` 映射到 Vben 菜单生成器读取的 `meta.order`,保证侧边栏菜单展示以后端返回顺序为准。默认首页入口收敛到环境总览 `/analytics`,不再保留假工作台 `/workspace` 页面。 - 系统管理 / 菜单管理维护后端 `admin_menu.sort` 排序字段;`/menu/all` caller 会把后端 `sort` 映射到 Vben 菜单生成器读取的 `meta.order`,保证侧边栏菜单展示以后端返回顺序为准。默认首页入口收敛到环境总览 `/analytics`,不再保留假工作台 `/workspace` 页面。
- 系统管理 / 站内信是日志级通知列表,只展示 API 错误、QQBot 下线、NapCat 离线等后端自动捕获事件;页面提供筛选、处理/重新打开、置顶和删除,不提供人工新增或编辑。 - 系统管理 / 站内信是日志级通知列表,只展示 API 错误、QQBot 下线、NapCat 离线等后端自动捕获事件;页面提供筛选、处理/重新打开、置顶和删除,不提供人工新增或编辑。
- 系统管理 / 网络管理使用 TSX、KtTable 与统一 Vben 表单维护 API 持久化的 TCP/UDP 单端口转发期望状态,并通过独立页签管理腾讯云云解析 DNS 的 A/AAAA 自动更新绑定。页面展示 Agent、路由同步、UDP Keeper、公网端点租约和 DDNS 同步状态,支持异步 CRUD、重试、Keeper 启停、立即 STUN 刷新及端点历史A 只使用合格 UDP Keeper 的公网 IPv4AAAA 只使用 Agent 全局 IPv6DNS 值不包含端口。首屏读取一次 HTTP 快照,后续只按 API SSE 的资源来源刷新当前活动页签心跳和其他页签事件不刷新不使用定时轮询。Admin 不接触路由器、MQTT 或腾讯云凭据;当前已验证切片只执行 UDP 路由器写入TCP 可保存 CRUD 期望但 Agent 会显示设备协议门禁失败STUN 操作保持可见且禁用。 - 系统管理 / 网络管理使用 TSX、KtTable 与统一 Vben 表单维护 API 持久化的 TCP/UDP 单端口转发期望状态,并通过独立页签管理腾讯云云解析 DNS 的 A/AAAA 自动更新绑定。页面展示 Agent、路由同步、UDP Keeper、公网端点租约和 DDNS 同步状态,支持异步 CRUD、重试、Keeper 启停、立即 STUN 刷新及端点历史A 只使用合格 UDP Keeper 的公网 IPv4AAAA 只使用 Agent 全局 IPv6DNS 值不包含端口。首屏读取一次 HTTP 快照,后续只按 API SSE 的资源来源刷新当前活动页签心跳和其他页签事件不刷新不使用定时轮询。Admin 不接触路由器、MQTT 或腾讯云凭据;当前已验证切片只执行 UDP 路由器写入TCP 可保存 CRUD 期望但 Agent 会显示设备协议门禁失败STUN 操作保持可见且禁用。
- Vue i18n 文案中的普通 `@` 必须写成字面量插值 `{'@'}`,否则生产消息编译器会把它识别为 linked message 语法。网络管理语言包由 `network-locale.spec.ts` 逐条通过实际 i18n runtime 校验,不能只依赖 JSON 解析或组件测试里的 `$t` mock。
- QQBot / 账号连接页拆分 OneBot 连接、QQ 登录、NapCat 运行和运行说明列;更新登录通过 SSE 展示 quick / password / captcha / new-device / qrcode 每步中文进度,密码登录触发 QQ 安全验证时在弹窗内完成腾讯验证码并回交 API新设备验证二维码和腾讯验证码分开展示行操作“运行态”打开只读抽屉展示 NapCat runtime/protocol/session behavior profile、风险模式和登录事件证据。 - QQBot / 账号连接页拆分 OneBot 连接、QQ 登录、NapCat 运行和运行说明列;更新登录通过 SSE 展示 quick / password / captcha / new-device / qrcode 每步中文进度,密码登录触发 QQ 安全验证时在弹窗内完成腾讯验证码并回交 API新设备验证二维码和腾讯验证码分开展示行操作“运行态”打开只读抽屉展示 NapCat runtime/protocol/session behavior profile、风险模式和登录事件证据。
- QQBot / 插件平台页保留在线命令能力表,并提供 manifest 校验、本地插件安装、安装记录、运行事件和账号绑定抽屉,接口走 `/qqbot/plugin-platform/*` - QQBot / 插件平台页保留在线命令能力表,并提供 manifest 校验、本地插件安装、安装记录、运行事件和账号绑定抽屉,接口走 `/qqbot/plugin-platform/*`
- 博客管理 / 文章管理提供“预览”行操作,打开隐藏二级路由 `/blog/article/:articleId/preview`;预览页按 NapCat WebUI 的微服务嵌入形态实现iframe 独占容器,文章标题、状态、预览 Host 和返回/刷新/新窗口操作放在右下角悬浮卡片,不占用 iframe 布局空间。新增隐藏路由和按钮权限需要同步 API `blog-menu.sql` / `vben-admin-init.sql` 中的 `BlogArticlePreview``BlogArticlePreviewButton` - 博客管理 / 文章管理提供“预览”行操作,打开隐藏二级路由 `/blog/article/:articleId/preview`;预览页按 NapCat WebUI 的微服务嵌入形态实现iframe 独占容器,文章标题、状态、预览 Host 和返回/刷新/新窗口操作放在右下角悬浮卡片,不占用 iframe 布局空间。新增隐藏路由和按钮权限需要同步 API `blog-menu.sql` / `vben-admin-init.sql` 中的 `BlogArticlePreview``BlogArticlePreviewButton`

View File

@ -156,7 +156,7 @@
"ddnsStatusSyncing": "Syncing", "ddnsStatusSyncing": "Syncing",
"ddnsStatusWaitingSource": "Waiting for Source", "ddnsStatusWaitingSource": "Waiting for Source",
"ddnsSubDomain": "Host Record", "ddnsSubDomain": "Host Record",
"ddnsSubDomainInvalid": "Enter a valid host record; use @ for the root", "ddnsSubDomainInvalid": "Enter a valid host record; use {'@'} for the root",
"ddnsSyncInProgress": "Synchronization is in progress", "ddnsSyncInProgress": "Synchronization is in progress",
"ddnsSyncStatus": "DDNS Status", "ddnsSyncStatus": "DDNS Status",
"ddnsTab": "Automatic DDNS", "ddnsTab": "Automatic DDNS",

View File

@ -158,7 +158,7 @@
"ddnsStatusSyncing": "同步中", "ddnsStatusSyncing": "同步中",
"ddnsStatusWaitingSource": "等待来源", "ddnsStatusWaitingSource": "等待来源",
"ddnsSubDomain": "主机记录", "ddnsSubDomain": "主机记录",
"ddnsSubDomainInvalid": "请输入有效主机记录,根记录使用 @", "ddnsSubDomainInvalid": "请输入有效主机记录,根记录使用 {'@'}",
"ddnsSyncInProgress": "同步正在进行中", "ddnsSyncInProgress": "同步正在进行中",
"ddnsSyncStatus": "DDNS 状态", "ddnsSyncStatus": "DDNS 状态",
"ddnsTab": "自动 DDNS", "ddnsTab": "自动 DDNS",

View File

@ -0,0 +1,35 @@
import { i18n } from '@vben/locales';
import { afterEach, describe, expect, it, vi } from 'vitest';
import enSystem from '#/locales/langs/en-US/system.json';
import zhSystem from '#/locales/langs/zh-CN/system.json';
const testLocales = ['network-en-US', 'network-zh-CN'];
afterEach(() => {
vi.restoreAllMocks();
for (const locale of testLocales) {
i18n.global.setLocaleMessage(locale, {});
}
});
describe.each([
['network-en-US', enSystem.network],
['network-zh-CN', zhSystem.network],
])('network locale message syntax: %s', (locale, networkMessages) => {
it('compiles every message through the production i18n runtime', () => {
const consoleError = vi
.spyOn(console, 'error')
.mockImplementation(() => {});
i18n.global.setLocaleMessage(locale, {
system: { network: networkMessages },
});
i18n.global.locale.value = locale;
for (const key of Object.keys(networkMessages)) {
i18n.global.t(`system.network.${key}`);
}
expect(consoleError).not.toHaveBeenCalled();
});
});

View File

@ -105,6 +105,12 @@ packages/locales/
} }
``` ```
## 消息语法边界
Vue i18n 会把 `@` 解析为 linked message 起始符。文案需要显示普通 `@` 时必须使用字面量插值 `{'@'}`,不能直接写裸 `@`,否则生产消息编译器可能抛出 `SyntaxError: 14`
新增或修改业务语言包后,应通过实际 i18n runtime 逐条调用对应 namespace并断言没有 message compilation error。网络管理的回归入口为 `apps/web-antdv-next/src/views/system/network/network-locale.spec.ts`
## 远程加载语言包 ## 远程加载语言包
```ts ```ts