diff --git a/.vscode/settings.json b/.vscode/settings.json index 92b4f1d2..9a5d56cd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -197,11 +197,14 @@ "playground/src/locales/langs", "apps/*/src/locales/langs" ], - "i18n-ally.pathMatcher": "{locale}.json", - "i18n-ally.enabledParsers": ["json", "ts", "js", "yaml"], + "i18n-ally.pathMatcher": "{locale}/{namespace}.{ext}", + "i18n-ally.enabledParsers": ["json"], "i18n-ally.sourceLanguage": "en", "i18n-ally.displayLanguage": "zh-CN", "i18n-ally.enabledFrameworks": ["vue", "react"], + "i18n-ally.keystyle": "nested", + "i18n-ally.sortKeys": true, + "i18n-ally.namespace": true, // 控制相关文件嵌套展示 "explorer.fileNesting.enabled": true, @@ -216,7 +219,6 @@ "tailwind.config.mjs": "postcss.*" }, "commentTranslate.hover.enabled": false, - "i18n-ally.keystyle": "nested", "commentTranslate.multiLineMerge": true, "vue.server.hybridMode": true, "typescript.tsdk": "node_modules/typescript/lib" diff --git a/apps/backend-mock/utils/mock-data.ts b/apps/backend-mock/utils/mock-data.ts index b0a2bc1a..71970a28 100644 --- a/apps/backend-mock/utils/mock-data.ts +++ b/apps/backend-mock/utils/mock-data.ts @@ -86,7 +86,7 @@ const createDemosMenus = (role: 'admin' | 'super' | 'user') => { component: '/demos/access/admin-visible', meta: { icon: 'mdi:button-cursor', - title: 'page.demos.access.adminVisible', + title: 'demos.access.adminVisible', }, name: 'AccessAdminVisibleDemo', path: '/demos/access/admin-visible', @@ -95,7 +95,7 @@ const createDemosMenus = (role: 'admin' | 'super' | 'user') => { component: '/demos/access/super-visible', meta: { icon: 'mdi:button-cursor', - title: 'page.demos.access.superVisible', + title: 'demos.access.superVisible', }, name: 'AccessSuperVisibleDemo', path: '/demos/access/super-visible', @@ -104,7 +104,7 @@ const createDemosMenus = (role: 'admin' | 'super' | 'user') => { component: '/demos/access/user-visible', meta: { icon: 'mdi:button-cursor', - title: 'page.demos.access.userVisible', + title: 'demos.access.userVisible', }, name: 'AccessUserVisibleDemo', path: '/demos/access/user-visible', @@ -118,7 +118,7 @@ const createDemosMenus = (role: 'admin' | 'super' | 'user') => { icon: 'ic:baseline-view-in-ar', keepAlive: true, order: 1000, - title: 'page.demos.title', + title: 'demos.title', }, name: 'Demos', path: '/demos', @@ -129,7 +129,7 @@ const createDemosMenus = (role: 'admin' | 'super' | 'user') => { path: '/demosaccess', meta: { icon: 'mdi:cloud-key-outline', - title: 'page.demos.access.backendPermissions', + title: 'demos.access.backendPermissions', }, redirect: '/demos/access/page-control', children: [ @@ -139,7 +139,7 @@ const createDemosMenus = (role: 'admin' | 'super' | 'user') => { component: '/demos/access/index', meta: { icon: 'mdi:page-previous-outline', - title: 'page.demos.access.pageAccess', + title: 'demos.access.pageAccess', }, }, { @@ -148,7 +148,7 @@ const createDemosMenus = (role: 'admin' | 'super' | 'user') => { component: '/demos/access/button-control', meta: { icon: 'mdi:button-cursor', - title: 'page.demos.access.buttonControl', + title: 'demos.access.buttonControl', }, }, { @@ -159,7 +159,7 @@ const createDemosMenus = (role: 'admin' | 'super' | 'user') => { authority: ['no-body'], icon: 'mdi:button-cursor', menuVisibleWithForbidden: true, - title: 'page.demos.access.menuVisible403', + title: 'demos.access.menuVisible403', }, }, roleWithMenus[role], diff --git a/apps/web-antd/src/adapter/component/index.ts b/apps/web-antd/src/adapter/component/index.ts index 12849dc3..1afa6217 100644 --- a/apps/web-antd/src/adapter/component/index.ts +++ b/apps/web-antd/src/adapter/component/index.ts @@ -41,7 +41,7 @@ const withDefaultPlaceholder = ( type: 'input' | 'select', ) => { return (props: any, { attrs, slots }: Omit) => { - const placeholder = props?.placeholder || $t(`placeholder.${type}`); + const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`); return h(component, { ...props, ...attrs, placeholder }, slots); }; }; diff --git a/apps/web-antd/src/adapter/form.ts b/apps/web-antd/src/adapter/form.ts index 9b95ac75..65ff793b 100644 --- a/apps/web-antd/src/adapter/form.ts +++ b/apps/web-antd/src/adapter/form.ts @@ -25,14 +25,14 @@ setupVbenForm({ // 输入项目必填国际化适配 required: (value, _params, ctx) => { if (value === undefined || value === null || value.length === 0) { - return $t('formRules.required', [ctx.label]); + return $t('ui.formRules.required', [ctx.label]); } return true; }, // 选择项目必填国际化适配 selectRequired: (value, _params, ctx) => { if (value === undefined || value === null) { - return $t('formRules.selectRequired', [ctx.label]); + return $t('ui.formRules.selectRequired', [ctx.label]); } return true; }, diff --git a/apps/web-antd/src/layouts/basic.vue b/apps/web-antd/src/layouts/basic.vue index d7435b8a..51412956 100644 --- a/apps/web-antd/src/layouts/basic.vue +++ b/apps/web-antd/src/layouts/basic.vue @@ -68,7 +68,7 @@ const menus = computed(() => [ }); }, icon: BookOpenText, - text: $t('widgets.document'), + text: $t('ui.widgets.document'), }, { handler: () => { @@ -86,7 +86,7 @@ const menus = computed(() => [ }); }, icon: CircleHelp, - text: $t('widgets.qa'), + text: $t('ui.widgets.qa'), }, ]); diff --git a/apps/web-antd/src/locales/index.ts b/apps/web-antd/src/locales/index.ts index af8c01d2..1972e06e 100644 --- a/apps/web-antd/src/locales/index.ts +++ b/apps/web-antd/src/locales/index.ts @@ -4,7 +4,11 @@ import type { Locale } from 'ant-design-vue/es/locale'; import type { App } from 'vue'; import { ref } from 'vue'; -import { $t, setupI18n as coreSetup, loadLocalesMap } from '@vben/locales'; +import { + $t, + setupI18n as coreSetup, + loadLocalesMapFromDir, +} from '@vben/locales'; import { preferences } from '@vben/preferences'; import antdEnLocale from 'ant-design-vue/es/locale/en_US'; @@ -13,10 +17,12 @@ import dayjs from 'dayjs'; const antdLocale = ref(antdDefaultLocale); -const modules = import.meta.glob('./langs/*.json'); - -const localesMap = loadLocalesMap(modules); +const modules = import.meta.glob('./langs/**/*.json'); +const localesMap = loadLocalesMapFromDir( + /\.\/langs\/([^/]+)\/(.*)\.json$/, + modules, +); /** * 加载应用特有的语言包 * 这里也可以改造为从服务端获取翻译数据 diff --git a/apps/web-antd/src/locales/langs/en-US.json b/apps/web-antd/src/locales/langs/en-US.json deleted file mode 100644 index 864c721f..00000000 --- a/apps/web-antd/src/locales/langs/en-US.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "page": { - "demos": { - "title": "Demos", - "antd": "Ant Design Vue" - } - } -} diff --git a/apps/web-antd/src/locales/langs/en-US/demos.json b/apps/web-antd/src/locales/langs/en-US/demos.json new file mode 100644 index 00000000..07156434 --- /dev/null +++ b/apps/web-antd/src/locales/langs/en-US/demos.json @@ -0,0 +1,12 @@ +{ + "title": "Demos", + "antd": "Ant Design Vue", + "vben": { + "title": "Project", + "about": "About", + "document": "Document", + "antdv": "Ant Design Vue Version", + "naive-ui": "Naive UI Version", + "element-plus": "Element Plus Version" + } +} diff --git a/apps/web-antd/src/locales/langs/en-US/page.json b/apps/web-antd/src/locales/langs/en-US/page.json new file mode 100644 index 00000000..618a258c --- /dev/null +++ b/apps/web-antd/src/locales/langs/en-US/page.json @@ -0,0 +1,14 @@ +{ + "auth": { + "login": "Login", + "register": "Register", + "codeLogin": "Code Login", + "qrcodeLogin": "Qr Code Login", + "forgetPassword": "Forget Password" + }, + "dashboard": { + "title": "Dashboard", + "analytics": "Analytics", + "workspace": "Workspace" + } +} diff --git a/apps/web-antd/src/locales/langs/zh-CN.json b/apps/web-antd/src/locales/langs/zh-CN.json deleted file mode 100644 index 31d3475b..00000000 --- a/apps/web-antd/src/locales/langs/zh-CN.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "page": { - "demos": { - "title": "演示", - "antd": "Ant Design Vue" - } - } -} diff --git a/apps/web-antd/src/locales/langs/zh-CN/demos.json b/apps/web-antd/src/locales/langs/zh-CN/demos.json new file mode 100644 index 00000000..93ee722f --- /dev/null +++ b/apps/web-antd/src/locales/langs/zh-CN/demos.json @@ -0,0 +1,12 @@ +{ + "title": "演示", + "antd": "Ant Design Vue", + "vben": { + "title": "项目", + "about": "关于", + "document": "文档", + "antdv": "Ant Design Vue 版本", + "naive-ui": "Naive UI 版本", + "element-plus": "Element Plus 版本" + } +} diff --git a/apps/web-antd/src/locales/langs/zh-CN/page.json b/apps/web-antd/src/locales/langs/zh-CN/page.json new file mode 100644 index 00000000..85fa1597 --- /dev/null +++ b/apps/web-antd/src/locales/langs/zh-CN/page.json @@ -0,0 +1,14 @@ +{ + "auth": { + "login": "登陆", + "register": "注册", + "codeLogin": "验证码登陆", + "qrcodeLogin": "二维码登陆", + "forgetPassword": "忘记密码" + }, + "dashboard": { + "title": "概览", + "analytics": "分析页", + "workspace": "工作台" + } +} diff --git a/apps/web-antd/src/router/routes/core.ts b/apps/web-antd/src/router/routes/core.ts index d85de5a4..059fca62 100644 --- a/apps/web-antd/src/router/routes/core.ts +++ b/apps/web-antd/src/router/routes/core.ts @@ -43,7 +43,7 @@ const coreRoutes: RouteRecordRaw[] = [ path: 'login', component: Login, meta: { - title: $t('page.core.login'), + title: $t('page.auth.login'), }, }, { @@ -51,7 +51,7 @@ const coreRoutes: RouteRecordRaw[] = [ path: 'code-login', component: () => import('#/views/_core/authentication/code-login.vue'), meta: { - title: $t('page.core.codeLogin'), + title: $t('page.auth.codeLogin'), }, }, { @@ -60,7 +60,7 @@ const coreRoutes: RouteRecordRaw[] = [ component: () => import('#/views/_core/authentication/qrcode-login.vue'), meta: { - title: $t('page.core.qrcodeLogin'), + title: $t('page.auth.qrcodeLogin'), }, }, { @@ -69,7 +69,7 @@ const coreRoutes: RouteRecordRaw[] = [ component: () => import('#/views/_core/authentication/forget-password.vue'), meta: { - title: $t('page.core.forgetPassword'), + title: $t('page.auth.forgetPassword'), }, }, { @@ -77,7 +77,7 @@ const coreRoutes: RouteRecordRaw[] = [ path: 'register', component: () => import('#/views/_core/authentication/register.vue'), meta: { - title: $t('page.core.register'), + title: $t('page.auth.register'), }, }, ], diff --git a/apps/web-antd/src/router/routes/modules/demos.ts b/apps/web-antd/src/router/routes/modules/demos.ts index fa28acc7..32bb338e 100644 --- a/apps/web-antd/src/router/routes/modules/demos.ts +++ b/apps/web-antd/src/router/routes/modules/demos.ts @@ -10,14 +10,14 @@ const routes: RouteRecordRaw[] = [ icon: 'ic:baseline-view-in-ar', keepAlive: true, order: 1000, - title: $t('page.demos.title'), + title: $t('demos.title'), }, name: 'Demos', path: '/demos', children: [ { meta: { - title: $t('page.demos.antd'), + title: $t('demos.antd'), }, name: 'AntDesignDemos', path: '/demos/ant-design', diff --git a/apps/web-antd/src/router/routes/modules/vben.ts b/apps/web-antd/src/router/routes/modules/vben.ts index 46947212..210e8610 100644 --- a/apps/web-antd/src/router/routes/modules/vben.ts +++ b/apps/web-antd/src/router/routes/modules/vben.ts @@ -18,7 +18,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: VBEN_LOGO_URL, order: 9999, - title: $t('page.vben.title'), + title: $t('demos.vben.title'), }, name: 'VbenProject', path: '/vben-admin', @@ -29,7 +29,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/_core/about/index.vue'), meta: { icon: 'lucide:copyright', - title: $t('page.vben.about'), + title: $t('demos.vben.about'), }, }, { @@ -39,7 +39,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'lucide:book-open-text', link: VBEN_DOC_URL, - title: $t('page.vben.document'), + title: $t('demos.vben.document'), }, }, { @@ -60,7 +60,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: 'logos:naiveui', link: VBEN_NAIVE_PREVIEW_URL, - title: $t('page.vben.naive-ui'), + title: $t('demos.vben.naive-ui'), }, }, { @@ -71,7 +71,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: 'logos:element', link: VBEN_ELE_PREVIEW_URL, - title: $t('page.vben.element-plus'), + title: $t('demos.vben.element-plus'), }, }, ], diff --git a/apps/web-ele/src/adapter/component/index.ts b/apps/web-ele/src/adapter/component/index.ts index 1d415bc8..a819535a 100644 --- a/apps/web-ele/src/adapter/component/index.ts +++ b/apps/web-ele/src/adapter/component/index.ts @@ -33,7 +33,7 @@ const withDefaultPlaceholder = ( type: 'input' | 'select', ) => { return (props: any, { attrs, slots }: Omit) => { - const placeholder = props?.placeholder || $t(`placeholder.${type}`); + const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`); return h(component, { ...props, ...attrs, placeholder }, slots); }; }; diff --git a/apps/web-ele/src/adapter/form.ts b/apps/web-ele/src/adapter/form.ts index 832a6342..1b6e0471 100644 --- a/apps/web-ele/src/adapter/form.ts +++ b/apps/web-ele/src/adapter/form.ts @@ -17,13 +17,13 @@ setupVbenForm({ defineRules: { required: (value, _params, ctx) => { if (value === undefined || value === null || value.length === 0) { - return $t('formRules.required', [ctx.label]); + return $t('ui.formRules.required', [ctx.label]); } return true; }, selectRequired: (value, _params, ctx) => { if (value === undefined || value === null) { - return $t('formRules.selectRequired', [ctx.label]); + return $t('ui.formRules.selectRequired', [ctx.label]); } return true; }, diff --git a/apps/web-ele/src/layouts/basic.vue b/apps/web-ele/src/layouts/basic.vue index d7435b8a..51412956 100644 --- a/apps/web-ele/src/layouts/basic.vue +++ b/apps/web-ele/src/layouts/basic.vue @@ -68,7 +68,7 @@ const menus = computed(() => [ }); }, icon: BookOpenText, - text: $t('widgets.document'), + text: $t('ui.widgets.document'), }, { handler: () => { @@ -86,7 +86,7 @@ const menus = computed(() => [ }); }, icon: CircleHelp, - text: $t('widgets.qa'), + text: $t('ui.widgets.qa'), }, ]); diff --git a/apps/web-ele/src/locales/index.ts b/apps/web-ele/src/locales/index.ts index be39b2b3..1f3e22c9 100644 --- a/apps/web-ele/src/locales/index.ts +++ b/apps/web-ele/src/locales/index.ts @@ -4,7 +4,11 @@ import type { Language } from 'element-plus/es/locale'; import type { App } from 'vue'; import { ref } from 'vue'; -import { $t, setupI18n as coreSetup, loadLocalesMap } from '@vben/locales'; +import { + $t, + setupI18n as coreSetup, + loadLocalesMapFromDir, +} from '@vben/locales'; import { preferences } from '@vben/preferences'; import dayjs from 'dayjs'; @@ -13,10 +17,12 @@ import defaultLocale from 'element-plus/es/locale/lang/zh-cn'; const elementLocale = ref(defaultLocale); -const modules = import.meta.glob('./langs/*.json'); - -const localesMap = loadLocalesMap(modules); +const modules = import.meta.glob('./langs/**/*.json'); +const localesMap = loadLocalesMapFromDir( + /\.\/langs\/([^/]+)\/(.*)\.json$/, + modules, +); /** * 加载应用特有的语言包 * 这里也可以改造为从服务端获取翻译数据 diff --git a/apps/web-ele/src/locales/langs/en-US.json b/apps/web-ele/src/locales/langs/en-US.json deleted file mode 100644 index 268732d9..00000000 --- a/apps/web-ele/src/locales/langs/en-US.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "page": { - "demos": { - "title": "Demos", - "element-plus": "Element Plus" - } - } -} diff --git a/apps/web-ele/src/locales/langs/en-US/demos.json b/apps/web-ele/src/locales/langs/en-US/demos.json new file mode 100644 index 00000000..056da0da --- /dev/null +++ b/apps/web-ele/src/locales/langs/en-US/demos.json @@ -0,0 +1,12 @@ +{ + "title": "Demos", + "elementPlus": "Element Plus", + "vben": { + "title": "Project", + "about": "About", + "document": "Document", + "antdv": "Ant Design Vue Version", + "naive-ui": "Naive UI Version", + "element-plus": "Element Plus Version" + } +} diff --git a/apps/web-ele/src/locales/langs/en-US/page.json b/apps/web-ele/src/locales/langs/en-US/page.json new file mode 100644 index 00000000..618a258c --- /dev/null +++ b/apps/web-ele/src/locales/langs/en-US/page.json @@ -0,0 +1,14 @@ +{ + "auth": { + "login": "Login", + "register": "Register", + "codeLogin": "Code Login", + "qrcodeLogin": "Qr Code Login", + "forgetPassword": "Forget Password" + }, + "dashboard": { + "title": "Dashboard", + "analytics": "Analytics", + "workspace": "Workspace" + } +} diff --git a/apps/web-ele/src/locales/langs/zh-CN.json b/apps/web-ele/src/locales/langs/zh-CN.json deleted file mode 100644 index 3b5a4a95..00000000 --- a/apps/web-ele/src/locales/langs/zh-CN.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "page": { - "demos": { - "title": "演示", - "element-plus": "Element Plus" - } - } -} diff --git a/apps/web-ele/src/locales/langs/zh-CN/demos.json b/apps/web-ele/src/locales/langs/zh-CN/demos.json new file mode 100644 index 00000000..0620e16a --- /dev/null +++ b/apps/web-ele/src/locales/langs/zh-CN/demos.json @@ -0,0 +1,12 @@ +{ + "title": "演示", + "elementPlus": "Element Plus", + "vben": { + "title": "项目", + "about": "关于", + "document": "文档", + "antdv": "Ant Design Vue 版本", + "naive-ui": "Naive UI 版本", + "element-plus": "Element Plus 版本" + } +} diff --git a/apps/web-ele/src/locales/langs/zh-CN/page.json b/apps/web-ele/src/locales/langs/zh-CN/page.json new file mode 100644 index 00000000..85fa1597 --- /dev/null +++ b/apps/web-ele/src/locales/langs/zh-CN/page.json @@ -0,0 +1,14 @@ +{ + "auth": { + "login": "登陆", + "register": "注册", + "codeLogin": "验证码登陆", + "qrcodeLogin": "二维码登陆", + "forgetPassword": "忘记密码" + }, + "dashboard": { + "title": "概览", + "analytics": "分析页", + "workspace": "工作台" + } +} diff --git a/apps/web-ele/src/router/routes/core.ts b/apps/web-ele/src/router/routes/core.ts index d85de5a4..059fca62 100644 --- a/apps/web-ele/src/router/routes/core.ts +++ b/apps/web-ele/src/router/routes/core.ts @@ -43,7 +43,7 @@ const coreRoutes: RouteRecordRaw[] = [ path: 'login', component: Login, meta: { - title: $t('page.core.login'), + title: $t('page.auth.login'), }, }, { @@ -51,7 +51,7 @@ const coreRoutes: RouteRecordRaw[] = [ path: 'code-login', component: () => import('#/views/_core/authentication/code-login.vue'), meta: { - title: $t('page.core.codeLogin'), + title: $t('page.auth.codeLogin'), }, }, { @@ -60,7 +60,7 @@ const coreRoutes: RouteRecordRaw[] = [ component: () => import('#/views/_core/authentication/qrcode-login.vue'), meta: { - title: $t('page.core.qrcodeLogin'), + title: $t('page.auth.qrcodeLogin'), }, }, { @@ -69,7 +69,7 @@ const coreRoutes: RouteRecordRaw[] = [ component: () => import('#/views/_core/authentication/forget-password.vue'), meta: { - title: $t('page.core.forgetPassword'), + title: $t('page.auth.forgetPassword'), }, }, { @@ -77,7 +77,7 @@ const coreRoutes: RouteRecordRaw[] = [ path: 'register', component: () => import('#/views/_core/authentication/register.vue'), meta: { - title: $t('page.core.register'), + title: $t('page.auth.register'), }, }, ], diff --git a/apps/web-ele/src/router/routes/modules/demos.ts b/apps/web-ele/src/router/routes/modules/demos.ts index 7b638a99..223efcf9 100644 --- a/apps/web-ele/src/router/routes/modules/demos.ts +++ b/apps/web-ele/src/router/routes/modules/demos.ts @@ -10,14 +10,14 @@ const routes: RouteRecordRaw[] = [ icon: 'ic:baseline-view-in-ar', keepAlive: true, order: 1000, - title: $t('page.demos.title'), + title: $t('demos.title'), }, name: 'Demos', path: '/demos', children: [ { meta: { - title: $t('page.demos.element-plus'), + title: $t('demos.elementPlus'), }, name: 'NaiveDemos', path: '/demos/element', diff --git a/apps/web-ele/src/router/routes/modules/vben.ts b/apps/web-ele/src/router/routes/modules/vben.ts index 6cd3588a..2cfef549 100644 --- a/apps/web-ele/src/router/routes/modules/vben.ts +++ b/apps/web-ele/src/router/routes/modules/vben.ts @@ -19,7 +19,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: VBEN_LOGO_URL, order: 9999, - title: $t('page.vben.title'), + title: $t('demos.vben.title'), }, name: 'VbenProject', path: '/vben-admin', @@ -30,7 +30,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/_core/about/index.vue'), meta: { icon: 'lucide:copyright', - title: $t('page.vben.about'), + title: $t('demos.vben.about'), }, }, { @@ -40,7 +40,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'lucide:book-open-text', link: VBEN_DOC_URL, - title: $t('page.vben.document'), + title: $t('demos.vben.document'), }, }, { @@ -61,7 +61,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: 'logos:naiveui', link: VBEN_NAIVE_PREVIEW_URL, - title: $t('page.vben.naive-ui'), + title: $t('demos.vben.naive-ui'), }, }, { @@ -72,7 +72,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: SvgAntdvLogoIcon, link: VBEN_ANT_PREVIEW_URL, - title: $t('page.vben.antdv'), + title: $t('demos.vben.antdv'), }, }, ], diff --git a/apps/web-naive/src/adapter/component/index.ts b/apps/web-naive/src/adapter/component/index.ts index d2b5f192..66b3744b 100644 --- a/apps/web-naive/src/adapter/component/index.ts +++ b/apps/web-naive/src/adapter/component/index.ts @@ -35,7 +35,7 @@ const withDefaultPlaceholder = ( type: 'input' | 'select', ) => { return (props: any, { attrs, slots }: Omit) => { - const placeholder = props?.placeholder || $t(`placeholder.${type}`); + const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`); return h(component, { ...props, ...attrs, placeholder }, slots); }; }; diff --git a/apps/web-naive/src/adapter/form.ts b/apps/web-naive/src/adapter/form.ts index 511518cc..2c3cee87 100644 --- a/apps/web-naive/src/adapter/form.ts +++ b/apps/web-naive/src/adapter/form.ts @@ -24,13 +24,13 @@ setupVbenForm({ defineRules: { required: (value, _params, ctx) => { if (value === undefined || value === null || value.length === 0) { - return $t('formRules.required', [ctx.label]); + return $t('ui.formRules.required', [ctx.label]); } return true; }, selectRequired: (value, _params, ctx) => { if (value === undefined || value === null) { - return $t('formRules.selectRequired', [ctx.label]); + return $t('ui.formRules.selectRequired', [ctx.label]); } return true; }, diff --git a/apps/web-naive/src/layouts/basic.vue b/apps/web-naive/src/layouts/basic.vue index bd0cbca0..f75b3ddc 100644 --- a/apps/web-naive/src/layouts/basic.vue +++ b/apps/web-naive/src/layouts/basic.vue @@ -68,7 +68,7 @@ const menus = computed(() => [ }); }, icon: BookOpenText, - text: $t('widgets.document'), + text: $t('ui.widgets.document'), }, { handler: () => { @@ -86,7 +86,7 @@ const menus = computed(() => [ }); }, icon: CircleHelp, - text: $t('widgets.qa'), + text: $t('ui.widgets.qa'), }, ]); diff --git a/apps/web-naive/src/locales/index.ts b/apps/web-naive/src/locales/index.ts index 67595b02..3d77913a 100644 --- a/apps/web-naive/src/locales/index.ts +++ b/apps/web-naive/src/locales/index.ts @@ -2,12 +2,19 @@ import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales'; import type { App } from 'vue'; -import { $t, setupI18n as coreSetup, loadLocalesMap } from '@vben/locales'; +import { + $t, + setupI18n as coreSetup, + loadLocalesMapFromDir, +} from '@vben/locales'; import { preferences } from '@vben/preferences'; -const modules = import.meta.glob('./langs/*.json'); +const modules = import.meta.glob('./langs/**/*.json'); -const localesMap = loadLocalesMap(modules); +const localesMap = loadLocalesMapFromDir( + /\.\/langs\/([^/]+)\/(.*)\.json$/, + modules, +); /** * 加载应用特有的语言包 diff --git a/apps/web-naive/src/locales/langs/en-US.json b/apps/web-naive/src/locales/langs/en-US.json deleted file mode 100644 index c22d75df..00000000 --- a/apps/web-naive/src/locales/langs/en-US.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "page": { - "demos": { - "title": "Demos", - "naive": "Naive UI", - "table": "Table" - } - } -} diff --git a/apps/web-naive/src/locales/langs/en-US/demos.json b/apps/web-naive/src/locales/langs/en-US/demos.json new file mode 100644 index 00000000..9fdffc76 --- /dev/null +++ b/apps/web-naive/src/locales/langs/en-US/demos.json @@ -0,0 +1,13 @@ +{ + "title": "Demos", + "naive": "Naive UI", + "table": "Table", + "vben": { + "title": "Project", + "about": "About", + "document": "Document", + "antdv": "Ant Design Vue Version", + "naive-ui": "Naive UI Version", + "element-plus": "Element Plus Version" + } +} diff --git a/apps/web-naive/src/locales/langs/en-US/page.json b/apps/web-naive/src/locales/langs/en-US/page.json new file mode 100644 index 00000000..618a258c --- /dev/null +++ b/apps/web-naive/src/locales/langs/en-US/page.json @@ -0,0 +1,14 @@ +{ + "auth": { + "login": "Login", + "register": "Register", + "codeLogin": "Code Login", + "qrcodeLogin": "Qr Code Login", + "forgetPassword": "Forget Password" + }, + "dashboard": { + "title": "Dashboard", + "analytics": "Analytics", + "workspace": "Workspace" + } +} diff --git a/apps/web-naive/src/locales/langs/zh-CN.json b/apps/web-naive/src/locales/langs/zh-CN.json deleted file mode 100644 index 50535ba3..00000000 --- a/apps/web-naive/src/locales/langs/zh-CN.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "page": { - "demos": { - "title": "演示", - "naive": "Naive UI", - "table": "Table" - } - } -} diff --git a/apps/web-naive/src/locales/langs/zh-CN/demos.json b/apps/web-naive/src/locales/langs/zh-CN/demos.json new file mode 100644 index 00000000..79b54fa2 --- /dev/null +++ b/apps/web-naive/src/locales/langs/zh-CN/demos.json @@ -0,0 +1,13 @@ +{ + "title": "演示", + "naive": "Naive UI", + "table": "Table", + "vben": { + "title": "项目", + "about": "关于", + "document": "文档", + "antdv": "Ant Design Vue 版本", + "naive-ui": "Naive UI 版本", + "element-plus": "Element Plus 版本" + } +} diff --git a/apps/web-naive/src/locales/langs/zh-CN/page.json b/apps/web-naive/src/locales/langs/zh-CN/page.json new file mode 100644 index 00000000..85fa1597 --- /dev/null +++ b/apps/web-naive/src/locales/langs/zh-CN/page.json @@ -0,0 +1,14 @@ +{ + "auth": { + "login": "登陆", + "register": "注册", + "codeLogin": "验证码登陆", + "qrcodeLogin": "二维码登陆", + "forgetPassword": "忘记密码" + }, + "dashboard": { + "title": "概览", + "analytics": "分析页", + "workspace": "工作台" + } +} diff --git a/apps/web-naive/src/router/routes/core.ts b/apps/web-naive/src/router/routes/core.ts index d85de5a4..059fca62 100644 --- a/apps/web-naive/src/router/routes/core.ts +++ b/apps/web-naive/src/router/routes/core.ts @@ -43,7 +43,7 @@ const coreRoutes: RouteRecordRaw[] = [ path: 'login', component: Login, meta: { - title: $t('page.core.login'), + title: $t('page.auth.login'), }, }, { @@ -51,7 +51,7 @@ const coreRoutes: RouteRecordRaw[] = [ path: 'code-login', component: () => import('#/views/_core/authentication/code-login.vue'), meta: { - title: $t('page.core.codeLogin'), + title: $t('page.auth.codeLogin'), }, }, { @@ -60,7 +60,7 @@ const coreRoutes: RouteRecordRaw[] = [ component: () => import('#/views/_core/authentication/qrcode-login.vue'), meta: { - title: $t('page.core.qrcodeLogin'), + title: $t('page.auth.qrcodeLogin'), }, }, { @@ -69,7 +69,7 @@ const coreRoutes: RouteRecordRaw[] = [ component: () => import('#/views/_core/authentication/forget-password.vue'), meta: { - title: $t('page.core.forgetPassword'), + title: $t('page.auth.forgetPassword'), }, }, { @@ -77,7 +77,7 @@ const coreRoutes: RouteRecordRaw[] = [ path: 'register', component: () => import('#/views/_core/authentication/register.vue'), meta: { - title: $t('page.core.register'), + title: $t('page.auth.register'), }, }, ], diff --git a/apps/web-naive/src/router/routes/modules/demos.ts b/apps/web-naive/src/router/routes/modules/demos.ts index cac10a9b..cf565880 100644 --- a/apps/web-naive/src/router/routes/modules/demos.ts +++ b/apps/web-naive/src/router/routes/modules/demos.ts @@ -10,14 +10,14 @@ const routes: RouteRecordRaw[] = [ icon: 'ic:baseline-view-in-ar', keepAlive: true, order: 1000, - title: $t('page.demos.title'), + title: $t('demos.title'), }, name: 'Demos', path: '/demos', children: [ { meta: { - title: $t('page.demos.naive'), + title: $t('demos.naive'), }, name: 'NaiveDemos', path: '/demos/naive', @@ -25,7 +25,7 @@ const routes: RouteRecordRaw[] = [ }, { meta: { - title: $t('page.demos.table'), + title: $t('demos.table'), }, name: 'Table', path: '/demos/table', diff --git a/apps/web-naive/src/router/routes/modules/vben.ts b/apps/web-naive/src/router/routes/modules/vben.ts index 01041bf4..44461a7f 100644 --- a/apps/web-naive/src/router/routes/modules/vben.ts +++ b/apps/web-naive/src/router/routes/modules/vben.ts @@ -19,7 +19,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: VBEN_LOGO_URL, order: 9999, - title: $t('page.vben.title'), + title: $t('demos.vben.title'), }, name: 'VbenProject', path: '/vben-admin', @@ -30,7 +30,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/_core/about/index.vue'), meta: { icon: 'lucide:copyright', - title: $t('page.vben.about'), + title: $t('demos.vben.about'), }, }, { @@ -40,7 +40,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'lucide:book-open-text', link: VBEN_DOC_URL, - title: $t('page.vben.document'), + title: $t('demos.vben.document'), }, }, { @@ -61,7 +61,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: SvgAntdvLogoIcon, link: VBEN_ANT_PREVIEW_URL, - title: $t('page.vben.antdv'), + title: $t('demos.vben.antdv'), }, }, { @@ -72,7 +72,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: 'logos:element', link: VBEN_ELE_PREVIEW_URL, - title: $t('page.vben.element-plus'), + title: $t('demos.vben.element-plus'), }, }, ], diff --git a/docs/src/_env/adapter/component.ts b/docs/src/_env/adapter/component.ts index 12849dc3..1afa6217 100644 --- a/docs/src/_env/adapter/component.ts +++ b/docs/src/_env/adapter/component.ts @@ -41,7 +41,7 @@ const withDefaultPlaceholder = ( type: 'input' | 'select', ) => { return (props: any, { attrs, slots }: Omit) => { - const placeholder = props?.placeholder || $t(`placeholder.${type}`); + const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`); return h(component, { ...props, ...attrs, placeholder }, slots); }; }; diff --git a/docs/src/_env/adapter/form.ts b/docs/src/_env/adapter/form.ts index 760cf7ce..67e2483e 100644 --- a/docs/src/_env/adapter/form.ts +++ b/docs/src/_env/adapter/form.ts @@ -28,13 +28,13 @@ setupVbenForm({ defineRules: { required: (value, _params, ctx) => { if (value === undefined || value === null || value.length === 0) { - return $t('formRules.required', [ctx.label]); + return $t('ui.formRules.required', [ctx.label]); } return true; }, selectRequired: (value, _params, ctx) => { if (value === undefined || value === null) { - return $t('formRules.selectRequired', [ctx.label]); + return $t('ui.formRules.selectRequired', [ctx.label]); } return true; }, diff --git a/docs/src/components/common-ui/vben-drawer.md b/docs/src/components/common-ui/vben-drawer.md index 070e80ab..e149b6aa 100644 --- a/docs/src/components/common-ui/vben-drawer.md +++ b/docs/src/components/common-ui/vben-drawer.md @@ -53,7 +53,7 @@ Drawer 内的内容一般业务中,会比较复杂,所以我们可以将 dra ::: info 注意 - `VbenDrawer` 组件对与参数的处理优先级是 `slot` > `props` > `state`(通过api更新的状态以及useVbenDrawer参数)。如果你已经传入了 `slot` 或者 `props`,那么 `setState` 将不会生效,这种情况下你可以通过 `slot` 或者 `props` 来更新状态。 -- 如果你使用到了 `connectedComponent` 参数,那么会存在 2 个`useVbenDrawer`, 此时,如果同时设置了相同的参数,那么以内部为准(也就是没有设置 connectedComponent 的代码)。比如 同时设置了 `onComfirm`,那么以内部的 `onComfirm` 为准。`onOpenChange`事件除外,内外都会触发。 +- 如果你使用到了 `connectedComponent` 参数,那么会存在 2 个`useVbenDrawer`, 此时,如果同时设置了相同的参数,那么以内部为准(也就是没有设置 connectedComponent 的代码)。比如 同时设置了 `onConfirm`,那么以内部的 `onConfirm` 为准。`onOpenChange`事件除外,内外都会触发。 ::: diff --git a/docs/src/components/common-ui/vben-form.md b/docs/src/components/common-ui/vben-form.md index 5c2e3c94..ef0e99ee 100644 --- a/docs/src/components/common-ui/vben-form.md +++ b/docs/src/components/common-ui/vben-form.md @@ -51,14 +51,14 @@ setupVbenForm({ // 输入项目必填国际化适配 required: (value, _params, ctx) => { if (value === undefined || value === null || value.length === 0) { - return $t('formRules.required', [ctx.label]); + return $t('ui.formRules.required', [ctx.label]); } return true; }, // 选择项目必填国际化适配 selectRequired: (value, _params, ctx) => { if (value === undefined || value === null) { - return $t('formRules.selectRequired', [ctx.label]); + return $t('ui.formRules.selectRequired', [ctx.label]); } return true; }, @@ -120,7 +120,7 @@ const withDefaultPlaceholder = ( type: 'input' | 'select', ) => { return (props: any, { attrs, slots }: Omit) => { - const placeholder = props?.placeholder || $t(`placeholder.${type}`); + const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`); return h(component, { ...props, ...attrs, placeholder }, slots); }; }; diff --git a/docs/src/components/common-ui/vben-modal.md b/docs/src/components/common-ui/vben-modal.md index 487e5e8a..afdce8a1 100644 --- a/docs/src/components/common-ui/vben-modal.md +++ b/docs/src/components/common-ui/vben-modal.md @@ -59,7 +59,7 @@ Modal 内的内容一般业务中,会比较复杂,所以我们可以将 moda ::: info 注意 - `VbenModal` 组件对与参数的处理优先级是 `slot` > `props` > `state`(通过api更新的状态以及useVbenModal参数)。如果你已经传入了 `slot` 或者 `props`,那么 `setState` 将不会生效,这种情况下你可以通过 `slot` 或者 `props` 来更新状态。 -- 如果你使用到了 `connectedComponent` 参数,那么会存在 2 个`useVbenModal`, 此时,如果同时设置了相同的参数,那么以内部为准(也就是没有设置 connectedComponent 的代码)。比如 同时设置了 `onComfirm`,那么以内部的 `onComfirm` 为准。`onOpenChange`事件除外,内外都会触发。 +- 如果你使用到了 `connectedComponent` 参数,那么会存在 2 个`useVbenModal`, 此时,如果同时设置了相同的参数,那么以内部为准(也就是没有设置 connectedComponent 的代码)。比如 同时设置了 `onConfirm`,那么以内部的 `onConfirm` 为准。`onOpenChange`事件除外,内外都会触发。 ::: diff --git a/docs/src/en/guide/essentials/route.md b/docs/src/en/guide/essentials/route.md index 0b3d0d6c..8592056f 100644 --- a/docs/src/en/guide/essentials/route.md +++ b/docs/src/en/guide/essentials/route.md @@ -106,7 +106,7 @@ const routes: RouteRecordRaw[] = [ icon: 'ic:baseline-view-in-ar', keepAlive: true, order: 1000, - title: $t('page.demos.title'), + title: $t('demos.title'), }, name: 'Demos', path: '/demos', @@ -116,7 +116,7 @@ const routes: RouteRecordRaw[] = [ { meta: { icon: 'ic:round-menu', - title: $t('page.demos.nested.title'), + title: $t('demos.nested.title'), }, name: 'NestedDemos', path: '/demos/nested', @@ -129,7 +129,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu1'), + title: $t('demos.nested.menu1'), }, }, { @@ -138,7 +138,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu2'), + title: $t('demos.nested.menu2'), }, redirect: '/demos/nested/menu2/menu2-1', children: [ @@ -149,7 +149,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu2_1'), + title: $t('demos.nested.menu2_1'), }, }, ], @@ -159,7 +159,7 @@ const routes: RouteRecordRaw[] = [ path: '/demos/nested/menu3', meta: { icon: 'ic:round-menu', - title: $t('page.demos.nested.menu3'), + title: $t('demos.nested.menu3'), }, redirect: '/demos/nested/menu3/menu3-1', children: [ @@ -170,7 +170,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu3_1'), + title: $t('demos.nested.menu3_1'), }, }, { @@ -178,7 +178,7 @@ const routes: RouteRecordRaw[] = [ path: 'menu3-2', meta: { icon: 'ic:round-menu', - title: $t('page.demos.nested.menu3_2'), + title: $t('demos.nested.menu3_2'), }, redirect: '/demos/nested/menu3/menu3-2/menu3-2-1', children: [ @@ -190,7 +190,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu3_2_1'), + title: $t('demos.nested.menu3_2_1'), }, }, ], diff --git a/docs/src/en/guide/in-depth/locale.md b/docs/src/en/guide/in-depth/locale.md index 98974be2..549bc83f 100644 --- a/docs/src/en/guide/in-depth/locale.md +++ b/docs/src/en/guide/in-depth/locale.md @@ -58,7 +58,7 @@ updateLocale('en-US'); To add new translation texts, simply find `src/locales/langs/` in the corresponding application and add the texts accordingly, for example: -**src/locales/langs/zh-CN.ts** +**src/locales/langs/zh-CN/\*.json** ````ts ```json diff --git a/docs/src/guide/essentials/route.md b/docs/src/guide/essentials/route.md index 51da3d72..bc71e0a6 100644 --- a/docs/src/guide/essentials/route.md +++ b/docs/src/guide/essentials/route.md @@ -105,7 +105,7 @@ const routes: RouteRecordRaw[] = [ icon: 'ic:baseline-view-in-ar', keepAlive: true, order: 1000, - title: $t('page.demos.title'), + title: $t('demos.title'), }, name: 'Demos', path: '/demos', @@ -115,7 +115,7 @@ const routes: RouteRecordRaw[] = [ { meta: { icon: 'ic:round-menu', - title: $t('page.demos.nested.title'), + title: $t('demos.nested.title'), }, name: 'NestedDemos', path: '/demos/nested', @@ -128,7 +128,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu1'), + title: $t('demos.nested.menu1'), }, }, { @@ -137,7 +137,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu2'), + title: $t('demos.nested.menu2'), }, redirect: '/demos/nested/menu2/menu2-1', children: [ @@ -148,7 +148,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu2_1'), + title: $t('demos.nested.menu2_1'), }, }, ], @@ -158,7 +158,7 @@ const routes: RouteRecordRaw[] = [ path: '/demos/nested/menu3', meta: { icon: 'ic:round-menu', - title: $t('page.demos.nested.menu3'), + title: $t('demos.nested.menu3'), }, redirect: '/demos/nested/menu3/menu3-1', children: [ @@ -169,7 +169,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu3_1'), + title: $t('demos.nested.menu3_1'), }, }, { @@ -177,7 +177,7 @@ const routes: RouteRecordRaw[] = [ path: 'menu3-2', meta: { icon: 'ic:round-menu', - title: $t('page.demos.nested.menu3_2'), + title: $t('demos.nested.menu3_2'), }, redirect: '/demos/nested/menu3/menu3-2/menu3-2-1', children: [ @@ -189,7 +189,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu3_2_1'), + title: $t('demos.nested.menu3_2_1'), }, }, ], diff --git a/docs/src/guide/in-depth/locale.md b/docs/src/guide/in-depth/locale.md index 66626b7e..e4a4a659 100644 --- a/docs/src/guide/in-depth/locale.md +++ b/docs/src/guide/in-depth/locale.md @@ -58,7 +58,7 @@ updateLocale('en-US'); 新增翻译文本,只需要在对应的应用内,找到 `src/locales/langs/`,新增对应的文本即可,例: -**src/locales/langs/zh-CN.ts** +**src/locales/langs/zh-CN/\*.json** ````ts ```json diff --git a/package.json b/package.json index 78d59ed7..2e88dfe8 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "vben-admin-pro", + "name": "vben-admin-monorepo", "version": "5.4.1", "private": true, "keywords": [ diff --git a/packages/@core/ui-kit/tabs-ui/package.json b/packages/@core/ui-kit/tabs-ui/package.json index f45aef8f..9a59b475 100644 --- a/packages/@core/ui-kit/tabs-ui/package.json +++ b/packages/@core/ui-kit/tabs-ui/package.json @@ -40,7 +40,6 @@ "@vben-core/composables": "workspace:*", "@vben-core/icons": "workspace:*", "@vben-core/shadcn-ui": "workspace:*", - "@vben-core/shared": "workspace:*", "@vben-core/typings": "workspace:*", "@vueuse/core": "catalog:", "vue": "catalog:" diff --git a/packages/effects/common-ui/src/ui/fallback/fallback.vue b/packages/effects/common-ui/src/ui/fallback/fallback.vue index b2014e6c..dc46ef42 100644 --- a/packages/effects/common-ui/src/ui/fallback/fallback.vue +++ b/packages/effects/common-ui/src/ui/fallback/fallback.vue @@ -40,19 +40,19 @@ const titleText = computed(() => { switch (props.status) { case '403': { - return $t('fallback.forbidden'); + return $t('ui.fallback.forbidden'); } case '404': { - return $t('fallback.pageNotFound'); + return $t('ui.fallback.pageNotFound'); } case '500': { - return $t('fallback.internalError'); + return $t('ui.fallback.internalError'); } case 'coming-soon': { - return $t('fallback.comingSoon'); + return $t('ui.fallback.comingSoon'); } case 'offline': { - return $t('fallback.offlineError'); + return $t('ui.fallback.offlineError'); } default: { return ''; @@ -66,16 +66,16 @@ const descText = computed(() => { } switch (props.status) { case '403': { - return $t('fallback.forbiddenDesc'); + return $t('ui.fallback.forbiddenDesc'); } case '404': { - return $t('fallback.pageNotFoundDesc'); + return $t('ui.fallback.pageNotFoundDesc'); } case '500': { - return $t('fallback.internalErrorDesc'); + return $t('ui.fallback.internalErrorDesc'); } case 'offline': { - return $t('fallback.offlineErrorDesc'); + return $t('ui.fallback.offlineErrorDesc'); } default: { return ''; diff --git a/packages/effects/layouts/src/widgets/check-updates/check-updates.vue b/packages/effects/layouts/src/widgets/check-updates/check-updates.vue index f39ea9dc..a0c9adea 100644 --- a/packages/effects/layouts/src/widgets/check-updates/check-updates.vue +++ b/packages/effects/layouts/src/widgets/check-updates/check-updates.vue @@ -123,12 +123,12 @@ onUnmounted(() => { :cancel-text="$t('common.cancel')" :confirm-text="$t('common.refresh')" :fullscreen-button="false" - :title="$t('widgets.checkUpdatesTitle')" + :title="$t('ui.widgets.checkUpdatesTitle')" centered content-class="px-8 min-h-10" footer-class="border-none mb-3 mr-3" header-class="border-none" > - {{ $t('widgets.checkUpdatesDescription') }} + {{ $t('ui.widgets.checkUpdatesDescription') }} diff --git a/packages/effects/layouts/src/widgets/global-search/global-search.vue b/packages/effects/layouts/src/widgets/global-search/global-search.vue index ae002622..2f42d6bf 100644 --- a/packages/effects/layouts/src/widgets/global-search/global-search.vue +++ b/packages/effects/layouts/src/widgets/global-search/global-search.vue @@ -102,7 +102,7 @@ onMounted(() => { @@ -113,16 +113,16 @@ onMounted(() => {
- {{ $t('widgets.search.select') }} + {{ $t('ui.widgets.search.select') }}
- {{ $t('widgets.search.navigate') }} + {{ $t('ui.widgets.search.navigate') }}
- {{ $t('widgets.search.close') }} + {{ $t('ui.widgets.search.close') }}
@@ -137,7 +137,7 @@ onMounted(() => { { >

- {{ $t('widgets.search.noResults') }} + {{ $t('ui.widgets.search.noResults') }} "{{ keyword }}" @@ -242,7 +242,7 @@ onMounted(() => { class="text-muted-foreground text-center" >

- {{ $t('widgets.search.noRecent') }} + {{ $t('ui.widgets.search.noRecent') }}

@@ -251,7 +251,7 @@ onMounted(() => { v-if="searchHistory.length > 0 && !keyword" class="text-muted-foreground mb-2 text-xs" > - {{ $t('widgets.search.recent') }} + {{ $t('ui.widgets.search.recent') }}
  • - {{ $t('widgets.lockScreen.screenButton') }} + {{ $t('ui.widgets.lockScreen.screenButton') }}
    diff --git a/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue b/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue index 8153de7c..cce417da 100644 --- a/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue +++ b/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue @@ -46,7 +46,7 @@ const [Form, { form, validate }] = useVbenForm( { component: 'VbenInputPassword' as const, componentProps: { - placeholder: $t('widgets.lockScreen.placeholder'), + placeholder: $t('ui.widgets.lockScreen.placeholder'), }, fieldName: 'password', label: $t('authentication.password'), @@ -90,7 +90,7 @@ useScrollLock(); - {{ $t('widgets.lockScreen.unlock') }} + {{ $t('ui.widgets.lockScreen.unlock') }}
    - {{ $t('widgets.lockScreen.entry') }} + {{ $t('ui.widgets.lockScreen.entry') }} - {{ $t('widgets.lockScreen.backToLogin') }} + {{ $t('ui.widgets.lockScreen.backToLogin') }}
    -
    {{ $t('widgets.notifications') }}
    +
    {{ $t('ui.widgets.notifications') }}
    @@ -138,10 +138,10 @@ function handleClick(item: NotificationItem) { variant="ghost" @click="handleClear" > - {{ $t('widgets.clearNotifications') }} + {{ $t('ui.widgets.clearNotifications') }} - {{ $t('widgets.viewAll') }} + {{ $t('ui.widgets.viewAll') }}
    diff --git a/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue b/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue index 483e2099..f71a1f6c 100644 --- a/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue +++ b/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue @@ -44,7 +44,7 @@ const altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥')); --> - {{ $t('widgets.lockScreen.title') }} + {{ $t('ui.widgets.lockScreen.title') }} 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 2cfa0ed3..475ba6f6 100644 --- a/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue +++ b/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue @@ -152,7 +152,7 @@ if (enableShortcutKey.value) { footer-class="border-none mb-3 mr-3" header-class="border-none" > - {{ $t('widgets.logoutTip') }} + {{ $t('ui.widgets.logoutTip') }} @@ -206,7 +206,7 @@ if (enableShortcutKey.value) { @click="handleOpenLock" > - {{ $t('widgets.lockScreen.title') }} + {{ $t('ui.widgets.lockScreen.title') }} {{ altView }} L diff --git a/packages/effects/request/src/request-client/preset-interceptors.ts b/packages/effects/request/src/request-client/preset-interceptors.ts index 89970161..2049eeaa 100644 --- a/packages/effects/request/src/request-client/preset-interceptors.ts +++ b/packages/effects/request/src/request-client/preset-interceptors.ts @@ -82,9 +82,9 @@ export const errorMessageResponseInterceptor = ( const err: string = error?.toString?.() ?? ''; let errMsg = ''; if (err?.includes('Network Error')) { - errMsg = $t('fallback.http.networkError'); + errMsg = $t('ui.fallback.http.networkError'); } else if (error?.message?.includes?.('timeout')) { - errMsg = $t('fallback.http.requestTimeout'); + errMsg = $t('ui.fallback.http.requestTimeout'); } if (errMsg) { makeErrorMessage?.(errMsg, error); @@ -96,27 +96,27 @@ export const errorMessageResponseInterceptor = ( switch (status) { case 400: { - errorMessage = $t('fallback.http.badRequest'); + errorMessage = $t('ui.fallback.http.badRequest'); break; } case 401: { - errorMessage = $t('fallback.http.unauthorized'); + errorMessage = $t('ui.fallback.http.unauthorized'); break; } case 403: { - errorMessage = $t('fallback.http.forbidden'); + errorMessage = $t('ui.fallback.http.forbidden'); break; } case 404: { - errorMessage = $t('fallback.http.notFound'); + errorMessage = $t('ui.fallback.http.notFound'); break; } case 408: { - errorMessage = $t('fallback.http.requestTimeout'); + errorMessage = $t('ui.fallback.http.requestTimeout'); break; } default: { - errorMessage = $t('fallback.http.internalServerError'); + errorMessage = $t('ui.fallback.http.internalServerError'); } } makeErrorMessage?.(errorMessage, error); diff --git a/packages/locales/src/i18n.ts b/packages/locales/src/i18n.ts index b44fcfa6..99259c3c 100644 --- a/packages/locales/src/i18n.ts +++ b/packages/locales/src/i18n.ts @@ -19,12 +19,14 @@ const i18n = createI18n({ messages: {}, }); -const modules = import.meta.glob('./langs/*.json'); +const modules = import.meta.glob('./langs/**/*.json'); const { setSimpleLocale } = useSimpleLocale(); -const localesMap = loadLocalesMap(modules); - +const localesMap = loadLocalesMapFromDir( + /\.\/langs\/([^/]+)\/(.*)\.json$/, + modules, +); let loadMessages: LoadMessageFn; /** @@ -40,6 +42,48 @@ function loadLocalesMap(modules: Record Promise>) { localesMap[key] = loadLocale as ImportLocaleFn; } } + return localesMap; +} + +/** + * Load locale modules with directory structure + * @param regexp - Regular expression to match language and file names + * @param modules - The modules object containing paths and import functions + * @returns A map of locales to their corresponding import functions + */ +function loadLocalesMapFromDir( + regexp: RegExp, + modules: Record Promise>, +): Record { + const localesRaw: Record Promise>> = {}; + const localesMap: Record = {}; + + // Iterate over the modules to extract language and file names + for (const path in modules) { + const match = path.match(regexp); + if (match) { + const [_, locale, fileName] = match; + if (locale && fileName) { + if (!localesRaw[locale]) { + localesRaw[locale] = {}; + } + if (modules[path]) { + localesRaw[locale][fileName] = modules[path]; + } + } + } + } + + // Convert raw locale data into async import functions + for (const [locale, files] of Object.entries(localesRaw)) { + localesMap[locale] = async () => { + const messages: Record = {}; + for (const [fileName, importFn] of Object.entries(files)) { + messages[fileName] = ((await importFn()) as any)?.default; + } + return { default: messages }; + }; + } return localesMap; } @@ -93,4 +137,10 @@ async function loadLocaleMessages(lang: SupportedLanguagesType) { return setI18nLanguage(lang); } -export { i18n, loadLocaleMessages, loadLocalesMap, setupI18n }; +export { + i18n, + loadLocaleMessages, + loadLocalesMap, + loadLocalesMapFromDir, + setupI18n, +}; diff --git a/packages/locales/src/index.ts b/packages/locales/src/index.ts index 91f6f212..eb2251ad 100644 --- a/packages/locales/src/index.ts +++ b/packages/locales/src/index.ts @@ -1,8 +1,21 @@ -import { i18n, loadLocaleMessages, loadLocalesMap, setupI18n } from './i18n'; +import { + i18n, + loadLocaleMessages, + loadLocalesMap, + loadLocalesMapFromDir, + setupI18n, +} from './i18n'; const $t = i18n.global.t; -export { $t, i18n, loadLocaleMessages, loadLocalesMap, setupI18n }; +export { + $t, + i18n, + loadLocaleMessages, + loadLocalesMap, + loadLocalesMapFromDir, + setupI18n, +}; export { type ImportLocaleFn, type LocaleSetupOptions, diff --git a/packages/locales/src/langs/en-US.json b/packages/locales/src/langs/en-US.json deleted file mode 100644 index 2f303c23..00000000 --- a/packages/locales/src/langs/en-US.json +++ /dev/null @@ -1,339 +0,0 @@ -{ - "page": { - "core": { - "login": "Login", - "register": "Register", - "codeLogin": "Code Login", - "qrcodeLogin": "Qr Code Login", - "forgetPassword": "Forget Password" - }, - "dashboard": { - "title": "Dashboard", - "analytics": "Analytics", - "workspace": "Workspace" - }, - "vben": { - "title": "Project", - "about": "About", - "document": "Document", - "antdv": "Ant Design Vue Version", - "naive-ui": "Naive UI Version", - "element-plus": "Element Plus Version" - } - }, - "common": { - "back": "Back", - "backToHome": "Back To Home", - "login": "Login", - "logout": "Logout", - "prompt": "Prompt", - "cancel": "Cancel", - "confirm": "Comfirm", - "noData": "No Data", - "refresh": "Refresh", - "loadingMenu": "Loading Menu", - "query": "Search" - }, - "fallback": { - "pageNotFound": "Oops! Page Not Found", - "pageNotFoundDesc": "Sorry, we couldn't find the page you were looking for.", - "forbidden": "Oops! Access Denied", - "forbiddenDesc": "Sorry, but you don't have permission to access this page.", - "internalError": "Oops! Something Went Wrong", - "internalErrorDesc": "Sorry, but the server encountered an error.", - "offline": "Offline Page", - "offlineError": "Oops! Network Error", - "offlineErrorDesc": "Sorry, can't connect to the internet. Check your connection.", - "comingSoon": "Coming Soon", - "http": { - "requestTimeout": "The request timed out. Please try again later.", - "networkError": "A network error occurred. Please check your internet connection and try again.", - "badRequest": "Bad Request. Please check your input and try again.", - "unauthorized": "Unauthorized. Please log in to continue.", - "forbidden": "Forbidden. You do not have permission to access this resource.", - "notFound": "Not Found. The requested resource could not be found.", - "internalServerError": "Internal Server Error. Something went wrong on our end. Please try again later." - } - }, - "formRules": { - "required": "Please enter {0}", - "selectRequired": "Please select {0}" - }, - "placeholder": { - "input": "Please enter", - "select": "Please select" - }, - "widgets": { - "document": "Document", - "qa": "Q&A", - "setting": "Settings", - "logoutTip": "Do you want to logout?", - "viewAll": "View All Messages", - "notifications": "Notifications", - "markAllAsRead": "Make All as Read", - "clearNotifications": "Clear", - "checkUpdatesTitle": "New Version Available", - "checkUpdatesDescription": "Click to refresh and get the latest version", - "search": { - "title": "Search", - "searchNavigate": "Search Navigation", - "select": "Select", - "navigate": "Navigate", - "close": "Close", - "noResults": "No Search Results Found", - "noRecent": "No Search History", - "recent": "Search History" - }, - "lockScreen": { - "title": "Lock Screen", - "screenButton": "Locking", - "password": "Password", - "placeholder": "Please enter password", - "unlock": "Click to unlock", - "errorPasswordTip": "Password error, please re-enter", - "backToLogin": "Back to login", - "entry": "Enter the system" - } - }, - "authentication": { - "welcomeBack": "Welcome Back", - "pageTitle": "Plug-and-play Admin system", - "pageDesc": "Efficient, versatile frontend template", - "loginSuccess": "Login Successful", - "loginSuccessDesc": "Welcome Back", - "loginSubtitle": "Enter your account details to manage your projects", - "selectAccount": "Quick Select Account", - "username": "Username", - "password": "Password", - "usernameTip": "Please enter username", - "passwordErrorTip": "Password is incorrect", - "passwordTip": "Please enter password", - "verifyRequiredTip": "Please complete the verification first", - "rememberMe": "Remember Me", - "createAnAccount": "Create an Account", - "createAccount": "Create Account", - "alreadyHaveAccount": "Already have an account?", - "accountTip": "Don't have an account?", - "signUp": "Sign Up", - "signUpSubtitle": "Make managing your applications simple and fun", - "confirmPassword": "Comfirm Password", - "confirmPasswordTip": "The passwords do not match", - "agree": "I agree to", - "privacyPolicy": "Privacy-policy", - "terms": "Terms", - "agreeTip": "Please agree to the Privacy Policy and Terms", - "goToLogin": "Login instead", - "passwordStrength": "Use 8 or more characters with a mix of letters, numbers & symbols", - "forgetPassword": "Forget Password?", - "forgetPasswordSubtitle": "Enter your email and we'll send you instructions to reset your password", - "emailTip": "Please enter email", - "emailValidErrorTip": "The email format you entered is incorrect", - "sendResetLink": "Send Reset Link", - "email": "Email", - "qrcodeSubtitle": "Scan the QR code with your phone to login", - "qrcodePrompt": "Click 'Confirm' after scanning to complete login", - "qrcodeLogin": "QR Code Login", - "codeSubtitle": "Enter your phone number to start managing your project", - "code": "Security code", - "codeTip": "Security code is required", - "mobile": "Mobile", - "mobileLogin": "Mobile Login", - "mobileTip": "Please enter mobile number", - "mobileErrortip": "The phone number format is incorrect", - "sendCode": "Get Security code", - "sendText": "Resend in {0}s", - "thirdPartyLogin": "Or continue with", - "loginAgainTitle": "Please Log In Again", - "loginAgainSubTitle": "Your login session has expired. Please log in again to continue.", - "layout": { - "center": "Align Center", - "alignLeft": "Align Left", - "alignRight": "Align Right" - } - }, - "preferences": { - "title": "Preferences", - "subtitle": "Customize Preferences & Preview in Real Time", - "resetTip": "Data has changed, click to reset", - "resetTitle": "Reset Preferences", - "resetSuccess": "Preferences reset successfully", - "appearance": "Appearance", - "layout": "Layout", - "content": "Content", - "other": "Other", - "wide": "Wide", - "compact": "Fixed", - "followSystem": "Follow System", - "vertical": "Vertical", - "verticalTip": "Side vertical menu mode", - "horizontal": "Horizontal", - "horizontalTip": "Horizontal menu mode, all menus displayed at the top", - "twoColumn": "Two Column", - "twoColumnTip": "Vertical Two Column Menu Mode", - "mixedMenu": "Mixed Menu", - "mixedMenuTip": "Vertical & Horizontal Menu Co-exists", - "fullContent": "Full Content", - "fullContentTip": "Only display content body, hide all menus", - "normal": "Normal", - "plain": "Plain", - "rounded": "Rounded", - "copyPreferences": "Copy Preferences", - "copyPreferencesSuccessTitle": "Copy successful", - "copyPreferencesSuccess": "Copy successful, please override in `src/preferences.ts` under app", - "clearAndLogout": "Clear Cache & Logout", - "mode": "Mode", - "general": "General", - "language": "Language", - "dynamicTitle": "Dynamic Title", - "watermark": "Watermark", - "checkUpdates": "Periodic update check", - "position": { - "title": "Preferences Postion", - "header": "Header", - "auto": "Auto", - "fixed": "Fixed" - }, - "sidebar": { - "title": "Sidebar", - "width": "Width", - "visible": "Show Sidebar", - "collapsed": "Collpase Menu", - "collapsedShowTitle": "Show Menu Title" - }, - "tabbar": { - "title": "Tabbar", - "enable": "Enable Tab Bar", - "icon": "Show Tabbar Icon", - "showMore": "Show More Button", - "showMaximize": "Show Maximize Button", - "persist": "Persist Tabs", - "draggable": "Enable Draggable Sort", - "styleType": { - "title": "Tabs Style", - "chrome": "Chrome", - "card": "Card", - "plain": "Plain", - "brisk": "Brisk" - }, - "contextMenu": { - "reload": "Reload", - "close": "Close", - "pin": "Pin", - "unpin": "Unpin", - "closeLeft": "Close Left Tabs", - "closeRight": "Close Right Tabs", - "closeOther": "Close Other Tabs", - "closeAll": "Close All Tabs", - "openInNewWindow": "Open in New Window", - "maximize": "Maximize", - "restoreMaximize": "Restore" - } - }, - "navigationMenu": { - "title": "Navigation Menu", - "style": "Navigation Menu Style", - "accordion": "Sidebar Accordion Menu", - "split": "Navigation Menu Separation", - "splitTip": "When enabled, the sidebar displays the top bar's submenu" - }, - "breadcrumb": { - "title": "Breadcrumb", - "home": "Show Home Button", - "enable": "Enable Breadcrumb", - "icon": "Show Breadcrumb Icon", - "background": "background", - "style": "Breadcrumb Style", - "hideOnlyOne": "Hidden when only one" - }, - "animation": { - "title": "Animation", - "loading": "Page Loading", - "transition": "Page Transition", - "progress": "Page Progress" - }, - "theme": { - "title": "Theme", - "radius": "Radius", - "light": "Light", - "dark": "Dark", - "darkSidebar": "Semi Dark Sidebar", - "darkHeader": "Semi Dark Header", - "weakMode": "Weak Mode", - "grayMode": "Gray Mode", - "builtin": { - "title": "Built-in", - "default": "Default", - "violet": "Violet", - "pink": "Pink", - "rose": "Rose", - "skyBlue": "Sky Blue", - "deepBlue": "Deep Blue", - "green": "Green", - "deepGreen": "Deep Green", - "orange": "Orange", - "yellow": "Yellow", - "zinc": "Zinc", - "neutral": "Neutral", - "slate": "Slate", - "gray": "Gray", - "custom": "Custom" - } - }, - "header": { - "title": "Header", - "visible": "Show Header", - "modeStatic": "Static", - "modeFixed": "Fixed", - "modeAuto": "Auto hide & Show", - "modeAutoScroll": "Scroll to Hide & Show" - }, - "footer": { - "title": "Footer", - "visible": "Show Footer", - "fixed": "Fixed at Bottom" - }, - "copyright": { - "title": "Copyright", - "enable": "Enable Copyright", - "companyName": "Company Name", - "companySiteLink": "Company Site Link", - "date": "Date", - "icp": "ICP License Number", - "icpLink": "ICP Site Link" - }, - "shortcutKeys": { - "title": "Shortcut Keys", - "global": "Global", - "search": "Global Search", - "logout": "Logout", - "preferences": "Preferences" - }, - "widget": { - "title": "Widget", - "globalSearch": "Enable Global Search", - "fullscreen": "Enable Fullscreen", - "themeToggle": "Enable Theme Toggle", - "languageToggle": "Enable Language Toggle", - "notification": "Enable Notification", - "sidebarToggle": "Enable Sidebar Toggle", - "lockScreen": "Enable Lock Screen", - "refresh": "Enable Refresh" - } - }, - "ui": { - "captcha": { - "title": "Please complete the security verification", - "sliderSuccessText": "Passed", - "sliderDefaultText": "Slider and drag", - "alt": "Supports img tag src attribute value", - "sliderRotateDefaultTip": "Click picture to refresh", - "sliderRotateFailTip": "Validation failed", - "sliderRotateSuccessTip": "Validation successful, time {0} seconds", - "refreshAriaLabel": "Refresh captcha", - "confirmAriaLabel": "Confirm selection", - "confirm": "Confirm", - "pointAriaLabel": "Click point", - "clickInOrder": "Please click in order" - } - } -} diff --git a/packages/locales/src/langs/en-US/authentication.json b/packages/locales/src/langs/en-US/authentication.json new file mode 100644 index 00000000..4155f871 --- /dev/null +++ b/packages/locales/src/langs/en-US/authentication.json @@ -0,0 +1,56 @@ +{ + "welcomeBack": "Welcome Back", + "pageTitle": "Plug-and-play Admin system", + "pageDesc": "Efficient, versatile frontend template", + "loginSuccess": "Login Successful", + "loginSuccessDesc": "Welcome Back", + "loginSubtitle": "Enter your account details to manage your projects", + "selectAccount": "Quick Select Account", + "username": "Username", + "password": "Password", + "usernameTip": "Please enter username", + "passwordErrorTip": "Password is incorrect", + "passwordTip": "Please enter password", + "verifyRequiredTip": "Please complete the verification first", + "rememberMe": "Remember Me", + "createAnAccount": "Create an Account", + "createAccount": "Create Account", + "alreadyHaveAccount": "Already have an account?", + "accountTip": "Don't have an account?", + "signUp": "Sign Up", + "signUpSubtitle": "Make managing your applications simple and fun", + "confirmPassword": "Confirm Password", + "confirmPasswordTip": "The passwords do not match", + "agree": "I agree to", + "privacyPolicy": "Privacy-policy", + "terms": "Terms", + "agreeTip": "Please agree to the Privacy Policy and Terms", + "goToLogin": "Login instead", + "passwordStrength": "Use 8 or more characters with a mix of letters, numbers & symbols", + "forgetPassword": "Forget Password?", + "forgetPasswordSubtitle": "Enter your email and we'll send you instructions to reset your password", + "emailTip": "Please enter email", + "emailValidErrorTip": "The email format you entered is incorrect", + "sendResetLink": "Send Reset Link", + "email": "Email", + "qrcodeSubtitle": "Scan the QR code with your phone to login", + "qrcodePrompt": "Click 'Confirm' after scanning to complete login", + "qrcodeLogin": "QR Code Login", + "codeSubtitle": "Enter your phone number to start managing your project", + "code": "Security code", + "codeTip": "Security code is required", + "mobile": "Mobile", + "mobileLogin": "Mobile Login", + "mobileTip": "Please enter mobile number", + "mobileErrortip": "The phone number format is incorrect", + "sendCode": "Get Security code", + "sendText": "Resend in {0}s", + "thirdPartyLogin": "Or continue with", + "loginAgainTitle": "Please Log In Again", + "loginAgainSubTitle": "Your login session has expired. Please log in again to continue.", + "layout": { + "center": "Align Center", + "alignLeft": "Align Left", + "alignRight": "Align Right" + } +} diff --git a/packages/locales/src/langs/en-US/common.json b/packages/locales/src/langs/en-US/common.json new file mode 100644 index 00000000..23308b77 --- /dev/null +++ b/packages/locales/src/langs/en-US/common.json @@ -0,0 +1,13 @@ +{ + "back": "Back", + "backToHome": "Back To Home", + "login": "Login", + "logout": "Logout", + "prompt": "Prompt", + "cancel": "Cancel", + "confirm": "Confirm", + "noData": "No Data", + "refresh": "Refresh", + "loadingMenu": "Loading Menu", + "query": "Search" +} diff --git a/packages/locales/src/langs/en-US/preferences.json b/packages/locales/src/langs/en-US/preferences.json new file mode 100644 index 00000000..8ba3cce6 --- /dev/null +++ b/packages/locales/src/langs/en-US/preferences.json @@ -0,0 +1,169 @@ +{ + "title": "Preferences", + "subtitle": "Customize Preferences & Preview in Real Time", + "resetTip": "Data has changed, click to reset", + "resetTitle": "Reset Preferences", + "resetSuccess": "Preferences reset successfully", + "appearance": "Appearance", + "layout": "Layout", + "content": "Content", + "other": "Other", + "wide": "Wide", + "compact": "Fixed", + "followSystem": "Follow System", + "vertical": "Vertical", + "verticalTip": "Side vertical menu mode", + "horizontal": "Horizontal", + "horizontalTip": "Horizontal menu mode, all menus displayed at the top", + "twoColumn": "Two Column", + "twoColumnTip": "Vertical Two Column Menu Mode", + "mixedMenu": "Mixed Menu", + "mixedMenuTip": "Vertical & Horizontal Menu Co-exists", + "fullContent": "Full Content", + "fullContentTip": "Only display content body, hide all menus", + "normal": "Normal", + "plain": "Plain", + "rounded": "Rounded", + "copyPreferences": "Copy Preferences", + "copyPreferencesSuccessTitle": "Copy successful", + "copyPreferencesSuccess": "Copy successful, please override in `src/preferences.ts` under app", + "clearAndLogout": "Clear Cache & Logout", + "mode": "Mode", + "general": "General", + "language": "Language", + "dynamicTitle": "Dynamic Title", + "watermark": "Watermark", + "checkUpdates": "Periodic update check", + "position": { + "title": "Preferences Postion", + "header": "Header", + "auto": "Auto", + "fixed": "Fixed" + }, + "sidebar": { + "title": "Sidebar", + "width": "Width", + "visible": "Show Sidebar", + "collapsed": "Collpase Menu", + "collapsedShowTitle": "Show Menu Title" + }, + "tabbar": { + "title": "Tabbar", + "enable": "Enable Tab Bar", + "icon": "Show Tabbar Icon", + "showMore": "Show More Button", + "showMaximize": "Show Maximize Button", + "persist": "Persist Tabs", + "draggable": "Enable Draggable Sort", + "styleType": { + "title": "Tabs Style", + "chrome": "Chrome", + "card": "Card", + "plain": "Plain", + "brisk": "Brisk" + }, + "contextMenu": { + "reload": "Reload", + "close": "Close", + "pin": "Pin", + "unpin": "Unpin", + "closeLeft": "Close Left Tabs", + "closeRight": "Close Right Tabs", + "closeOther": "Close Other Tabs", + "closeAll": "Close All Tabs", + "openInNewWindow": "Open in New Window", + "maximize": "Maximize", + "restoreMaximize": "Restore" + } + }, + "navigationMenu": { + "title": "Navigation Menu", + "style": "Navigation Menu Style", + "accordion": "Sidebar Accordion Menu", + "split": "Navigation Menu Separation", + "splitTip": "When enabled, the sidebar displays the top bar's submenu" + }, + "breadcrumb": { + "title": "Breadcrumb", + "home": "Show Home Button", + "enable": "Enable Breadcrumb", + "icon": "Show Breadcrumb Icon", + "background": "background", + "style": "Breadcrumb Style", + "hideOnlyOne": "Hidden when only one" + }, + "animation": { + "title": "Animation", + "loading": "Page Loading", + "transition": "Page Transition", + "progress": "Page Progress" + }, + "theme": { + "title": "Theme", + "radius": "Radius", + "light": "Light", + "dark": "Dark", + "darkSidebar": "Semi Dark Sidebar", + "darkHeader": "Semi Dark Header", + "weakMode": "Weak Mode", + "grayMode": "Gray Mode", + "builtin": { + "title": "Built-in", + "default": "Default", + "violet": "Violet", + "pink": "Pink", + "rose": "Rose", + "skyBlue": "Sky Blue", + "deepBlue": "Deep Blue", + "green": "Green", + "deepGreen": "Deep Green", + "orange": "Orange", + "yellow": "Yellow", + "zinc": "Zinc", + "neutral": "Neutral", + "slate": "Slate", + "gray": "Gray", + "custom": "Custom" + } + }, + "header": { + "title": "Header", + "visible": "Show Header", + "modeStatic": "Static", + "modeFixed": "Fixed", + "modeAuto": "Auto hide & Show", + "modeAutoScroll": "Scroll to Hide & Show" + }, + "footer": { + "title": "Footer", + "visible": "Show Footer", + "fixed": "Fixed at Bottom" + }, + "copyright": { + "title": "Copyright", + "enable": "Enable Copyright", + "companyName": "Company Name", + "companySiteLink": "Company Site Link", + "date": "Date", + "icp": "ICP License Number", + "icpLink": "ICP Site Link" + }, + "shortcutKeys": { + "title": "Shortcut Keys", + "global": "Global", + "search": "Global Search", + "logout": "Logout", + "preferences": "Preferences" + }, + "widget": { + "title": "Widget", + "globalSearch": "Enable Global Search", + "fullscreen": "Enable Fullscreen", + "themeToggle": "Enable Theme Toggle", + "languageToggle": "Enable Language Toggle", + "notification": "Enable Notification", + "sidebarToggle": "Enable Sidebar Toggle", + "lockScreen": "Enable Lock Screen", + "refresh": "Enable Refresh" + } +} diff --git a/packages/locales/src/langs/en-US/ui.json b/packages/locales/src/langs/en-US/ui.json new file mode 100644 index 00000000..dc99c2f7 --- /dev/null +++ b/packages/locales/src/langs/en-US/ui.json @@ -0,0 +1,77 @@ +{ + "formRules": { + "required": "Please enter {0}", + "selectRequired": "Please select {0}" + }, + "placeholder": { + "input": "Please enter", + "select": "Please select" + }, + "captcha": { + "title": "Please complete the security verification", + "sliderSuccessText": "Passed", + "sliderDefaultText": "Slider and drag", + "alt": "Supports img tag src attribute value", + "sliderRotateDefaultTip": "Click picture to refresh", + "sliderRotateFailTip": "Validation failed", + "sliderRotateSuccessTip": "Validation successful, time {0} seconds", + "refreshAriaLabel": "Refresh captcha", + "confirmAriaLabel": "Confirm selection", + "confirm": "Confirm", + "pointAriaLabel": "Click point", + "clickInOrder": "Please click in order" + }, + "fallback": { + "pageNotFound": "Oops! Page Not Found", + "pageNotFoundDesc": "Sorry, we couldn't find the page you were looking for.", + "forbidden": "Oops! Access Denied", + "forbiddenDesc": "Sorry, but you don't have permission to access this page.", + "internalError": "Oops! Something Went Wrong", + "internalErrorDesc": "Sorry, but the server encountered an error.", + "offline": "Offline Page", + "offlineError": "Oops! Network Error", + "offlineErrorDesc": "Sorry, can't connect to the internet. Check your connection.", + "comingSoon": "Coming Soon", + "http": { + "requestTimeout": "The request timed out. Please try again later.", + "networkError": "A network error occurred. Please check your internet connection and try again.", + "badRequest": "Bad Request. Please check your input and try again.", + "unauthorized": "Unauthorized. Please log in to continue.", + "forbidden": "Forbidden. You do not have permission to access this resource.", + "notFound": "Not Found. The requested resource could not be found.", + "internalServerError": "Internal Server Error. Something went wrong on our end. Please try again later." + } + }, + "widgets": { + "document": "Document", + "qa": "Q&A", + "setting": "Settings", + "logoutTip": "Do you want to logout?", + "viewAll": "View All Messages", + "notifications": "Notifications", + "markAllAsRead": "Make All as Read", + "clearNotifications": "Clear", + "checkUpdatesTitle": "New Version Available", + "checkUpdatesDescription": "Click to refresh and get the latest version", + "search": { + "title": "Search", + "searchNavigate": "Search Navigation", + "select": "Select", + "navigate": "Navigate", + "close": "Close", + "noResults": "No Search Results Found", + "noRecent": "No Search History", + "recent": "Search History" + }, + "lockScreen": { + "title": "Lock Screen", + "screenButton": "Locking", + "password": "Password", + "placeholder": "Please enter password", + "unlock": "Click to unlock", + "errorPasswordTip": "Password error, please re-enter", + "backToLogin": "Back to login", + "entry": "Enter the system" + } + } +} diff --git a/packages/locales/src/langs/zh-CN.json b/packages/locales/src/langs/zh-CN.json deleted file mode 100644 index 0fa5981a..00000000 --- a/packages/locales/src/langs/zh-CN.json +++ /dev/null @@ -1,339 +0,0 @@ -{ - "page": { - "core": { - "login": "登陆", - "register": "注册", - "codeLogin": "验证码登陆", - "qrcodeLogin": "二维码登陆", - "forgetPassword": "忘记密码" - }, - "dashboard": { - "title": "概览", - "analytics": "分析页", - "workspace": "工作台" - }, - "vben": { - "title": "项目", - "about": "关于", - "document": "文档", - "antdv": "Ant Design Vue 版本", - "naive-ui": "Naive UI 版本", - "element-plus": "Element Plus 版本" - } - }, - "common": { - "back": "返回", - "backToHome": "返回首页", - "login": "登录", - "logout": "退出登录", - "prompt": "提示", - "cancel": "取消", - "confirm": "确认", - "noData": "暂无数据", - "refresh": "刷新", - "loadingMenu": "加载菜单中", - "query": "查询" - }, - "fallback": { - "pageNotFound": "哎呀!未找到页面", - "pageNotFoundDesc": "抱歉,我们无法找到您要找的页面。", - "forbidden": "哎呀!访问被拒绝", - "forbiddenDesc": "抱歉,您没有权限访问此页面。", - "internalError": "哎呀!出错了", - "internalErrorDesc": "抱歉,服务器遇到错误。", - "offline": "离线页面", - "offlineError": "哎呀!网络错误", - "offlineErrorDesc": "抱歉,无法连接到互联网,请检查您的网络连接并重试。", - "comingSoon": "即将推出", - "http": { - "requestTimeout": "请求超时,请稍后再试。", - "networkError": "网络异常,请检查您的网络连接后重试。", - "badRequest": "请求错误。请检查您的输入并重试。", - "unauthorized": "登录认证过期,请重新登录后继续。", - "forbidden": "禁止访问, 您没有权限访问此资源。", - "notFound": "未找到, 请求的资源不存在。", - "internalServerError": "内部服务器错误,请稍后再试。" - } - }, - "formRules": { - "required": "请输入{0}", - "selectRequired": "请选择{0}" - }, - "placeholder": { - "input": "请输入", - "select": "请选择" - }, - "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": "进入系统" - } - }, - "authentication": { - "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": "扫码登录", - "codeSubtitle": "请输入您的手机号码以开始管理您的项目", - "code": "验证码", - "codeTip": "请输入验证码", - "mobile": "手机号码", - "mobileTip": "请输入手机号", - "mobileErrortip": "手机号码格式错误", - "mobileLogin": "手机号登录", - "sendCode": "获取验证码", - "sendText": "{0}秒后重新获取", - "thirdPartyLogin": "其他登录方式", - "loginAgainTitle": "重新登录", - "loginAgainSubTitle": "您的登录状态已过期,请重新登录以继续。", - "layout": { - "center": "居中", - "alignLeft": "居左", - "alignRight": "居右" - } - }, - "preferences": { - "title": "偏好设置", - "subtitle": "自定义偏好设置 & 实时预览", - "resetTitle": "重置偏好设置", - "resetTip": "数据有变化,点击可进行重置", - "resetSuccess": "重置偏好设置成功", - "appearance": "外观", - "layout": "布局", - "content": "内容", - "other": "其它", - "wide": "流式", - "compact": "定宽", - "followSystem": "跟随系统", - "vertical": "垂直", - "verticalTip": "侧边垂直菜单模式", - "horizontal": "水平", - "horizontalTip": "水平菜单模式,菜单全部显示在顶部", - "twoColumn": "双列菜单", - "twoColumnTip": "垂直双列菜单模式", - "mixedMenu": "混合菜单", - "mixedMenuTip": "垂直水平菜单共存", - "fullContent": "内容全屏", - "fullContentTip": "不显示任何菜单,只显示内容主体", - "normal": "常规", - "plain": "朴素", - "rounded": "圆润", - "copyPreferences": "复制偏好设置", - "copyPreferencesSuccessTitle": "复制成功", - "copyPreferencesSuccess": "复制成功,请在 app 下的 `src/preferences.ts`内进行覆盖", - "clearAndLogout": "清空缓存 & 退出登录", - "mode": "模式", - "general": "通用", - "language": "语言", - "dynamicTitle": "动态标题", - "watermark": "水印", - "checkUpdates": "定时检查更新", - "position": { - "title": "偏好设置位置", - "header": "顶栏", - "auto": "自动", - "fixed": "固定" - }, - "sidebar": { - "title": "侧边栏", - "width": "宽度", - "visible": "显示侧边栏", - "collapsed": "折叠菜单", - "collapsedShowTitle": "折叠显示菜单名" - }, - "tabbar": { - "title": "标签栏", - "enable": "启用标签栏", - "icon": "显示标签栏图标", - "showMore": "显示更多按钮", - "showMaximize": "显示最大化按钮", - "persist": "持久化标签页", - "draggable": "启动拖拽排序", - "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": "圆角", - "light": "浅色", - "dark": "深色", - "darkSidebar": "深色侧边栏", - "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": "显示顶栏" - }, - "footer": { - "title": "底栏", - "visible": "显示底栏", - "fixed": "固定在底部" - }, - "copyright": { - "title": "版权", - "enable": "启用版权", - "companyName": "公司名", - "companySiteLink": "公司主页", - "date": "日期", - "icp": "ICP 备案号", - "icpLink": "ICP 网站链接" - }, - "shortcutKeys": { - "title": "快捷键", - "global": "全局", - "search": "全局搜索", - "logout": "退出登录", - "preferences": "偏好设置" - }, - "widget": { - "title": "小部件", - "globalSearch": "启用全局搜索", - "fullscreen": "启用全屏", - "themeToggle": "启用主题切换", - "languageToggle": "启用语言切换", - "notification": "启用通知", - "sidebarToggle": "启用侧边栏切换", - "lockScreen": "启用锁屏", - "refresh": "启用刷新" - } - }, - "ui": { - "captcha": { - "title": "请完成安全验证", - "sliderSuccessText": "验证通过", - "sliderDefaultText": "请按住滑块拖动", - "sliderRotateDefaultTip": "点击图片可刷新", - "sliderRotateFailTip": "验证失败", - "sliderRotateSuccessTip": "验证成功,耗时{0}秒", - "alt": "支持img标签src属性值", - "refreshAriaLabel": "刷新验证码", - "confirmAriaLabel": "确认选择", - "confirm": "确认", - "pointAriaLabel": "点击点", - "clickInOrder": "请依次点击" - } - } -} diff --git a/packages/locales/src/langs/zh-CN/authentication.json b/packages/locales/src/langs/zh-CN/authentication.json new file mode 100644 index 00000000..4533db87 --- /dev/null +++ b/packages/locales/src/langs/zh-CN/authentication.json @@ -0,0 +1,56 @@ +{ + "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": "扫码登录", + "codeSubtitle": "请输入您的手机号码以开始管理您的项目", + "code": "验证码", + "codeTip": "请输入验证码", + "mobile": "手机号码", + "mobileTip": "请输入手机号", + "mobileErrortip": "手机号码格式错误", + "mobileLogin": "手机号登录", + "sendCode": "获取验证码", + "sendText": "{0}秒后重新获取", + "thirdPartyLogin": "其他登录方式", + "loginAgainTitle": "重新登录", + "loginAgainSubTitle": "您的登录状态已过期,请重新登录以继续。", + "layout": { + "center": "居中", + "alignLeft": "居左", + "alignRight": "居右" + } +} diff --git a/packages/locales/src/langs/zh-CN/common.json b/packages/locales/src/langs/zh-CN/common.json new file mode 100644 index 00000000..fdfc6e49 --- /dev/null +++ b/packages/locales/src/langs/zh-CN/common.json @@ -0,0 +1,13 @@ +{ + "back": "返回", + "backToHome": "返回首页", + "login": "登录", + "logout": "退出登录", + "prompt": "提示", + "cancel": "取消", + "confirm": "确认", + "noData": "暂无数据", + "refresh": "刷新", + "loadingMenu": "加载菜单中", + "query": "查询" +} diff --git a/packages/locales/src/langs/zh-CN/preferences.json b/packages/locales/src/langs/zh-CN/preferences.json new file mode 100644 index 00000000..8f5038ee --- /dev/null +++ b/packages/locales/src/langs/zh-CN/preferences.json @@ -0,0 +1,169 @@ +{ + "title": "偏好设置", + "subtitle": "自定义偏好设置 & 实时预览", + "resetTitle": "重置偏好设置", + "resetTip": "数据有变化,点击可进行重置", + "resetSuccess": "重置偏好设置成功", + "appearance": "外观", + "layout": "布局", + "content": "内容", + "other": "其它", + "wide": "流式", + "compact": "定宽", + "followSystem": "跟随系统", + "vertical": "垂直", + "verticalTip": "侧边垂直菜单模式", + "horizontal": "水平", + "horizontalTip": "水平菜单模式,菜单全部显示在顶部", + "twoColumn": "双列菜单", + "twoColumnTip": "垂直双列菜单模式", + "mixedMenu": "混合菜单", + "mixedMenuTip": "垂直水平菜单共存", + "fullContent": "内容全屏", + "fullContentTip": "不显示任何菜单,只显示内容主体", + "normal": "常规", + "plain": "朴素", + "rounded": "圆润", + "copyPreferences": "复制偏好设置", + "copyPreferencesSuccessTitle": "复制成功", + "copyPreferencesSuccess": "复制成功,请在 app 下的 `src/preferences.ts`内进行覆盖", + "clearAndLogout": "清空缓存 & 退出登录", + "mode": "模式", + "general": "通用", + "language": "语言", + "dynamicTitle": "动态标题", + "watermark": "水印", + "checkUpdates": "定时检查更新", + "position": { + "title": "偏好设置位置", + "header": "顶栏", + "auto": "自动", + "fixed": "固定" + }, + "sidebar": { + "title": "侧边栏", + "width": "宽度", + "visible": "显示侧边栏", + "collapsed": "折叠菜单", + "collapsedShowTitle": "折叠显示菜单名" + }, + "tabbar": { + "title": "标签栏", + "enable": "启用标签栏", + "icon": "显示标签栏图标", + "showMore": "显示更多按钮", + "showMaximize": "显示最大化按钮", + "persist": "持久化标签页", + "draggable": "启动拖拽排序", + "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": "圆角", + "light": "浅色", + "dark": "深色", + "darkSidebar": "深色侧边栏", + "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": "显示顶栏" + }, + "footer": { + "title": "底栏", + "visible": "显示底栏", + "fixed": "固定在底部" + }, + "copyright": { + "title": "版权", + "enable": "启用版权", + "companyName": "公司名", + "companySiteLink": "公司主页", + "date": "日期", + "icp": "ICP 备案号", + "icpLink": "ICP 网站链接" + }, + "shortcutKeys": { + "title": "快捷键", + "global": "全局", + "search": "全局搜索", + "logout": "退出登录", + "preferences": "偏好设置" + }, + "widget": { + "title": "小部件", + "globalSearch": "启用全局搜索", + "fullscreen": "启用全屏", + "themeToggle": "启用主题切换", + "languageToggle": "启用语言切换", + "notification": "启用通知", + "sidebarToggle": "启用侧边栏切换", + "lockScreen": "启用锁屏", + "refresh": "启用刷新" + } +} diff --git a/packages/locales/src/langs/zh-CN/ui.json b/packages/locales/src/langs/zh-CN/ui.json new file mode 100644 index 00000000..e84c0ba5 --- /dev/null +++ b/packages/locales/src/langs/zh-CN/ui.json @@ -0,0 +1,77 @@ +{ + "formRules": { + "required": "请输入{0}", + "selectRequired": "请选择{0}" + }, + "placeholder": { + "input": "请输入", + "select": "请选择" + }, + "captcha": { + "title": "请完成安全验证", + "sliderSuccessText": "验证通过", + "sliderDefaultText": "请按住滑块拖动", + "sliderRotateDefaultTip": "点击图片可刷新", + "sliderRotateFailTip": "验证失败", + "sliderRotateSuccessTip": "验证成功,耗时{0}秒", + "alt": "支持img标签src属性值", + "refreshAriaLabel": "刷新验证码", + "confirmAriaLabel": "确认选择", + "confirm": "确认", + "pointAriaLabel": "点击点", + "clickInOrder": "请依次点击" + }, + "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": "进入系统" + } + } +} diff --git a/playground/src/adapter/component/index.ts b/playground/src/adapter/component/index.ts index 12849dc3..1afa6217 100644 --- a/playground/src/adapter/component/index.ts +++ b/playground/src/adapter/component/index.ts @@ -41,7 +41,7 @@ const withDefaultPlaceholder = ( type: 'input' | 'select', ) => { return (props: any, { attrs, slots }: Omit) => { - const placeholder = props?.placeholder || $t(`placeholder.${type}`); + const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`); return h(component, { ...props, ...attrs, placeholder }, slots); }; }; diff --git a/playground/src/adapter/form.ts b/playground/src/adapter/form.ts index 2bc7777d..dfe8fed0 100644 --- a/playground/src/adapter/form.ts +++ b/playground/src/adapter/form.ts @@ -24,14 +24,14 @@ setupVbenForm({ // 输入项目必填国际化适配 required: (value, _params, ctx) => { if (value === undefined || value === null || value.length === 0) { - return $t('formRules.required', [ctx.label]); + return $t('ui.formRules.required', [ctx.label]); } return true; }, // 选择项目必填国际化适配 selectRequired: (value, _params, ctx) => { if (value === undefined || value === null) { - return $t('formRules.selectRequired', [ctx.label]); + return $t('ui.formRules.selectRequired', [ctx.label]); } return true; }, diff --git a/playground/src/layouts/basic.vue b/playground/src/layouts/basic.vue index bd0cbca0..f75b3ddc 100644 --- a/playground/src/layouts/basic.vue +++ b/playground/src/layouts/basic.vue @@ -68,7 +68,7 @@ const menus = computed(() => [ }); }, icon: BookOpenText, - text: $t('widgets.document'), + text: $t('ui.widgets.document'), }, { handler: () => { @@ -86,7 +86,7 @@ const menus = computed(() => [ }); }, icon: CircleHelp, - text: $t('widgets.qa'), + text: $t('ui.widgets.qa'), }, ]); diff --git a/playground/src/locales/index.ts b/playground/src/locales/index.ts index af8c01d2..1972e06e 100644 --- a/playground/src/locales/index.ts +++ b/playground/src/locales/index.ts @@ -4,7 +4,11 @@ import type { Locale } from 'ant-design-vue/es/locale'; import type { App } from 'vue'; import { ref } from 'vue'; -import { $t, setupI18n as coreSetup, loadLocalesMap } from '@vben/locales'; +import { + $t, + setupI18n as coreSetup, + loadLocalesMapFromDir, +} from '@vben/locales'; import { preferences } from '@vben/preferences'; import antdEnLocale from 'ant-design-vue/es/locale/en_US'; @@ -13,10 +17,12 @@ import dayjs from 'dayjs'; const antdLocale = ref(antdDefaultLocale); -const modules = import.meta.glob('./langs/*.json'); - -const localesMap = loadLocalesMap(modules); +const modules = import.meta.glob('./langs/**/*.json'); +const localesMap = loadLocalesMapFromDir( + /\.\/langs\/([^/]+)\/(.*)\.json$/, + modules, +); /** * 加载应用特有的语言包 * 这里也可以改造为从服务端获取翻译数据 diff --git a/playground/src/locales/langs/en-US.json b/playground/src/locales/langs/en-US.json deleted file mode 100644 index 0d3cf57d..00000000 --- a/playground/src/locales/langs/en-US.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "page": { - "demos": { - "title": "Demos", - "access": { - "frontendPermissions": "Frontend Permissions", - "backendPermissions": "Backend Permissions", - "pageAccess": "Page Access", - "buttonControl": "Button Control", - "menuVisible403": "Menu Visible(403)", - "superVisible": "Visible to Super", - "adminVisible": "Visible to Admin", - "userVisible": "Visible to User" - }, - "nested": { - "title": "Nested Menu", - "menu1": "Menu 1", - "menu2": "Menu 2", - "menu2_1": "Menu 2-1", - "menu3": "Menu 3", - "menu3_1": "Menu 3-1", - "menu3_2": "Menu 3-2", - "menu3_2_1": "Menu 3-2-1" - }, - "outside": { - "title": "External Pages", - "embedded": "Embedded", - "externalLink": "External Link" - }, - "badge": { - "title": "Menu Badge", - "dot": "Dot Badge", - "text": "Text Badge", - "color": "Badge Color" - }, - "activeIcon": { - "title": "Active Menu Icon", - "children": "Children Active Icon" - }, - "fallback": { - "title": "Fallback Page" - }, - "features": { - "title": "Features", - "hideChildrenInMenu": "Hide Menu Children", - "loginExpired": "Login Expired", - "icons": "Icons", - "watermark": "Watermark", - "tabs": "Tabs", - "tabDetail": "Tab Detail Page", - "fullScreen": { - "title": "FullScreen" - }, - "clipboard": "Clipboard" - }, - "breadcrumb": { - "navigation": "Breadcrumb Navigation", - "lateral": "Lateral Mode", - "lateralDetail": "Lateral Mode Detail", - "level": "Level Mode", - "levelDetail": "Level Mode Detail" - } - }, - "examples": { - "title": "Examples", - "modal": { - "title": "Modal" - }, - "drawer": { - "title": "Drawer" - }, - "ellipsis": { - "title": "EllipsisText" - }, - "form": { - "title": "Form", - "basic": "Basic Form", - "query": "Query Form", - "rules": "Form Rules", - "dynamic": "Dynamic Form", - "custom": "Custom Component", - "api": "Api", - "merge": "Merge Form" - }, - "vxeTable": { - "title": "Vxe Table", - "basic": "Basic Table", - "remote": "Remote Load", - "tree": "Tree Table", - "fixed": "Fixed Header/Column", - "virtual": "Virtual Scroll", - "editCell": "Edit Cell", - "editRow": "Edit Row", - "custom-cell": "Custom Cell", - "form": "Form Table" - }, - "captcha": { - "title": "Captcha", - "pointSelection": "Point Selection Captcha", - "sliderCaptcha": "Slider Captcha", - "sliderRotateCaptcha": "Rotate Captcha", - "captchaCardTitle": "Please complete the security verification", - "pageDescription": "Verify user identity by clicking on specific locations in the image.", - "pageTitle": "Captcha Component Example", - "basic": "Basic Usage", - "titlePlaceholder": "Captcha Title Text", - "captchaImageUrlPlaceholder": "Captcha Image (supports img tag src attribute value)", - "hintImage": "Hint Image", - "hintText": "Hint Text", - "hintImagePlaceholder": "Hint Image (supports img tag src attribute value)", - "hintTextPlaceholder": "Hint Text", - "showConfirm": "Show Confirm", - "hideConfirm": "Hide Confirm", - "widthPlaceholder": "Captcha Image Width Default 300px", - "heightPlaceholder": "Captcha Image Height Default 220px", - "paddingXPlaceholder": "Horizontal Padding Default 12px", - "paddingYPlaceholder": "Vertical Padding Default 16px", - "index": "Index:", - "timestamp": "Timestamp:", - "x": "x:", - "y": "y:" - } - } - } -} diff --git a/playground/src/locales/langs/en-US/demos.json b/playground/src/locales/langs/en-US/demos.json new file mode 100644 index 00000000..d2d7d34d --- /dev/null +++ b/playground/src/locales/langs/en-US/demos.json @@ -0,0 +1,69 @@ +{ + "title": "Demos", + "access": { + "frontendPermissions": "Frontend Permissions", + "backendPermissions": "Backend Permissions", + "pageAccess": "Page Access", + "buttonControl": "Button Control", + "menuVisible403": "Menu Visible(403)", + "superVisible": "Visible to Super", + "adminVisible": "Visible to Admin", + "userVisible": "Visible to User" + }, + "nested": { + "title": "Nested Menu", + "menu1": "Menu 1", + "menu2": "Menu 2", + "menu2_1": "Menu 2-1", + "menu3": "Menu 3", + "menu3_1": "Menu 3-1", + "menu3_2": "Menu 3-2", + "menu3_2_1": "Menu 3-2-1" + }, + "outside": { + "title": "External Pages", + "embedded": "Embedded", + "externalLink": "External Link" + }, + "badge": { + "title": "Menu Badge", + "dot": "Dot Badge", + "text": "Text Badge", + "color": "Badge Color" + }, + "activeIcon": { + "title": "Active Menu Icon", + "children": "Children Active Icon" + }, + "fallback": { + "title": "Fallback Page" + }, + "features": { + "title": "Features", + "hideChildrenInMenu": "Hide Menu Children", + "loginExpired": "Login Expired", + "icons": "Icons", + "watermark": "Watermark", + "tabs": "Tabs", + "tabDetail": "Tab Detail Page", + "fullScreen": { + "title": "FullScreen" + }, + "clipboard": "Clipboard" + }, + "breadcrumb": { + "navigation": "Breadcrumb Navigation", + "lateral": "Lateral Mode", + "lateralDetail": "Lateral Mode Detail", + "level": "Level Mode", + "levelDetail": "Level Mode Detail" + }, + "vben": { + "title": "Project", + "about": "About", + "document": "Document", + "antdv": "Ant Design Vue Version", + "naive-ui": "Naive UI Version", + "element-plus": "Element Plus Version" + } +} diff --git a/playground/src/locales/langs/en-US/examples.json b/playground/src/locales/langs/en-US/examples.json new file mode 100644 index 00000000..490a17a3 --- /dev/null +++ b/playground/src/locales/langs/en-US/examples.json @@ -0,0 +1,60 @@ +{ + "title": "Examples", + "modal": { + "title": "Modal" + }, + "drawer": { + "title": "Drawer" + }, + "ellipsis": { + "title": "EllipsisText" + }, + "form": { + "title": "Form", + "basic": "Basic Form", + "query": "Query Form", + "rules": "Form Rules", + "dynamic": "Dynamic Form", + "custom": "Custom Component", + "api": "Api", + "merge": "Merge Form" + }, + "vxeTable": { + "title": "Vxe Table", + "basic": "Basic Table", + "remote": "Remote Load", + "tree": "Tree Table", + "fixed": "Fixed Header/Column", + "virtual": "Virtual Scroll", + "editCell": "Edit Cell", + "editRow": "Edit Row", + "custom-cell": "Custom Cell", + "form": "Form Table" + }, + "captcha": { + "title": "Captcha", + "pointSelection": "Point Selection Captcha", + "sliderCaptcha": "Slider Captcha", + "sliderRotateCaptcha": "Rotate Captcha", + "captchaCardTitle": "Please complete the security verification", + "pageDescription": "Verify user identity by clicking on specific locations in the image.", + "pageTitle": "Captcha Component Example", + "basic": "Basic Usage", + "titlePlaceholder": "Captcha Title Text", + "captchaImageUrlPlaceholder": "Captcha Image (supports img tag src attribute value)", + "hintImage": "Hint Image", + "hintText": "Hint Text", + "hintImagePlaceholder": "Hint Image (supports img tag src attribute value)", + "hintTextPlaceholder": "Hint Text", + "showConfirm": "Show Confirm", + "hideConfirm": "Hide Confirm", + "widthPlaceholder": "Captcha Image Width Default 300px", + "heightPlaceholder": "Captcha Image Height Default 220px", + "paddingXPlaceholder": "Horizontal Padding Default 12px", + "paddingYPlaceholder": "Vertical Padding Default 16px", + "index": "Index:", + "timestamp": "Timestamp:", + "x": "x:", + "y": "y:" + } +} diff --git a/playground/src/locales/langs/en-US/page.json b/playground/src/locales/langs/en-US/page.json new file mode 100644 index 00000000..618a258c --- /dev/null +++ b/playground/src/locales/langs/en-US/page.json @@ -0,0 +1,14 @@ +{ + "auth": { + "login": "Login", + "register": "Register", + "codeLogin": "Code Login", + "qrcodeLogin": "Qr Code Login", + "forgetPassword": "Forget Password" + }, + "dashboard": { + "title": "Dashboard", + "analytics": "Analytics", + "workspace": "Workspace" + } +} diff --git a/playground/src/locales/langs/zh-CN.json b/playground/src/locales/langs/zh-CN.json deleted file mode 100644 index 727d6262..00000000 --- a/playground/src/locales/langs/zh-CN.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "page": { - "demos": { - "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": "水印", - "tabs": "标签页", - "tabDetail": "标签详情页", - "fullScreen": { - "title": "全屏" - }, - "clipboard": "剪贴板" - }, - "breadcrumb": { - "navigation": "面包屑导航", - "lateral": "平级模式", - "level": "层级模式", - "levelDetail": "层级模式详情", - "lateralDetail": "平级模式详情" - } - }, - "examples": { - "title": "示例", - "modal": { - "title": "弹窗" - }, - "drawer": { - "title": "抽屉" - }, - "ellipsis": { - "title": "文本省略" - }, - "form": { - "title": "表单", - "basic": "基础表单", - "query": "查询表单", - "rules": "表单校验", - "dynamic": "动态表单", - "custom": "自定义组件", - "api": "Api", - "merge": "合并表单" - }, - "vxeTable": { - "title": "Vxe 表格", - "basic": "基础表格", - "remote": "远程加载", - "tree": "树形表格", - "fixed": "固定表头/列", - "virtual": "虚拟滚动", - "editCell": "单元格编辑", - "editRow": "行编辑", - "custom-cell": "自定义单元格", - "form": "搜索表单" - }, - "captcha": { - "title": "验证码", - "pointSelection": "点选验证", - "sliderCaptcha": "滑块验证", - "sliderRotateCaptcha": "旋转验证", - "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:" - } - } - } -} diff --git a/playground/src/locales/langs/zh-CN/demos.json b/playground/src/locales/langs/zh-CN/demos.json new file mode 100644 index 00000000..9bcf3042 --- /dev/null +++ b/playground/src/locales/langs/zh-CN/demos.json @@ -0,0 +1,69 @@ +{ + "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": "水印", + "tabs": "标签页", + "tabDetail": "标签详情页", + "fullScreen": { + "title": "全屏" + }, + "clipboard": "剪贴板" + }, + "breadcrumb": { + "navigation": "面包屑导航", + "lateral": "平级模式", + "level": "层级模式", + "levelDetail": "层级模式详情", + "lateralDetail": "平级模式详情" + }, + "vben": { + "title": "项目", + "about": "关于", + "document": "文档", + "antdv": "Ant Design Vue 版本", + "naive-ui": "Naive UI 版本", + "element-plus": "Element Plus 版本" + } +} diff --git a/playground/src/locales/langs/zh-CN/examples.json b/playground/src/locales/langs/zh-CN/examples.json new file mode 100644 index 00000000..5a6c1a27 --- /dev/null +++ b/playground/src/locales/langs/zh-CN/examples.json @@ -0,0 +1,60 @@ +{ + "title": "示例", + "modal": { + "title": "弹窗" + }, + "drawer": { + "title": "抽屉" + }, + "ellipsis": { + "title": "文本省略" + }, + "form": { + "title": "表单", + "basic": "基础表单", + "query": "查询表单", + "rules": "表单校验", + "dynamic": "动态表单", + "custom": "自定义组件", + "api": "Api", + "merge": "合并表单" + }, + "vxeTable": { + "title": "Vxe 表格", + "basic": "基础表格", + "remote": "远程加载", + "tree": "树形表格", + "fixed": "固定表头/列", + "virtual": "虚拟滚动", + "editCell": "单元格编辑", + "editRow": "行编辑", + "custom-cell": "自定义单元格", + "form": "搜索表单" + }, + "captcha": { + "title": "验证码", + "pointSelection": "点选验证", + "sliderCaptcha": "滑块验证", + "sliderRotateCaptcha": "旋转验证", + "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:" + } +} diff --git a/playground/src/locales/langs/zh-CN/page.json b/playground/src/locales/langs/zh-CN/page.json new file mode 100644 index 00000000..85fa1597 --- /dev/null +++ b/playground/src/locales/langs/zh-CN/page.json @@ -0,0 +1,14 @@ +{ + "auth": { + "login": "登陆", + "register": "注册", + "codeLogin": "验证码登陆", + "qrcodeLogin": "二维码登陆", + "forgetPassword": "忘记密码" + }, + "dashboard": { + "title": "概览", + "analytics": "分析页", + "workspace": "工作台" + } +} diff --git a/playground/src/router/routes/core.ts b/playground/src/router/routes/core.ts index d85de5a4..059fca62 100644 --- a/playground/src/router/routes/core.ts +++ b/playground/src/router/routes/core.ts @@ -43,7 +43,7 @@ const coreRoutes: RouteRecordRaw[] = [ path: 'login', component: Login, meta: { - title: $t('page.core.login'), + title: $t('page.auth.login'), }, }, { @@ -51,7 +51,7 @@ const coreRoutes: RouteRecordRaw[] = [ path: 'code-login', component: () => import('#/views/_core/authentication/code-login.vue'), meta: { - title: $t('page.core.codeLogin'), + title: $t('page.auth.codeLogin'), }, }, { @@ -60,7 +60,7 @@ const coreRoutes: RouteRecordRaw[] = [ component: () => import('#/views/_core/authentication/qrcode-login.vue'), meta: { - title: $t('page.core.qrcodeLogin'), + title: $t('page.auth.qrcodeLogin'), }, }, { @@ -69,7 +69,7 @@ const coreRoutes: RouteRecordRaw[] = [ component: () => import('#/views/_core/authentication/forget-password.vue'), meta: { - title: $t('page.core.forgetPassword'), + title: $t('page.auth.forgetPassword'), }, }, { @@ -77,7 +77,7 @@ const coreRoutes: RouteRecordRaw[] = [ path: 'register', component: () => import('#/views/_core/authentication/register.vue'), meta: { - title: $t('page.core.register'), + title: $t('page.auth.register'), }, }, ], diff --git a/playground/src/router/routes/modules/demos.ts b/playground/src/router/routes/modules/demos.ts index 6d9014ed..82c47dbc 100644 --- a/playground/src/router/routes/modules/demos.ts +++ b/playground/src/router/routes/modules/demos.ts @@ -10,7 +10,7 @@ const routes: RouteRecordRaw[] = [ icon: 'ic:baseline-view-in-ar', keepAlive: true, order: 1000, - title: $t('page.demos.title'), + title: $t('demos.title'), }, name: 'Demos', path: '/demos', @@ -19,7 +19,7 @@ const routes: RouteRecordRaw[] = [ { meta: { icon: 'mdi:shield-key-outline', - title: $t('page.demos.access.frontendPermissions'), + title: $t('demos.access.frontendPermissions'), }, name: 'AccessDemos', path: '/demos/access', @@ -30,7 +30,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/demos/access/index.vue'), meta: { icon: 'mdi:page-previous-outline', - title: $t('page.demos.access.pageAccess'), + title: $t('demos.access.pageAccess'), }, }, { @@ -39,7 +39,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/demos/access/button-control.vue'), meta: { icon: 'mdi:button-cursor', - title: $t('page.demos.access.buttonControl'), + title: $t('demos.access.buttonControl'), }, }, { @@ -51,7 +51,7 @@ const routes: RouteRecordRaw[] = [ authority: ['no-body'], icon: 'mdi:button-cursor', menuVisibleWithForbidden: true, - title: $t('page.demos.access.menuVisible403'), + title: $t('demos.access.menuVisible403'), }, }, { @@ -61,7 +61,7 @@ const routes: RouteRecordRaw[] = [ meta: { authority: ['super'], icon: 'mdi:button-cursor', - title: $t('page.demos.access.superVisible'), + title: $t('demos.access.superVisible'), }, }, { @@ -71,7 +71,7 @@ const routes: RouteRecordRaw[] = [ meta: { authority: ['admin'], icon: 'mdi:button-cursor', - title: $t('page.demos.access.adminVisible'), + title: $t('demos.access.adminVisible'), }, }, { @@ -81,7 +81,7 @@ const routes: RouteRecordRaw[] = [ meta: { authority: ['user'], icon: 'mdi:button-cursor', - title: $t('page.demos.access.userVisible'), + title: $t('demos.access.userVisible'), }, }, ], @@ -90,7 +90,7 @@ const routes: RouteRecordRaw[] = [ { meta: { icon: 'mdi:feature-highlight', - title: $t('page.demos.features.title'), + title: $t('demos.features.title'), }, name: 'FeaturesDemos', path: '/demos/features', @@ -102,7 +102,7 @@ const routes: RouteRecordRaw[] = [ import('#/views/demos/features/login-expired/index.vue'), meta: { icon: 'mdi:encryption-expiration', - title: $t('page.demos.features.loginExpired'), + title: $t('demos.features.loginExpired'), }, }, { @@ -111,7 +111,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/demos/features/icons/index.vue'), meta: { icon: 'lucide:annoyed', - title: $t('page.demos.features.icons'), + title: $t('demos.features.icons'), }, }, { @@ -121,7 +121,7 @@ const routes: RouteRecordRaw[] = [ import('#/views/demos/features/watermark/index.vue'), meta: { icon: 'lucide:tags', - title: $t('page.demos.features.watermark'), + title: $t('demos.features.watermark'), }, }, { @@ -130,7 +130,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/demos/features/tabs/index.vue'), meta: { icon: 'lucide:app-window', - title: $t('page.demos.features.tabs'), + title: $t('demos.features.tabs'), }, }, { @@ -142,7 +142,7 @@ const routes: RouteRecordRaw[] = [ activePath: '/demos/features/tabs', hideInMenu: true, maxNumOfOpenTab: 3, - title: $t('page.demos.features.tabDetail'), + title: $t('demos.features.tabDetail'), }, }, { @@ -153,7 +153,7 @@ const routes: RouteRecordRaw[] = [ meta: { hideChildrenInMenu: true, icon: 'ic:round-menu', - title: $t('page.demos.features.hideChildrenInMenu'), + title: $t('demos.features.hideChildrenInMenu'), }, children: [ { @@ -163,7 +163,7 @@ const routes: RouteRecordRaw[] = [ import( '#/views/demos/features/hide-menu-children/children.vue' ), - meta: { title: $t('page.demos.features.hideChildrenInMenu') }, + meta: { title: $t('demos.features.hideChildrenInMenu') }, }, ], }, @@ -174,7 +174,7 @@ const routes: RouteRecordRaw[] = [ import('#/views/demos/features/full-screen/index.vue'), meta: { icon: 'lucide:fullscreen', - title: $t('page.demos.features.fullScreen.title'), + title: $t('demos.features.fullScreen.title'), }, }, { @@ -184,7 +184,7 @@ const routes: RouteRecordRaw[] = [ import('#/views/demos/features/clipboard/index.vue'), meta: { icon: 'lucide:copy', - title: $t('page.demos.features.clipboard'), + title: $t('demos.features.clipboard'), }, }, { @@ -205,7 +205,7 @@ const routes: RouteRecordRaw[] = [ path: '/demos/breadcrumb', meta: { icon: 'lucide:navigation', - title: $t('page.demos.breadcrumb.navigation'), + title: $t('demos.breadcrumb.navigation'), }, children: [ { @@ -214,7 +214,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/demos/breadcrumb/lateral.vue'), meta: { icon: 'lucide:navigation', - title: $t('page.demos.breadcrumb.lateral'), + title: $t('demos.breadcrumb.lateral'), }, }, { @@ -225,7 +225,7 @@ const routes: RouteRecordRaw[] = [ meta: { activePath: '/demos/breadcrumb/lateral', hideInMenu: true, - title: $t('page.demos.breadcrumb.lateralDetail'), + title: $t('demos.breadcrumb.lateralDetail'), }, }, { @@ -233,7 +233,7 @@ const routes: RouteRecordRaw[] = [ path: '/demos/breadcrumb/level', meta: { icon: 'lucide:navigation', - title: $t('page.demos.breadcrumb.level'), + title: $t('demos.breadcrumb.level'), }, children: [ { @@ -242,7 +242,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/demos/breadcrumb/level-detail.vue'), meta: { - title: $t('page.demos.breadcrumb.levelDetail'), + title: $t('demos.breadcrumb.levelDetail'), }, }, ], @@ -253,7 +253,7 @@ const routes: RouteRecordRaw[] = [ { meta: { icon: 'mdi:lightbulb-error-outline', - title: $t('page.demos.fallback.title'), + title: $t('demos.fallback.title'), }, name: 'FallbackDemos', path: '/demos/fallback', @@ -292,7 +292,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/_core/fallback/offline.vue'), meta: { icon: 'mdi:offline', - title: $t('fallback.offline'), + title: $t('ui.fallback.offline'), }, }, ], @@ -303,7 +303,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', badgeVariants: 'destructive', icon: 'lucide:circle-dot', - title: $t('page.demos.badge.title'), + title: $t('demos.badge.title'), }, name: 'BadgeDemos', path: '/demos/badge', @@ -315,7 +315,7 @@ const routes: RouteRecordRaw[] = [ meta: { badgeType: 'dot', icon: 'lucide:square-dot', - title: $t('page.demos.badge.dot'), + title: $t('demos.badge.dot'), }, }, { @@ -325,7 +325,7 @@ const routes: RouteRecordRaw[] = [ meta: { badge: '10', icon: 'lucide:square-dot', - title: $t('page.demos.badge.text'), + title: $t('demos.badge.text'), }, }, { @@ -336,7 +336,7 @@ const routes: RouteRecordRaw[] = [ badge: 'Hot', badgeVariants: 'destructive', icon: 'lucide:square-dot', - title: $t('page.demos.badge.color'), + title: $t('demos.badge.color'), }, }, ], @@ -346,7 +346,7 @@ const routes: RouteRecordRaw[] = [ meta: { activeIcon: 'fluent-emoji:radioactive', icon: 'bi:radioactive', - title: $t('page.demos.activeIcon.title'), + title: $t('demos.activeIcon.title'), }, name: 'ActiveIconDemos', path: '/demos/active-icon', @@ -358,7 +358,7 @@ const routes: RouteRecordRaw[] = [ meta: { activeIcon: 'fluent-emoji:radioactive', icon: 'bi:radioactive', - title: $t('page.demos.activeIcon.children'), + title: $t('demos.activeIcon.children'), }, }, ], @@ -367,7 +367,7 @@ const routes: RouteRecordRaw[] = [ { meta: { icon: 'ic:round-settings-input-composite', - title: $t('page.demos.outside.title'), + title: $t('demos.outside.title'), }, name: 'OutsideDemos', path: '/demos/outside', @@ -377,7 +377,7 @@ const routes: RouteRecordRaw[] = [ path: '/demos/outside/iframe', meta: { icon: 'mdi:newspaper-variant-outline', - title: $t('page.demos.outside.embedded'), + title: $t('demos.outside.embedded'), }, children: [ { @@ -409,7 +409,7 @@ const routes: RouteRecordRaw[] = [ path: '/demos/outside/external-link', meta: { icon: 'mdi:newspaper-variant-multiple-outline', - title: $t('page.demos.outside.externalLink'), + title: $t('demos.outside.externalLink'), }, children: [ { @@ -440,7 +440,7 @@ const routes: RouteRecordRaw[] = [ { meta: { icon: 'ic:round-menu', - title: $t('page.demos.nested.title'), + title: $t('demos.nested.title'), }, name: 'NestedDemos', path: '/demos/nested', @@ -452,7 +452,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu1'), + title: $t('demos.nested.menu1'), }, }, { @@ -461,7 +461,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu2'), + title: $t('demos.nested.menu2'), }, children: [ { @@ -471,7 +471,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu2_1'), + title: $t('demos.nested.menu2_1'), }, }, ], @@ -481,7 +481,7 @@ const routes: RouteRecordRaw[] = [ path: '/demos/nested/menu3', meta: { icon: 'ic:round-menu', - title: $t('page.demos.nested.menu3'), + title: $t('demos.nested.menu3'), }, children: [ { @@ -491,7 +491,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu3_1'), + title: $t('demos.nested.menu3_1'), }, }, { @@ -499,7 +499,7 @@ const routes: RouteRecordRaw[] = [ path: 'menu3-2', meta: { icon: 'ic:round-menu', - title: $t('page.demos.nested.menu3_2'), + title: $t('demos.nested.menu3_2'), }, children: [ { @@ -510,7 +510,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'ic:round-menu', keepAlive: true, - title: $t('page.demos.nested.menu3_2_1'), + title: $t('demos.nested.menu3_2_1'), }, }, ], diff --git a/playground/src/router/routes/modules/examples.ts b/playground/src/router/routes/modules/examples.ts index b1cdd588..877ad373 100644 --- a/playground/src/router/routes/modules/examples.ts +++ b/playground/src/router/routes/modules/examples.ts @@ -10,7 +10,7 @@ const routes: RouteRecordRaw[] = [ icon: 'ion:layers-outline', keepAlive: true, order: 1000, - title: $t('page.examples.title'), + title: $t('examples.title'), }, name: 'Examples', path: '/examples', @@ -21,7 +21,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/examples/modal/index.vue'), meta: { icon: 'system-uicons:window-content', - title: $t('page.examples.modal.title'), + title: $t('examples.modal.title'), }, }, { @@ -30,7 +30,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/examples/drawer/index.vue'), meta: { icon: 'iconoir:drawer', - title: $t('page.examples.drawer.title'), + title: $t('examples.drawer.title'), }, }, { @@ -39,7 +39,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/examples/ellipsis/index.vue'), meta: { icon: 'ion:ellipsis-horizontal', - title: $t('page.examples.ellipsis.title'), + title: $t('examples.ellipsis.title'), }, }, { @@ -47,7 +47,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/form', meta: { icon: 'mdi:form-select', - title: $t('page.examples.form.title'), + title: $t('examples.form.title'), }, children: [ { @@ -55,7 +55,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/form/basic', component: () => import('#/views/examples/form/basic.vue'), meta: { - title: $t('page.examples.form.basic'), + title: $t('examples.form.basic'), }, }, { @@ -63,7 +63,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/form/query', component: () => import('#/views/examples/form/query.vue'), meta: { - title: $t('page.examples.form.query'), + title: $t('examples.form.query'), }, }, { @@ -71,7 +71,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/form/rules', component: () => import('#/views/examples/form/rules.vue'), meta: { - title: $t('page.examples.form.rules'), + title: $t('examples.form.rules'), }, }, { @@ -79,7 +79,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/form/dynamic', component: () => import('#/views/examples/form/dynamic.vue'), meta: { - title: $t('page.examples.form.dynamic'), + title: $t('examples.form.dynamic'), }, }, { @@ -87,7 +87,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/form/custom', component: () => import('#/views/examples/form/custom.vue'), meta: { - title: $t('page.examples.form.custom'), + title: $t('examples.form.custom'), }, }, { @@ -95,7 +95,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/form/api', component: () => import('#/views/examples/form/api.vue'), meta: { - title: $t('page.examples.form.api'), + title: $t('examples.form.api'), }, }, { @@ -103,7 +103,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/form/merge', component: () => import('#/views/examples/form/merge.vue'), meta: { - title: $t('page.examples.form.merge'), + title: $t('examples.form.merge'), }, }, ], @@ -113,7 +113,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/vxe-table', meta: { icon: 'lucide:table', - title: $t('page.examples.vxeTable.title'), + title: $t('examples.vxeTable.title'), }, children: [ { @@ -121,7 +121,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/vxe-table/basic', component: () => import('#/views/examples/vxe-table/basic.vue'), meta: { - title: $t('page.examples.vxeTable.basic'), + title: $t('examples.vxeTable.basic'), }, }, { @@ -129,7 +129,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/vxe-table/remote', component: () => import('#/views/examples/vxe-table/remote.vue'), meta: { - title: $t('page.examples.vxeTable.remote'), + title: $t('examples.vxeTable.remote'), }, }, { @@ -137,7 +137,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/vxe-table/tree', component: () => import('#/views/examples/vxe-table/tree.vue'), meta: { - title: $t('page.examples.vxeTable.tree'), + title: $t('examples.vxeTable.tree'), }, }, { @@ -145,7 +145,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/vxe-table/fixed', component: () => import('#/views/examples/vxe-table/fixed.vue'), meta: { - title: $t('page.examples.vxeTable.fixed'), + title: $t('examples.vxeTable.fixed'), }, }, { @@ -154,7 +154,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/examples/vxe-table/custom-cell.vue'), meta: { - title: $t('page.examples.vxeTable.custom-cell'), + title: $t('examples.vxeTable.custom-cell'), }, }, { @@ -162,7 +162,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/vxe-table/form', component: () => import('#/views/examples/vxe-table/form.vue'), meta: { - title: $t('page.examples.vxeTable.form'), + title: $t('examples.vxeTable.form'), }, }, { @@ -170,7 +170,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/vxe-table/edit-cell', component: () => import('#/views/examples/vxe-table/edit-cell.vue'), meta: { - title: $t('page.examples.vxeTable.editCell'), + title: $t('examples.vxeTable.editCell'), }, }, { @@ -178,7 +178,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/vxe-table/edit-row', component: () => import('#/views/examples/vxe-table/edit-row.vue'), meta: { - title: $t('page.examples.vxeTable.editRow'), + title: $t('examples.vxeTable.editRow'), }, }, { @@ -186,7 +186,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/vxe-table/virtual', component: () => import('#/views/examples/vxe-table/virtual.vue'), meta: { - title: $t('page.examples.vxeTable.virtual'), + title: $t('examples.vxeTable.virtual'), }, }, ], @@ -196,7 +196,7 @@ const routes: RouteRecordRaw[] = [ path: '/examples/captcha', meta: { icon: 'logos:recaptcha', - title: $t('page.examples.captcha.title'), + title: $t('examples.captcha.title'), }, children: [ { @@ -205,7 +205,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/examples/captcha/slider-captcha.vue'), meta: { - title: $t('page.examples.captcha.sliderCaptcha'), + title: $t('examples.captcha.sliderCaptcha'), }, }, { @@ -214,7 +214,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/examples/captcha/slider-rotate-captcha.vue'), meta: { - title: $t('page.examples.captcha.sliderRotateCaptcha'), + title: $t('examples.captcha.sliderRotateCaptcha'), }, }, { @@ -223,7 +223,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/examples/captcha/point-selection-captcha.vue'), meta: { - title: $t('page.examples.captcha.pointSelection'), + title: $t('examples.captcha.pointSelection'), }, }, ], diff --git a/playground/src/router/routes/modules/vben.ts b/playground/src/router/routes/modules/vben.ts index baf24756..2f2eb660 100644 --- a/playground/src/router/routes/modules/vben.ts +++ b/playground/src/router/routes/modules/vben.ts @@ -20,7 +20,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: VBEN_LOGO_URL, order: 9999, - title: $t('page.vben.title'), + title: $t('demos.vben.title'), }, name: 'VbenProject', path: '/vben-admin', @@ -31,7 +31,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/_core/about/index.vue'), meta: { icon: 'lucide:copyright', - title: $t('page.vben.about'), + title: $t('demos.vben.about'), }, }, { @@ -41,7 +41,7 @@ const routes: RouteRecordRaw[] = [ meta: { icon: 'lucide:book-open-text', link: VBEN_DOC_URL, - title: $t('page.vben.document'), + title: $t('demos.vben.document'), }, }, { @@ -62,7 +62,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: SvgAntdvLogoIcon, link: VBEN_ANT_PREVIEW_URL, - title: $t('page.vben.antdv'), + title: $t('demos.vben.antdv'), }, }, { @@ -73,7 +73,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: 'logos:naiveui', link: VBEN_NAIVE_PREVIEW_URL, - title: $t('page.vben.naive-ui'), + title: $t('demos.vben.naive-ui'), }, }, { @@ -84,7 +84,7 @@ const routes: RouteRecordRaw[] = [ badgeType: 'dot', icon: 'logos:element', link: VBEN_ELE_PREVIEW_URL, - title: $t('page.vben.element-plus'), + title: $t('demos.vben.element-plus'), }, }, ], diff --git a/playground/src/views/examples/captcha/point-selection-captcha.vue b/playground/src/views/examples/captcha/point-selection-captcha.vue index 4a247c4b..ae8ab0af 100644 --- a/playground/src/views/examples/captcha/point-selection-captcha.vue +++ b/playground/src/views/examples/captcha/point-selection-captcha.vue @@ -47,47 +47,44 @@ const handleClick = (point: CaptchaPoint) => {