From 25a73a8c41da584dc212b59fb0e7a7b0910e2771 Mon Sep 17 00:00:00 2001 From: Dream <1012377328@qq.com> Date: Wed, 26 Aug 2026 15:19:11 +0800 Subject: [PATCH 01/13] =?UTF-8?q?fix(@vben/playground):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20vue-query=20=E6=BC=94=E7=A4=BA=E7=9A=84=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @tanstack/vue-query 升级后已移除 experimental_prefetchInRender 选项与返回值上的 promise 属性,导致类型检查失败。 改用 refetch 提供选项数据:多个组件并发调用时,query 层会将 请求去重合并为同一次,保持"共用一个数据源"的演示语义不变。 --- .../demos/features/vue-query/concurrency-caching.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/playground/src/views/demos/features/vue-query/concurrency-caching.vue b/playground/src/views/demos/features/vue-query/concurrency-caching.vue index 1e0f32800..339efc228 100644 --- a/playground/src/views/demos/features/vue-query/concurrency-caching.vue +++ b/playground/src/views/demos/features/vue-query/concurrency-caching.vue @@ -9,9 +9,7 @@ import { getMenuList } from '#/api'; const queryKey = ['demo', 'api', 'options']; const count = 4; -const { dataUpdatedAt, promise: fetchDataFn } = useQuery({ - // 在组件渲染期间预取数据 - experimental_prefetchInRender: true, +const { dataUpdatedAt, refetch } = useQuery({ // 获取接口数据的函数 queryFn: getMenuList, queryKey, @@ -21,8 +19,10 @@ const { dataUpdatedAt, promise: fetchDataFn } = useQuery({ staleTime: 1000 * 60 * 5, }); +// 多个组件并发调用时,query 内部会将请求去重合并为同一次 async function fetchOptions() { - return await fetchDataFn.value; + const { data } = await refetch(); + return data ?? []; } const schema = []; From 912f0cddf66183a026da6178f1f3a27c4d7a57ae Mon Sep 17 00:00:00 2001 From: Dream <1012377328@qq.com> Date: Wed, 26 Aug 2026 15:20:21 +0800 Subject: [PATCH 02/13] style: format docs to satisfy oxfmt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对齐 markdown 表格列宽,修复 main 分支上 oxfmt --check 的存量格式错误,恢复 lint 检查通过。 --- docs/src/en/guide/essentials/stores.md | 12 +++++++----- docs/src/guide/essentials/cache.md | 26 +++++++++++++------------- docs/src/guide/essentials/stores.md | 12 +++++++----- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/docs/src/en/guide/essentials/stores.md b/docs/src/en/guide/essentials/stores.md index 88ee68aa5..3f56ba5fa 100644 --- a/docs/src/en/guide/essentials/stores.md +++ b/docs/src/en/guide/essentials/stores.md @@ -16,10 +16,10 @@ outline: deep ::: details UserState definition -| Field | Default | Description | -| --- | --- | --- | -| `userInfo` | `null` | User info | -| `userRoles` | `[]` | User roles | +| Field | Default | Description | +| ----------- | ------- | ----------- | +| `userInfo` | `null` | User info | +| `userRoles` | `[]` | User roles | ::: @@ -143,7 +143,9 @@ await store.setTimezone('Asia/Shanghai'); ### Persistence strategy ```ts -persist: { pick: ['timezone'] } +persist: { + pick: ['timezone']; +} ``` The `timezone` field is persisted and preserved on page refresh; the handler logic injected by `setTimezoneHandler` is runtime config and is not persisted. diff --git a/docs/src/guide/essentials/cache.md b/docs/src/guide/essentials/cache.md index df4171ab1..8d2f9eceb 100644 --- a/docs/src/guide/essentials/cache.md +++ b/docs/src/guide/essentials/cache.md @@ -35,11 +35,11 @@ outline: deep **分层职责:** -| 层级 | 职责 | -| --- | --- | +| 层级 | 职责 | +| ---------------- | -------------------------------------------- | | `StorageManager` | 命名空间前缀隔离、TTL 过期检查、统一对外 API | -| `IStorageDriver` | 纯粹的 KV 存取抽象接口 | -| 各 Driver 实现 | 对接具体存储引擎,不感知前缀和 TTL | +| `IStorageDriver` | 纯粹的 KV 存取抽象接口 | +| 各 Driver 实现 | 对接具体存储引擎,不感知前缀和 TTL | ## 快速开始 @@ -182,15 +182,15 @@ const cache = new StorageManager({ ### Driver 对比 -| 特性 | LocalStorageDriver | IndexedDBDriver | MemoryStorageDriver | -| --- | --- | --- | --- | -| 持久化 | ✅ | ✅ | ❌ | -| 容量 | 5–10 MB | 数百 MB+ | 受内存限制 | -| 速度 | 快(同步) | 中等(异步 I/O) | 最快 | -| 数据类型 | 仅 JSON 可序列化 | 结构化克隆 | 任意 JS 对象 | -| 浏览器支持 | 所有现代浏览器 | 所有现代浏览器 | 任意环境 | -| 阻塞主线程 | 是 | 否 | 否 | -| 适用场景 | 配置、Token、小数据 | 离线缓存、大数据 | 测试、SSR | +| 特性 | LocalStorageDriver | IndexedDBDriver | MemoryStorageDriver | +| ---------- | ------------------- | ---------------- | ------------------- | +| 持久化 | ✅ | ✅ | ❌ | +| 容量 | 5–10 MB | 数百 MB+ | 受内存限制 | +| 速度 | 快(同步) | 中等(异步 I/O) | 最快 | +| 数据类型 | 仅 JSON 可序列化 | 结构化克隆 | 任意 JS 对象 | +| 浏览器支持 | 所有现代浏览器 | 所有现代浏览器 | 任意环境 | +| 阻塞主线程 | 是 | 否 | 否 | +| 适用场景 | 配置、Token、小数据 | 离线缓存、大数据 | 测试、SSR | ## API 参考 diff --git a/docs/src/guide/essentials/stores.md b/docs/src/guide/essentials/stores.md index 114acecd3..d3370cbf1 100644 --- a/docs/src/guide/essentials/stores.md +++ b/docs/src/guide/essentials/stores.md @@ -16,10 +16,10 @@ outline: deep ::: details UserState 状态定义 -| 字段 | 默认值 | 说明 | -| --- | --- | --- | -| `userInfo` | `null` | 用户信息 | -| `userRoles` | `[]` | 用户角色 | +| 字段 | 默认值 | 说明 | +| ----------- | ------ | -------- | +| `userInfo` | `null` | 用户信息 | +| `userRoles` | `[]` | 用户角色 | ::: @@ -143,7 +143,9 @@ await store.setTimezone('Asia/Shanghai'); ### 持久化策略 ```ts -persist: { pick: ['timezone'] } +persist: { + pick: ['timezone']; +} ``` `timezone` 字段会被持久化,刷新页面后保留;`setTimezoneHandler` 注入的处理逻辑属于运行时配置,不持久化。 From 702d7ea7ee5eea379a4dcce1013e88083f2f6c13 Mon Sep 17 00:00:00 2001 From: Dream <1012377328@qq.com> Date: Wed, 26 Aug 2026 15:20:44 +0800 Subject: [PATCH 03/13] =?UTF-8?q?refactor(@vben-core/typings):=20=E8=AF=AD?= =?UTF-8?q?=E8=A8=80=E7=B1=BB=E5=9E=8B=E6=94=B9=E4=B8=BA=E5=8F=AF=E5=A3=B0?= =?UTF-8?q?=E6=98=8E=E5=90=88=E5=B9=B6=E6=89=A9=E5=B1=95=E7=9A=84=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=B3=A8=E5=86=8C=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 53b1529 为支持运行时动态语言注册,将 SupportedLanguagesType 等四处语言类型从字面量联合放宽为 string,换来扩展便利的同时 完全丢失了编译期类型约束。 本提交以 keyof interface 注册表恢复类型安全: - typings 新增 SupportedLanguages 接口(默认 en-US / zh-CN), SupportedLanguagesType = keyof SupportedLanguages 派生联合 - locales / composables / preferences / constants 恢复引用该 联合,LanguageOption 泛型化(默认 string 保留运行时注册 自定义语言的逃生舱),SUPPORT_LANGUAGES 默认列表约束回联合 - 应用扩展语言时无需改动核心包:在应用内 d.ts 通过 declare module '@vben-core/typings' 追加接口键即可让联合 自动扩展(先例:vue-router 的 RouteMeta 增强) - 运行时语言列表仍由 setSupportLanguages 注册,53b1529 的 动态注册机制与 en-US 回退行为完整保留 - 声明依赖的五个包补齐 @vben-core/typings workspace 依赖 --- packages/@core/base/typings/src/index.ts | 1 + packages/@core/base/typings/src/languages.ts | 28 +++++ packages/@core/composables/package.json | 1 + .../src/use-simple-locale/messages.ts | 6 +- packages/@core/preferences/src/types.ts | 2 +- packages/constants/package.json | 3 +- packages/constants/src/core.ts | 17 ++- packages/effects/plugins/package.json | 1 + packages/locales/package.json | 1 + packages/locales/src/typing.ts | 4 +- playground/package.json | 1 + pnpm-lock.yaml | 100 ++++++++++++++++++ 12 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 packages/@core/base/typings/src/languages.ts diff --git a/packages/@core/base/typings/src/index.ts b/packages/@core/base/typings/src/index.ts index 33c356610..5a7f563d9 100644 --- a/packages/@core/base/typings/src/index.ts +++ b/packages/@core/base/typings/src/index.ts @@ -1,6 +1,7 @@ export type * from './app'; export type * from './basic'; export type * from './helper'; +export type * from './languages'; export type * from './menu-record'; export type * from './tabs'; export type * from './vue-router'; diff --git a/packages/@core/base/typings/src/languages.ts b/packages/@core/base/typings/src/languages.ts new file mode 100644 index 000000000..516aac038 --- /dev/null +++ b/packages/@core/base/typings/src/languages.ts @@ -0,0 +1,28 @@ +/** + * 支持的语言注册表(核心默认语言)。 + * + * 接口值仅为文档用途的语言标签,类型系统只消费键。 + * 应用如需扩展语言,无需改动核心包,只需在应用内新建 d.ts 文件, + * 通过模块增强(declaration merging)追加语言键: + * + * ```ts + * declare module '@vben-core/typings' { + * interface SupportedLanguages { + * 'zh-TW': '繁體中文'; + * } + * } + * ``` + * + * 追加后 `SupportedLanguagesType` 联合类型会自动包含新语言, + * 所有引用该类型的包(preferences、locales、constants 等)同步获得类型约束; + * 运行时语言列表则通过 `setSupportLanguages` 注册。 + */ +export interface SupportedLanguages { + 'en-US': 'English'; + 'zh-CN': '简体中文'; +} + +/** + * 支持的语言类型 + */ +export type SupportedLanguagesType = keyof SupportedLanguages; diff --git a/packages/@core/composables/package.json b/packages/@core/composables/package.json index de58e59ff..6206f1c29 100644 --- a/packages/@core/composables/package.json +++ b/packages/@core/composables/package.json @@ -37,6 +37,7 @@ }, "dependencies": { "@vben-core/shared": "workspace:*", + "@vben-core/typings": "workspace:*", "@vueuse/core": "catalog:", "reka-ui": "catalog:", "sortablejs": "catalog:", diff --git a/packages/@core/composables/src/use-simple-locale/messages.ts b/packages/@core/composables/src/use-simple-locale/messages.ts index 2ba80801a..6e522f8e0 100644 --- a/packages/@core/composables/src/use-simple-locale/messages.ts +++ b/packages/@core/composables/src/use-simple-locale/messages.ts @@ -1,6 +1,8 @@ -export type Locale = string; +import type { SupportedLanguagesType } from '@vben-core/typings'; -export const messages: Record> = { +export type Locale = SupportedLanguagesType; + +export const messages: Partial>> = { 'en-US': { cancel: 'Cancel', collapse: 'Collapse', diff --git a/packages/@core/preferences/src/types.ts b/packages/@core/preferences/src/types.ts index ffc46b83f..fcb71c847 100644 --- a/packages/@core/preferences/src/types.ts +++ b/packages/@core/preferences/src/types.ts @@ -12,11 +12,11 @@ import type { NavigationStyleType, PageTransitionType, PreferencesButtonPositionType, + SupportedLanguagesType, TabsStyleType, ThemeModeType, } from '@vben-core/typings'; -type SupportedLanguagesType = string; type CustomPreferencesValue = boolean | number | string; interface CustomPreferencesOption { diff --git a/packages/constants/package.json b/packages/constants/package.json index edf5533d9..67c643257 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -20,6 +20,7 @@ } }, "dependencies": { - "@vben-core/shared": "workspace:*" + "@vben-core/shared": "workspace:*", + "@vben-core/typings": "workspace:*" } } diff --git a/packages/constants/src/core.ts b/packages/constants/src/core.ts index 4e21951df..9e7bc77e8 100644 --- a/packages/constants/src/core.ts +++ b/packages/constants/src/core.ts @@ -1,17 +1,24 @@ +import type { SupportedLanguagesType } from '@vben-core/typings'; + /** * @zh_CN 登录页面 url 地址 */ export const LOGIN_PATH = '/auth/login'; -export interface LanguageOption { +/** + * 语言选项;value 默认为 string 以支持运行时注册自定义语言(见 setSupportLanguages) + */ +export interface LanguageOption { label: string; - value: string; + value: TValue; } /** - * 支持的语言(默认值,可在运行时通过 setSupportLanguages 覆盖) + * 支持的语言(默认值,可在运行时通过 setSupportLanguages 覆盖)。 + * value 约束到 SupportedLanguagesType,应用通过模块增强扩展语言后, + * 默认列表同样接受新语言,拼写错误会在编译期报错 */ -export const SUPPORT_LANGUAGES: LanguageOption[] = [ +export const SUPPORT_LANGUAGES: LanguageOption[] = [ { label: '简体中文', value: 'zh-CN', @@ -50,7 +57,7 @@ export function setSupportLanguages(languages: LanguageOption[]) { const nextLanguages = cloneLanguages(languages); currentLanguages = nextLanguages; // 迭代监听器快照,避免监听器在回调中取消订阅导致跳过后续监听器 - for (const listener of listeners.slice()) { + for (const listener of [...listeners]) { listener(cloneLanguages(nextLanguages)); } } diff --git a/packages/effects/plugins/package.json b/packages/effects/plugins/package.json index 6f4e71f5a..e586bc5ff 100644 --- a/packages/effects/plugins/package.json +++ b/packages/effects/plugins/package.json @@ -53,6 +53,7 @@ "@vben-core/popup-ui": "workspace:*", "@vben-core/shadcn-ui": "workspace:*", "@vben-core/shared": "workspace:*", + "@vben-core/typings": "workspace:*", "@vben/hooks": "workspace:*", "@vben/icons": "workspace:*", "@vben/locales": "workspace:*", diff --git a/packages/locales/package.json b/packages/locales/package.json index 709b264e1..981a8816c 100644 --- a/packages/locales/package.json +++ b/packages/locales/package.json @@ -22,6 +22,7 @@ "dependencies": { "@intlify/core-base": "catalog:", "@vben-core/composables": "workspace:*", + "@vben-core/typings": "workspace:*", "vue": "catalog:", "vue-i18n": "catalog:" } diff --git a/packages/locales/src/typing.ts b/packages/locales/src/typing.ts index 9d57086cb..040f64c23 100644 --- a/packages/locales/src/typing.ts +++ b/packages/locales/src/typing.ts @@ -1,4 +1,6 @@ -export type SupportedLanguagesType = string; +import type { SupportedLanguagesType } from '@vben-core/typings'; + +export type { SupportedLanguagesType }; export type ImportLocaleFn = () => Promise<{ default: Record }>; diff --git a/playground/package.json b/playground/package.json index 0410d158c..b4c9f0edd 100644 --- a/playground/package.json +++ b/playground/package.json @@ -33,6 +33,7 @@ "@tanstack/vue-query": "catalog:", "@vben-core/design": "workspace:*", "@vben-core/menu-ui": "workspace:*", + "@vben-core/typings": "workspace:*", "@vben/access": "workspace:*", "@vben/common-ui": "workspace:*", "@vben/constants": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f4340ac50..6bc24e239 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1369,6 +1369,9 @@ importers: '@vben-core/shared': specifier: workspace:* version: link:../base/shared + '@vben-core/typings': + specifier: workspace:* + version: link:../base/typings '@vueuse/core': specifier: 'catalog:' version: 14.4.0(vue@3.5.41(typescript@6.0.3)) @@ -1606,6 +1609,9 @@ importers: '@vben-core/shared': specifier: workspace:* version: link:../@core/base/shared + '@vben-core/typings': + specifier: workspace:* + version: link:../@core/base/typings packages/effects/access: dependencies: @@ -1850,6 +1856,9 @@ importers: '@vben-core/shared': specifier: workspace:* version: link:../../@core/base/shared + '@vben-core/typings': + specifier: workspace:* + version: link:../../@core/base/typings '@vben/hooks': specifier: workspace:* version: link:../hooks @@ -1923,6 +1932,9 @@ importers: '@vben-core/composables': specifier: workspace:* version: link:../@core/composables + '@vben-core/typings': + specifier: workspace:* + version: link:../@core/base/typings vue: specifier: ^3.5.40 version: 3.5.41(typescript@6.0.3) @@ -2007,6 +2019,9 @@ importers: '@vben-core/menu-ui': specifier: workspace:* version: link:../packages/@core/ui-kit/menu-ui + '@vben-core/typings': + specifier: workspace:* + version: link:../packages/@core/base/typings '@vben/access': specifier: workspace:* version: link:../packages/effects/access @@ -4309,6 +4324,12 @@ packages: cpu: [x64] os: [win32] + '@oxlint/binding-android-arm-eabi@1.79.0': + resolution: {integrity: sha512-TebFaaMklO/RXzTv7PucaCq9l3X6D1gA+C8H6K4njtjFOV+zWE9MKLpulcJZN9bzytbUbQIY0mZuz12nQ5Kv4Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + '@oxlint/binding-android-arm64@1.79.0': resolution: {integrity: sha512-KqqnOtAVgNsPPF0YSodkFZA1O80jcKoCZCTu3bgsszxA+MrMP9TLzfXitKjEj1FmrPprKDMdRDMmY3weESO9sg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4339,6 +4360,12 @@ packages: cpu: [arm] os: [linux] + '@oxlint/binding-linux-arm-musleabihf@1.79.0': + resolution: {integrity: sha512-ZOQUjkzDnvlhSE3+tWC3YXx94MMl+sYMlwH+u1+YGApGHOJP/YAc8ZBRFOXZ6eOBmxtXAWuS/fBcdZr8qqNO1A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@oxlint/binding-linux-arm64-gnu@1.79.0': resolution: {integrity: sha512-lu158FR4nGqGeRS3BQvtG85wRgU/Fy4MD5Cxp1hzJXizGiLo6u2742wJSCDKh8cFcZntvX7fcxlq4mMmfryH1g==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4346,6 +4373,41 @@ packages: os: [linux] libc: [glibc] + '@oxlint/binding-linux-arm64-musl@1.79.0': + resolution: {integrity: sha512-mbpKQeE2aflTjddaHK7MP8KP/OFbUM++lt5M635ENM8IyIdK0jm2t9pb+2v9mVVIvhF6TqA4l7F79Pll1mi+uw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxlint/binding-linux-ppc64-gnu@1.79.0': + resolution: {integrity: sha512-WpGNua7gaxaHnpSDeog2ji8IDHn/QLPl9LPzwkR/FvVv58vT5BcXjRXnU+wbu3N75cpeha8CdC7ho/U2OIsB4g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-riscv64-gnu@1.79.0': + resolution: {integrity: sha512-tK1E93A5LVzISg4ngpKJnfTs7EqtIUceGI7MQ4GyDjJiLi8wPCkEyKlj2xkyKWZ1yzkDJyLHTBJ5/iFWRdnJvg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-riscv64-musl@1.79.0': + resolution: {integrity: sha512-qhQvUIrngXivA2A9pQ+xPCychztn/5qUv7yS3gDwXv3w7Rag+eTeeXWmRyx+t7XsW5x6LuY/8AsTq36UgFIblg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxlint/binding-linux-s390x-gnu@1.79.0': + resolution: {integrity: sha512-sv6AaVgU/eE6u+6WFiQVDcPPwTxP6IJMSB9k701W2r/r6Tx465e8vPvVyRxquNH4Vy6KwRNu90mVbxXJN8+5gg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@oxlint/binding-linux-x64-gnu@1.79.0': resolution: {integrity: sha512-iFZL02deziHslb3jEX9KdqlAkYoo4fGyotchKDzdfK1f5mxlIBeiQeHhvK3iFpuEJSB4ma/qeFn9oxPiwnhUPQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4372,6 +4434,12 @@ packages: cpu: [arm64] os: [win32] + '@oxlint/binding-win32-ia32-msvc@1.79.0': + resolution: {integrity: sha512-+KyXjIvcpaXmWW/j9NNY5yWjrIVxaX18VyIheQy3jwc2GSYgpCr7MGI/HxIGQ/shAL5IWEKbhsqoMpAO5Stiog==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + '@oxlint/binding-win32-x64-msvc@1.79.0': resolution: {integrity: sha512-mEelcCMMBS57sIXh2veGMNy+pQwuGtcMxHxGIZWQ5Ba9pJ5jCCUFOZB9E2JhBaxGsURe+WGe0zJp4RVre52gpQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -13471,6 +13539,9 @@ snapshots: '@oxlint-tsgolint/win32-x64@0.25.0': optional: true + '@oxlint/binding-android-arm-eabi@1.79.0': + optional: true + '@oxlint/binding-android-arm64@1.79.0': optional: true @@ -13486,9 +13557,27 @@ snapshots: '@oxlint/binding-linux-arm-gnueabihf@1.79.0': optional: true + '@oxlint/binding-linux-arm-musleabihf@1.79.0': + optional: true + '@oxlint/binding-linux-arm64-gnu@1.79.0': optional: true + '@oxlint/binding-linux-arm64-musl@1.79.0': + optional: true + + '@oxlint/binding-linux-ppc64-gnu@1.79.0': + optional: true + + '@oxlint/binding-linux-riscv64-gnu@1.79.0': + optional: true + + '@oxlint/binding-linux-riscv64-musl@1.79.0': + optional: true + + '@oxlint/binding-linux-s390x-gnu@1.79.0': + optional: true + '@oxlint/binding-linux-x64-gnu@1.79.0': optional: true @@ -13501,6 +13590,9 @@ snapshots: '@oxlint/binding-win32-arm64-msvc@1.79.0': optional: true + '@oxlint/binding-win32-ia32-msvc@1.79.0': + optional: true + '@oxlint/binding-win32-x64-msvc@1.79.0': optional: true @@ -18331,16 +18423,24 @@ snapshots: oxlint@1.79.0(oxlint-tsgolint@0.25.0): optionalDependencies: + '@oxlint/binding-android-arm-eabi': 1.79.0 '@oxlint/binding-android-arm64': 1.79.0 '@oxlint/binding-darwin-arm64': 1.79.0 '@oxlint/binding-darwin-x64': 1.79.0 '@oxlint/binding-freebsd-x64': 1.79.0 '@oxlint/binding-linux-arm-gnueabihf': 1.79.0 + '@oxlint/binding-linux-arm-musleabihf': 1.79.0 '@oxlint/binding-linux-arm64-gnu': 1.79.0 + '@oxlint/binding-linux-arm64-musl': 1.79.0 + '@oxlint/binding-linux-ppc64-gnu': 1.79.0 + '@oxlint/binding-linux-riscv64-gnu': 1.79.0 + '@oxlint/binding-linux-riscv64-musl': 1.79.0 + '@oxlint/binding-linux-s390x-gnu': 1.79.0 '@oxlint/binding-linux-x64-gnu': 1.79.0 '@oxlint/binding-linux-x64-musl': 1.79.0 '@oxlint/binding-openharmony-arm64': 1.79.0 '@oxlint/binding-win32-arm64-msvc': 1.79.0 + '@oxlint/binding-win32-ia32-msvc': 1.79.0 '@oxlint/binding-win32-x64-msvc': 1.79.0 oxlint-tsgolint: 0.25.0 From 8a3f5ffb547a88f34da091415e22e69c610c2ecc Mon Sep 17 00:00:00 2001 From: Dream <1012377328@qq.com> Date: Wed, 26 Aug 2026 15:21:13 +0800 Subject: [PATCH 04/13] =?UTF-8?q?refactor(@vben/plugins):=20vxe-table=20?= =?UTF-8?q?=E8=AF=AD=E8=A8=80=E6=98=A0=E5=B0=84=E6=81=A2=E5=A4=8D=E5=AD=97?= =?UTF-8?q?=E9=9D=A2=E9=87=8F=E9=94=AE=E7=BA=A6=E6=9D=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit localMap 恢复为 Partial>, 语言代码拼写错误重新回到编译期报错;应用扩展语言未打包 对应 vxe 语言包时仍回退 en-US(断言保留并说明原因: vxe-table 仅为内置语言提供类型定义)。 --- packages/effects/plugins/src/vxe-table/init.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/effects/plugins/src/vxe-table/init.ts b/packages/effects/plugins/src/vxe-table/init.ts index 8742bcacd..d55198ac5 100644 --- a/packages/effects/plugins/src/vxe-table/init.ts +++ b/packages/effects/plugins/src/vxe-table/init.ts @@ -1,3 +1,5 @@ +import type { SupportedLanguagesType } from '@vben-core/typings'; + import type { SetupVxeTable } from './types'; import { defineComponent, watch } from 'vue'; @@ -119,7 +121,7 @@ export function setupVbenVxeTable(setupOptions: SetupVxeTable) { } const { isDark, locale } = usePreferences(); - const localMap: Record = { + const localMap: Partial> = { 'zh-CN': normalizeVxeLocale(zhCN), 'en-US': normalizeVxeLocale(enUS), }; @@ -128,8 +130,9 @@ export function setupVbenVxeTable(setupOptions: SetupVxeTable) { [() => isDark.value, () => locale.value], ([isDarkValue, localeValue]) => { VxeUI.setTheme(isDarkValue ? 'dark' : 'light'); - // 应用语言是运行时字符串(见 SupportedLanguagesType);vxe-table 只为内置 - // 语言提供类型定义,因此这里需要断言,未打包的自定义语言回退到 en-US + // vxe-table 仅为其内置语言提供类型定义,应用通过模块增强扩展的 + // 语言可能超出 VxeGlobalI18nLocale 联合范围,因此边界处需要断言, + // 未打包的自定义语言回退到 en-US VxeUI.setI18n( localeValue as any, localMap[localeValue] ?? localMap['en-US'], From 58f06c7925eac234f9fee47d14d21f089cbf6f52 Mon Sep 17 00:00:00 2001 From: Dream <1012377328@qq.com> Date: Wed, 26 Aug 2026 15:21:41 +0800 Subject: [PATCH 05/13] =?UTF-8?q?refactor(@vben/layouts):=20user-dropdown?= =?UTF-8?q?=20=E8=AF=AD=E8=A8=80=E5=88=87=E6=8D=A2=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=E5=AF=B9=E9=BD=90=E8=81=94=E5=90=88=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 下拉菜单回调参数为 string,写入偏好设置前断言收窄到 SupportedLanguagesType,与 language-toggle 的边界处理一致。 --- .../layouts/src/widgets/user-dropdown/user-dropdown.vue | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue b/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue index 3b158d7cd..380b77a8a 100644 --- a/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue +++ b/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue @@ -2,6 +2,7 @@ import type { Component } from 'vue'; import type { LanguageOption } from '@vben/constants'; +import type { SupportedLanguagesType } from '@vben/locales'; import type { AnyFunction } from '@vben/types'; import { computed, onUnmounted, ref, useTemplateRef, watch } from 'vue'; @@ -291,8 +292,10 @@ function handleLanguageToggleSelect(event?: Event) { async function handleLocaleChange(event: Event, value: string) { // 阻止默认关闭,让用户能继续看到选择结果;选完手动收起 event.preventDefault(); - updatePreferences({ app: { locale: value } }); - await loadLocaleMessages(value); + // 菜单项来自运行时语言列表(可为自定义语言),此处为运行时边界断言 + const locale = value as SupportedLanguagesType; + updatePreferences({ app: { locale } }); + await loadLocaleMessages(locale); showLanguageList.value = false; openPopover.value = false; } From 13c4def8f0f458c0d257965a92e20797f1759651 Mon Sep 17 00:00:00 2001 From: Dream <1012377328@qq.com> Date: Wed, 26 Aug 2026 15:22:17 +0800 Subject: [PATCH 06/13] =?UTF-8?q?feat(@vben/playground):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E7=B9=81=E4=BD=93=E4=B8=AD=E6=96=87=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E5=8C=85=E6=BC=94=E7=A4=BA=E8=AF=AD=E8=A8=80=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 以 zh-TW 为活体示例展示新增语言的完整三步: - packages/locales 与 playground 各自新增 zh-TW 语言包 目录(核心语言包由 glob 自动捕获,无需注册) - languages.d.ts 通过 declare module 增强 SupportedLanguages 接口,联合类型自动扩展出 zh-TW - bootstrap 中 setSupportLanguages 注册三语运行时列表, dayjs / antd locale 同步接入繁体包 演示未增强接口时联合自动回到默认两语言、demo 应用零改动 的向后兼容性。 --- .../src/langs/zh-TW/authentication.json | 65 +++++ packages/locales/src/langs/zh-TW/common.json | 26 ++ .../locales/src/langs/zh-TW/preferences.json | 245 ++++++++++++++++++ packages/locales/src/langs/zh-TW/profile.json | 4 + packages/locales/src/langs/zh-TW/ui.json | 165 ++++++++++++ playground/src/bootstrap.ts | 9 + playground/src/locales/index.ts | 9 + playground/src/locales/langs/zh-TW/demos.json | 131 ++++++++++ .../src/locales/langs/zh-TW/examples.json | 90 +++++++ playground/src/locales/langs/zh-TW/page.json | 17 ++ .../src/locales/langs/zh-TW/system.json | 80 ++++++ playground/src/locales/languages.d.ts | 17 ++ 12 files changed, 858 insertions(+) create mode 100644 packages/locales/src/langs/zh-TW/authentication.json create mode 100644 packages/locales/src/langs/zh-TW/common.json create mode 100644 packages/locales/src/langs/zh-TW/preferences.json create mode 100644 packages/locales/src/langs/zh-TW/profile.json create mode 100644 packages/locales/src/langs/zh-TW/ui.json create mode 100644 playground/src/locales/langs/zh-TW/demos.json create mode 100644 playground/src/locales/langs/zh-TW/examples.json create mode 100644 playground/src/locales/langs/zh-TW/page.json create mode 100644 playground/src/locales/langs/zh-TW/system.json create mode 100644 playground/src/locales/languages.d.ts diff --git a/packages/locales/src/langs/zh-TW/authentication.json b/packages/locales/src/langs/zh-TW/authentication.json new file mode 100644 index 000000000..8cfee0e04 --- /dev/null +++ b/packages/locales/src/langs/zh-TW/authentication.json @@ -0,0 +1,65 @@ +{ + "welcomeBack": "歡迎回來", + "pageTitle": "開箱即用的大型中後臺管理系統", + "pageDesc": "工程化、高效能、跨元件庫的前端模版", + "loginSuccess": "登入成功", + "loginSuccessDesc": "歡迎回來", + "loginSubtitle": "請輸入您的賬戶資訊以開始管理您的專案", + "selectAccount": "快速選擇賬號", + "username": "賬號", + "password": "密碼", + "usernameTip": "請輸入使用者名稱", + "passwordTip": "請輸入密碼", + "verifyRequiredTip": "請先完成驗證", + "passwordErrorTip": "密碼錯誤", + "rememberMe": "記住賬號", + "createAnAccount": "建立一個賬號", + "createAccount": "建立賬號", + "alreadyHaveAccount": "已經有賬號了?", + "accountTip": "還沒有賬號?", + "signUp": "註冊", + "signUpSubtitle": "讓您的應用程式管理變得簡單而有趣", + "confirmPassword": "確認密碼", + "confirmPasswordTip": "兩次輸入的密碼不一致", + "agree": "我同意", + "privacyPolicy": "隱私政策", + "terms": "條款", + "agreeTip": "請同意隱私政策和條款", + "goToLogin": "去登入", + "passwordStrength": "使用 8 個或更多字元,混合字母、數字和符號", + "forgetPassword": "忘記密碼?", + "forgetPasswordSubtitle": "輸入您的電子郵件,我們將向您傳送重置密碼的連線", + "emailTip": "請輸入郵箱", + "emailValidErrorTip": "你輸入的郵箱格式不正確", + "sendResetLink": "傳送重置連結", + "email": "郵箱", + "qrcodeSubtitle": "請用手機掃描二維碼登入", + "qrcodePrompt": "掃碼後點擊 '確認',即可完成登入", + "qrcodeLogin": "掃碼登入", + "wechatLogin": "微信登入", + "qqLogin": "QQ登入", + "githubLogin": "Github登入", + "googleLogin": "Google登入", + "dingdingLogin": "釘釘登入", + "codeSubtitle": "請輸入您的手機號碼以開始管理您的專案", + "code": "驗證碼", + "codeTip": "請輸入{0}位驗證碼", + "mobile": "手機號碼", + "mobileTip": "請輸入手機號", + "mobileErrortip": "手機號碼格式錯誤", + "mobileLogin": "手機號登入", + "sendCode": "獲取驗證碼", + "sendText": "{0}秒後重新獲取", + "thirdPartyLogin": "其他登入方式", + "weChat": "微信", + "qq": "QQ", + "gitHub": "GitHub", + "google": "Google", + "loginAgainTitle": "重新登入", + "loginAgainSubTitle": "您的登入狀態已過期,請重新登入以繼續。", + "layout": { + "center": "居中", + "alignLeft": "居左", + "alignRight": "居右" + } +} diff --git a/packages/locales/src/langs/zh-TW/common.json b/packages/locales/src/langs/zh-TW/common.json new file mode 100644 index 000000000..e56344769 --- /dev/null +++ b/packages/locales/src/langs/zh-TW/common.json @@ -0,0 +1,26 @@ +{ + "back": "返回", + "backToHome": "返回首頁", + "login": "登入", + "logout": "退出登入", + "prompt": "提示", + "cancel": "取消", + "confirm": "確認", + "reset": "重置", + "noData": "暫無資料", + "refresh": "重新整理", + "loadingMenu": "載入選單中", + "query": "查詢", + "search": "搜尋", + "enabled": "已啟用", + "disabled": "已停用", + "edit": "修改", + "delete": "刪除", + "detail": "詳情", + "create": "新增", + "yes": "是", + "no": "否", + "showSearchPanel": "顯示搜尋面板", + "hideSearchPanel": "隱藏搜尋面板", + "notShow": "不顯示" +} diff --git a/packages/locales/src/langs/zh-TW/preferences.json b/packages/locales/src/langs/zh-TW/preferences.json new file mode 100644 index 000000000..3e95e9d27 --- /dev/null +++ b/packages/locales/src/langs/zh-TW/preferences.json @@ -0,0 +1,245 @@ +{ + "title": "偏好設定", + "subtitle": "自定義偏好設定 & 即時預覽", + "enableStickyPreferencesNavigationBar": "開啟首選項導航欄吸頂效果", + "disableStickyPreferencesNavigationBar": "關閉首選項導航欄吸頂效果", + "resetTitle": "重置偏好設定", + "resetTip": "資料有變化,點選可進行重置", + "resetSuccess": "重置偏好設定成功", + "appearance": "外觀", + "layout": "佈局", + "content": "內容", + "other": "其它", + "wide": "流式", + "compact": "定寬", + "followSystem": "跟隨系統", + "vertical": "垂直", + "verticalTip": "側邊垂直選單模式", + "horizontal": "水平", + "horizontalTip": "水平選單模式,選單全部顯示在頂部", + "twoColumn": "雙列選單", + "twoColumnTip": "垂直雙列選單模式", + "headerSidebarNav": "側邊導航", + "headerSidebarNavTip": "頂部通欄,側邊導航模式", + "headerTwoColumn": "混合雙列", + "headerTwoColumnTip": "雙列、水平選單共存模式", + "mixedMenu": "混合垂直", + "mixedMenuTip": "垂直水平選單共存", + "fullContent": "內容全屏", + "fullContentTip": "不顯示任何選單,只顯示內容主體", + "normal": "常規", + "plain": "樸素", + "rounded": "圓潤", + "copyPreferences": "複製偏好設定", + "enableCopyPreferences": "顯示覆制偏好設定按鈕", + "copyPreferencesSuccessTitle": "複製成功", + "copyPreferencesSuccess": "複製成功,請在 app 下的 `src/preferences.ts`內進行覆蓋", + "clearAndLogout": "清空快取 & 退出登入", + "mode": "模式", + "general": "通用", + "language": "語言", + "timezone": "時區", + "dynamicTitle": "動態標題", + "watermark": "水印", + "watermarkContent": "請輸入水印文案", + "checkUpdates": "定時檢查更新", + "position": { + "title": "偏好設定位置", + "header": "頂欄", + "auto": "自動", + "fixed": "固定", + "userDropdown": "使用者下拉窗" + }, + "sidebar": { + "buttons": "顯示按鈕", + "buttonFixed": "固定按鈕", + "buttonCollapsed": "摺疊按鈕", + "title": "側邊欄", + "width": "寬度", + "visible": "顯示側邊欄", + "draggable": "側邊欄選單拖拽", + "collapsed": "摺疊選單", + "collapsedShowTitle": "摺疊顯示選單名", + "autoActivateChild": "自動啟用子選單", + "autoActivateChildTip": "點選頂層選單時,自動啟用第一個子選單或者上一次啟用的子選單", + "expandOnHover": "滑鼠懸停展開", + "expandOnHoverTip": "滑鼠在摺疊區域懸浮時,`啟用`則展開當前子選單,`停用`則展開整個側邊欄" + }, + "tabbar": { + "title": "標籤欄", + "enable": "啟用標籤欄", + "icon": "顯示標籤欄圖示", + "showMore": "顯示更多按鈕", + "showMaximize": "顯示最大化按鈕", + "persist": "持久化標籤頁", + "visitHistory": "訪問歷史記錄", + "visitHistoryTip": "開啟後,標籤欄會記錄標籤訪問歷史\n關閉當前標籤,會自動選中上一個開啟的標籤", + "maxCount": "最大標籤數", + "maxCountTip": "每次開啟新的標籤時如果超過最大標籤數,\n會自動關閉一個最先開啟的標籤\n設定為 0 則不限制", + "draggable": "啟動拖拽排序", + "wheelable": "啟用縱向滾輪響應", + "middleClickClose": "點選滑鼠中鍵關閉標籤頁", + "wheelableTip": "開啟後,標籤欄區域可以響應滾輪的縱向滾動事件。\n關閉時,只能響應系統的橫向滾動事件(需要按下Shift再滾動滾輪)", + "styleType": { + "title": "標籤頁風格", + "chrome": "谷歌", + "card": "卡片", + "plain": "樸素", + "brisk": "輕快" + }, + "contextMenu": { + "reload": "重新載入", + "close": "關閉", + "pin": "固定", + "unpin": "取消固定", + "closeLeft": "關閉左側標籤頁", + "closeRight": "關閉右側標籤頁", + "closeOther": "關閉其它標籤頁", + "closeAll": "關閉全部標籤頁", + "openInNewWindow": "在新視窗開啟", + "maximize": "最大化", + "restoreMaximize": "還原" + } + }, + "navigationMenu": { + "title": "導航選單", + "style": "導航選單風格", + "accordion": "側邊導航選單手風琴模式", + "split": "導航選單分離", + "splitTip": "開啟時,側邊欄顯示頂欄對應選單的子選單" + }, + "breadcrumb": { + "title": "麵包屑導航", + "enable": "開啟麵包屑導航", + "icon": "顯示麵包屑圖示", + "home": "顯示首頁按鈕", + "style": "麵包屑風格", + "hideOnlyOne": "僅有一個時隱藏", + "background": "背景" + }, + "animation": { + "title": "動畫", + "loading": "頁面切換 Loading", + "transition": "頁面切換動畫", + "progress": "頁面切換進度條" + }, + "theme": { + "title": "主題", + "radius": "圓角", + "fontSize": "字型大小", + "fontSizeTip": "調整全域性字型大小,即時預覽效果", + "light": "淺色", + "dark": "深色", + "darkSidebar": "深色側邊欄", + "darkSidebarTip": "當主題為淺色,佈局不為水平選單或不為內容全屏時可開啟", + "darkSidebarSub": "深色側邊欄子欄", + "darkSidebarSubTip": "當主題為淺色,開啟深色側邊欄且佈局使用雙列選單模式時可開啟", + "darkHeader": "深色頂欄", + "weakMode": "色弱模式", + "grayMode": "灰色模式", + "builtin": { + "title": "內建主題", + "default": "預設", + "violet": "紫羅蘭", + "pink": "櫻花粉", + "rose": "玫瑰紅", + "skyBlue": "天藍色", + "deepBlue": "深藍色", + "green": "淺綠色", + "deepGreen": "深綠色", + "orange": "橙黃色", + "yellow": "檸檬黃", + "zinc": "鋅色灰", + "neutral": "中性色", + "slate": "石板灰", + "gray": "中灰色", + "custom": "自定義" + } + }, + "header": { + "title": "頂欄", + "modeStatic": "靜止", + "modeFixed": "固定", + "modeAuto": "自動隱藏和顯示", + "modeAutoScroll": "滾動隱藏和顯示", + "visible": "顯示頂欄", + "menuAlign": "選單位置", + "menuAlignStart": "左側", + "menuAlignEnd": "右側", + "menuAlignCenter": "居中" + }, + "footer": { + "title": "底欄", + "visible": "顯示底欄", + "fixed": "固定在底部" + }, + "copyright": { + "title": "版權", + "enable": "啟用版權", + "companyName": "公司名", + "companySiteLink": "公司主頁", + "date": "日期", + "icp": "ICP 備案號", + "icpLink": "ICP 網站連結" + }, + "shortcutKeys": { + "title": "快捷鍵", + "global": "全域性", + "search": "全域性搜尋", + "logout": "退出登入", + "escape": "關閉當前視窗", + "preferences": "偏好設定" + }, + "widget": { + "title": "小部件", + "globalSearch": "全域性搜尋", + "globalSearchPosition": "全域性搜尋位置", + "fullscreen": "全屏", + "fullscreenPosition": "全屏按鈕位置", + "themeToggle": "主題切換", + "themeTogglePosition": "主題切換位置", + "languageToggle": "語言切換", + "languageTogglePosition": "語言切換位置", + "notification": "通知", + "notificationPosition": "通知位置", + "sidebarToggle": "啟用側邊欄切換", + "lockScreen": "鎖屏", + "lockScreenPosition": "鎖屏按鈕位置", + "logoutButtonPosition": "退出按鈕位置", + "header": "頂欄", + "userDropdown": "使用者下拉窗", + "hidden": "已隱藏", + "refresh": "重新整理", + "refreshPosition": "重新整理按鈕位置", + "timezone": "時區", + "timezonePosition": "時區按鈕位置" + }, + "antd": { + "tabLabel": "Antd 拓展", + "title": "業務偏好", + "fields": { + "enableFormFullscreen": { + "label": "啟用表單全屏模式", + "tip": "子專案可在自己的業務場景中讀取這個拓展配置。" + }, + "tenantMode": { + "label": "租戶模式", + "options": { + "single": { + "label": "單租戶" + }, + "multi": { + "label": "多租戶" + } + } + }, + "defaultTableSize": { + "label": "預設分頁條數" + }, + "reportTitle": { + "label": "報表預設標題", + "placeholder": "請輸入報表預設標題" + } + } + } +} diff --git a/packages/locales/src/langs/zh-TW/profile.json b/packages/locales/src/langs/zh-TW/profile.json new file mode 100644 index 000000000..ee398a454 --- /dev/null +++ b/packages/locales/src/langs/zh-TW/profile.json @@ -0,0 +1,4 @@ +{ + "updatePassword": "更新密碼", + "updateBasicProfile": "更新基本資訊" +} diff --git a/packages/locales/src/langs/zh-TW/ui.json b/packages/locales/src/langs/zh-TW/ui.json new file mode 100644 index 000000000..8c21c2029 --- /dev/null +++ b/packages/locales/src/langs/zh-TW/ui.json @@ -0,0 +1,165 @@ +{ + "formRules": { + "required": "請輸入{0}", + "selectRequired": "請選擇{0}", + "minLength": "{0}至少{1}個字元", + "maxLength": "{0}最多{1}個字元", + "length": "{0}長度必須為{1}個字元", + "alreadyExists": "{0} `{1}` 已存在", + "startWith": "{0}必須以 {1} 開頭", + "invalidURL": "請輸入有效的連結", + "sizeLimit": "檔案大小不能超過 {0}MB", + "previewWarning": "無法開啟檔案,沒有可用的URL或預覽地址" + }, + "actionTitle": { + "edit": "修改{0}", + "create": "新增{0}", + "delete": "刪除{0}", + "view": "檢視{0}" + }, + "actionMessage": { + "deleteConfirm": "確定刪除 {0} 嗎?", + "deleting": "正在刪除 {0} ...", + "deleteSuccess": "{0} 刪除成功", + "operationSuccess": "操作成功", + "operationFailed": "操作失敗" + }, + "placeholder": { + "input": "請輸入", + "select": "請選擇", + "upload": "點選上傳" + }, + "captcha": { + "title": "請完成安全驗證", + "sliderSuccessText": "驗證通過", + "sliderDefaultText": "請按住滑塊拖動", + "sliderRotateDefaultTip": "點選圖片可重新整理", + "sliderTranslateDefaultTip": "點選圖片可重新整理", + "sliderRotateFailTip": "驗證失敗", + "sliderRotateSuccessTip": "驗證成功,耗時{0}秒", + "sliderTranslateFailTip": "驗證失敗", + "sliderTranslateSuccessTip": "驗證成功,耗時{0}秒", + "alt": "支援img標籤src屬性值", + "refreshAriaLabel": "重新整理驗證碼", + "confirmAriaLabel": "確認選擇", + "confirm": "確認", + "pointAriaLabel": "點選點", + "clickInOrder": "請依次點選" + }, + "iconPicker": { + "placeholder": "選擇一個圖示", + "search": "搜尋圖示..." + }, + "jsonViewer": { + "copy": "複製", + "copied": "已複製" + }, + "crop": { + "title": "圖片裁剪", + "titleTip": "裁剪比例 {0}", + "confirm": "裁剪", + "cancel": "取消裁剪", + "errorTip": "裁剪錯誤" + }, + "tiptap": { + "placeholder": "請輸入內容...", + "prompts": { + "image": "請輸入圖片地址", + "link": "請輸入連結地址" + }, + "toolbar": { + "bold": "加粗", + "italic": "斜體", + "underline": "下劃線", + "strike": "刪除線", + "code": "行內程式碼", + "codeBlock": "程式碼塊", + "heading": "標題", + "paragraph": "正文", + "heading1": "標題1", + "heading2": "標題2", + "heading3": "標題3", + "heading4": "標題4", + "bulletList": "無序列表", + "orderedList": "有序列表", + "blockquote": "引用", + "link": "連結", + "unlink": "移除連結", + "image": "圖片", + "imageUrl": "圖片URL", + "imageUpload": "從本地上傳", + "textColor": "文字顏色", + "highlightColor": "高亮顏色", + "alignLeft": "左對齊", + "alignCenter": "居中", + "alignRight": "右對齊", + "preview": "預覽", + "undo": "撤銷", + "redo": "重做", + "clear": "清除" + }, + "upload": { + "fileTooLarge": "檔案大小超出限制", + "fileTypeNotAllowed": "不支援的檔案型別", + "onlySingleImage": "僅支援單張圖片上傳,已選取第一張", + "uploadFailed": "上傳失敗" + } + }, + "fallback": { + "pageNotFound": "哎呀!未找到頁面", + "pageNotFoundDesc": "抱歉,我們無法找到您要找的頁面。", + "forbidden": "哎呀!訪問被拒絕", + "forbiddenDesc": "抱歉,您沒有許可權訪問此頁面。", + "internalError": "哎呀!出錯了", + "internalErrorDesc": "抱歉,伺服器遇到錯誤。", + "offline": "離線頁面", + "offlineError": "哎呀!網路錯誤", + "offlineErrorDesc": "抱歉,無法連線到網際網路,請檢查您的網路連線並重試。", + "comingSoon": "即將推出", + "http": { + "requestTimeout": "請求超時,請稍後再試。", + "networkError": "網路異常,請檢查您的網路連線後重試。", + "badRequest": "請求錯誤。請檢查您的輸入並重試。", + "unauthorized": "登入認證過期,請重新登入後繼續。", + "forbidden": "禁止訪問, 您沒有許可權訪問此資源。", + "notFound": "未找到, 請求的資源不存在。", + "internalServerError": "內部伺服器錯誤,請稍後再試。" + } + }, + "widgets": { + "document": "文件", + "qa": "問題 & 幫助", + "setting": "設定", + "logoutTip": "是否退出登入?", + "viewAll": "檢視所有訊息", + "notifications": "通知", + "markAllAsRead": "全部標記為已讀", + "clearNotifications": "清空", + "checkUpdatesTitle": "新版本可用", + "checkUpdatesDescription": "點選重新整理以獲取最新版本", + "search": { + "title": "搜尋", + "searchNavigate": "搜尋導航選單", + "select": "選擇", + "navigate": "導航", + "close": "關閉", + "noResults": "未找到搜尋結果", + "noRecent": "沒有搜尋歷史", + "recent": "搜尋歷史" + }, + "lockScreen": { + "title": "鎖定螢幕", + "screenButton": "鎖定", + "password": "密碼", + "placeholder": "請輸入鎖屏密碼", + "unlock": "點選解鎖", + "errorPasswordTip": "密碼錯誤,請重新輸入", + "backToLogin": "返回登入", + "entry": "進入系統" + }, + "timezone": { + "setTimezone": "設定時區", + "setSuccess": "時區設定成功" + } + } +} diff --git a/playground/src/bootstrap.ts b/playground/src/bootstrap.ts index 981a30a69..3a97b6b8e 100644 --- a/playground/src/bootstrap.ts +++ b/playground/src/bootstrap.ts @@ -2,6 +2,7 @@ import { createApp, watchEffect } from 'vue'; import { registerAccessDirective } from '@vben/access'; import { registerLoadingDirective } from '@vben/common-ui'; +import { setSupportLanguages, SUPPORT_LANGUAGES } from '@vben/constants'; import { providePluginsOptions } from '@vben/plugins'; import { preferences } from '@vben/preferences'; import { initStores } from '@vben/stores'; @@ -19,6 +20,14 @@ import App from './app.vue'; import { initTimezone } from './timezone-init'; async function bootstrap(namespace: string) { + // 演示扩展语言:d.ts 模块增强已向 SupportedLanguages 注册表追加 zh-TW + // (见 src/locales/languages.d.ts),此处同步注册运行时语言列表, + // 语言切换组件即可显示三语 + setSupportLanguages([ + ...SUPPORT_LANGUAGES, + { label: '繁體中文', value: 'zh-TW' }, + ]); + // 初始化组件适配器 await initComponentAdapter(); diff --git a/playground/src/locales/index.ts b/playground/src/locales/index.ts index 2586d859b..c0684b65d 100644 --- a/playground/src/locales/index.ts +++ b/playground/src/locales/index.ts @@ -61,6 +61,10 @@ async function loadDayjsLocale(lang: SupportedLanguagesType) { locale = await import('dayjs/locale/zh-cn'); break; } + case 'zh-TW': { + locale = await import('dayjs/locale/zh-tw'); + break; + } // 默认使用英语 default: { locale = await import('dayjs/locale/en'); @@ -87,6 +91,11 @@ async function loadAntdLocale(lang: SupportedLanguagesType) { antdLocale.value = antdDefaultLocale; break; } + case 'zh-TW': { + const twLocale = await import('antdv-next/dist/locale/zh_TW'); + antdLocale.value = twLocale.default; + break; + } } } diff --git a/playground/src/locales/langs/zh-TW/demos.json b/playground/src/locales/langs/zh-TW/demos.json new file mode 100644 index 000000000..507fbad33 --- /dev/null +++ b/playground/src/locales/langs/zh-TW/demos.json @@ -0,0 +1,131 @@ +{ + "title": "演示", + "access": { + "frontendPermissions": "前端許可權", + "backendPermissions": "後端許可權", + "pageAccess": "頁面訪問", + "buttonControl": "按鈕控制", + "menuVisible403": "選單可見(403)", + "superVisible": "Super 可見", + "adminVisible": "Admin 可見", + "userVisible": "User 可見" + }, + "nested": { + "title": "巢狀選單", + "menu1": "選單 1", + "menu2": "選單 2", + "menu2_1": "選單 2-1", + "menu3": "選單 3", + "menu3_1": "選單 3-1", + "menu3_2": "選單 3-2", + "menu3_2_1": "選單 3-2-1" + }, + "outside": { + "title": "外部頁面", + "embedded": "內嵌", + "externalLink": "外鏈" + }, + "badge": { + "title": "選單徽標", + "dot": "點徽標", + "text": "文本徽標", + "color": "徽標顏色" + }, + "activeIcon": { + "title": "選單啟用圖示", + "children": "子級啟用圖示" + }, + "fallback": { + "title": "預設頁" + }, + "features": { + "title": "功能", + "hideChildrenInMenu": "隱藏子選單", + "loginExpired": "登入過期", + "icons": "圖示", + "watermark": "水印", + "preferencesExtension": "偏好擴充套件示例", + "tabs": "標籤頁", + "tabDetail": "標籤詳情頁", + "fullScreen": "全屏", + "clipboard": "剪貼簿", + "menuWithQuery": "帶參選單", + "openInNewWindow": "新視窗開啟", + "fileDownload": "檔案下載", + "requestParamsSerializer": "引數序列化" + }, + "preferencesExtensionDemo": { + "description": "這個頁面直接讀取 playground 子專案定義的拓展偏好。你可以在右上角的“偏好設定 → Playground 拓展”中修改欄位,也可以點選下方預設按鈕,頁面會即時聯動。", + "currentConfig": "當前拓展配置", + "currentTitle": "當前標題:{title}", + "currentDescription": "預設展示 {count} 條任務;{quickActionText} 快捷操作;當前高亮風格為“{tone}”。", + "showQuickActions": "顯示", + "hideQuickActions": "隱藏", + "boardDescription": "這是一個“真實使用”的示例:頁面標題、操作區、列表條數和高亮樣式都由拓展偏好驅動。", + "quickActionsEnabled": "當前已關閉快捷操作,頁面只保留只讀資訊展示。", + "quickActions": { + "create": "新建任務", + "export": "批次匯出", + "refresh": "重新整理資料" + }, + "presetTitle": "快捷預設(演示 updateCustomPreferences 用法)", + "presetButtons": { + "default": "恢復預設", + "compact": "切換緊湊模式", + "review": "切換評審模式" + }, + "presetTitles": { + "compact": "緊湊模式看板", + "default": "本週運營概覽", + "review": "評審態工作看板" + }, + "tones": { + "default": "預設", + "success": "成功", + "warning": "警告" + }, + "owner": "負責人" + }, + "preferencesExtensionConfig": { + "tabLabel": "拓展", + "title": "Playground 業務偏好", + "fields": { + "reportTitle": { + "label": "看板標題", + "placeholder": "請輸入看板標題" + }, + "defaultVisibleRows": { + "label": "預設展示條數", + "tip": "用於控制示例頁中任務列表預設渲染多少條資料。" + }, + "enableQuickActions": { + "label": "顯示快捷操作" + }, + "highlightTone": { + "label": "高亮風格", + "options": { + "default": "預設", + "success": "成功", + "warning": "警告" + } + } + } + }, + "breadcrumb": { + "navigation": "麵包屑導航", + "lateral": "平級模式", + "level": "層級模式", + "levelDetail": "層級模式詳情", + "lateralDetail": "平級模式詳情" + }, + "vben": { + "title": "專案", + "about": "關於", + "document": "文件", + "antdv": "Ant Design Vue 版本", + "antdv-next": "Antdv Next 版本", + "naive-ui": "Naive UI 版本", + "element-plus": "Element Plus 版本", + "tdesign": "TDesign Vue 版本" + } +} diff --git a/playground/src/locales/langs/zh-TW/examples.json b/playground/src/locales/langs/zh-TW/examples.json new file mode 100644 index 000000000..409649c9e --- /dev/null +++ b/playground/src/locales/langs/zh-TW/examples.json @@ -0,0 +1,90 @@ +{ + "title": "示例", + "modal": { + "title": "彈窗" + }, + "drawer": { + "title": "抽屜" + }, + "ellipsis": { + "title": "文本省略" + }, + "resize": { + "title": "拖動調整" + }, + "form": { + "title": "表單", + "basic": "基礎表單", + "layout": "自定義佈局", + "query": "查詢表單", + "valueFormat": "值格式化", + "rules": "表單校驗", + "dynamic": "動態表單", + "custom": "自定義元件", + "api": "Api", + "merge": "合併表單", + "scrollToError": "滾動到錯誤欄位", + "upload-error": "部分檔案上傳失敗", + "upload-urls": "檔案上傳後的網址", + "file": "檔案", + "crop-image": "裁剪圖片", + "upload-image": "點選上傳圖片", + "collapsible": "單項表單摺疊", + "labelWidth": "Label 自動寬度" + }, + "vxeTable": { + "title": "Vxe 表格", + "basic": "基礎表格", + "remote": "遠端載入", + "tree": "樹形表格", + "fixed": "固定表頭/列", + "virtual": "虛擬滾動", + "editCell": "單元格編輯", + "editRow": "行編輯", + "custom-cell": "自定義單元格", + "form": "搜尋表單", + "viewed": "行標記" + }, + "captcha": { + "title": "驗證碼", + "pointSelection": "點選驗證", + "sliderCaptcha": "滑塊驗證", + "sliderRotateCaptcha": "旋轉驗證", + "sliderTranslateCaptcha": "拼圖滑塊驗證", + "captchaCardTitle": "請完成安全驗證", + "pageDescription": "通過點選圖片中的特定位置來驗證使用者身份。", + "pageTitle": "驗證碼元件示例", + "basic": "基本使用", + "titlePlaceholder": "驗證碼標題文案", + "captchaImageUrlPlaceholder": "驗證碼圖片(支援img標籤src屬性值)", + "hintImage": "提示圖片", + "hintText": "提示文本", + "hintImagePlaceholder": "提示圖片(支援img標籤src屬性值)", + "hintTextPlaceholder": "提示文本", + "showConfirm": "展示確認", + "hideConfirm": "隱藏確認", + "widthPlaceholder": "驗證碼圖片寬度 預設300px", + "heightPlaceholder": "驗證碼圖片高度 預設220px", + "paddingXPlaceholder": "水平內邊距 預設12px", + "paddingYPlaceholder": "垂直內邊距 預設16px", + "index": "索引:", + "timestamp": "時間戳:", + "x": "x:", + "y": "y:" + }, + "layout": { + "col-page": "雙列布局" + }, + "button-group": { + "title": "按鈕組" + }, + "function": { + "contentMenu": "上下文選單" + }, + "cropper": { + "title": "圖片裁剪" + }, + "tiptap": { + "title": "富文本編輯器" + } +} diff --git a/playground/src/locales/langs/zh-TW/page.json b/playground/src/locales/langs/zh-TW/page.json new file mode 100644 index 000000000..d9005ce2c --- /dev/null +++ b/playground/src/locales/langs/zh-TW/page.json @@ -0,0 +1,17 @@ +{ + "auth": { + "login": "登入", + "register": "註冊", + "codeLogin": "驗證碼登入", + "qrcodeLogin": "二維碼登入", + "forgetPassword": "忘記密碼", + "sendingCode": "正在傳送驗證碼", + "codeSentTo": "驗證碼已傳送至{0}", + "profile": "個人中心" + }, + "dashboard": { + "title": "概覽", + "analytics": "分析頁", + "workspace": "工作臺" + } +} diff --git a/playground/src/locales/langs/zh-TW/system.json b/playground/src/locales/langs/zh-TW/system.json new file mode 100644 index 000000000..84ae7a729 --- /dev/null +++ b/playground/src/locales/langs/zh-TW/system.json @@ -0,0 +1,80 @@ +{ + "title": "系統管理", + "user": { + "title": "使用者管理", + "list": "使用者列表", + "name": "使用者名稱", + "userName": "使用者名稱稱", + "id": "使用者ID", + "dept": "部門", + "status": "狀態", + "remark": "備註", + "createTime": "建立時間", + "operation": "操作", + "placeholder": "搜尋部門..." + }, + "dept": { + "list": "部門列表", + "createTime": "建立時間", + "deptName": "部門名稱", + "name": "部門", + "operation": "操作", + "parentDept": "上級部門", + "remark": "備註", + "status": "狀態", + "title": "部門管理" + }, + "menu": { + "list": "選單列表", + "activeIcon": "啟用圖示", + "activePath": "啟用路徑", + "activePathHelp": "跳轉到當前路由時,需要啟用的選單路徑。\n當不在導航選單中顯示時,需要指定啟用路徑", + "activePathMustExist": "該路徑未能找到有效的選單", + "advancedSettings": "其它設定", + "affixTab": "固定在標籤", + "authCode": "許可權標識", + "badge": "徽章內容", + "badgeVariants": "徽標樣式", + "badgeType": { + "dot": "點", + "none": "無", + "normal": "文字", + "title": "徽標型別" + }, + "component": "頁面元件", + "hideChildrenInMenu": "隱藏子選單", + "hideInBreadcrumb": "在麵包屑中隱藏", + "hideInMenu": "隱藏選單", + "hideInTab": "在標籤欄中隱藏", + "icon": "圖示", + "keepAlive": "快取標籤頁", + "linkSrc": "連結地址", + "menuName": "選單名稱", + "menuTitle": "標題", + "name": "選單", + "operation": "操作", + "parent": "上級選單", + "path": "路由地址", + "status": "狀態", + "title": "選單管理", + "type": "型別", + "typeButton": "按鈕", + "typeCatalog": "目錄", + "typeEmbedded": "內嵌", + "typeLink": "外鏈", + "typeMenu": "選單" + }, + "role": { + "title": "角色管理", + "list": "角色列表", + "name": "角色", + "roleName": "角色名稱", + "id": "角色ID", + "status": "狀態", + "remark": "備註", + "createTime": "建立時間", + "operation": "操作", + "permissions": "許可權", + "setPermissions": "授權" + } +} diff --git a/playground/src/locales/languages.d.ts b/playground/src/locales/languages.d.ts new file mode 100644 index 000000000..d258a8f9b --- /dev/null +++ b/playground/src/locales/languages.d.ts @@ -0,0 +1,17 @@ +export type { SupportedLanguages } from '@vben-core/typings'; + +/** + * 扩展支持的语言(演示): + * 通过模块增强向 SupportedLanguages 注册表追加 zh-TW, + * SupportedLanguagesType 联合类型会自动包含 'zh-TW', + * 运行时语言列表需在 bootstrap 中通过 setSupportLanguages 注册。 + * + * 注意:顶部的 re-export 不可省略——它使本文件成为模块, + * declare module 才是模块增强而非覆盖原模块的环境声明; + * 同时应用必须声明 `@vben-core/typings` 依赖以保证模块可解析。 + */ +declare module '@vben-core/typings' { + interface SupportedLanguages { + 'zh-TW': '繁體中文'; + } +} From e3cd9860081cc348b3e96984d7bd5abcf07d8fdb Mon Sep 17 00:00:00 2001 From: Dream <1012377328@qq.com> Date: Wed, 26 Aug 2026 15:22:49 +0800 Subject: [PATCH 07/13] =?UTF-8?q?docs:=20=E9=87=8D=E5=86=99=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E8=AF=AD=E8=A8=80=E5=8C=85=E6=8C=87=E5=8D=97=E4=B8=BA?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E5=A2=9E=E5=BC=BA=E4=B8=89=E6=AD=A5=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按新的类型扩展机制更新中英文档:语言包目录、d.ts 模块 增强、setSupportLanguages 运行时注册三步,并以 zh-TW 为 例给出可运行的完整代码。 --- docs/src/en/guide/in-depth/locale.md | 48 ++++++++++++++-------------- docs/src/guide/in-depth/locale.md | 48 ++++++++++++++-------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/docs/src/en/guide/in-depth/locale.md b/docs/src/en/guide/in-depth/locale.md index d186c1f68..609c6efb8 100644 --- a/docs/src/en/guide/in-depth/locale.md +++ b/docs/src/en/guide/in-depth/locale.md @@ -101,42 +101,42 @@ const items = computed(() => [{ title: $t('demos.title') }]); ## Adding a New Language Pack -If you need to add a new language pack, follow these steps: +If you need to add a new language pack, follow these steps (taking `zh-TW` Traditional Chinese as an example): - Create the corresponding language pack folder and files under `packages/locales/langs` (e.g., `zh-TW/*.json`) and translate the texts accordingly. - In the corresponding application, find the `src/locales/langs` directory and create the same language pack folder and files (e.g., `zh-TW/*.json`). -- Add the corresponding language in `packages/constants/src/core.ts`: +- Create a new d.ts file in the application (e.g., `src/locales/languages.d.ts`) and extend the language types via module augmentation: ```ts - export interface LanguageOption { - label: string; - value: 'en-US' | 'zh-CN'; // [!code --] - value: 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++] + export type { SupportedLanguages } from '@vben-core/typings'; + + declare module '@vben-core/typings' { + interface SupportedLanguages { + 'zh-TW': '繁體中文'; + } } - export const SUPPORT_LANGUAGES: LanguageOption[] = [ - { - label: '简体中文', - value: 'zh-CN', - }, - { - label: 'English', - value: 'en-US', - }, - { - label: '繁体中文', // [!code ++] - value: 'zh-TW', // [!code ++] - }, - ]; ``` -- In `packages/locales/typing.ts`, add a new TypeScript type: + ::: tip Tip + + The re-export at the top must not be omitted: it makes the file a module so that `declare module` acts as module augmentation. Otherwise it would be treated as an ambient module declaration that shadows the original module and loses all its types. The application also needs to declare the `@vben-core/typings` dependency (usually already available for internal monorepo packages). + + ::: + +- Register the runtime language list at application startup (e.g., in `src/bootstrap.ts`). The language toggle component will display the new language automatically: ```ts - export type SupportedLanguagesType = 'en-US' | 'zh-CN'; // [!code --] - export type SupportedLanguagesType = 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++] + import { setSupportLanguages, SUPPORT_LANGUAGES } from '@vben/constants'; + + setSupportLanguages([ + ...SUPPORT_LANGUAGES, + { label: '繁體中文', value: 'zh-TW' }, + ]); ``` -At this point, you can use the newly added language pack in the project. +- If the application uses third-party libraries such as dayjs or component libraries, add the corresponding language pack branches in the locale loading logic of `src/locales/index.ts`. + +At this point, you can use the newly added language pack in the project. The `SupportedLanguagesType` union will automatically include the new language, and all related APIs gain full type constraints. ## Interface Language Switching Function diff --git a/docs/src/guide/in-depth/locale.md b/docs/src/guide/in-depth/locale.md index 6bba311f3..f05061b8f 100644 --- a/docs/src/guide/in-depth/locale.md +++ b/docs/src/guide/in-depth/locale.md @@ -101,42 +101,42 @@ const items = computed(() => [{ title: $t('demos.title') }]); ## 新增语言包 -如果你需要新增语言包,需要按照以下步骤进行: +如果你需要新增语言包,按照以下步骤进行(以新增 `zh-TW` 繁体中文为例): - 在 `packages/locales/langs` 目录下新增对应的语言包文件夹和文件,例:`zh-TW/*.json`,并翻译对应的文本。 - 在对应的应用内,找到 `src/locales/langs` 目录,新增对应的语言包文件夹和文件 `zh-TW/*.json`。 -- 在 `packages/constants/src/core.ts`内,新增对应的语言: +- 在应用内新建一个 d.ts 文件(例:`src/locales/languages.d.ts`),通过模块增强扩展语言类型: ```ts - export interface LanguageOption { - label: string; - value: 'en-US' | 'zh-CN'; // [!code --] - value: 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++] + export type { SupportedLanguages } from '@vben-core/typings'; + + declare module '@vben-core/typings' { + interface SupportedLanguages { + 'zh-TW': '繁體中文'; + } } - export const SUPPORT_LANGUAGES: LanguageOption[] = [ - { - label: '简体中文', - value: 'zh-CN', - }, - { - label: 'English', - value: 'en-US', - }, - { - label: '繁体中文', // [!code ++] - value: 'zh-TW', // [!code ++] - }, - ]; ``` -- 在 `packages/locales/typing.ts`内,新增 Typescript 类型: + ::: tip 提示 + + 顶部的 re-export 不可省略:它使文件成为模块,`declare module` 才是模块增强;否则会被视为环境模块声明,遮蔽原模块导致其下所有类型丢失。同时应用需要声明 `@vben-core/typings` 依赖(monorepo 内部包通常已具备)。 + + ::: + +- 在应用启动时(例:`src/bootstrap.ts`)注册运行时语言列表,语言切换组件会自动显示新语言: ```ts - export type SupportedLanguagesType = 'en-US' | 'zh-CN'; // [!code --] - export type SupportedLanguagesType = 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++] + import { setSupportLanguages, SUPPORT_LANGUAGES } from '@vben/constants'; + + setSupportLanguages([ + ...SUPPORT_LANGUAGES, + { label: '繁體中文', value: 'zh-TW' }, + ]); ``` -到这里,你就可以在项目内使用新增的语言包了。 +- 如果应用使用了 dayjs、组件库等第三方库,在 `src/locales/index.ts` 的语言加载逻辑中补充对应的语言包分支。 + +到这里,你就可以在项目内使用新增的语言包了,`SupportedLanguagesType` 联合类型会自动包含新语言,所有相关 API 均获得完整的类型约束。 ## 界面切换语言功能 From 25ed93a6acbdd4f0672dd65da8be459adf36e556 Mon Sep 17 00:00:00 2001 From: Dream <1012377328@qq.com> Date: Wed, 26 Aug 2026 16:27:27 +0800 Subject: [PATCH 08/13] =?UTF-8?q?fix(@vben/locales):=20=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E7=B9=81=E4=BD=93=E5=81=8F=E5=A5=BD=E8=AE=BE=E7=BD=AE=E7=BF=BB?= =?UTF-8?q?=E8=AF=91=E9=94=99=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 「顯示覆制」应为「顯示複製」。 --- packages/locales/src/langs/zh-TW/preferences.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/locales/src/langs/zh-TW/preferences.json b/packages/locales/src/langs/zh-TW/preferences.json index 3e95e9d27..82400aa99 100644 --- a/packages/locales/src/langs/zh-TW/preferences.json +++ b/packages/locales/src/langs/zh-TW/preferences.json @@ -31,7 +31,7 @@ "plain": "樸素", "rounded": "圓潤", "copyPreferences": "複製偏好設定", - "enableCopyPreferences": "顯示覆制偏好設定按鈕", + "enableCopyPreferences": "顯示複製偏好設定按鈕", "copyPreferencesSuccessTitle": "複製成功", "copyPreferencesSuccess": "複製成功,請在 app 下的 `src/preferences.ts`內進行覆蓋", "clearAndLogout": "清空快取 & 退出登入", From 9acd09d8d8bded58be24edc5cb54c4baf2fc14df Mon Sep 17 00:00:00 2001 From: Dream <1012377328@qq.com> Date: Wed, 26 Aug 2026 16:28:16 +0800 Subject: [PATCH 09/13] =?UTF-8?q?fix(@vben/playground):=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=20antd=20locale=20=E5=9B=9E=E9=80=80=E5=B9=B6?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=B9=81=E4=BD=93=E7=BF=BB=E8=AF=91=E9=94=99?= =?UTF-8?q?=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit loadAntdLocale 为未打包语言包的语言增加 default 分支回退 en-US,避免切换到此类语言时残留上一次的 antd 语言; 「使用者名稱稱」去掉重复的「稱」。 --- playground/src/locales/index.ts | 4 ++++ playground/src/locales/langs/zh-TW/system.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/playground/src/locales/index.ts b/playground/src/locales/index.ts index c0684b65d..88f23ceda 100644 --- a/playground/src/locales/index.ts +++ b/playground/src/locales/index.ts @@ -96,6 +96,10 @@ async function loadAntdLocale(lang: SupportedLanguagesType) { antdLocale.value = twLocale.default; break; } + // 未打包对应语言包的语言回退到 en-US,避免残留上一次的语言 + default: { + antdLocale.value = antdEnLocale; + } } } diff --git a/playground/src/locales/langs/zh-TW/system.json b/playground/src/locales/langs/zh-TW/system.json index 84ae7a729..2c47a8168 100644 --- a/playground/src/locales/langs/zh-TW/system.json +++ b/playground/src/locales/langs/zh-TW/system.json @@ -4,7 +4,7 @@ "title": "使用者管理", "list": "使用者列表", "name": "使用者名稱", - "userName": "使用者名稱稱", + "userName": "使用者名稱", "id": "使用者ID", "dept": "部門", "status": "狀態", From 6594c5f82e6f83640c4bb4f681597cc7d5e748d5 Mon Sep 17 00:00:00 2001 From: Dream <1012377328@qq.com> Date: Wed, 26 Aug 2026 16:29:06 +0800 Subject: [PATCH 10/13] =?UTF-8?q?refactor(@vben/playground):=20vue-query?= =?UTF-8?q?=20=E6=BC=94=E7=A4=BA=E6=94=B9=E7=94=A8=20fetchQuery=20?= =?UTF-8?q?=E8=AF=BB=E5=8F=96=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refetch 每次调用都会强制刷新(cancelRefetch 默认 true 会取消 进行中的请求另起新请求),绕过 staleTime 缓存;且 refetch 默认 不抛错,失败时会静默退化为空选项列表。 改用 queryClient.fetchQuery:缓存新鲜期内直接命中缓存,并发 调用共享同一次请求,真正演示"并发与缓存"主题;请求失败显式 捕获并记录日志。 --- .../vue-query/concurrency-caching.vue | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/playground/src/views/demos/features/vue-query/concurrency-caching.vue b/playground/src/views/demos/features/vue-query/concurrency-caching.vue index 339efc228..559d8dffa 100644 --- a/playground/src/views/demos/features/vue-query/concurrency-caching.vue +++ b/playground/src/views/demos/features/vue-query/concurrency-caching.vue @@ -1,28 +1,40 @@