td-octopus 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cmds/import.js CHANGED
@@ -1,9 +1,9 @@
1
- const { excel } = require('../src/import');
1
+ const { importExcel } = require('../src/import');
2
2
 
3
- exports.command = 'import [langs]';
3
+ exports.command = 'import';
4
4
 
5
- exports.describe = 'import [langs] 将excel中人工翻译的部分替换未翻译的key';
5
+ exports.describe = 'import 将excel中人工翻译的部分替换未翻译的key';
6
6
 
7
- exports.handler = (args) => {
8
- excel(args.langs)
7
+ exports.handler = () => {
8
+ importExcel()
9
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "td-octopus",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "I18N tool",
5
5
  "author": "Anthony Li",
6
6
  "bin": {
@@ -9,7 +9,7 @@
9
9
  "license": "MIT",
10
10
  "dependencies": {
11
11
  "@babel/core": "^7.18.2",
12
- "baidu-translate": "^1.1.0",
12
+ "baidu-translate": "^1.3.0",
13
13
  "colors": "^1.4.0",
14
14
  "glob": "^8.0.3",
15
15
  "google-translate": "^3.0.0",
@@ -1,12 +1,10 @@
1
1
  /*
2
- * @Description:
2
+ * @Description: 讲excel的内容导入会json
3
3
  * @Author: 郑泳健
4
4
  * @Date: 2022-06-26 11:29:33
5
5
  * @LastEditors: 郑泳健
6
- * @LastEditTime: 2022-06-30 18:36:59
6
+ * @LastEditTime: 2022-07-06 14:24:58
7
7
  */
8
- const fs = require('fs');
9
- const path = require('path');
10
8
  const {
11
9
  otpPath,
12
10
  flatObject,
@@ -16,30 +14,24 @@ const {
16
14
  } = require('../utils/translate');
17
15
  const syncLang = require('../utils/syncLang')
18
16
  const { getProjectConfig } = require('../utils/index')
19
-
17
+ const ora = require('ora');
20
18
  const { OCTOPUS_CONFIG_FILE } = require('../utils/const')
21
19
 
20
+ const spinner = ora('开始import');
22
21
  // 人工翻译后对象
23
- function excel(str) {
22
+ function importExcel() {
24
23
  (async () => {
25
- const list = str ? str.split(',') : undefined;
26
24
  const otpConfig = getProjectConfig()
27
25
  const distLang = otpConfig && otpConfig.distLangs
28
26
 
29
- if (str && (!Array.isArray(list) || !list.length)) {
30
- console.log('参数必须为各语言用逗号隔开,例如en-US,zh-TW')
31
- return;
32
- }
33
- if (!str && !Array.isArray(distLang)) {
27
+ if (!Array.isArray(distLang)) {
34
28
  console.log(`请配置${OCTOPUS_CONFIG_FILE}里面的distLangs`)
35
29
  return;
36
30
  }
37
31
 
38
32
  await syncLang();
39
-
40
- const arr = list || distLang
41
-
42
- arr.forEach((lang) => {
33
+ spinner.start('正在从excel开始同步')
34
+ distLang.forEach((lang) => {
43
35
  parseExcel(otpPath + `/${lang}/translate_${lang}.xls`, function (translateMap) {
44
36
  const { default: currentLangMap } = require(`../temp/${lang}`);
45
37
  const langFlat = flatObject(currentLangMap);
@@ -54,9 +46,10 @@ function excel(str) {
54
46
  rewriteFiles(fileKeyValueList, lang);
55
47
  });
56
48
  })
49
+ spinner.succeed('从excel同步成功')
57
50
  })()
58
51
  }
59
52
 
60
53
  module.exports = {
61
- excel
54
+ importExcel
62
55
  }
@@ -3,10 +3,8 @@
3
3
  * @Author: 郑泳健
4
4
  * @Date: 2022-06-01 13:56:18
5
5
  * @LastEditors: 郑泳健
6
- * @LastEditTime: 2022-06-30 20:20:06
6
+ * @LastEditTime: 2022-07-06 14:21:43
7
7
  */
8
- const fs = require('fs');
9
- const path = require('path');
10
8
  const {
11
9
  syncFiles,
12
10
  otpPath,
@@ -15,37 +13,47 @@ const {
15
13
  generateExcel,
16
14
  rewriteFiles,
17
15
  } = require('../utils/translate');
18
- const { getProjectConfig } = require('../utils/index')
19
16
  const syncLang = require('../utils/syncLang')
17
+ const { getProjectConfig } = require('../utils/index')
18
+ const ora = require('ora');
19
+ const { OCTOPUS_CONFIG_FILE } = require('../utils/const')
20
+
21
+ const spinner = ora('开始translate');
20
22
 
21
23
  // 同步不同的语言包
22
24
  function translate() {
23
25
  (async () => {
24
26
  const otpConfig = getProjectConfig()
25
27
  const distLang = otpConfig && otpConfig.distLangs
28
+
29
+ if (!Array.isArray(distLang)) {
30
+ console.log(`请配置${OCTOPUS_CONFIG_FILE}里面的distLangs`)
31
+ return;
32
+ }
33
+ spinner.start('正在同步文件')
26
34
  await syncFiles(distLang);
35
+ spinner.succeed('同步文件成功')
27
36
  await syncLang();
28
37
 
29
38
  const { default: zhCN } = require('../temp/zh-CN');
30
39
  const zhCNflat = flatObject(zhCN);
31
40
 
32
- if (!Array.isArray(distLang)) {
33
- console.log('请配置otp-config.json里面的distLangs')
34
- return;
35
- }
36
-
37
- distLang.forEach((lang) => {
41
+ for (const lang of distLang) {
38
42
  const { default: currentLangMap } = require(`../temp/${lang}`);
39
43
  const langFlat = flatObject(currentLangMap);
40
-
44
+ spinner.start('正在同步文件的key')
41
45
  // 删除掉多余的key,增加新的key,同时提取没有翻译过的key的列表
42
- const { fileKeyValueList, addList } = getAdjustLangObjAndAddList(langFlat, zhCNflat);
43
-
46
+ const { fileKeyValueList, addList } = await getAdjustLangObjAndAddList(lang, langFlat, zhCNflat);
47
+ spinner.succeed('同步文件的key成功')
44
48
  // 重写文件
45
49
  rewriteFiles(fileKeyValueList, lang);
50
+ spinner.start(`正在生成${lang} excel`)
46
51
  // 生成excel
47
52
  generateExcel(addList, otpPath + '/' + lang, lang);
48
- });
53
+ spinner.succeed(`生成${lang} excel成功`)
54
+ }
55
+
56
+ spinner.stop('translate成功')
49
57
  })()
50
58
  }
51
59
 
@@ -31,9 +31,9 @@ const PROJECT_CONFIG = {
31
31
  },
32
32
  zhIndexFile: `import common from './common';
33
33
 
34
- export default Object.assign({}, {
35
- common
36
- });`,
34
+ export default Object.assign({}, {
35
+ common
36
+ });`,
37
37
  zhTestFile: `export default {
38
38
  test: '测试'
39
39
  }`
@@ -1,18 +1,19 @@
1
1
  /*
2
- * @Description: 公用方法
2
+ * @Description: 翻译公用方法
3
3
  * @Author: 郑泳健
4
4
  * @Date: 2022-06-02 10:09:01
5
5
  * @LastEditors: 郑泳健
6
- * @LastEditTime: 2022-06-30 18:55:03
6
+ * @LastEditTime: 2022-07-06 11:24:00
7
7
  */
8
8
  const fs = require('fs');
9
9
  const path = require('path');
10
+ const baiduTranslate = require('baidu-translate');
10
11
  const shell = require('shelljs');
11
12
  const _ = require('lodash');
12
13
  const XLSX = require('xlsx');
13
- const { PROJECT_CONFIG } = require('./const')
14
+ const { getProjectConfig } = require('../utils/index');
14
15
 
15
- const otpPath = path.resolve(process.cwd(), PROJECT_CONFIG.dir);
16
+ const otpPath = path.resolve(process.cwd(), getProjectConfig().otpDir);
16
17
 
17
18
  /**
18
19
  * 判断对象是否为纯对象
@@ -129,12 +130,12 @@ function getFileKeyValueList(adjustLangObj) {
129
130
  * @param {*} zhCNObj zh-CN 的key/value
130
131
  * @returns { fileKeyValueList: [{fileName: a, value: {"b.c": xx}}], addList: [["a.b.c": "dd"]] }
131
132
  */
132
- function getAdjustLangObjAndAddList(langObj = {}, zhCNObj = {}) {
133
+ async function getAdjustLangObjAndAddList(lang, langObj = {}, zhCNObj = {}) {
133
134
  const langObjKeys = Object.keys(langObj);
134
135
  // 调整后的语言包key/value
135
136
  const adjustLangObj = {};
136
137
  // 需要新增的key/value
137
- const addList = [];
138
+ const needAddList = [];
138
139
  // 循环zh-CN的key,得到当前语言包的key
139
140
  for (let key in zhCNObj) {
140
141
  // 4种情况下,需要将key放入到翻译对象里面去
@@ -143,18 +144,131 @@ function getAdjustLangObjAndAddList(langObj = {}, zhCNObj = {}) {
143
144
  // 3: 语言包的key的value值为""
144
145
  // 4: 语言包的key的value和zh-CN的key的value一样
145
146
  if (!langObjKeys.includes(key) || typeof langObj[key] !== 'string' || langObj[key] === '' || langObj[key] === zhCNObj[key]) {
146
- addList.push([key, zhCNObj[key], '', '']);
147
+ needAddList.push([key, zhCNObj[key], '', '']);
147
148
  }
148
149
 
149
150
  adjustLangObj[key] = langObj[key] || zhCNObj[key];
150
151
  }
151
152
 
153
+ const addList = await combinText(needAddList, lang);
154
+
152
155
  return {
153
156
  fileKeyValueList: getFileKeyValueList(adjustLangObj),
154
157
  addList
155
158
  };
156
159
  }
157
160
 
161
+ /**
162
+ * 合并需要翻译的中文,因为百度翻译限制一次性中文只能有3000字
163
+ * 因为百度免费翻译有时候会抽风,会导致翻译结果出错,为了减少没被翻译的,所以现在设置一次性翻译200字
164
+ * @param {*} needAddList
165
+ */
166
+ async function combinText(needAddList, lang) {
167
+ const otpConfig = getProjectConfig()
168
+ const { baiduApiKey, baiduLangMap } = otpConfig || {}
169
+ const { appId, appKey } = baiduApiKey || {}
170
+ const toLang = baiduLangMap?.[lang] || '';
171
+
172
+ if (!Array.isArray(needAddList)) {
173
+ return []
174
+ }
175
+
176
+ // 如果不配置百度翻译就直接返回
177
+ if (!appId || !appKey || !toLang) {
178
+ return needAddList;
179
+ }
180
+
181
+ // 分组
182
+ const groupList = groupByLength(needAddList, 200)
183
+ // 分组翻译结果
184
+ const transformResultList = await getTransformResultList(groupList, appId, appKey, 'zh', toLang)
185
+
186
+ return needAddList.map((i, index) => {
187
+ i[2] = transformResultList[index];
188
+ return i
189
+ })
190
+ }
191
+
192
+ /**
193
+ * 对分组的结果进行翻译
194
+ * @param {*} groupList
195
+ * @param {*} appId
196
+ * @param {*} appKey
197
+ * @param {*} fromLang
198
+ * @param {*} toLang
199
+ * @returns
200
+ */
201
+ async function getTransformResultList(groupList, appId, appKey, fromLang, toLang) {
202
+ let translatList = []
203
+ for (const i of groupList) {
204
+ const baiduResult = await baiduTranslation(appId, appKey, fromLang, toLang, JSON.stringify(i))
205
+
206
+ try {
207
+ const splitBaiduResult = baiduResult?.[0]
208
+ const transResultList = JSON.parse(splitBaiduResult);
209
+ // 这里是判断百度翻译返回的长度是不是和传入的一样
210
+ const reduceNum = i.length - transResultList.length;
211
+ translatList = [...translatList, ...transResultList].concat(Array(reduceNum).fill(''))
212
+
213
+ } catch (e) {
214
+ console.log(`百度翻译出现部分失败, 失败原因: ${e.message}`)
215
+ translatList = translatList.concat(Array(i.length).fill(''))
216
+ }
217
+ }
218
+
219
+ return translatList
220
+ }
221
+
222
+ /**
223
+ * 对数组进行分组
224
+ * @param {*} groupList 原数组
225
+ * @param {*} max 最大多少字
226
+ * @returns
227
+ */
228
+ function groupByLength(groupList, max) {
229
+ const list = [[]]
230
+ let str = ''
231
+ // 变成${max}个字符一组的数组,用于一次百度翻译
232
+ groupList.forEach((it) => {
233
+ let [, text] = it;
234
+
235
+ if ((str + text).length < max) {
236
+ list[list.length - 1] = Array.isArray(list[list.length - 1]) ? [...list[list.length - 1], text] : [text]
237
+ str = str + text
238
+ } else {
239
+ list.push([text])
240
+ str = ''
241
+ }
242
+ })
243
+ return list
244
+ }
245
+
246
+ /**
247
+ * 百度翻译
248
+ * @param {*} from
249
+ * @param {*} to
250
+ * @param {*} text
251
+ * @returns
252
+ */
253
+ async function baiduTranslation(appId, appKey, from, to, text) {
254
+ return new Promise((resolve, reject) => {
255
+ // 延迟1000ms是因为百度翻译对调用频率有限制
256
+ setTimeout(() => {
257
+ return baiduTranslate(appId, appKey, to, from)(text)
258
+ .then(data => {
259
+ if (data && data.trans_result) {
260
+ const result = data.trans_result.map(item => item.dst) || [];
261
+ resolve(result);
262
+ } else {
263
+ resolve('[]')
264
+ }
265
+ }).catch(err => {
266
+ reject('[]');
267
+ });
268
+ }, 1000)
269
+ })
270
+ }
271
+
158
272
  /**
159
273
  * 转换数据结构 {"a.b.c": "测试"} ==> {a: {b: {c: "测试"}}}
160
274
  * @param {*} adjustLangObj
@@ -173,7 +287,7 @@ function getDistRst(adjustLangObj) {
173
287
  * @param {*} path 生成的路径
174
288
  */
175
289
  function generateExcel(addList, path, lang) {
176
- const excleData = [['需要翻译的字段', '中文', '人工翻译'], ...addList];
290
+ const excleData = [['需要翻译的字段', '中文', '百度翻译', '人工翻译'], ...addList];
177
291
 
178
292
  const options = {
179
293
  '!cols': [{ wpx: 100 }, { wpx: 100 }, { wpx: 100 }]