Quellcode durchsuchen

feat: multi-language support

vben vor 4 Jahren
Ursprung
Commit
19011296ed
76 geänderte Dateien mit 764 neuen und 307 gelöschten Zeilen
  1. 2 1
      CHANGELOG.zh_CN.md
  2. 22 3
      build/vite/plugin/transform/globby/index.ts
  3. 12 2
      src/components/Menu/src/BasicMenu.tsx
  4. 13 2
      src/hooks/web/useI18n.ts
  5. 18 0
      src/hooks/web/useTitle.ts
  6. 3 2
      src/layouts/default/header/LayoutBreadcrumb.tsx
  7. 25 1
      src/layouts/default/menu/useLayoutMenu.ts
  8. 3 1
      src/layouts/default/multitabs/TabContent.tsx
  9. 1 0
      src/locales/lang/en/routes/README.MD
  10. 3 0
      src/locales/lang/en/routes/baisc.ts
  11. 6 0
      src/locales/lang/en/routes/dashboard.ts
  12. 7 0
      src/locales/lang/en/routes/demo/charts.ts
  13. 27 0
      src/locales/lang/en/routes/demo/comp.ts
  14. 8 0
      src/locales/lang/en/routes/demo/editor.ts
  15. 7 0
      src/locales/lang/en/routes/demo/excel.ts
  16. 17 0
      src/locales/lang/en/routes/demo/feat.ts
  17. 10 0
      src/locales/lang/en/routes/demo/form.ts
  18. 6 0
      src/locales/lang/en/routes/demo/iframe.ts
  19. 27 0
      src/locales/lang/en/routes/demo/page.ts
  20. 13 0
      src/locales/lang/en/routes/demo/permission.ts
  21. 19 0
      src/locales/lang/en/routes/demo/table.ts
  22. 7 0
      src/locales/lang/en/routes/demo/tree.ts
  23. 0 3
      src/locales/lang/en/routes/menus/dashboard.ts
  24. 21 0
      src/locales/lang/en/sys/api.ts
  25. 5 0
      src/locales/lang/en/sys/app.ts
  26. 0 1
      src/locales/lang/zh_CN/component/modal.ts
  27. 1 0
      src/locales/lang/zh_CN/routes/README.MD
  28. 3 0
      src/locales/lang/zh_CN/routes/baisc.ts
  29. 6 0
      src/locales/lang/zh_CN/routes/dashboard.ts
  30. 7 0
      src/locales/lang/zh_CN/routes/demo/charts.ts
  31. 27 0
      src/locales/lang/zh_CN/routes/demo/comp.ts
  32. 8 0
      src/locales/lang/zh_CN/routes/demo/editor.ts
  33. 7 0
      src/locales/lang/zh_CN/routes/demo/excel.ts
  34. 17 0
      src/locales/lang/zh_CN/routes/demo/feat.ts
  35. 10 0
      src/locales/lang/zh_CN/routes/demo/form.ts
  36. 6 0
      src/locales/lang/zh_CN/routes/demo/iframe.ts
  37. 27 0
      src/locales/lang/zh_CN/routes/demo/page.ts
  38. 13 0
      src/locales/lang/zh_CN/routes/demo/permission.ts
  39. 19 0
      src/locales/lang/zh_CN/routes/demo/table.ts
  40. 7 0
      src/locales/lang/zh_CN/routes/demo/tree.ts
  41. 0 3
      src/locales/lang/zh_CN/routes/menus/dashboard.ts
  42. 21 0
      src/locales/lang/zh_CN/sys/api.ts
  43. 5 0
      src/locales/lang/zh_CN/sys/app.ts
  44. 3 1
      src/router/guard/index.ts
  45. 5 10
      src/router/menus/modules/dashboard.ts
  46. 6 5
      src/router/menus/modules/demo/charts.ts
  47. 21 30
      src/router/menus/modules/demo/comp.ts
  48. 6 5
      src/router/menus/modules/demo/editor.ts
  49. 6 5
      src/router/menus/modules/demo/excel.ts
  50. 16 15
      src/router/menus/modules/demo/feat.ts
  51. 9 8
      src/router/menus/modules/demo/form.ts
  52. 5 4
      src/router/menus/modules/demo/iframe.ts
  53. 20 19
      src/router/menus/modules/demo/page.ts
  54. 10 9
      src/router/menus/modules/demo/permission.ts
  55. 17 16
      src/router/menus/modules/demo/table.ts
  56. 5 4
      src/router/menus/modules/demo/tree.ts
  57. 1 1
      src/router/routes/index.ts
  58. 4 4
      src/router/routes/modules/dashboard.ts
  59. 5 5
      src/router/routes/modules/demo/charts.ts
  60. 20 20
      src/router/routes/modules/demo/comp.ts
  61. 5 5
      src/router/routes/modules/demo/editor.ts
  62. 5 5
      src/router/routes/modules/demo/excel.ts
  63. 13 13
      src/router/routes/modules/demo/feat.ts
  64. 8 8
      src/router/routes/modules/demo/form.ts
  65. 4 4
      src/router/routes/modules/demo/iframe.ts
  66. 19 19
      src/router/routes/modules/demo/page.ts
  67. 9 9
      src/router/routes/modules/demo/permission.ts
  68. 16 16
      src/router/routes/modules/demo/table.ts
  69. 4 4
      src/router/routes/modules/demo/tree.ts
  70. 1 1
      src/setup/App.ts
  71. 6 7
      src/setup/i18n/index.ts
  72. 4 1
      src/store/modules/permission.ts
  73. 5 2
      src/store/modules/user.ts
  74. 14 11
      src/utils/http/axios/checkStatus.ts
  75. 9 7
      src/utils/http/axios/index.ts
  76. 17 15
      src/views/sys/login/Login.vue

+ 2 - 1
CHANGELOG.zh_CN.md

@@ -2,7 +2,7 @@
 
 ### ✨ Refactor
 
-- 重构整体 layout。更改代码实现方式。代码更精简,并加入多语言支持
+- 重构整体 layout。更改代码实现方式。代码更精简
 - 配置项重构
 - 移除 messageSetting 配置
 
@@ -10,6 +10,7 @@
 
 - 缓存可以配置是否加密,默认生产环境开启 Aes 加密
 - 新增标签页拖拽排序
+- 除示例外加入全局国际化功能,支持中文与英文
 
 ### 🎫 Chores
 

+ 22 - 3
build/vite/plugin/transform/globby/index.ts

@@ -61,13 +61,20 @@ function varTemplate(data: string[][], name: string) {
 
     // lastKey is a data
     let pathValue = v[0].replace(/\//g, '.').split('.');
+    // let scopeKey = '';
+    //   const len=pathValue.length
+    //   const scope=pathValue[len-2]
     let lastKey: string | undefined = pathValue.pop();
 
     let deepValue: Record<any, any> = {};
     if (lastKey) {
-      deepValue[lastKey.replace('_' + pathValue[0], '')] = lastKey;
+      // Solve the problem of files with the same name in different folders
+      const lastKeyList = lastKey.replace('_' + pathValue[0], '').split('_');
+      const key = lastKeyList.pop();
+      if (key) {
+        deepValue[key] = lastKey;
+      }
     }
-
     // Set Deep Value
     deepValue = Object.assign(deepValue, dotProp.get(deepData, pathValue.join('.')));
     dotProp.set(deepData, pathValue.join('.'), deepValue);
@@ -169,7 +176,15 @@ const globTransform = function (config: SharedConfig): Transform {
 
                 if (matchedGroups && matchedGroups.length) {
                   const matchedSegments = matchedGroups[1]; //first everytime "Full Match"
-                  const name = matchedGroups[2] + '_' + matchedSegments.split('/').shift();
+                  const matchList = matchedSegments.split('/').filter(Boolean);
+                  const lang = matchList.shift();
+                  const scope = matchList.pop();
+
+                  // Solve the problem of files with the same name in different folders
+                  const scopeKey = scope ? `${scope}_` : '';
+                  const fileName = matchedGroups[2];
+                  const name = scopeKey + fileName + '_' + lang;
+
                   //send deep way like an (en/modules/system/dashboard) into groups
                   groups.push([matchedSegments + name, file]);
                   return templateRender({
@@ -186,6 +201,10 @@ const globTransform = function (config: SharedConfig): Transform {
             const filesJoined = replaceFiles.join('\n');
 
             urlMap.set(path, filesJoined);
+
+            // console.log('======================');
+            // console.log(filesJoined, varTemplate(groups, name));
+            // console.log('======================');
             return [
               filesJoined,
               compareString(injectPath, groups),

+ 12 - 2
src/components/Menu/src/BasicMenu.tsx

@@ -3,7 +3,17 @@ import './index.less';
 import type { MenuState } from './types';
 import type { Menu as MenuType } from '/@/router/types';
 
-import { computed, defineComponent, unref, reactive, watch, onMounted, ref, toRefs } from 'vue';
+import {
+  computed,
+  defineComponent,
+  unref,
+  reactive,
+  watch,
+  onMounted,
+  ref,
+  toRefs,
+  ComputedRef,
+} from 'vue';
 import { Menu } from 'ant-design-vue';
 import SearchInput from './SearchInput.vue';
 import MenuContent from './MenuContent';
@@ -34,7 +44,7 @@ export default defineComponent({
     const menuState = reactive<MenuState>({
       defaultSelectedKeys: [],
       mode: props.mode,
-      theme: computed(() => props.theme),
+      theme: computed(() => props.theme) as ComputedRef<ThemeEnum>,
       openKeys: [],
       searchValue: '',
       selectedKeys: [],

+ 13 - 2
src/hooks/web/useI18n.ts

@@ -1,8 +1,7 @@
 import { getI18n } from '/@/setup/i18n';
+import projectSetting from '/@/settings/projectSetting';
 
 export function useI18n(namespace?: string) {
-  const { t, ...methods } = getI18n().global;
-
   function getKey(key: string) {
     if (!namespace) {
       return key;
@@ -12,6 +11,18 @@ export function useI18n(namespace?: string) {
     }
     return `${namespace}.${key}`;
   }
+  const normalFn = {
+    t: (key: string) => {
+      return getKey(key);
+    },
+  };
+
+  if (!projectSetting.locale.show || !getI18n()) {
+    return normalFn;
+  }
+
+  const { t, ...methods } = getI18n().global;
+
   return {
     ...methods,
     t: (key: string, ...arg: Parameters<typeof t>) => {

+ 18 - 0
src/hooks/web/useTitle.ts

@@ -0,0 +1,18 @@
+import { watch } from 'vue';
+import { useRouter } from 'vue-router';
+import { useGlobSetting } from '../setting';
+import { useI18n } from './useI18n';
+import { setTitle } from '/@/utils/browser';
+
+export function useTitle() {
+  const { currentRoute } = useRouter();
+  const { t } = useI18n();
+  watch(
+    () => currentRoute.value.path,
+    () => {
+      const globSetting = useGlobSetting();
+      setTitle(t(currentRoute.value.meta.title), globSetting.title);
+    },
+    { immediate: true, flush: 'post' }
+  );
+}

+ 3 - 2
src/layouts/default/header/LayoutBreadcrumb.tsx

@@ -15,6 +15,7 @@ import { compile } from 'path-to-regexp';
 import router from '/@/router';
 
 import { PageEnum } from '/@/enums/pageEnum';
+import { useI18n } from '/@/hooks/web/useI18n';
 
 export default defineComponent({
   name: 'BasicBreadcrumb',
@@ -28,7 +29,7 @@ export default defineComponent({
     const itemList = ref<AppRouteRecordRaw[]>([]);
 
     const { currentRoute, push } = useRouter();
-
+    const { t } = useI18n();
     watch(
       () => currentRoute.value,
       () => {
@@ -88,7 +89,7 @@ export default defineComponent({
               }}
             />
           )}
-          {item.meta.title}
+          {t(item.meta.title)}
         </>
       );
     }

+ 25 - 1
src/layouts/default/menu/useLayoutMenu.ts

@@ -17,7 +17,10 @@ import {
   getShallowMenus,
 } from '/@/router/menus';
 import { permissionStore } from '/@/store/modules/permission';
+import { useI18n } from '/@/hooks/web/useI18n';
+import { cloneDeep } from 'lodash-es';
 
+const { t } = useI18n();
 export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
   // Menu array
   const menusRef = ref<Menu[]>([]);
@@ -42,6 +45,14 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
     return unref(splitType) === MenuSplitTyeEnum.NONE || !unref(getSplit);
   });
 
+  const getI18nFlatMenus = computed(() => {
+    return setI18nName(flatMenusRef.value, true, false);
+  });
+
+  const getI18nMenus = computed(() => {
+    return setI18nName(menusRef.value, true, true);
+  });
+
   watch(
     [() => unref(currentRoute).path, () => unref(splitType)],
     async ([path]: [string, MenuSplitTyeEnum]) => {
@@ -72,6 +83,18 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
     genMenus();
   });
 
+  function setI18nName(list: Menu[], clone = false, deep = true) {
+    const menus = clone ? cloneDeep(list) : list;
+    menus.forEach((item) => {
+      if (!item.name.includes('.')) return;
+      item.name = t(item.name);
+      if (item.children && deep) {
+        setI18nName(item.children, false, deep);
+      }
+    });
+    return menus;
+  }
+
   // Handle left menu split
   async function handleSplitLeftMenu(parentPath: string) {
     if (unref(splitLeft)) return;
@@ -109,5 +132,6 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
       return;
     }
   }
-  return { flatMenusRef, menusRef };
+
+  return { flatMenusRef: getI18nFlatMenus, menusRef: getI18nMenus };
 }

+ 3 - 1
src/layouts/default/multitabs/TabContent.tsx

@@ -15,6 +15,8 @@ import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
 import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
 import { useI18n } from '/@/hooks/web/useI18n';
 
+const { t: titleT } = useI18n();
+
 const ExtraContent: FunctionalComponent = () => {
   return (
     <span class={`multiple-tabs-content__extra `}>
@@ -38,7 +40,7 @@ const TabContent: FunctionalComponent<{ tabItem: TabItem }> = (props) => {
 
   return (
     <div class={`multiple-tabs-content__content `} onContextmenu={handleContextMenu}>
-      <span class="ml-1">{meta && meta.title}</span>
+      <span class="ml-1">{meta && titleT(meta.title)}</span>
     </div>
   );
 };

+ 1 - 0
src/locales/lang/en/routes/README.MD

@@ -0,0 +1 @@
+Share with menu

+ 3 - 0
src/locales/lang/en/routes/baisc.ts

@@ -0,0 +1,3 @@
+export default {
+  login: 'Login',
+};

+ 6 - 0
src/locales/lang/en/routes/dashboard.ts

@@ -0,0 +1,6 @@
+export default {
+  dashboard: 'Dashboard',
+  welcome: 'Home',
+  workbench: 'Workbench',
+  analysis: 'Analysis',
+};

+ 7 - 0
src/locales/lang/en/routes/demo/charts.ts

@@ -0,0 +1,7 @@
+export default {
+  charts: 'Chart',
+  map: 'Map',
+  line: 'Line',
+  pie: 'Pie',
+  apexChart: 'ApexChart',
+};

+ 27 - 0
src/locales/lang/en/routes/demo/comp.ts

@@ -0,0 +1,27 @@
+export default {
+  comp: 'Component',
+  basic: 'Basic',
+  transition: 'Animation',
+  countTo: 'Count To',
+
+  scroll: 'Scroll',
+  scrollBasic: 'Basic',
+  scrollAction: 'Scroll Function',
+  virtualScroll: 'Virtual Scroll',
+
+  modal: 'Modal',
+  drawer: 'Drawer',
+  desc: 'Desc',
+
+  lazy: 'Lazy',
+  lazyBasic: 'Basic',
+  lazyTransition: 'Animation',
+
+  verify: 'Verify',
+  verifyDrag: 'Drag ',
+  verifyRotate: 'Picture Restore',
+
+  qrcode: 'QR code',
+  strength: 'Password strength',
+  upload: 'Upload',
+};

+ 8 - 0
src/locales/lang/en/routes/demo/editor.ts

@@ -0,0 +1,8 @@
+export default {
+  editor: 'Editor',
+  markdown: 'Markdown editor',
+
+  tinymce: 'Rich text',
+  tinymceBasic: 'Basic',
+  tinymceForm: 'embedded form',
+};

+ 7 - 0
src/locales/lang/en/routes/demo/excel.ts

@@ -0,0 +1,7 @@
+export default {
+  excel: 'Excel',
+  customExport: 'Select export format',
+  jsonExport: 'JSON data export',
+  arrayExport: 'Array data export',
+  importExcel: 'Import',
+};

+ 17 - 0
src/locales/lang/en/routes/demo/feat.ts

@@ -0,0 +1,17 @@
+export default {
+  feat: 'Page Function',
+  icon: 'Icon',
+  tabs: 'Tabs',
+  contextMenu: 'Context Menu',
+  download: 'Download',
+  clickOutSide: 'ClickOutSide',
+  imgPreview: 'Picture Preview',
+  copy: 'Clipboard',
+  msg: 'Message prompt',
+  watermark: 'Watermark',
+  fullScreen: 'Full Screen',
+  errorLog: 'Error Log',
+  tab: 'Tab with parameters',
+  tab1: 'Tab with parameter 1',
+  tab2: 'Tab with parameter 2',
+};

+ 10 - 0
src/locales/lang/en/routes/demo/form.ts

@@ -0,0 +1,10 @@
+export default {
+  form: 'Form',
+  basic: 'Basic',
+  useForm: 'useForm',
+  refForm: 'RefForm',
+  advancedForm: 'Shrinkable',
+  ruleForm: 'Form validation',
+  dynamicForm: 'Dynamic',
+  customerForm: 'Custom',
+};

+ 6 - 0
src/locales/lang/en/routes/demo/iframe.ts

@@ -0,0 +1,6 @@
+export default {
+  frame: 'External',
+  antv: 'antVue doc (embedded)',
+  doc: 'Project doc (embedded)',
+  docExternal: 'Project doc (external)',
+};

+ 27 - 0
src/locales/lang/en/routes/demo/page.ts

@@ -0,0 +1,27 @@
+export default {
+  page: 'Page',
+
+  form: 'Form',
+  formBasic: 'Basic Form',
+  formStep: 'Step Form',
+  formHigh: 'Advanced Form',
+
+  desc: 'Details',
+  descBasic: 'Basic Details',
+  descHigh: 'Advanced Details',
+
+  result: 'Result',
+  resultSuccess: 'Success',
+  resultFail: 'Failed',
+
+  account: 'Personal',
+  accountCenter: 'Personal Center',
+  accountSetting: 'Personal Settings',
+
+  exception: 'Exception',
+  netWorkError: 'Network Error',
+  notData: 'No data',
+
+  list: 'List page',
+  listCard: 'Card list',
+};

+ 13 - 0
src/locales/lang/en/routes/demo/permission.ts

@@ -0,0 +1,13 @@
+export default {
+  permission: 'Permission',
+
+  front: 'front-end',
+  frontPage: 'Page',
+  frontBtn: 'Button',
+  frontTestA: 'Test page A',
+  frontTestB: 'Test page B',
+
+  back: 'background',
+  backPage: 'Page',
+  backBtn: 'Button',
+};

+ 19 - 0
src/locales/lang/en/routes/demo/table.ts

@@ -0,0 +1,19 @@
+export default {
+  table: 'Table',
+
+  basic: 'Basic',
+  treeTable: 'Tree',
+  fetchTable: 'Remote loading',
+  fixedColumn: 'Fixed column',
+  customerCell: 'Custom column',
+  formTable: 'Open search',
+  useTable: 'UseTable',
+  refTable: 'RefTable',
+  multipleHeader: 'MultiLevel header',
+  mergeHeader: 'Merge cells',
+  expandTable: 'Expandable table',
+  fixedHeight: 'Fixed height',
+  footerTable: 'Footer',
+  editCellTable: 'Editable cell',
+  editRowTable: 'Editable row',
+};

+ 7 - 0
src/locales/lang/en/routes/demo/tree.ts

@@ -0,0 +1,7 @@
+export default {
+  tree: 'Tree',
+
+  basic: 'Basic',
+  editTree: 'Right-click',
+  actionTree: 'Function operation',
+};

+ 0 - 3
src/locales/lang/en/routes/menus/dashboard.ts

@@ -1,3 +0,0 @@
-export default {
-  someentry: 'some text',
-};

+ 21 - 0
src/locales/lang/en/sys/api.ts

@@ -0,0 +1,21 @@
+export default {
+  operationFailed: 'Operation failed',
+  errorTip: 'Error Tip',
+  errorMessage: 'The operation failed, the system is abnormal!',
+  timeoutMessage: 'Login timed out, please log in again!',
+  apiTimeoutMessage: 'The interface request timed out, please refresh the page and try again!',
+  networkException: 'network anomaly',
+  networkExceptionMsg: 'Please check if your network connection is normal! The network is abnormal',
+
+  errMsg401: 'The user does not have permission (token, user name, password error)!',
+  errMsg403: 'The user is authorized, but access is forbidden!',
+  errMsg404: 'Network request error, the resource was not found!',
+  errMsg405: 'Network request error, request method not allowed!',
+  errMsg408: 'Network request timed out!',
+  errMsg500: 'Server error, please contact the administrator!',
+  errMsg501: 'The network is not implemented!',
+  errMsg502: 'Network Error!',
+  errMsg503: 'The service is unavailable, the server is temporarily overloaded or maintained!',
+  errMsg504: 'Network timeout!',
+  errMsg505: 'The http version does not support the request!',
+};

+ 5 - 0
src/locales/lang/en/sys/app.ts

@@ -0,0 +1,5 @@
+export default {
+  loginOutTip: 'Reminder',
+  loginOutMessage: 'Confirm to exit the system?',
+  menuLoading: 'Menu loading...',
+};

+ 0 - 1
src/locales/lang/zh_CN/component/modal.ts

@@ -1,5 +1,4 @@
 export default {
-  loadingText: '加载中...',
   cancelText: '关闭',
   okText: '确认',
 };

+ 1 - 0
src/locales/lang/zh_CN/routes/README.MD

@@ -0,0 +1 @@
+Share with menu

+ 3 - 0
src/locales/lang/zh_CN/routes/baisc.ts

@@ -0,0 +1,3 @@
+export default {
+  login: '登录',
+};

+ 6 - 0
src/locales/lang/zh_CN/routes/dashboard.ts

@@ -0,0 +1,6 @@
+export default {
+  dashboard: 'Dashboard',
+  welcome: '首页',
+  workbench: '工作台',
+  analysis: '分析页',
+};

+ 7 - 0
src/locales/lang/zh_CN/routes/demo/charts.ts

@@ -0,0 +1,7 @@
+export default {
+  charts: '图表库',
+  map: '地图',
+  line: '折线图',
+  pie: '饼图',
+  apexChart: 'ApexChart',
+};

+ 27 - 0
src/locales/lang/zh_CN/routes/demo/comp.ts

@@ -0,0 +1,27 @@
+export default {
+  comp: '组件',
+  basic: '基础组件',
+  transition: '动画组件',
+  countTo: '数字动画',
+
+  scroll: '滚动组件',
+  scrollBasic: '基础滚动',
+  scrollAction: '滚动函数',
+  virtualScroll: '虚拟滚动',
+
+  modal: '弹窗扩展',
+  drawer: '抽屉扩展',
+  desc: '详情组件',
+
+  lazy: '懒加载组件',
+  lazyBasic: '基础示例',
+  lazyTransition: '动画效果',
+
+  verify: '验证组件',
+  verifyDrag: '拖拽校验',
+  verifyRotate: '图片还原',
+
+  qrcode: '二维码组件',
+  strength: '密码强度组件',
+  upload: '上传组件',
+};

+ 8 - 0
src/locales/lang/zh_CN/routes/demo/editor.ts

@@ -0,0 +1,8 @@
+export default {
+  editor: '编辑器',
+  markdown: 'markdown编辑器',
+
+  tinymce: '富文本',
+  tinymceBasic: '基础使用',
+  tinymceForm: '嵌入form',
+};

+ 7 - 0
src/locales/lang/zh_CN/routes/demo/excel.ts

@@ -0,0 +1,7 @@
+export default {
+  excel: 'Excel',
+  customExport: '选择导出格式',
+  jsonExport: 'JSON数据导出',
+  arrayExport: 'Array数据导出',
+  importExcel: '导入',
+};

+ 17 - 0
src/locales/lang/zh_CN/routes/demo/feat.ts

@@ -0,0 +1,17 @@
+export default {
+  feat: '页面功能',
+  icon: '图标',
+  tabs: '标签页操作',
+  contextMenu: '右键菜单',
+  download: '文件下载',
+  clickOutSide: 'ClickOutSide组件',
+  imgPreview: '图片预览',
+  copy: '剪切板',
+  msg: '消息提示',
+  watermark: '水印',
+  fullScreen: '全屏',
+  errorLog: '错误日志',
+  tab: 'Tab带参',
+  tab1: 'Tab带参1',
+  tab2: 'Tab带参2',
+};

+ 10 - 0
src/locales/lang/zh_CN/routes/demo/form.ts

@@ -0,0 +1,10 @@
+export default {
+  form: 'Form',
+  basic: '基础表单',
+  useForm: 'useForm',
+  refForm: 'RefForm',
+  advancedForm: '可收缩表单',
+  ruleForm: '表单验证',
+  dynamicForm: '动态表单',
+  customerForm: '自定义组件',
+};

+ 6 - 0
src/locales/lang/zh_CN/routes/demo/iframe.ts

@@ -0,0 +1,6 @@
+export default {
+  frame: '外部页面',
+  antv: 'antVue文档(内嵌)',
+  doc: '项目文档(内嵌)',
+  docExternal: '项目文档(外链)',
+};

+ 27 - 0
src/locales/lang/zh_CN/routes/demo/page.ts

@@ -0,0 +1,27 @@
+export default {
+  page: '页面',
+
+  form: '表单页',
+  formBasic: '基础表单',
+  formStep: '分步表单',
+  formHigh: '高级表单',
+
+  desc: '详情页',
+  descBasic: '基础详情页',
+  descHigh: '高级详情页',
+
+  result: '结果页',
+  resultSuccess: '成功页',
+  resultFail: '失败页',
+
+  account: '个人页',
+  accountCenter: '个人中心',
+  accountSetting: '个人设置',
+
+  exception: '异常页',
+  netWorkError: '网络错误',
+  notData: '无数据',
+
+  list: '列表页',
+  listCard: '卡片列表',
+};

+ 13 - 0
src/locales/lang/zh_CN/routes/demo/permission.ts

@@ -0,0 +1,13 @@
+export default {
+  permission: '权限管理',
+
+  front: '基于前端权限',
+  frontPage: '页面权限',
+  frontBtn: '按钮权限',
+  frontTestA: '权限测试页A',
+  frontTestB: '权限测试页B',
+
+  back: '基于后台权限',
+  backPage: '页面权限',
+  backBtn: '按钮权限',
+};

+ 19 - 0
src/locales/lang/zh_CN/routes/demo/table.ts

@@ -0,0 +1,19 @@
+export default {
+  table: 'Table',
+
+  basic: '基础表格',
+  treeTable: '树形表格',
+  fetchTable: '远程加载示例',
+  fixedColumn: '固定列',
+  customerCell: '自定义列',
+  formTable: '开启搜索区域',
+  useTable: 'UseTable',
+  refTable: 'RefTable',
+  multipleHeader: '多级表头',
+  mergeHeader: '合并单元格',
+  expandTable: '可展开表格',
+  fixedHeight: '定高/头部自定义',
+  footerTable: '表尾行合计',
+  editCellTable: '可编辑单元格',
+  editRowTable: '可编辑行',
+};

+ 7 - 0
src/locales/lang/zh_CN/routes/demo/tree.ts

@@ -0,0 +1,7 @@
+export default {
+  tree: 'Tree',
+
+  basic: '基础树',
+  editTree: '右键示例',
+  actionTree: '函数操作示例',
+};

+ 0 - 3
src/locales/lang/zh_CN/routes/menus/dashboard.ts

@@ -1,3 +0,0 @@
-export default {
-  someentry: '一些文本',
-};

+ 21 - 0
src/locales/lang/zh_CN/sys/api.ts

@@ -0,0 +1,21 @@
+export default {
+  operationFailed: '操作失败',
+  errorTip: '错误提示',
+  errorMessage: '操作失败,系统异常!',
+  timeoutMessage: '登录超时,请重新登录!',
+  apiTimeoutMessage: '接口请求超时,请刷新页面重试!',
+  networkException: '网络异常',
+  networkExceptionMsg: '网请检查您的网络连接是否正常!络异常',
+
+  errMsg401: '用户没有权限(令牌、用户名、密码错误)!',
+  errMsg403: '用户得到授权,但是访问是被禁止的。!',
+  errMsg404: '网络请求错误,未找到该资源!',
+  errMsg405: '网络请求错误,请求方法未允许!',
+  errMsg408: '网络请求超时!',
+  errMsg500: '服务器错误,请联系管理员!',
+  errMsg501: '网络未实现!',
+  errMsg502: '网络错误!',
+  errMsg503: '服务不可用,服务器暂时过载或维护!',
+  errMsg504: '网络超时!',
+  errMsg505: 'http版本不支持该请求!',
+};

+ 5 - 0
src/locales/lang/zh_CN/sys/app.ts

@@ -0,0 +1,5 @@
+export default {
+  loginOutTip: '温馨提醒',
+  loginOutMessage: '是否确认退出系统?',
+  menuLoading: '菜单加载中...',
+};

+ 3 - 1
src/router/guard/index.ts

@@ -13,6 +13,7 @@ import { setTitle } from '/@/utils/browser';
 import { AxiosCanceler } from '/@/utils/http/axios/axiosCancel';
 
 import { tabStore } from '/@/store/modules/tab';
+import { useI18n } from '/@/hooks/web/useI18n';
 
 const { closeMessageOnSwitch, removeAllHttpPending } = useProjectSetting();
 const globSetting = useGlobSetting();
@@ -54,8 +55,9 @@ export function createGuard(router: Router) {
   });
 
   router.afterEach((to) => {
+    const { t } = useI18n();
     // change html title
-    setTitle(to.meta.title, globSetting.title);
+    setTitle(t(to.meta.title), globSetting.title);
   });
   createProgressGuard(router);
   createPermissionGuard(router);

+ 5 - 10
src/router/menus/modules/dashboard.ts

@@ -1,27 +1,22 @@
 import type { MenuModule } from '/@/router/types.d';
+
 const menu: MenuModule = {
   orderNo: 10,
   menu: {
-    name: 'Dashboard',
+    name: 'routes.dashboard.dashboard',
     path: '/dashboard',
-    // tag: {
-    //   dot: true,
-    // },
     children: [
       {
         path: '/workbench',
-        name: '工作台',
-        // tag: {
-        //   content: 'new',
-        // },
+        name: 'routes.dashboard.workbench',
       },
       {
         path: '/analysis',
-        name: '分析页',
+        name: 'routes.dashboard.analysis',
       },
       {
         path: '/welcome',
-        name: '首页',
+        name: 'routes.dashboard.welcome',
       },
     ],
   },

+ 6 - 5
src/router/menus/modules/demo/charts.ts

@@ -1,13 +1,14 @@
 import type { MenuModule } from '/@/router/types.d';
+
 const menu: MenuModule = {
   orderNo: 500,
   menu: {
-    name: '图表',
+    name: 'routes.demo.charts.charts',
     path: '/charts',
     children: [
       {
         path: 'apexChart',
-        name: 'ApexChart',
+        name: 'routes.demo.charts.apexChart',
       },
       {
         path: 'echarts',
@@ -15,15 +16,15 @@ const menu: MenuModule = {
         children: [
           {
             path: 'map',
-            name: '地图',
+            name: 'routes.demo.charts.map',
           },
           {
             path: 'line',
-            name: '折线图',
+            name: 'routes.demo.charts.line',
           },
           {
             path: 'pie',
-            name: '饼图',
+            name: 'routes.demo.charts.pie',
           },
         ],
       },

+ 21 - 30
src/router/menus/modules/demo/comp.ts

@@ -1,101 +1,92 @@
 import type { MenuModule } from '/@/router/types.d';
+
 const menu: MenuModule = {
   orderNo: 30,
   menu: {
-    name: '组件',
+    name: 'routes.demo.comp.comp',
     path: '/comp',
 
     children: [
       {
         path: 'basic',
-        name: '基础组件',
+        name: 'routes.demo.comp.basic',
       },
       {
         path: 'countTo',
-        name: '数字动画',
+        name: 'routes.demo.comp.countTo',
       },
       {
         path: 'transition',
-        name: '动画组件',
+        name: 'routes.demo.comp.transition',
       },
 
       {
         path: 'modal',
-        name: '弹窗扩展',
+        name: 'routes.demo.comp.modal',
       },
       {
         path: 'drawer',
-        name: '抽屉扩展',
+        name: 'routes.demo.comp.drawer',
       },
       {
         path: 'desc',
-        name: '详情组件',
+        name: 'routes.demo.comp.desc',
       },
       {
         path: 'qrcode',
-        name: '二维码组件',
+        name: 'routes.demo.comp.qrcode',
       },
       {
         path: 'strength-meter',
-        name: '密码强度组件',
+        name: 'routes.demo.comp.strength',
       },
       {
         path: 'upload',
-        name: '上传组件',
+        name: 'routes.demo.comp.upload',
       },
       {
         path: 'scroll',
-        name: '滚动组件',
+        name: 'routes.demo.comp.scroll',
         children: [
           {
             path: 'basic',
-            name: '基础示例',
+            name: 'routes.demo.comp.scrollBasic',
           },
           {
             path: 'action',
-            name: '函数操作示例',
+            name: 'routes.demo.comp.scrollAction',
           },
           {
             path: 'virtualScroll',
-            name: '虚拟滚动',
+            name: 'routes.demo.comp.virtualScroll',
           },
         ],
       },
       {
         path: 'lazy',
-        name: '懒加载组件',
+        name: 'routes.demo.comp.lazy',
         children: [
           {
             path: 'basic',
-            name: '基础示例',
+            name: 'routes.demo.comp.lazyBasic',
           },
           {
             path: 'transition',
-            name: '动画效果',
+            name: 'routes.demo.comp.lazyTransition',
           },
         ],
       },
       {
         path: 'verify',
-        name: '验证组件',
+        name: 'routes.demo.comp.verify',
         children: [
           {
             path: 'drag',
-            name: '拖拽校验',
+            name: 'routes.demo.comp.verifyDrag',
           },
           {
             path: 'rotate',
-            name: '图片还原校验',
-          },
-        ],
-      },
-      {
-        path: '/form',
-        name: '验证组件',
-        children: [
-          {
-            path: '/base',
-            name: '拖拽校验',
+            name: 'routes.demo.comp.verifyRotate',
           },
         ],
       },

+ 6 - 5
src/router/menus/modules/demo/editor.ts

@@ -1,25 +1,26 @@
 import type { MenuModule } from '/@/router/types.d';
+
 const menu: MenuModule = {
   orderNo: 500,
   menu: {
-    name: '编辑器',
+    name: 'routes.demo.editor.editor',
     path: '/editor',
     children: [
       {
         path: 'markdown',
-        name: 'markdown编辑器',
+        name: 'routes.demo.editor.markdown',
       },
       {
         path: 'tinymce',
-        name: '富文本',
+        name: 'routes.demo.editor.tinymce',
         children: [
           {
             path: 'index',
-            name: '基础使用',
+            name: 'routes.demo.editor.tinymceBasic',
           },
           {
             path: 'editor',
-            name: '嵌入form使用',
+            name: 'routes.demo.editor.tinymceForm',
           },
         ],
       },

+ 6 - 5
src/router/menus/modules/demo/excel.ts

@@ -1,25 +1,26 @@
 import type { MenuModule } from '/@/router/types.d';
+
 const menu: MenuModule = {
   orderNo: 500,
   menu: {
-    name: 'Excel',
+    name: 'routes.demo.excel.excel',
     path: '/excel',
     children: [
       {
         path: 'customExport',
-        name: '选择导出格式',
+        name: 'routes.demo.excel.customExport',
       },
       {
         path: 'jsonExport',
-        name: 'JSON数据导出',
+        name: 'routes.demo.excel.jsonExport',
       },
       {
         path: 'arrayExport',
-        name: 'Array数据导出',
+        name: 'routes.demo.excel.arrayExport',
       },
       {
         path: 'importExcel',
-        name: '导入',
+        name: 'routes.demo.excel.importExcel',
       },
     ],
   },

+ 16 - 15
src/router/menus/modules/demo/feat.ts

@@ -1,66 +1,67 @@
 import type { MenuModule } from '/@/router/types.d';
+
 const menu: MenuModule = {
   orderNo: 19,
   menu: {
-    name: '功能',
+    name: 'routes.demo.feat.feat',
     path: '/feat',
 
     children: [
       {
         path: 'icon',
-        name: '图标',
+        name: 'routes.demo.feat.icon',
       },
       {
         path: 'tabs',
-        name: '标签页操作',
+        name: 'routes.demo.feat.tabs',
       },
       {
         path: 'context-menu',
-        name: '右键菜单',
+        name: 'routes.demo.feat.contextMenu',
       },
       {
         path: 'download',
-        name: '文件下载',
+        name: 'routes.demo.feat.download',
       },
       {
         path: 'click-out-side',
-        name: 'ClickOutSide',
+        name: 'routes.demo.feat.clickOutSide',
       },
       {
         path: 'img-preview',
-        name: '图片预览',
+        name: 'routes.demo.feat.imgPreview',
       },
       {
         path: 'copy',
-        name: '剪切板',
+        name: 'routes.demo.feat.copy',
       },
       {
         path: 'msg',
-        name: '消息提示',
+        name: 'routes.demo.feat.msg',
       },
       {
         path: 'watermark',
-        name: '水印',
+        name: 'routes.demo.feat.watermark',
       },
       {
         path: 'full-screen',
-        name: '全屏',
+        name: 'routes.demo.feat.fullScreen',
       },
       {
         path: 'error-log',
-        name: '错误日志',
+        name: 'routes.demo.feat.errorLog',
       },
       {
         path: 'testTab',
-        name: '带参Tab',
+        name: 'routes.demo.feat.tab',
         children: [
           {
             path: 'id1',
-            name: '带参tab1',
+            name: 'routes.demo.feat.tab1',
           },
           {
             path: 'id2',
-            name: '带参tab2',
+            name: 'routes.demo.feat.tab2',
           },
         ],
       },

+ 9 - 8
src/router/menus/modules/demo/form.ts

@@ -1,38 +1,39 @@
 import type { MenuModule } from '/@/router/types.d';
+
 const menu: MenuModule = {
   orderNo: 40,
   menu: {
     path: '/form',
-    name: 'Form',
+    name: 'routes.demo.form.form',
 
     children: [
       {
         path: 'basic',
-        name: '基础表单',
+        name: 'routes.demo.form.basic',
       },
       {
         path: 'useForm',
-        name: 'useForm',
+        name: 'routes.demo.form.useForm',
       },
       {
         path: 'refForm',
-        name: 'RefForm',
+        name: 'routes.demo.form.refForm',
       },
       {
         path: 'advancedForm',
-        name: '可收缩表单',
+        name: 'routes.demo.form.advancedForm',
       },
       {
         path: 'ruleForm',
-        name: '表单校验',
+        name: 'routes.demo.form.ruleForm',
       },
       {
         path: 'dynamicForm',
-        name: '动态表单',
+        name: 'routes.demo.form.dynamicForm',
       },
       {
         path: 'customerForm',
-        name: '自定义组件',
+        name: 'routes.demo.form.customerForm',
       },
     ],
   },

+ 5 - 4
src/router/menus/modules/demo/iframe.ts

@@ -1,21 +1,22 @@
 import type { MenuModule } from '/@/router/types.d';
+
 const menu: MenuModule = {
   orderNo: 1000,
   menu: {
-    name: '外部页面',
+    name: 'routes.demo.iframe.frame',
     path: '/frame',
     children: [
       {
         path: 'antv',
-        name: 'antVue文档(内嵌)',
+        name: 'routes.demo.iframe.antv',
       },
       {
         path: 'doc',
-        name: '项目文档(内嵌)',
+        name: 'routes.demo.iframe.doc',
       },
       {
         path: 'docExternal',
-        name: '项目文档(外链)',
+        name: 'routes.demo.iframe.docExternal',
       },
     ],
   },

+ 20 - 19
src/router/menus/modules/demo/page.ts

@@ -1,8 +1,9 @@
 import type { MenuModule } from '/@/router/types.d';
+
 const menu: MenuModule = {
   orderNo: 20,
   menu: {
-    name: '页面',
+    name: 'routes.demo.page.page',
     path: '/page-demo',
     tag: {
       dot: true,
@@ -10,56 +11,56 @@ const menu: MenuModule = {
     children: [
       {
         path: 'form',
-        name: '表单页',
+        name: 'routes.demo.page.form',
 
         children: [
           {
             path: 'basic',
-            name: '基础表单',
+            name: 'routes.demo.page.formBasic',
           },
           {
             path: 'step',
-            name: '分步表单',
+            name: 'routes.demo.page.formStep',
           },
           {
             path: 'high',
-            name: '高级表单',
+            name: 'routes.demo.page.formHigh',
           },
         ],
       },
       {
         path: 'desc',
-        name: '详情页',
+        name: 'routes.demo.page.desc',
 
         children: [
           {
             path: 'basic',
-            name: '基础详情页',
+            name: 'routes.demo.page.descBasic',
           },
           {
             path: 'high',
-            name: '高级详情页',
+            name: 'routes.demo.page.descHigh',
           },
         ],
       },
       {
         path: 'result',
-        name: '结果页',
+        name: 'routes.demo.page.result',
 
         children: [
           {
             path: 'success',
-            name: '成功页',
+            name: 'routes.demo.page.resultSuccess',
           },
           {
             path: 'fail',
-            name: '失败页',
+            name: 'routes.demo.page.resultFail',
           },
         ],
       },
       {
         path: 'exception',
-        name: '异常页',
+        name: 'routes.demo.page.exception',
         children: [
           {
             path: '403',
@@ -75,38 +76,38 @@ const menu: MenuModule = {
           },
           {
             path: 'net-work-error',
-            name: '网络错误',
+            name: 'routes.demo.page.netWorkError',
           },
           {
             path: 'not-data',
-            name: '无数据',
+            name: 'routes.demo.page.notData',
           },
         ],
       },
       {
         path: 'account',
-        name: '个人页',
+        name: 'routes.demo.page.account',
         children: [
           {
             path: 'center',
-            name: '个人中心',
+            name: 'routes.demo.page.accountCenter',
           },
           {
             path: 'setting',
-            name: '个人设置',
+            name: 'routes.demo.page.accountSetting',
           },
         ],
       },
       {
         path: 'list',
-        name: '列表页',
+        name: 'routes.demo.page.list',
         tag: {
           content: 'new',
         },
         children: [
           {
             path: 'card',
-            name: '卡片列表',
+            name: 'routes.demo.page.listCard',
           },
         ],
       },

+ 10 - 9
src/router/menus/modules/demo/permission.ts

@@ -1,43 +1,44 @@
 import type { MenuModule } from '/@/router/types.d';
+
 const menu: MenuModule = {
   orderNo: 15,
   menu: {
-    name: '权限管理',
+    name: 'routes.demo.permission.permission',
     path: '/permission',
     children: [
       {
         path: 'front',
-        name: '基于前端',
+        name: 'routes.demo.permission.front',
         children: [
           {
             path: 'page',
-            name: '页面权限',
+            name: 'routes.demo.permission.frontPage',
           },
           {
             path: 'btn',
-            name: '按钮权限',
+            name: 'routes.demo.permission.frontBtn',
           },
           {
             path: 'auth-pageA',
-            name: '权限测试页A',
+            name: 'routes.demo.permission.frontTestA',
           },
           {
             path: 'auth-pageB',
-            name: '权限测试页B',
+            name: 'routes.demo.permission.frontTestB',
           },
         ],
       },
       {
         path: 'back',
-        name: '基于后台',
+        name: 'routes.demo.permission.back',
         children: [
           {
             path: 'page',
-            name: '页面权限',
+            name: 'routes.demo.permission.backPage',
           },
           {
             path: 'btn',
-            name: '按钮权限',
+            name: 'routes.demo.permission.backBtn',
           },
         ],
       },

+ 17 - 16
src/router/menus/modules/demo/table.ts

@@ -1,69 +1,70 @@
 import type { MenuModule } from '/@/router/types.d';
+
 const menu: MenuModule = {
   orderNo: 30,
   menu: {
     path: '/table',
-    name: 'Table',
+    name: 'routes.demo.table.table',
     children: [
       {
         path: 'basic',
-        name: '基础表格',
+        name: 'routes.demo.table.basic',
       },
       {
         path: 'treeTable',
-        name: '树形表格',
+        name: 'routes.demo.table.treeTable',
       },
       {
         path: 'fetchTable',
-        name: '远程加载',
+        name: 'routes.demo.table.fetchTable',
       },
       {
         path: 'fixedColumn',
-        name: '固定列',
+        name: 'routes.demo.table.fixedColumn',
       },
       {
         path: 'customerCell',
-        name: '自定义列',
+        name: 'routes.demo.table.customerCell',
       },
       {
         path: 'formTable',
-        name: '开启搜索区域',
+        name: 'routes.demo.table.formTable',
       },
       {
         path: 'useTable',
-        name: 'UseTable',
+        name: 'routes.demo.table.useTable',
       },
       {
         path: 'refTable',
-        name: 'RefTable',
+        name: 'routes.demo.table.refTable',
       },
       {
         path: 'multipleHeader',
-        name: '多级表头',
+        name: 'routes.demo.table.multipleHeader',
       },
       {
         path: 'mergeHeader',
-        name: '合并单元格',
+        name: 'routes.demo.table.mergeHeader',
       },
       {
         path: 'expandTable',
-        name: '可展开表格',
+        name: 'routes.demo.table.expandTable',
       },
       {
         path: 'fixedHeight',
-        name: '定高/头部自定义',
+        name: 'routes.demo.table.fixedHeight',
       },
       {
         path: 'footerTable',
-        name: '表尾行合计',
+        name: 'routes.demo.table.footerTable',
       },
       {
         path: 'editCellTable',
-        name: '可编辑单元格',
+        name: 'routes.demo.table.editCellTable',
       },
       {
         path: 'editRowTable',
-        name: '可编辑行',
+        name: 'routes.demo.table.editRowTable',
       },
     ],
   },

+ 5 - 4
src/router/menus/modules/demo/tree.ts

@@ -1,21 +1,22 @@
 import type { MenuModule } from '/@/router/types.d';
+
 const menu: MenuModule = {
   orderNo: 50,
   menu: {
     path: '/tree',
-    name: 'Tree',
+    name: 'routes.demo.tree.tree',
     children: [
       {
         path: 'basic',
-        name: '基础示例',
+        name: 'routes.demo.tree.basic',
       },
       {
         path: 'editTree',
-        name: '右键示例',
+        name: 'routes.demo.tree.editTree',
       },
       {
         path: 'actionTree',
-        name: '函数操作示例',
+        name: 'routes.demo.tree.actionTree',
       },
     ],
   },

+ 1 - 1
src/router/routes/index.ts

@@ -33,7 +33,7 @@ export const LoginRoute: AppRouteRecordRaw = {
   name: 'Login',
   component: () => import('/@/views/sys/login/Login.vue'),
   meta: {
-    title: '登录',
+    title: 'routes.basic.login',
   },
 };
 

+ 4 - 4
src/router/routes/modules/dashboard.ts

@@ -10,7 +10,7 @@ const dashboard: AppRouteModule = {
     redirect: '/dashboard/workbench',
     meta: {
       icon: 'ant-design:home-outlined',
-      title: 'Dashboard',
+      title: 'routes.dashboard.dashboard',
     },
   },
 
@@ -20,7 +20,7 @@ const dashboard: AppRouteModule = {
       name: 'Welcome',
       component: () => import('/@/views/dashboard/welcome/index.vue'),
       meta: {
-        title: '首页',
+        title: 'routes.dashboard.welcome',
       },
     },
     {
@@ -28,7 +28,7 @@ const dashboard: AppRouteModule = {
       name: 'Workbench',
       component: () => import('/@/views/dashboard/workbench/index.vue'),
       meta: {
-        title: '工作台',
+        title: 'routes.dashboard.workbench',
         affix: true,
       },
     },
@@ -37,7 +37,7 @@ const dashboard: AppRouteModule = {
       name: 'Analysis',
       component: () => import('/@/views/dashboard/analysis/index.vue'),
       meta: {
-        title: '分析页',
+        title: 'routes.dashboard.analysis',
       },
     },
   ],

+ 5 - 5
src/router/routes/modules/demo/charts.ts

@@ -10,7 +10,7 @@ const charts: AppRouteModule = {
     redirect: '/charts/apexChart',
     meta: {
       icon: 'ant-design:area-chart-outlined',
-      title: '图表库',
+      title: 'routes.demo.charts.charts',
     },
   },
 
@@ -27,7 +27,7 @@ const charts: AppRouteModule = {
           name: 'Map',
           component: () => import('/@/views/demo/echarts/Map.vue'),
           meta: {
-            title: '地图',
+            title: 'routes.demo.charts.map',
           },
         },
         {
@@ -35,7 +35,7 @@ const charts: AppRouteModule = {
           name: 'Line',
           component: () => import('/@/views/demo/echarts/Line.vue'),
           meta: {
-            title: '折线图',
+            title: 'routes.demo.charts.line',
           },
         },
         {
@@ -43,7 +43,7 @@ const charts: AppRouteModule = {
           name: 'Pie',
           component: () => import('/@/views/demo/echarts/Pie.vue'),
           meta: {
-            title: '饼图',
+            title: 'routes.demo.charts.pie',
           },
         },
       ],
@@ -52,7 +52,7 @@ const charts: AppRouteModule = {
       path: '/apexChart',
       name: 'ApexChart',
       meta: {
-        title: 'ApexChart',
+        title: 'routes.demo.charts.apexChart',
       },
       component: () => import('/@/views/demo/echarts/apex/index.vue'),
     },

+ 20 - 20
src/router/routes/modules/demo/comp.ts

@@ -10,7 +10,7 @@ const comp: AppRouteModule = {
     redirect: '/comp/basic',
     meta: {
       icon: 'ant-design:table-outlined',
-      title: '组件',
+      title: 'routes.demo.comp.comp',
     },
   },
 
@@ -20,7 +20,7 @@ const comp: AppRouteModule = {
       name: 'BasicDemo',
       component: () => import('/@/views/demo/comp/button/index.vue'),
       meta: {
-        title: '基础组件',
+        title: 'routes.demo.comp.basic',
       },
     },
     {
@@ -28,7 +28,7 @@ const comp: AppRouteModule = {
       name: 'transitionDemo',
       component: () => import('/@/views/demo/comp/transition/index.vue'),
       meta: {
-        title: '动画组件',
+        title: 'routes.demo.comp.transition',
       },
     },
     {
@@ -36,7 +36,7 @@ const comp: AppRouteModule = {
       name: 'CountTo',
       component: () => import('/@/views/demo/comp/count-to/index.vue'),
       meta: {
-        title: '数字动画',
+        title: 'routes.demo.comp.countTo',
       },
     },
 
@@ -45,7 +45,7 @@ const comp: AppRouteModule = {
       name: 'ScrollDemo',
       redirect: '/comp/scroll/basic',
       meta: {
-        title: '滚动组件',
+        title: 'routes.demo.comp.scroll',
       },
       children: [
         {
@@ -53,7 +53,7 @@ const comp: AppRouteModule = {
           name: 'BasicScrollDemo',
           component: () => import('/@/views/demo/comp/scroll/index.vue'),
           meta: {
-            title: '基础滚动',
+            title: 'routes.demo.comp.scrollBasic',
           },
         },
         {
@@ -61,7 +61,7 @@ const comp: AppRouteModule = {
           name: 'ActionScrollDemo',
           component: () => import('/@/views/demo/comp/scroll/Action.vue'),
           meta: {
-            title: '滚动函数',
+            title: 'routes.demo.comp.scrollAction',
           },
         },
         {
@@ -69,7 +69,7 @@ const comp: AppRouteModule = {
           name: 'VirtualScrollDemo',
           component: () => import('/@/views/demo/comp/scroll/VirtualScroll.vue'),
           meta: {
-            title: '虚拟滚动',
+            title: 'routes.demo.comp.virtualScroll',
           },
         },
       ],
@@ -80,7 +80,7 @@ const comp: AppRouteModule = {
       name: 'ModalDemo',
       component: () => import('/@/views/demo/comp/modal/index.vue'),
       meta: {
-        title: '弹窗扩展',
+        title: 'routes.demo.comp.modal',
       },
     },
     {
@@ -88,7 +88,7 @@ const comp: AppRouteModule = {
       name: 'DrawerDemo',
       component: () => import('/@/views/demo/comp/drawer/index.vue'),
       meta: {
-        title: '抽屉扩展',
+        title: 'routes.demo.comp.drawer',
       },
     },
     {
@@ -96,7 +96,7 @@ const comp: AppRouteModule = {
       name: 'DescDemo',
       component: () => import('/@/views/demo/comp/desc/index.vue'),
       meta: {
-        title: '详情组件',
+        title: 'routes.demo.comp.desc',
       },
     },
 
@@ -105,7 +105,7 @@ const comp: AppRouteModule = {
       name: 'lazyDemo',
       redirect: '/comp/lazy/basic',
       meta: {
-        title: '懒加载组件',
+        title: 'routes.demo.comp.lazy',
       },
       children: [
         {
@@ -113,7 +113,7 @@ const comp: AppRouteModule = {
           name: 'BasicLazyDemo',
           component: () => import('/@/views/demo/comp/lazy/index.vue'),
           meta: {
-            title: '基础示例',
+            title: 'routes.demo.comp.lazyBasic',
           },
         },
         {
@@ -121,7 +121,7 @@ const comp: AppRouteModule = {
           name: 'BasicTransitionDemo',
           component: () => import('/@/views/demo/comp/lazy/Transition.vue'),
           meta: {
-            title: '动画效果',
+            title: 'routes.demo.comp.lazyTransition',
           },
         },
       ],
@@ -131,7 +131,7 @@ const comp: AppRouteModule = {
       name: 'VerifyDemo',
       redirect: '/comp/verify/drag',
       meta: {
-        title: '验证组件',
+        title: 'routes.demo.comp.verify',
       },
       children: [
         {
@@ -139,7 +139,7 @@ const comp: AppRouteModule = {
           name: 'VerifyDragDemo',
           component: () => import('/@/views/demo/comp/verify/index.vue'),
           meta: {
-            title: '拖拽校验',
+            title: 'routes.demo.comp.verifyDrag',
           },
         },
         {
@@ -147,7 +147,7 @@ const comp: AppRouteModule = {
           name: 'VerifyRotateDemo',
           component: () => import('/@/views/demo/comp/verify/Rotate.vue'),
           meta: {
-            title: '图片还原',
+            title: 'routes.demo.comp.verifyRotate',
           },
         },
       ],
@@ -159,7 +159,7 @@ const comp: AppRouteModule = {
       name: 'QrCodeDemo',
       component: () => import('/@/views/demo/comp/qrcode/index.vue'),
       meta: {
-        title: '二维码组件',
+        title: 'routes.demo.comp.qrcode',
       },
     },
     {
@@ -167,7 +167,7 @@ const comp: AppRouteModule = {
       name: 'StrengthMeterDemo',
       component: () => import('/@/views/demo/comp/strength-meter/index.vue'),
       meta: {
-        title: '密码强度组件',
+        title: 'routes.demo.comp.strength',
       },
     },
     {
@@ -175,7 +175,7 @@ const comp: AppRouteModule = {
       name: 'UploadDemo',
       component: () => import('/@/views/demo/comp/upload/index.vue'),
       meta: {
-        title: '上传组件',
+        title: 'routes.demo.comp.upload',
       },
     },
   ],

+ 5 - 5
src/router/routes/modules/demo/editor.ts

@@ -10,7 +10,7 @@ const editor: AppRouteModule = {
     redirect: '/editor/markdown',
     meta: {
       icon: 'ant-design:table-outlined',
-      title: '编辑器',
+      title: 'routes.demo.editor.editor',
     },
   },
 
@@ -20,14 +20,14 @@ const editor: AppRouteModule = {
       name: 'MarkdownDemo',
       component: () => import('/@/views/demo/editor/Markdown.vue'),
       meta: {
-        title: 'markdown编辑器',
+        title: 'routes.demo.editor.markdown',
       },
     },
     {
       path: '/tinymce',
       name: 'TinymceDemo',
       meta: {
-        title: '富文本',
+        title: 'routes.demo.editor.tinymce',
       },
       redirect: '/editor/tinymce/index',
       children: [
@@ -36,7 +36,7 @@ const editor: AppRouteModule = {
           name: 'TinymceBasicDemo',
           component: () => import('/@/views/demo/editor/tinymce/index.vue'),
           meta: {
-            title: '基础使用',
+            title: 'routes.demo.editor.tinymceBasic',
           },
         },
         // TODO
@@ -45,7 +45,7 @@ const editor: AppRouteModule = {
           name: 'TinymceFormDemo',
           component: () => import('/@/views/demo/editor/tinymce/Editor.vue'),
           meta: {
-            title: '嵌入form使用',
+            title: 'routes.demo.editor.tinymceForm',
           },
         },
       ],

+ 5 - 5
src/router/routes/modules/demo/excel.ts

@@ -10,7 +10,7 @@ const excel: AppRouteModule = {
     redirect: '/excel/customExport',
     meta: {
       icon: 'mdi:microsoft-excel',
-      title: 'Excel',
+      title: 'routes.demo.excel.excel',
     },
   },
 
@@ -20,7 +20,7 @@ const excel: AppRouteModule = {
       name: 'CustomExport',
       component: () => import('/@/views/demo/excel/CustomExport.vue'),
       meta: {
-        title: '选择导出格式',
+        title: 'routes.demo.excel.customExport',
       },
     },
     {
@@ -28,7 +28,7 @@ const excel: AppRouteModule = {
       name: 'JsonExport',
       component: () => import('/@/views/demo/excel/JsonExport.vue'),
       meta: {
-        title: 'JSON数据导出',
+        title: 'routes.demo.excel.jsonExport',
       },
     },
     {
@@ -36,7 +36,7 @@ const excel: AppRouteModule = {
       name: 'ArrayExport',
       component: () => import('/@/views/demo/excel/ArrayExport.vue'),
       meta: {
-        title: 'Array数据导出',
+        title: 'routes.demo.excel.arrayExport',
       },
     },
     {
@@ -44,7 +44,7 @@ const excel: AppRouteModule = {
       name: 'ImportExcel',
       component: () => import('/@/views/demo/excel/ImportExcel.vue'),
       meta: {
-        title: '导入',
+        title: 'routes.demo.excel.importExcel',
       },
     },
   ],

+ 13 - 13
src/router/routes/modules/demo/feat.ts

@@ -10,7 +10,7 @@ const feat: AppRouteModule = {
     redirect: '/feat/icon',
     meta: {
       icon: 'ic:outline-featured-play-list',
-      title: '页面功能',
+      title: 'routes.demo.feat.feat',
     },
   },
 
@@ -20,7 +20,7 @@ const feat: AppRouteModule = {
       name: 'IconDemo',
       component: () => import('/@/views/demo/feat/icon/index.vue'),
       meta: {
-        title: '图标',
+        title: 'routes.demo.feat.icon',
       },
     },
     {
@@ -28,7 +28,7 @@ const feat: AppRouteModule = {
       name: 'TabsDemo',
       component: () => import('/@/views/demo/feat/tabs/index.vue'),
       meta: {
-        title: '标签页操作',
+        title: 'routes.demo.feat.tabs',
       },
     },
 
@@ -37,7 +37,7 @@ const feat: AppRouteModule = {
       name: 'ContextMenuDemo',
       component: () => import('/@/views/demo/feat/context-menu/index.vue'),
       meta: {
-        title: '右键菜单',
+        title: 'routes.demo.feat.contextMenu',
       },
     },
     {
@@ -45,7 +45,7 @@ const feat: AppRouteModule = {
       name: 'DownLoadDemo',
       component: () => import('/@/views/demo/feat/download/index.vue'),
       meta: {
-        title: '文件下载',
+        title: 'routes.demo.feat.download',
       },
     },
     {
@@ -53,7 +53,7 @@ const feat: AppRouteModule = {
       name: 'ClickOutSideDemo',
       component: () => import('/@/views/demo/feat/click-out-side/index.vue'),
       meta: {
-        title: 'ClickOutSide组件',
+        title: 'routes.demo.feat.clickOutSide',
       },
     },
     {
@@ -61,7 +61,7 @@ const feat: AppRouteModule = {
       name: 'ImgPreview',
       component: () => import('/@/views/demo/feat/img-preview/index.vue'),
       meta: {
-        title: '图片预览',
+        title: 'routes.demo.feat.imgPreview',
       },
     },
     {
@@ -69,7 +69,7 @@ const feat: AppRouteModule = {
       name: 'CopyDemo',
       component: () => import('/@/views/demo/feat/copy/index.vue'),
       meta: {
-        title: '剪切板',
+        title: 'routes.demo.feat.copy',
       },
     },
     {
@@ -77,7 +77,7 @@ const feat: AppRouteModule = {
       name: 'MsgDemo',
       component: () => import('/@/views/demo/feat/msg/index.vue'),
       meta: {
-        title: '消息提示',
+        title: 'routes.demo.feat.msg',
       },
     },
     {
@@ -85,7 +85,7 @@ const feat: AppRouteModule = {
       name: 'WatermarkDemo',
       component: () => import('/@/views/demo/feat/watermark/index.vue'),
       meta: {
-        title: '水印',
+        title: 'routes.demo.feat.watermark',
       },
     },
     {
@@ -93,7 +93,7 @@ const feat: AppRouteModule = {
       name: 'FullScreenDemo',
       component: () => import('/@/views/demo/feat/full-screen/index.vue'),
       meta: {
-        title: '全屏',
+        title: 'routes.demo.feat.fullScreen',
       },
     },
     {
@@ -101,7 +101,7 @@ const feat: AppRouteModule = {
       name: 'ErrorLog',
       component: () => import('/@/views/sys/error-log/index.vue'),
       meta: {
-        title: '错误日志',
+        title: 'routes.demo.feat.errorLog',
       },
     },
     {
@@ -109,7 +109,7 @@ const feat: AppRouteModule = {
       name: 'TestTab',
       component: () => import('/@/views/demo/feat/tab-params/index.vue'),
       meta: {
-        title: 'Tab带参',
+        title: 'routes.demo.feat.tab',
         carryParam: true,
       },
     },

+ 8 - 8
src/router/routes/modules/demo/form.ts

@@ -10,7 +10,7 @@ const form: AppRouteModule = {
     redirect: '/form/basic',
     meta: {
       icon: 'ant-design:table-outlined',
-      title: 'Form',
+      title: 'rroutes.demo.form.form',
     },
   },
 
@@ -20,7 +20,7 @@ const form: AppRouteModule = {
       name: 'FormBasicDemo',
       component: () => import('/@/views/demo/form/index.vue'),
       meta: {
-        title: '基础表单',
+        title: 'rroutes.demo.form.basic',
       },
     },
     {
@@ -28,7 +28,7 @@ const form: AppRouteModule = {
       name: 'UseFormDemo',
       component: () => import('/@/views/demo/form/UseForm.vue'),
       meta: {
-        title: 'useForm',
+        title: 'rroutes.demo.form.useForm',
       },
     },
     {
@@ -36,7 +36,7 @@ const form: AppRouteModule = {
       name: 'RefFormDemo',
       component: () => import('/@/views/demo/form/RefForm.vue'),
       meta: {
-        title: 'RefForm',
+        title: 'rroutes.demo.form.refForm',
       },
     },
     {
@@ -44,7 +44,7 @@ const form: AppRouteModule = {
       name: 'AdvancedFormDemo',
       component: () => import('/@/views/demo/form/AdvancedForm.vue'),
       meta: {
-        title: '可收缩表单',
+        title: 'rroutes.demo.form.advancedForm',
       },
     },
     {
@@ -52,7 +52,7 @@ const form: AppRouteModule = {
       name: 'RuleFormDemo',
       component: () => import('/@/views/demo/form/RuleForm.vue'),
       meta: {
-        title: '表单验证',
+        title: 'rroutes.demo.form.ruleForm',
       },
     },
     {
@@ -60,7 +60,7 @@ const form: AppRouteModule = {
       name: 'DynamicFormDemo',
       component: () => import('/@/views/demo/form/DynamicForm.vue'),
       meta: {
-        title: '动态表单',
+        title: 'rroutes.demo.form.dynamicForm',
       },
     },
     {
@@ -68,7 +68,7 @@ const form: AppRouteModule = {
       name: 'CustomerFormDemo',
       component: () => import('/@/views/demo/form/CustomerForm.vue'),
       meta: {
-        title: '自定义组件',
+        title: 'rroutes.demo.form.customerForm',
       },
     },
   ],

+ 4 - 4
src/router/routes/modules/demo/iframe.ts

@@ -11,7 +11,7 @@ const iframe: AppRouteModule = {
     redirect: '/frame/antv',
     meta: {
       icon: 'mdi:page-next-outline',
-      title: '外部页面',
+      title: 'routes.demo.iframe.frame',
     },
   },
 
@@ -22,7 +22,7 @@ const iframe: AppRouteModule = {
       component: IFrame,
       meta: {
         frameSrc: 'https://2x.antdv.com/docs/vue/introduce-cn/',
-        title: 'antVue文档(内嵌)',
+        title: 'routes.demo.iframe.antv',
         afterCloseLoading: true,
       },
     },
@@ -32,7 +32,7 @@ const iframe: AppRouteModule = {
       component: IFrame,
       meta: {
         frameSrc: 'https://vvbin.cn/doc-next/',
-        title: '项目文档(内嵌)',
+        title: 'routes.demo.iframe.doc',
         afterCloseLoading: true,
       },
     },
@@ -42,7 +42,7 @@ const iframe: AppRouteModule = {
       component: IFrame,
       meta: {
         externalLink: 'https://vvbin.cn/doc-next/',
-        title: '项目文档(外链)',
+        title: 'routes.demo.iframe.docExternal',
       },
     },
   ],

+ 19 - 19
src/router/routes/modules/demo/page.ts

@@ -12,7 +12,7 @@ const page: AppRouteModule = {
   redirect: '/page-demo/exception',
   meta: {
     icon: 'mdi:page-next-outline',
-    title: '页面',
+    title: 'routes.demo.page.page',
   },
   children: [
     // =============================form start=============================
@@ -21,7 +21,7 @@ const page: AppRouteModule = {
       name: 'FormPage',
       redirect: '/page-demo/form/basic',
       meta: {
-        title: '表单页',
+        title: 'routes.demo.page.form',
       },
       children: [
         {
@@ -29,7 +29,7 @@ const page: AppRouteModule = {
           name: 'FormBasicPage',
           component: () => import('/@/views/demo/page/form/basic/index.vue'),
           meta: {
-            title: '基础表单',
+            title: 'routes.demo.page.formBasic',
           },
         },
         {
@@ -37,7 +37,7 @@ const page: AppRouteModule = {
           name: 'FormStepPage',
           component: () => import('/@/views/demo/page/form/step/index.vue'),
           meta: {
-            title: '分步表单',
+            title: 'routes.demo.page.formStep',
           },
         },
         {
@@ -45,7 +45,7 @@ const page: AppRouteModule = {
           name: 'FormHightPage',
           component: () => import('/@/views/demo/page/form/high/index.vue'),
           meta: {
-            title: '高级表单',
+            title: 'routes.demo.page.formHigh',
           },
         },
       ],
@@ -57,7 +57,7 @@ const page: AppRouteModule = {
       name: 'DescPage',
       redirect: '/page-demo/desc/basic',
       meta: {
-        title: '详情页',
+        title: 'routes.demo.page.desc',
       },
       children: [
         {
@@ -65,7 +65,7 @@ const page: AppRouteModule = {
           name: 'DescBasicPage',
           component: () => import('/@/views/demo/page/desc/basic/index.vue'),
           meta: {
-            title: '基础详情页',
+            title: 'routes.demo.page.descBasic',
           },
         },
         {
@@ -73,7 +73,7 @@ const page: AppRouteModule = {
           name: 'DescHighPage',
           component: () => import('/@/views/demo/page/desc/high/index.vue'),
           meta: {
-            title: '高级详情页',
+            title: 'routes.demo.page.descHigh',
           },
         },
       ],
@@ -86,7 +86,7 @@ const page: AppRouteModule = {
       name: 'ResultPage',
       redirect: '/page-demo/result/success',
       meta: {
-        title: '结果页',
+        title: 'routes.demo.page.result',
       },
       children: [
         {
@@ -94,7 +94,7 @@ const page: AppRouteModule = {
           name: 'ResultSuccessPage',
           component: () => import('/@/views/demo/page/result/success/index.vue'),
           meta: {
-            title: '成功页',
+            title: 'routes.demo.page.resultSuccess',
           },
         },
         {
@@ -102,7 +102,7 @@ const page: AppRouteModule = {
           name: 'ResultFailPage',
           component: () => import('/@/views/demo/page/result/fail/index.vue'),
           meta: {
-            title: '失败页',
+            title: 'routes.demo.page.resultFail',
           },
         },
       ],
@@ -115,7 +115,7 @@ const page: AppRouteModule = {
       name: 'AccountPage',
       redirect: '/page-demo/account/setting',
       meta: {
-        title: '个人页',
+        title: 'routes.demo.page.account',
       },
       children: [
         {
@@ -123,7 +123,7 @@ const page: AppRouteModule = {
           name: 'AccountCenterPage',
           component: () => import('/@/views/demo/page/account/center/index.vue'),
           meta: {
-            title: '个人中心',
+            title: 'routes.demo.page.accountCenter',
           },
         },
         {
@@ -131,7 +131,7 @@ const page: AppRouteModule = {
           name: 'AccountSettingPage',
           component: () => import('/@/views/demo/page/account/setting/index.vue'),
           meta: {
-            title: '个人设置',
+            title: 'routes.demo.page.accountSetting',
           },
         },
       ],
@@ -143,7 +143,7 @@ const page: AppRouteModule = {
       name: 'ExceptionPage',
       redirect: '/page-demo/exception/404',
       meta: {
-        title: '异常页',
+        title: 'routes.demo.page.exception',
       },
       children: [
         {
@@ -190,7 +190,7 @@ const page: AppRouteModule = {
             status: ExceptionEnum.NET_WORK_ERROR,
           },
           meta: {
-            title: '网络错误',
+            title: 'routes.demo.page.netWorkError',
             afterCloseLoading: true,
           },
         },
@@ -202,7 +202,7 @@ const page: AppRouteModule = {
             status: ExceptionEnum.PAGE_NOT_DATA,
           },
           meta: {
-            title: '无数据',
+            title: 'routes.demo.page.notData',
             afterCloseLoading: true,
           },
         },
@@ -215,7 +215,7 @@ const page: AppRouteModule = {
       name: 'ListPage',
       redirect: '/page-demo/list/card',
       meta: {
-        title: '列表页',
+        title: 'routes.demo.page.list',
       },
       children: [
         {
@@ -223,7 +223,7 @@ const page: AppRouteModule = {
           name: 'ListCardPage',
           component: () => import('/@/views/demo/page/list/card/index.vue'),
           meta: {
-            title: '卡片列表',
+            title: 'routes.demo.page.listCard',
           },
         },
       ],

+ 9 - 9
src/router/routes/modules/demo/permission.ts

@@ -11,7 +11,7 @@ const permission: AppRouteModule = {
     redirect: '/permission/front/page',
     meta: {
       icon: 'carbon:user-role',
-      title: '权限管理',
+      title: 'routes.demo.permission.permission',
     },
   },
 
@@ -20,7 +20,7 @@ const permission: AppRouteModule = {
       path: '/front',
       name: 'PermissionFrontDemo',
       meta: {
-        title: '基于前端权限',
+        title: 'routes.demo.permission.front',
       },
       children: [
         {
@@ -28,7 +28,7 @@ const permission: AppRouteModule = {
           name: 'FrontPageAuth',
           component: () => import('/@/views/demo/permission/front/index.vue'),
           meta: {
-            title: '页面权限',
+            title: 'routes.demo.permission.frontPage',
           },
         },
         {
@@ -36,7 +36,7 @@ const permission: AppRouteModule = {
           name: 'FrontBtnAuth',
           component: () => import('/@/views/demo/permission/front/Btn.vue'),
           meta: {
-            title: '按钮权限',
+            title: 'routes.demo.permission.frontBtn',
           },
         },
         {
@@ -44,7 +44,7 @@ const permission: AppRouteModule = {
           name: 'FrontAuthPageA',
           component: () => import('/@/views/demo/permission/front/AuthPageA.vue'),
           meta: {
-            title: '权限测试页A',
+            title: 'routes.demo.permission.frontTestA',
             roles: [RoleEnum.SUPER],
           },
         },
@@ -53,7 +53,7 @@ const permission: AppRouteModule = {
           name: 'FrontAuthPageB',
           component: () => import('/@/views/demo/permission/front/AuthPageB.vue'),
           meta: {
-            title: '权限测试页B',
+            title: 'routes.demo.permission.frontTestB',
             roles: [RoleEnum.TEST],
           },
         },
@@ -63,7 +63,7 @@ const permission: AppRouteModule = {
       path: '/back',
       name: 'PermissionBackDemo',
       meta: {
-        title: '基于后台权限',
+        title: 'routes.demo.permission.back',
       },
       children: [
         {
@@ -71,7 +71,7 @@ const permission: AppRouteModule = {
           name: 'BackAuthPage',
           component: () => import('/@/views/demo/permission/back/index.vue'),
           meta: {
-            title: '页面权限',
+            title: 'routes.demo.permission.backPage',
           },
         },
         {
@@ -79,7 +79,7 @@ const permission: AppRouteModule = {
           name: 'BackAuthBtn',
           component: () => import('/@/views/demo/permission/back/Btn.vue'),
           meta: {
-            title: '按钮权限',
+            title: 'routes.demo.permission.backBtn',
           },
         },
       ],

+ 16 - 16
src/router/routes/modules/demo/table.ts

@@ -10,7 +10,7 @@ const table: AppRouteModule = {
     redirect: '/table/basic',
     meta: {
       icon: 'ant-design:table-outlined',
-      title: 'Table',
+      title: 'routes.demo.table.table',
     },
   },
 
@@ -20,7 +20,7 @@ const table: AppRouteModule = {
       name: 'TableBasicDemo',
       component: () => import('/@/views/demo/table/Basic.vue'),
       meta: {
-        title: '基础表格',
+        title: 'routes.demo.table.basic',
       },
     },
     {
@@ -28,7 +28,7 @@ const table: AppRouteModule = {
       name: 'TreeTableDemo',
       component: () => import('/@/views/demo/table/TreeTable.vue'),
       meta: {
-        title: '树形表格',
+        title: 'routes.demo.table.treeTable',
       },
     },
     {
@@ -36,7 +36,7 @@ const table: AppRouteModule = {
       name: 'FetchTableDemo',
       component: () => import('/@/views/demo/table/FetchTable.vue'),
       meta: {
-        title: '远程加载示例',
+        title: 'routes.demo.table.fetchTable',
       },
     },
     {
@@ -44,7 +44,7 @@ const table: AppRouteModule = {
       name: 'FixedColumnDemo',
       component: () => import('/@/views/demo/table/FixedColumn.vue'),
       meta: {
-        title: '固定列',
+        title: 'routes.demo.table.fixedColumn',
       },
     },
     {
@@ -52,7 +52,7 @@ const table: AppRouteModule = {
       name: 'CustomerCellDemo',
       component: () => import('/@/views/demo/table/CustomerCell.vue'),
       meta: {
-        title: '自定义列',
+        title: 'routes.demo.table.customerCell',
       },
     },
     {
@@ -60,7 +60,7 @@ const table: AppRouteModule = {
       name: 'FormTableDemo',
       component: () => import('/@/views/demo/table/FormTable.vue'),
       meta: {
-        title: '开启搜索区域',
+        title: 'routes.demo.table.formTable',
       },
     },
     {
@@ -68,7 +68,7 @@ const table: AppRouteModule = {
       name: 'UseTableDemo',
       component: () => import('/@/views/demo/table/UseTable.vue'),
       meta: {
-        title: 'UseTable',
+        title: 'routes.demo.table.useTable',
       },
     },
     {
@@ -76,7 +76,7 @@ const table: AppRouteModule = {
       name: 'RefTableDemo',
       component: () => import('/@/views/demo/table/RefTable.vue'),
       meta: {
-        title: 'RefTable',
+        title: 'routes.demo.table.refTable',
       },
     },
     {
@@ -84,7 +84,7 @@ const table: AppRouteModule = {
       name: 'MultipleHeaderDemo',
       component: () => import('/@/views/demo/table/MultipleHeader.vue'),
       meta: {
-        title: '多级表头',
+        title: 'routes.demo.table.multipleHeader',
       },
     },
     {
@@ -92,7 +92,7 @@ const table: AppRouteModule = {
       name: 'MergeHeaderDemo',
       component: () => import('/@/views/demo/table/MergeHeader.vue'),
       meta: {
-        title: '合并单元格',
+        title: 'routes.demo.table.mergeHeader',
       },
     },
     {
@@ -100,7 +100,7 @@ const table: AppRouteModule = {
       name: 'ExpandTableDemo',
       component: () => import('/@/views/demo/table/ExpandTable.vue'),
       meta: {
-        title: '可展开表格',
+        title: 'routes.demo.table.expandTable',
       },
     },
     {
@@ -108,7 +108,7 @@ const table: AppRouteModule = {
       name: 'FixedHeightDemo',
       component: () => import('/@/views/demo/table/FixedHeight.vue'),
       meta: {
-        title: '定高/头部自定义',
+        title: 'routes.demo.table.fixedHeight',
       },
     },
     {
@@ -116,7 +116,7 @@ const table: AppRouteModule = {
       name: 'FooterTableDemo',
       component: () => import('/@/views/demo/table/FooterTable.vue'),
       meta: {
-        title: '表尾行合计',
+        title: 'routes.demo.table.footerTable',
       },
     },
     {
@@ -124,7 +124,7 @@ const table: AppRouteModule = {
       name: 'EditCellTableDemo',
       component: () => import('/@/views/demo/table/EditCellTable.vue'),
       meta: {
-        title: '可编辑单元格',
+        title: 'routes.demo.table.editCellTable',
       },
     },
     {
@@ -132,7 +132,7 @@ const table: AppRouteModule = {
       name: 'EditRowTableDemo',
       component: () => import('/@/views/demo/table/EditRowTable.vue'),
       meta: {
-        title: '可编辑行',
+        title: 'routes.demo.table.editRowTable',
       },
     },
   ],

+ 4 - 4
src/router/routes/modules/demo/tree.ts

@@ -10,7 +10,7 @@ const tree: AppRouteModule = {
     redirect: '/tree/basic',
     meta: {
       icon: 'clarity:tree-view-line',
-      title: 'Tree',
+      title: 'routes.demo.tree.tree',
     },
   },
   routes: [
@@ -19,7 +19,7 @@ const tree: AppRouteModule = {
       name: 'BasicTreeDemo',
       component: () => import('/@/views/demo/tree/index.vue'),
       meta: {
-        title: '基础树',
+        title: 'routes.demo.tree.basic',
       },
     },
     {
@@ -27,7 +27,7 @@ const tree: AppRouteModule = {
       name: 'EditTreeDemo',
       component: () => import('/@/views/demo/tree/EditTree.vue'),
       meta: {
-        title: '右键示例',
+        title: 'routes.demo.tree.editTree',
       },
     },
     {
@@ -35,7 +35,7 @@ const tree: AppRouteModule = {
       name: 'ActionTreeDemo',
       component: () => import('/@/views/demo/tree/ActionTree.vue'),
       meta: {
-        title: '函数操作示例',
+        title: 'routes.demo.tree.actionTree',
       },
     },
   ],

+ 1 - 1
src/setup/App.ts

@@ -20,7 +20,7 @@ import {
 } from '/@/setup/theme';
 
 import { appStore } from '/@/store/modules/app';
-import { deepMerge } from '../utils/index';
+import { deepMerge } from '/@/utils';
 
 // Used to share global app instances
 let app: App;

+ 6 - 7
src/setup/i18n/index.ts

@@ -1,20 +1,19 @@
-import { App, unref } from 'vue';
+import { App } from 'vue';
 import type { I18n, I18nOptions } from 'vue-i18n';
 
 import { createI18n } from 'vue-i18n';
 import localeMessages from '/@/locales';
 import { useLocale } from '/@/hooks/web/useLocale';
-import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting';
-
+import projectSetting from '/@/settings/projectSetting';
 const { setupLocale } = useLocale();
 
-const { getLang, getAvailableLocales, getFallbackLocale } = useLocaleSetting();
+const { lang, availableLocales, fallback } = projectSetting?.locale;
 const localeData: I18nOptions = {
   legacy: false,
-  locale: unref(getLang),
-  fallbackLocale: unref(getFallbackLocale),
+  locale: lang,
+  fallbackLocale: fallback,
   messages: localeMessages,
-  availableLocales: unref(getAvailableLocales),
+  availableLocales: availableLocales,
   sync: true, //If you don’t want to inherit locale from global scope, you need to set sync of i18n component option to false.
   silentTranslationWarn: false, // true - warning off
   silentFallbackWarn: true,

+ 4 - 1
src/store/modules/permission.ts

@@ -20,6 +20,9 @@ import { transformRouteToMenu } from '/@/utils/helper/menuHelper';
 
 import { useMessage } from '/@/hooks/web/useMessage';
 // import { warn } from '/@/utils/log';
+import { useI18n } from '/@/hooks/web/useI18n';
+
+const { t } = useI18n('sys.app');
 
 const { createMessage } = useMessage();
 const NAME = 'permission';
@@ -101,7 +104,7 @@ class Permission extends VuexModule {
     } else if (permissionMode === PermissionModeEnum.BACK) {
       const messageKey = 'loadMenu';
       createMessage.loading({
-        content: '菜单加载中...',
+        content: t('menuLoading'),
         key: messageKey,
         duration: 1,
       });

+ 5 - 2
src/store/modules/user.ts

@@ -21,6 +21,7 @@ import { loginApi, getUserInfoById } from '/@/api/sys/user';
 
 import { setLocal, getLocal, getSession, setSession } from '/@/utils/helper/persistent';
 import { useProjectSetting } from '/@/hooks/setting';
+import { useI18n } from '/@/hooks/web/useI18n';
 
 export type UserInfo = Omit<GetUserInfoByUserIdModel, 'roles'>;
 
@@ -29,6 +30,8 @@ hotModuleUnregisterModule(NAME);
 
 const { permissionCacheType } = useProjectSetting();
 
+const { t } = useI18n('sys.app');
+
 function getCache<T>(key: string) {
   const fn = permissionCacheType === CacheTypeEnum.LOCAL ? getLocal : getSession;
   return fn(key) as T;
@@ -144,8 +147,8 @@ class User extends VuexModule {
     const { createConfirm } = useMessage();
     createConfirm({
       iconType: 'warning',
-      title: '温馨提醒',
-      content: '是否确认退出系统?',
+      title: t('loginOutTip'),
+      content: t('loginOutMessage'),
       onOk: async () => {
         await this.loginOut(true);
       },

+ 14 - 11
src/utils/http/axios/checkStatus.ts

@@ -1,7 +1,10 @@
 import { useMessage } from '/@/hooks/web/useMessage';
 import { userStore } from '/@/store/modules/user';
+import { useI18n } from '/@/hooks/web/useI18n';
 const { createMessage } = useMessage();
 
+const { t } = useI18n('sys.api');
+
 const error = createMessage.error!;
 export function checkStatus(status: number, msg: string): void {
   switch (status) {
@@ -12,39 +15,39 @@ export function checkStatus(status: number, msg: string): void {
     // 未登录则跳转登录页面,并携带当前页面的路径
     // 在登录成功后返回当前页面,这一步需要在登录页操作。
     case 401:
-      error('用户没有权限(令牌、用户名、密码错误)!');
+      error(t('errMsg401'));
       userStore.loginOut(true);
       break;
     case 403:
-      error('用户得到授权,但是访问是被禁止的。!');
+      error(t('errMsg403'));
       break;
     // 404请求不存在
     case 404:
-      error('网络请求错误,未找到该资源!');
+      error(t('errMsg404'));
       break;
     case 405:
-      error('网络请求错误,请求方法未允许!');
+      error(t('errMsg405'));
       break;
     case 408:
-      error('网络请求超时!');
+      error(t('errMsg408'));
       break;
     case 500:
-      error('服务器错误,请联系管理员!');
+      error(t('errMsg500'));
       break;
     case 501:
-      error('网络未实现!');
+      error(t('errMsg501'));
       break;
     case 502:
-      error('网络错误!');
+      error(t('errMsg502'));
       break;
     case 503:
-      error('服务不可用,服务器暂时过载或维护!');
+      error(t('errMsg503'));
       break;
     case 504:
-      error('网络超时!');
+      error(t('errMsg504'));
       break;
     case 505:
-      error('http版本不支持该请求!');
+      error(t('errMsg505'));
       break;
     default:
   }

+ 9 - 7
src/utils/http/axios/index.ts

@@ -20,7 +20,9 @@ import { formatRequestDate } from '/@/utils/dateUtil';
 import { setObjToUrlParams, deepMerge } from '/@/utils';
 import { errorStore } from '/@/store/modules/error';
 import { errorResult } from './const';
+import { useI18n } from '/@/hooks/web/useI18n';
 
+const { t } = useI18n('sys.api');
 const globSetting = useGlobSetting();
 const prefix = globSetting.urlPrefix;
 const { createMessage, createErrorModal } = useMessage();
@@ -55,7 +57,7 @@ const transform: AxiosTransform = {
       if (message) {
         // errorMessageMode=‘modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误
         if (options.errorMessageMode === 'modal') {
-          createErrorModal({ title: '错误提示', content: message });
+          createErrorModal({ title: t('errorTip'), content: message });
         } else {
           createMessage.error(message);
         }
@@ -74,7 +76,7 @@ const transform: AxiosTransform = {
         createMessage.error(data.message);
         Promise.reject(new Error(message));
       } else {
-        const msg = '操作失败,系统异常!';
+        const msg = t('errorMessage');
         createMessage.error(msg);
         Promise.reject(new Error(msg));
       }
@@ -82,9 +84,9 @@ const transform: AxiosTransform = {
     }
     // 登录超时
     if (code === ResultEnum.TIMEOUT) {
-      const timeoutMsg = '登录超时,请重新登录!';
+      const timeoutMsg = t('timeoutMessage');
       createErrorModal({
-        title: '操作失败',
+        title: t('operationFailed'),
         content: timeoutMsg,
       });
       Promise.reject(new Error(timeoutMsg));
@@ -159,12 +161,12 @@ const transform: AxiosTransform = {
     const err: string = error.toString();
     try {
       if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
-        createMessage.error('接口请求超时,请刷新页面重试!');
+        createMessage.error(t('apiTimeoutMessage'));
       }
       if (err && err.includes('Network Error')) {
         createErrorModal({
-          title: '网络异常',
-          content: '请检查您的网络连接是否正常!',
+          title: t('networkException'),
+          content: t('networkExceptionMsg'),
         });
       }
     } catch (error) {

+ 17 - 15
src/views/sys/login/Login.vue

@@ -3,8 +3,8 @@
     <div class="login-mask" />
     <div class="login-form-wrap">
       <div class="login-form mx-6">
+        <AppLocalePicker v-if="showLocale" class="login-form__locale" />
         <div class="login-form__content px-2 py-10">
-          <AppLocalePicker v-if="showLocale" class="login-form__locale" />
           <header>
             <img :src="logo" class="mr-4" />
             <h1>{{ title }}</h1>
@@ -158,9 +158,16 @@
     },
   });
 </script>
-<style lang="less" scoped>
+<style lang="less">
   @import (reference) '../../../design/index.less';
 
+  .login-form__locale {
+    position: absolute;
+    top: 14px;
+    right: 14px;
+    z-index: 1;
+  }
+
   .login {
     position: relative;
     height: 100vh;
@@ -178,7 +185,9 @@
     }
 
     &-form {
-      width: 520px;
+      position: relative;
+      bottom: 60px;
+      width: 400px;
       background: @white;
       border: 10px solid rgba(255, 255, 255, 0.5);
       border-width: 8px;
@@ -192,26 +201,20 @@
         right: 0;
         display: flex;
         width: 100%;
-        height: 90%;
+        height: 100%;
+        // height: 90%;
         justify-content: center;
         align-items: center;
-        .respond-to(large, {
-          width: 600px;
-          right: calc(50% - 270px);
+        .respond-to(xlarge, {
+        justify-content: flex-end;
           });
-        .respond-to(xlarge, { width: 540px; right:0});
-      }
-
-      &__locale {
-        position: absolute;
-        top: 10px;
-        right: 10px;
       }
 
       &__content {
         position: relative;
         width: 100%;
         height: 100%;
+        padding: 60px 0 40px 0;
         border: 1px solid #999;
         border-radius: 2px;
 
@@ -228,7 +231,6 @@
           h1 {
             margin-bottom: 0;
             font-size: 24px;
-            // color: @primary-color;
             text-align: center;
           }
         }