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