Browse Source

feat: build internationalization config

richard1015 3 years ago
parent
commit
f50f8fbd1b

+ 6 - 5
jd/generate-nutui-taro-vue.js

@@ -2,7 +2,8 @@ const package = require('../package.json');
 const config = require('../src/config.json');
 const path = require('path');
 const fs = require('fs-extra');
-let importStr = `//import { App } from 'vue';\n`;
+let importStr = `import { App } from 'vue';
+import Locale from './locale';\n`;
 let importScssStr = `\n`;
 const packages = [];
 config.nav.map((item) => {
@@ -29,8 +30,8 @@ let installFunction = `function install(app: any) {
 let fileStrBuild = `${importStr}
 ${installFunction}
 const version = '${package.version}';
-export { install, version };
-export default { install, version};`;
+export { install, version, Locale };
+export default { install, version, Locale};`;
 
 fs.outputFile(path.resolve(__dirname, '../src/packages/nutui.taro.vue.build.ts'), fileStrBuild, 'utf8', (error) => {
   // logger.success(`${package_config_path} 文件写入成功`);
@@ -38,8 +39,8 @@ fs.outputFile(path.resolve(__dirname, '../src/packages/nutui.taro.vue.build.ts')
 let fileStrDev = `${importStr}
 ${installFunction}
 ${importScssStr}
-export { install, ${packages.join(',')}  };
-export default { install, version:'${package.version}'};`;
+export { install, Locale, ${packages.join(',')}  };
+export default { install, version:'${package.version}', Locale};`;
 fs.outputFile(path.resolve(__dirname, '../src/packages/nutui.taro.vue.ts'), fileStrDev, 'utf8', (error) => {
   // logger.success(`${package_config_path} 文件写入成功`);
 });

+ 6 - 5
jd/generate-nutui.js

@@ -2,7 +2,8 @@ const package = require('../package.json');
 const config = require('../src/config.json');
 const path = require('path');
 const fs = require('fs-extra');
-let importStr = `import { App } from 'vue';\n`;
+let importStr = `import { App } from 'vue';
+import Locale from './locale';\n`;
 let importScssStr = `\n`;
 const packages = [];
 config.nav.map((item) => {
@@ -26,8 +27,8 @@ let installFunction = `function install(app: App) {
 let fileStrBuild = `${importStr}
 ${installFunction}
 const version = '${package.version}';
-export { install, version, ${packages.join(',')}};
-export default { install, version};`;
+export { install, version, Locale, ${packages.join(',')}};
+export default { install, version, Locale};`;
 
 fs.outputFile(path.resolve(__dirname, '../src/packages/nutui.vue.build.ts'), fileStrBuild, 'utf8', (error) => {
   // logger.success(`${package_config_path} 文件写入成功`);
@@ -37,8 +38,8 @@ let fileStrDev = `${importStr}
 ${installFunction}
 ${importScssStr}
 export const testComponents = { ${packages.join(',')}};
-export { install, ${packages.join(',')}  };
-export default { install, version:'${package.version}'};`;
+export { install, Locale, ${packages.join(',')}  };
+export default { install, version:'${package.version}', Locale};`;
 fs.outputFile(path.resolve(__dirname, '../src/packages/nutui.vue.ts'), fileStrDev, 'utf8', (error) => {
   // logger.success(`${package_config_path} 文件写入成功`);
 });

+ 2 - 2
jd/generate-types-taro.js

@@ -1,7 +1,7 @@
 const config = require('../src/config.json');
 const path = require('path');
 const fs = require('fs-extra');
-let importStr = ``;
+let importStr = `import Locale from '../packages/locale';\n`;
 const packages = [];
 config.nav.map((item) => {
   item.packages.forEach((element) => {
@@ -15,7 +15,7 @@ config.nav.map((item) => {
   });
 });
 let installFunction = `
-export { ${packages.join(',')} };`;
+export { Locale,${packages.join(',')} };`;
 let fileStr = importStr + installFunction;
 fs.outputFileSync(path.resolve(__dirname, '../dist/types/nutui.d.ts'), fileStr, 'utf8');
 fs.outputFileSync(

+ 2 - 2
jd/generate-types.js

@@ -1,7 +1,7 @@
 const config = require('../src/config.json');
 const path = require('path');
 const fs = require('fs-extra');
-let importStr = ``;
+let importStr = `import Locale from '../packages/locale';\n`;
 const packages = [];
 config.nav.map((item) => {
   item.packages.forEach((element) => {
@@ -12,7 +12,7 @@ config.nav.map((item) => {
   });
 });
 let installFunction = `
-export { ${packages.join(',')} };`;
+export { Locale,${packages.join(',')} };`;
 let fileStr = importStr + installFunction;
 fs.outputFileSync(path.resolve(__dirname, '../dist/types/nutui.d.ts'), fileStr, 'utf8');
 fs.outputFileSync(

+ 2 - 2
package.json

@@ -40,8 +40,8 @@
     "dev:taro:h5": "npm run createTaroConfig && npm run checked:taro:vue && cd src/sites/mobile-taro/vue/ && npm run dev:h5",
     "build:site": "npm run checked && vite build",
     "build:site:oss": "npm run checked && vite build --base=/nutui/3x/",
-    "build": "npm run checked && vite build --config vite.config.build.ts && vite build --config vite.config.build.disperse.ts && npm run generate:types && npm run generate:themes && vite build --config vite.config.build.css.ts",
-    "build:taro:vue": "npm run checked:taro:vue && vite build --config vite.config.build.taro.vue.ts && vite build --config vite.config.build.taro.vue.disperse.ts && npm run generate:types:taro && npm run generate:themes && vite build --config vite.config.build.css.ts",
+    "build": "npm run checked && vite build --config vite.config.build.ts && vite build --config vite.config.build.disperse.ts && npm run generate:types && npm run generate:themes && vite build --config vite.config.build.css.ts && vite build --config vite.config.build.locale.ts",
+    "build:taro:vue": "npm run checked:taro:vue && vite build --config vite.config.build.taro.vue.ts && vite build --config vite.config.build.taro.vue.disperse.ts && npm run generate:types:taro && npm run generate:themes && vite build --config vite.config.build.css.ts && vite build --config vite.config.build.locale.ts",
     "serve": "vite preview",
     "upload": "yarn build:site:oss && node ./jd/upload.js",
     "add": "node jd/createComponentMode.js",

+ 12 - 10
src/packages/locale/index.ts

@@ -1,19 +1,21 @@
 import { ref, reactive } from 'vue';
-import lang from './lang/zh-CN';
-import defaultLang from './lang/zh-CN';
-import enUSLang from './lang/en-US';
+import ZhCNLang from './lang/zh-CN';
+import EnUSLang from './lang/en-US';
+// 组件默认语言设置
 const currentLang = ref('zh-CN');
-
-type lang = Record<string, any>;
-const langs = reactive<lang>({
-  'zh-CN': defaultLang,
-  'en-US': enUSLang
+export type Lang = Record<string, any>;
+const langs = reactive<Lang>({
+  'zh-CN': new ZhCNLang(),
+  'en-US': new EnUSLang()
 });
 export class Locale {
-  static languages(): lang {
+  static languages(): Lang {
     return langs[currentLang.value];
   }
-  static use(lang: string) {
+  static use(lang: string, newLanguages?: any) {
+    if (newLanguages) {
+      langs[lang] = new newLanguages();
+    }
     currentLang.value = lang;
   }
 }

+ 24 - 23
src/packages/locale/lang/baseLang.ts

@@ -1,24 +1,24 @@
-export interface BaseLang {
-  save: string;
-  confirm: string;
-  cancel: string;
-  done: string;
-  noData: string;
-  placeholder: string;
-  select: string;
-  video: {
+export abstract class BaseLang {
+  abstract save: string;
+  abstract confirm: string;
+  abstract cancel: string;
+  abstract done: string;
+  abstract noData: string;
+  abstract placeholder: string;
+  abstract select: string;
+  abstract video: {
     errorTip: string;
     clickRetry: string;
   };
-  fixednav: {
+  abstract fixednav: {
     activeText: string;
     unActiveText: string;
   };
-  pagination: {
+  abstract pagination: {
     prev: string;
     next: string;
   };
-  calendaritem: {
+  abstract calendaritem: {
     weekdays: Array<string>;
     end: string;
     start: string;
@@ -26,12 +26,12 @@ export interface BaseLang {
     monthTitle: Function;
     today: string;
   };
-  shortpassword: {
+  abstract shortpassword: {
     title: string;
     desc: string;
     tips: string;
   };
-  uploader: {
+  abstract uploader: {
     ready: string;
     readyUpload: string;
     waitingUpload: string;
@@ -39,43 +39,44 @@ export interface BaseLang {
     success: string;
     error: string;
   };
-  countdown: {
+  abstract countdown: {
     day: string;
     hour: string;
     minute: string;
     second: string;
   };
-  address: {
+  abstract address: {
     selectRegion: string;
     deliveryTo: string;
     chooseAnotherAddress: string;
   };
-  signature: {
+  abstract signature: {
     reSign: string;
     unSupportTpl: string;
   };
-  ecard: {
+  abstract ecard: {
     chooseText: string;
     otherValueText: string;
     placeholder: string;
   };
-  timeselect: {
+  abstract timeselect: {
     pickupTime: string;
   };
-  sku: {
+  abstract sku: {
     buyNow: string;
     buyNumber: string;
     addToCard: string;
   };
-  skuheader: {
+  abstract skuheader: {
     skuId: string;
   };
-  addresslist: {
+  abstract addresslist: {
     addAddress: string;
   };
-  comment: {
+  abstract comment: {
     complaintsText: string;
     additionalReview: Function;
     additionalImages: Function;
   };
 }
+export default BaseLang;

+ 40 - 40
src/packages/locale/lang/en-US.ts

@@ -1,83 +1,83 @@
 import { BaseLang } from './baseLang';
-const lang: BaseLang = {
-  save: 'Save',
-  confirm: 'Confirm',
-  cancel: 'Cancel',
-  done: 'Done',
-  noData: 'No Data',
-  placeholder: 'Placeholder',
-  select: 'Select',
-  video: {
+class Lang extends BaseLang {
+  save = 'Save';
+  confirm = 'Confirm';
+  cancel = 'Cancel';
+  done = 'Done';
+  noData = 'No Data';
+  placeholder = 'Placeholder';
+  select = 'Select';
+  video = {
     errorTip: 'Error Tip',
     clickRetry: 'Click Retry'
-  },
-  fixednav: {
+  };
+  fixednav = {
     activeText: 'Close Nav',
     unActiveText: 'Open Nav'
-  },
-  pagination: {
+  };
+  pagination = {
     prev: 'Previous',
     next: 'Next'
-  },
-  calendaritem: {
+  };
+  calendaritem = {
     weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
     end: 'End',
     start: 'Start',
     title: 'Calendar',
     monthTitle: (year: number, month: number) => `${year}/${month}`,
     today: 'Today'
-  },
-  shortpassword: {
+  };
+  shortpassword = {
     title: 'Please input a password',
     desc: 'Verify',
     tips: 'Forget password'
-  },
-  uploader: {
+  };
+  uploader = {
     ready: 'Ready',
     readyUpload: 'Ready to upload',
     waitingUpload: 'Waiting for upload',
     uploading: 'Uploading',
     success: 'Upload successful',
     error: 'Upload failed'
-  },
-  countdown: {
+  };
+  countdown = {
     day: ' Day ',
     hour: ' Hour ',
     minute: ' Minute ',
     second: ' Second '
-  },
-  address: {
+  };
+  address = {
     selectRegion: 'Select Region',
     deliveryTo: 'Delivery To',
     chooseAnotherAddress: 'Choose Another Address'
-  },
-  signature: {
+  };
+  signature = {
     reSign: 'Re Sign',
     unSupportTpl: `Sorry, the current browser doesn't support canvas, so we can't use this control!`
-  },
-  ecard: {
+  };
+  ecard = {
     chooseText: 'Select',
     otherValueText: 'Other Value',
     placeholder: 'Placeholder'
-  },
-  timeselect: {
+  };
+  timeselect = {
     pickupTime: 'Pickup Time'
-  },
-  sku: {
+  };
+  sku = {
     buyNow: 'Buy Now',
     buyNumber: 'Buy Number',
     addToCard: 'Add to Card'
-  },
-  skuheader: {
+  };
+  skuheader = {
     skuId: 'Sku Number'
-  },
-  addresslist: {
+  };
+  addresslist = {
     addAddress: 'Add New Address'
-  },
-  comment: {
+  };
+  comment = {
     complaintsText: 'I have a complaint',
     additionalReview: (day: number) => `Review after ${day} days of purchase`,
     additionalImages: (length: number) => `There are ${length} follow-up comments`
-  }
-};
-export default lang;
+  };
+}
+export default Lang;

+ 40 - 40
src/packages/locale/lang/zh-CN.ts

@@ -1,83 +1,83 @@
 import { BaseLang } from './baseLang';
-const lang: BaseLang = {
-  save: '保存',
-  confirm: '确认',
-  cancel: '取消',
-  done: '完成',
-  noData: '暂无数据',
-  placeholder: '请输入',
-  select: '请选择',
-  video: {
+class Lang extends BaseLang {
+  save = '保存';
+  confirm = '确认';
+  cancel = '取消';
+  done = '完成';
+  noData = '暂无数据';
+  placeholder = '请输入';
+  select = '请选择';
+  video = {
     errorTip: '视频加载失败',
     clickRetry: '点击重试'
-  },
-  fixednav: {
+  };
+  fixednav = {
     activeText: '收起导航',
     unActiveText: '快速导航'
-  },
-  pagination: {
+  };
+  pagination = {
     prev: '上一页',
     next: '下一页'
-  },
-  calendaritem: {
+  };
+  calendaritem = {
     weekdays: ['日', '一', '二', '三', '四', '五', '六'],
     end: '结束',
     start: '开始',
     title: '日历选择',
     monthTitle: (year: number, month: number) => `${year}年${month}月`,
     today: '今天'
-  },
-  shortpassword: {
+  };
+  shortpassword = {
     title: '请输入密码',
     desc: '您使用了虚拟资产,请进行验证',
     tips: '忘记密码'
-  },
-  uploader: {
+  };
+  uploader = {
     ready: '准备完成',
     readyUpload: '准备上传',
     waitingUpload: '等待上传',
     uploading: '上传中',
     success: '上传成功',
     error: '上传失败'
-  },
-  countdown: {
+  };
+  countdown = {
     day: '天',
     hour: '时',
     minute: '分',
     second: '秒'
-  },
-  address: {
+  };
+  address = {
     selectRegion: '请选择所在地区',
     deliveryTo: '配送至',
     chooseAnotherAddress: '选择其他地址'
-  },
-  signature: {
+  };
+  signature = {
     reSign: '重签',
     unSupportTpl: '对不起,当前浏览器不支持Canvas,无法使用本控件!'
-  },
-  ecard: {
+  };
+  ecard = {
     chooseText: '请选择电子卡面值',
     otherValueText: '其他面值',
     placeholder: '请输入1-5000整数'
-  },
-  timeselect: {
+  };
+  timeselect = {
     pickupTime: '取件时间'
-  },
-  sku: {
+  };
+  sku = {
     buyNow: '立即购买',
     buyNumber: '购买数量',
     addToCard: '加入购物车'
-  },
-  skuheader: {
+  };
+  skuheader = {
     skuId: '商品编号'
-  },
-  addresslist: {
+  };
+  addresslist = {
     addAddress: '新建地址'
-  },
-  comment: {
+  };
+  comment = {
     complaintsText: '我要投诉',
     additionalReview: (day: number) => `购买${day}天后追评`,
     additionalImages: (length: number) => `${length}张追评图片`
-  }
-};
-export default lang;
+  };
+}
+export default Lang;

+ 40 - 40
src/packages/locale/lang/zh-TW.ts

@@ -1,83 +1,83 @@
 import { BaseLang } from './baseLang';
-const lang: BaseLang = {
-  save: '保存',
-  confirm: '確認',
-  cancel: '取消',
-  done: '完成',
-  noData: '暫無數據',
-  placeholder: '請輸入',
-  select: '請選擇',
-  video: {
+class Lang extends BaseLang {
+  save = '保存';
+  confirm = '確認';
+  cancel = '取消';
+  done = '完成';
+  noData = '暫無數據';
+  placeholder = '請輸入';
+  select = '請選擇';
+  video = {
     errorTip: '視頻加載失敗',
     clickRetry: '點擊重試'
-  },
-  fixednav: {
+  };
+  fixednav = {
     activeText: '收起導航',
     unActiveText: '快速導航'
-  },
-  pagination: {
+  };
+  pagination = {
     prev: '上一頁',
     next: '下一頁'
-  },
-  calendaritem: {
+  };
+  calendaritem = {
     weekdays: ['日', '一', '二', '三', '四', '五', '六'],
     end: '結束',
     start: '開始',
     title: '行事曆選擇',
     monthTitle: (year: number, month: number) => `${year}年${month}月`,
     today: '今天'
-  },
-  shortpassword: {
+  };
+  shortpassword = {
     title: '請輸入密碼',
     desc: '您使用了虛擬資產,請進行驗證',
     tips: '忘記密碼'
-  },
-  uploader: {
+  };
+  uploader = {
     ready: '準備完成',
     readyUpload: '準備上傳',
     waitingUpload: '等待上傳',
     uploading: '上傳中',
     success: '上傳成功',
     error: '上傳失敗'
-  },
-  countdown: {
+  };
+  countdown = {
     day: '天',
     hour: '時',
     minute: '分',
     second: '秒'
-  },
-  address: {
+  };
+  address = {
     selectRegion: '請選擇所在地區',
     deliveryTo: '配送至',
     chooseAnotherAddress: '選擇其他地址'
-  },
-  signature: {
+  };
+  signature = {
     reSign: '重簽',
     unSupportTpl: '對不起,當前瀏覽器不支持Canvas,無法使用本控制項!'
-  },
-  ecard: {
+  };
+  ecard = {
     chooseText: '請選擇電子卡面值',
     otherValueText: '其他面值',
     placeholder: '請輸入1-5000整數'
-  },
-  timeselect: {
+  };
+  timeselect = {
     pickupTime: '取件時間'
-  },
-  sku: {
+  };
+  sku = {
     buyNow: '立即購買',
     buyNumber: '購買數量',
     addToCard: '加入購物車'
-  },
-  skuheader: {
+  };
+  skuheader = {
     skuId: '商品編號'
-  },
-  addresslist: {
+  };
+  addresslist = {
     addAddress: '新建地址'
-  },
-  comment: {
+  };
+  comment = {
     complaintsText: '我要投訴',
     additionalReview: (day: number) => `購買${day}天後追評`,
     additionalImages: (length: number) => `${length}張追評圖片`
-  }
-};
-export default lang;
+  };
+}
+export default Lang;

+ 3 - 2
src/packages/utils/create/component.ts

@@ -7,14 +7,15 @@ import {
   RenderFunction,
   Component
 } from 'vue';
-import locale from '../../locale';
+import locale from '@/packages/locale';
 import { getPropByPath, isFunction } from '../util';
 export function createComponent(name: string) {
-  const languages = locale.languages();
   const componentName = 'nut-' + name;
   return {
     componentName,
     translate(keyPath: string, ...args: unknown[]) {
+      // 依赖响应能力
+      const languages = locale.languages();
       const text = getPropByPath(languages, `${name.replace('-', '')}.${keyPath}`) || getPropByPath(languages, keyPath);
       return isFunction(text) ? text(...args) : text;
     },

+ 4 - 1
vite.config.build.disperse.ts

@@ -74,10 +74,13 @@ declare module 'vue' {
     },
     rollupOptions: {
       // 请确保外部化那些你的库中不需要的依赖
-      external: ['vue', 'vue-router'],
+      external: ['vue', 'vue-router', '@/packages/locale'],
       input,
       output: {
         banner,
+        paths: {
+          '@/packages/locale': '../locale/lang'
+        },
         dir: path.resolve(__dirname, './dist/packages/_es'),
         entryFileNames: '[name].js'
       }

+ 61 - 0
vite.config.build.locale.ts

@@ -0,0 +1,61 @@
+import { defineConfig } from 'vite';
+import path from 'path';
+import config from './package.json';
+import vue from '@vitejs/plugin-vue';
+import dts from 'vite-plugin-dts';
+const banner = `/*!
+* ${config.name} v${config.version} ${new Date()}
+* (c) 2022 @jdf2e.
+* Released under the MIT License.
+*/`;
+
+let input = {
+  index: `./src/packages/locale/index`
+};
+// 动态读取file name
+['zh-CN', 'zh-TW', 'en-US'].map((file) => {
+  input[file] = `./src/packages/locale/lang/${file}`;
+});
+import fs from 'fs-extra';
+// 构建index.scss 兼容插件市场按需加载插件
+fs.outputFile(path.resolve(__dirname, './dist/packages/locale/index.scss'), ' ', 'utf8', (error) => {});
+fs.outputFile(path.resolve(__dirname, './dist/packages/locale/lang/index.scss'), ' ', 'utf8', (error) => {});
+
+export default defineConfig({
+  plugins: [
+    vue(),
+    dts({
+      insertTypesEntry: true,
+      copyDtsFiles: true,
+      cleanVueFileName: true,
+      outputDir: path.resolve(__dirname, './dist/packages/locale'),
+      include: path.resolve(__dirname, './src/packages/locale')
+    })
+  ],
+  build: {
+    minify: true,
+    terserOptions: {
+      compress: {
+        drop_console: true,
+        drop_debugger: true
+      }
+    },
+    lib: {
+      entry: '',
+      name: 'index',
+      // fileName: (format) => format,
+      formats: ['es']
+    },
+    rollupOptions: {
+      // 请确保外部化那些你的库中不需要的依赖
+      external: ['vue'],
+      input,
+      output: {
+        banner,
+        dir: path.resolve(__dirname, './dist/packages/locale/lang'),
+        entryFileNames: '[name].js'
+      }
+    },
+    emptyOutDir: false
+  }
+});

+ 4 - 1
vite.config.build.taro.vue.disperse.ts

@@ -76,10 +76,13 @@ declare module 'vue' {
     },
     rollupOptions: {
       // 请确保外部化那些你的库中不需要的依赖
-      external: ['vue', 'vue-router', '@tarojs/taro'],
+      external: ['vue', 'vue-router', '@tarojs/taro', '@/packages/locale'],
       input,
       output: {
         banner,
+        paths: {
+          '@/packages/locale': '../locale/lang'
+        },
         dir: path.resolve(__dirname, './dist/packages/_es'),
         entryFileNames: '[name].js'
       }