浏览代码

feat: Support dayjs and component library in multiple languages

vben 9 月之前
父节点
当前提交
1d70d71537

+ 4 - 1
.vscode/settings.json

@@ -171,7 +171,10 @@
     "packages/@vben-core/shared/design-tokens/src/**/*.css"
   ],
 
-  "i18n-ally.localesPaths": ["packages/locales/src/langs"],
+  "i18n-ally.localesPaths": [
+    "packages/locales/src/langs",
+    "packages/@core/shared/i18n/src/langs"
+  ],
   "i18n-ally.enabledParsers": ["json", "ts", "js", "yaml"],
   "i18n-ally.sourceLanguage": "en",
   "i18n-ally.displayLanguage": "zh-CN",

+ 2 - 6
apps/web-antd/src/app.vue

@@ -5,15 +5,11 @@ import { GlobalProvider } from '@vben/widgets';
 import { preferences, usePreferences } from '@vben-core/preferences';
 
 import { App, ConfigProvider, theme } from 'ant-design-vue';
-import zhCN from 'ant-design-vue/es/locale/zh_CN';
-import dayjs from 'dayjs';
 
-import 'dayjs/locale/zh-cn';
+import { antdLocale } from '#/forward';
 
 defineOptions({ name: 'App' });
 
-dayjs.locale(zhCN.locale);
-
 const { isDark } = usePreferences();
 
 const tokenTheme = computed(() => {
@@ -35,7 +31,7 @@ const tokenTheme = computed(() => {
 
 <template>
   <GlobalProvider>
-    <ConfigProvider :locale="zhCN" :theme="tokenTheme">
+    <ConfigProvider :locale="antdLocale" :theme="tokenTheme">
       <App>
         <RouterView />
       </App>

+ 5 - 1
apps/web-antd/src/bootstrap.ts

@@ -4,6 +4,7 @@ import { setupI18n } from '@vben/locales';
 import '@vben/styles';
 import { preferences } from '@vben-core/preferences';
 
+import { loadThirdPartyMessage } from '#/forward';
 import { setupStore } from '#/store';
 
 import App from './app.vue';
@@ -13,7 +14,10 @@ async function bootstrap(namespace: string) {
   const app = createApp(App);
 
   // 国际化 i18n 配置
-  await setupI18n(app, { defaultLocale: preferences.app.locale });
+  await setupI18n(app, {
+    defaultLocale: preferences.app.locale,
+    loadThirdPartyMessage,
+  });
 
   // 配置 pinia-store
   await setupStore(app, { namespace });

+ 11 - 0
apps/web-antd/src/forward/README.md

@@ -0,0 +1,11 @@
+# forward
+
+用于扩展、转发大仓的包以及其他功能,方便在app内自定义不同的逻辑
+
+## request
+
+用于扩展请求的功能,例如添加header、错误响应等
+
+## locale
+
+用于扩展国际化的功能,例如扩展 dayjs、antd组件库的多语言切换

+ 1 - 0
apps/web-antd/src/forward/index.ts

@@ -1 +1,2 @@
+export * from './locale';
 export * from './request';

+ 48 - 0
apps/web-antd/src/forward/locale.ts

@@ -0,0 +1,48 @@
+import type { SupportedLanguagesType } from '@vben/types';
+import type { Locale } from 'ant-design-vue/es/locale';
+
+import { ref } from 'vue';
+
+import defaultLocale from 'ant-design-vue/es/locale/zh_CN';
+import dayjs from 'dayjs';
+
+const antdLocale = ref<Locale>(defaultLocale);
+
+async function loadDayjsLocale(lang: SupportedLanguagesType) {
+  let locale;
+  switch (lang) {
+    case 'zh-CN': {
+      locale = await import('dayjs/locale/zh-cn');
+      break;
+    }
+    case 'en-US': {
+      locale = await import('dayjs/locale/en');
+      break;
+    }
+    default: {
+      locale = await import('dayjs/locale/en');
+    } // 默认使用英语
+  }
+  dayjs.locale(locale);
+}
+
+async function loadAntdLocale(lang: SupportedLanguagesType) {
+  switch (lang) {
+    case 'zh-CN': {
+      antdLocale.value = defaultLocale;
+      break;
+    }
+    case 'en-US': {
+      antdLocale.value = (await import(
+        'ant-design-vue/es/locale/en_US'
+      )) as unknown as Locale;
+      break;
+    }
+  }
+}
+
+async function loadThirdPartyMessage(land: SupportedLanguagesType) {
+  await Promise.all([loadAntdLocale(land), loadDayjsLocale(land)]);
+}
+
+export { antdLocale, loadThirdPartyMessage };

+ 0 - 0
apps/web-antd/src/forward/request/index.ts → apps/web-antd/src/forward/request.ts


+ 3 - 3
apps/web-antd/src/layouts/index.ts

@@ -2,7 +2,7 @@ const BasicLayout = () => import('./basic.vue');
 
 const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);
 
-const AuthPageLayoutType = () =>
-  import('@vben/layouts').then((m) => m.AuthPageLayoutType);
+const AuthPageLayout = () =>
+  import('@vben/layouts').then((m) => m.AuthPageLayout);
 
-export { AuthPageLayoutType, BasicLayout, IFrameView };
+export { AuthPageLayout, BasicLayout, IFrameView };

+ 2 - 2
apps/web-antd/src/router/routes/_essentials.ts

@@ -3,7 +3,7 @@ import type { RouteRecordRaw } from 'vue-router';
 import { DEFAULT_HOME_PATH } from '@vben/constants';
 import { $t } from '@vben/locales';
 
-import { AuthPageLayoutType } from '#/layouts';
+import { AuthPageLayout } from '#/layouts';
 import Login from '#/views/_essential/authentication/login.vue';
 
 /** 全局404页面 */
@@ -30,7 +30,7 @@ const essentialsRoutes: RouteRecordRaw[] = [
     redirect: DEFAULT_HOME_PATH,
   },
   {
-    component: AuthPageLayoutType,
+    component: AuthPageLayout,
     meta: {
       title: 'Authentication',
     },

+ 3 - 2
packages/@core/ui-kit/menu-ui/src/styles/index.scss

@@ -495,11 +495,12 @@
     padding-right: 12px !important;
   }
 
-  &:not(.is-active):hover {
+  // &:not(.is-active):hover {
+  &:hover {
     color: var(--menu-submenu-hover-color);
     text-decoration: none;
     cursor: pointer;
-    background: var(--menu-submenu-hover-background-color);
+    background: var(--menu-submenu-hover-background-color) !important;
 
     svg {
       fill: var(--menu-submenu-hover-color);

+ 1 - 1
packages/business/layouts/src/authentication/index.ts

@@ -1 +1 @@
-export { default as AuthPageLayoutType } from './authentication.vue';
+export { default as AuthPageLayout } from './authentication.vue';

+ 2 - 2
packages/locales/src/i18n.ts

@@ -43,7 +43,7 @@ function setI18nLanguage(locale: Locale) {
  * Load locale messages
  * @param lang
  */
-async function loadLocaleMessages(lang: SupportedLanguagesType) {
+async function loadI18nMessages(lang: SupportedLanguagesType) {
   if (unref(i18n.global.locale) === lang) {
     return setI18nLanguage(lang);
   }
@@ -59,4 +59,4 @@ async function loadLocaleMessages(lang: SupportedLanguagesType) {
   return setI18nLanguage(lang);
 }
 
-export { i18n, loadLocaleMessages, setI18nLanguage };
+export { i18n, loadI18nMessages, setI18nLanguage };

+ 11 - 2
packages/locales/src/index.ts

@@ -1,13 +1,22 @@
-import type { LocaleSetupOptions } from './typing';
+import type { LocaleSetupOptions, SupportedLanguagesType } from './typing';
 
 import type { App } from 'vue';
 
-import { i18n, loadLocaleMessages } from './i18n';
+import { i18n, loadI18nMessages } from './i18n';
 
 const $t = i18n.global.t;
 
+let loadThirdPartyMessage: (lang: SupportedLanguagesType) => Promise<void>;
+
+async function loadLocaleMessages(lang: SupportedLanguagesType) {
+  await loadI18nMessages(lang);
+  await loadThirdPartyMessage(lang);
+}
+
 async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
   const { defaultLocale = 'zh-CN' } = options;
+  // app可以自行扩展一些第三方库和组件库的国际化
+  loadThirdPartyMessage = options.loadThirdPartyMessage || (async () => {});
   app.use(i18n);
   await loadLocaleMessages(defaultLocale);
 }

+ 0 - 0
packages/locales/src/third-party/.gitkeep


+ 6 - 0
packages/locales/src/typing.ts

@@ -8,6 +8,12 @@ interface LocaleSetupOptions {
    * @default zh-CN
    */
   defaultLocale?: SupportedLanguagesType;
+  /**
+   * Load third-party library messages
+   * @param lang
+   * @returns
+   */
+  loadThirdPartyMessage?: (lang: SupportedLanguagesType) => Promise<void>;
 }
 
 export type { ImportLocaleFn, LocaleSetupOptions, SupportedLanguagesType };