b28-cli 1.7.1 → 1.7.2

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.
Files changed (74) hide show
  1. package/.babelrc +13 -13
  2. package/README.MD +470 -466
  3. package/TestFile/output/lang/BRPT.json +24 -0
  4. package/TestFile/output/lang/CN.json +24 -0
  5. package/TestFile/output/lang/CS.json +24 -0
  6. package/TestFile/output/lang/DE.json +24 -0
  7. package/TestFile/output/lang/EN.json +24 -0
  8. package/TestFile/output/lang/ES.json +24 -0
  9. package/TestFile/output/lang/FR.json +24 -0
  10. package/TestFile/output/lang/HU.json +24 -0
  11. package/TestFile/output/lang/IT.json +24 -0
  12. package/TestFile/output/lang/KO.json +24 -0
  13. package/TestFile/output/lang/LAES.json +24 -0
  14. package/TestFile/output/lang/NL.json +24 -0
  15. package/TestFile/output/lang/PL.json +24 -0
  16. package/TestFile/output/lang/PT.json +24 -0
  17. package/TestFile/output/lang/RO.json +24 -0
  18. package/TestFile/output/lang/RU.json +24 -0
  19. package/TestFile/output/lang/TR.json +24 -0
  20. package/TestFile/output/lang/UK.json +24 -0
  21. package/TestFile/output/lang/ZH.json +24 -0
  22. package/TestFile/output/lang/brpt/translate.json +23 -0
  23. package/TestFile/output/lang/cn/translate.json +23 -0
  24. package/TestFile/output/lang/cs/translate.json +23 -0
  25. package/TestFile/output/lang/de/translate.json +23 -0
  26. package/TestFile/output/lang/es/translate.json +23 -0
  27. package/TestFile/output/lang/fr/translate.json +23 -0
  28. package/TestFile/output/lang/hu/translate.json +23 -0
  29. package/TestFile/output/lang/it/translate.json +23 -0
  30. package/TestFile/output/lang/ko/translate.json +23 -0
  31. package/TestFile/output/lang/laes/translate.json +23 -0
  32. package/TestFile/output/lang/nl/translate.json +23 -0
  33. package/TestFile/output/lang/pl/translate.json +23 -0
  34. package/TestFile/output/lang/pt/translate.json +23 -0
  35. package/TestFile/output/lang/ro/translate.json +23 -0
  36. package/TestFile/output/lang/ru/translate.json +23 -0
  37. package/TestFile/output/lang/tr/translate.json +23 -0
  38. package/TestFile/output/lang/uk/translate.json +23 -0
  39. package/TestFile/output/lang/zh/translate.json +23 -0
  40. package/TestFile/output/lang.json +25 -0
  41. package/b28n.js +739 -739
  42. package/b28nPigeonhole/11ac_ecos_b28n.js +677 -677
  43. package/b28nPigeonhole/11ac_linux_b28n_async.js +709 -709
  44. package/b28nPigeonhole/4G03_b28n_async.js +708 -708
  45. package/b28nPigeonhole/G5310P_b28n.js +650 -650
  46. package/b28nPigeonhole/es5b28n.js +711 -711
  47. package/b28nPigeonhole/es6b28n.js +857 -857
  48. package/b28nPigeonhole/readMe.md +20 -20
  49. package/b28nPigeonhole//345/276/256/344/274/201/350/267/257/347/224/261b28n.js +916 -916
  50. package/dist/ExtractLangExcel.js +138 -45
  51. package/dist/cmd.js +14 -9
  52. package/dist/excel2json.js +215 -54
  53. package/dist/extract/extract-html.js +2 -2
  54. package/dist/extract/extract-js.js +2 -2
  55. package/dist/extract/extract-regexp.js +2 -2
  56. package/dist/extract/extract-vue.js +9 -9
  57. package/dist/extract/extract.js +4 -4
  58. package/dist/extract/extractRegexp/index.js +6 -6
  59. package/dist/extract/vue/html-parser.js +16 -16
  60. package/dist/extract/vue/util.js +2 -2
  61. package/dist/extract/vue/vue-compiler.js +2 -2
  62. package/dist/extractOrigin/extract.js +2 -2
  63. package/dist/extractOrigin/extract_html_ori.js +2 -2
  64. package/dist/extractOrigin/extract_js_ori.js +2 -2
  65. package/dist/handle.js +57 -7
  66. package/dist/index.js +36 -7
  67. package/dist/mergeExcel.js +407 -0
  68. package/dist/mergeJson.js +423 -2
  69. package/dist/util/config.js +90 -32
  70. package/dist/util/index.js +48 -41
  71. package/index.js +5 -5
  72. package/package.json +63 -62
  73. package/result.txt +53 -53
  74. package/test.js +182 -182
@@ -1,857 +1,857 @@
1
- (function (window, document) {
2
- Array.prototype.indexOf =
3
- Array.prototype.indexOf ||
4
- function (item) {
5
- for (let i = 0, l = this.length; i < l; i++) {
6
- if (this[i] === item) {
7
- return i;
8
- }
9
- }
10
- return -1;
11
- };
12
-
13
- Array.prototype.filter =
14
- Array.prototype.filter ||
15
- function (cb) {
16
- let arr = [];
17
- if (cb && typeof cb === "function") {
18
- for (let i = 0, l = this.length; i < l; i++) {
19
- cb(this[i]) && arr.push(this[i]);
20
- }
21
- }
22
- return arr;
23
- };
24
-
25
- //翻译配置项
26
- let b28Cfg = {
27
- /**
28
- * 支持的语言项,若设置的语言不在配置项中,则显示默认语言
29
- */
30
- supportLang: ["en", "cn"],
31
- /**
32
- * 默认语言,若supportLang中没有设置的默认语言,则自动添加到supportLang中去
33
- */
34
- defaultLang: "en",
35
- /**
36
- * 配置语言包文件类型 within ["xml", "json"]
37
- */
38
- fileType: "json",
39
- /**
40
- * 用默认语言做id
41
- */
42
- idDefaultLang: true,
43
- /**
44
- * 是否对要翻译文字进行trim
45
- */
46
- trimText: true,
47
- /**
48
- * 默认替换节点中的文字,将其设为true可插入html
49
- */
50
- insertHTML: true,
51
- /**
52
- * 是否初始化下拉框
53
- */
54
- initSelect: true,
55
- /**
56
- * 时间戳
57
- */
58
- dateStr: new Date().getTime(),
59
-
60
- langArr: {
61
- cn: "简体中文",
62
- zh: "繁體中文",
63
- de: "Deutsch", //德语
64
- en: "English", //英语
65
- es: "Español", //西班牙
66
- fr: "Français", //法国
67
- hu: "Magyar", //匈牙利
68
- it: "Italiano", //意大利
69
- pl: "Polski", //波兰
70
- ro: "Română", //罗马尼亚
71
- ar: "العربية", //阿拉伯
72
- tr: "Türkçe", //土耳其
73
- ru: "Русский", //Russian 俄语
74
- pt: "Português", //Portugal 葡萄牙语
75
- },
76
- };
77
-
78
- let win = window,
79
- doc = document,
80
- core_version = "3.0.0",
81
- core_trim = core_version.trim,
82
- //获取语言文件相对路径
83
- js = document.scripts,
84
- langJs = js[js.length - 1]["src"],
85
- langPath = langJs.substring(0, langJs.lastIndexOf("/") + 1);
86
-
87
- /** 工具函数 start */
88
- //对象浅拷贝
89
- function extend(oldObj, newObj) {
90
- if (typeof newObj !== "object") {
91
- return;
92
- }
93
-
94
- for (let key in newObj) {
95
- if (newObj.hasOwnProperty(key)) {
96
- oldObj[key] = newObj[key];
97
- }
98
- }
99
- }
100
- /** 工具函数 end */
101
-
102
- /**
103
- * 创建ajax
104
- */
105
- function createXHR() {
106
- try {
107
- return new XMLHttpRequest();
108
- } catch (e) {
109
- try {
110
- return new window.ActiveXObject("Msxml2.XMLHTTP");
111
- } catch (e) {
112
- try {
113
- return new window.ActiveXObject("Microsoft.XMLHTTP");
114
- } catch (e) {
115
- return;
116
- }
117
- }
118
- }
119
- }
120
-
121
- /**
122
- * 添加文档加载完成后的事件委托
123
- */
124
- let domReady = (function () {
125
- let funcs = [],
126
- already = false,
127
- len,
128
- i;
129
-
130
- function handler(e) {
131
- e = e || win.event;
132
- if (already) {
133
- return;
134
- }
135
-
136
- if (e.type === "readystatechange" && doc.readyState !== "complete") {
137
- return;
138
- }
139
-
140
- for (i = 0, len = funcs.length; i < len; i++) {
141
- funcs[i].call(doc);
142
- }
143
-
144
- already = true;
145
- funcs = null;
146
- }
147
-
148
- if (doc.addEventListener) {
149
- doc.addEventListener("DOMContentLoaded", handler, false);
150
- doc.addEventListener("onreadystatechange", handler, false);
151
- win.addEventListener("load", handler, false);
152
- } else if (doc.attachEvent) {
153
- doc.attachEvent("onreadystatechange", handler);
154
- win.attachEvent("onload", handler);
155
- }
156
-
157
- return function ready(f) {
158
- if (already) {
159
- f.call(doc);
160
- } else {
161
- funcs.push(f);
162
- }
163
- };
164
- })();
165
-
166
- /**
167
- * 加载script
168
- */
169
- let loadScript = (function () {
170
- let scripts = doc.createElement("script"),
171
- hasReadyState = scripts.readyState;
172
-
173
- return hasReadyState
174
- ? function (url, callBack) {
175
- let scripts = doc.createElement("script");
176
-
177
- scripts.onreadystatechange = function () {
178
- if (scripts.readyState === "loaded" || scripts.readyState === "complete") {
179
- scripts.onreadystatechange = null;
180
-
181
- if (typeof callBack === "function") {
182
- callBack();
183
- callBack = null;
184
- }
185
- }
186
- };
187
- scripts.src = url;
188
- doc.getElementsByTagName("head")[0].appendChild(scripts);
189
- }
190
- : function (url, callBack) {
191
- let scripts = doc.createElement("script");
192
-
193
- scripts.onload = function () {
194
- if (typeof callBack === "function") {
195
- callBack();
196
- callBack = null;
197
- }
198
- };
199
- scripts.src = url;
200
- doc.getElementsByTagName("head")[0].appendChild(scripts);
201
- };
202
- })();
203
-
204
- // 获取数据文件 并注入到msg中
205
- let loadData = {
206
- reload(type, url, callBack) {
207
- let parseData = type === "json" ? loadData.parseJson : loadData.parseXML,
208
- request;
209
-
210
- request = createXHR();
211
- request.open("GET", url + "?" + Math.random(), false);
212
- request.send(null);
213
-
214
- if ((request.status >= 200 && request.status < 300) || request.status === 304) {
215
- let langData = parseData(request);
216
-
217
- if (typeof callBack === "function") {
218
- callBack(langData);
219
- langData = null;
220
- callBack = null;
221
- }
222
- }
223
- },
224
- parseXML(request) {
225
- let i,
226
- pos,
227
- posLen,
228
- langData = {};
229
-
230
- pos = request.responseXML.documentElement.getElementsByTagName("message");
231
- posLen = pos.length;
232
-
233
- for (i = 0; i < posLen; i++) {
234
- langData[pos[i].getAttribute("msgid")] = pos[i].getAttribute("msgstr");
235
- }
236
-
237
- return langData;
238
- },
239
- parseJson(request) {
240
- return window.JSON.parse(request.responseText) || request.responseText;
241
- },
242
- };
243
-
244
- /**
245
- * 去除lang-xx类名,并添加新的类名
246
- */
247
- function handleClass(classname) {
248
- let name = document.documentElement.className;
249
- if (name) {
250
- name = name.split(" ").filter((item) => {
251
- return !/^lang-/.test(item);
252
- });
253
- name.push(classname);
254
-
255
- document.documentElement.className = name.join(" ");
256
- } else {
257
- document.documentElement.className = classname;
258
- }
259
- }
260
-
261
- /**
262
- * 获取元素的文本内容 或者设置文本内容
263
- */
264
- let innerText = (function () {
265
- if (b28Cfg.insertHTML) {
266
- return function (elem, str) {
267
- elem.innerHTML = str;
268
- return elem;
269
- };
270
- }
271
-
272
- let element = doc.createElement("p");
273
- element.innerHTML = core_version;
274
- return element.textContent
275
- ? function (elem, str) {
276
- if (str) {
277
- elem.textContent = str;
278
- return elem;
279
- }
280
- return elem.textContent;
281
- }
282
- : function (elem, str) {
283
- if (str) {
284
- elem.innerText = str;
285
- return elem;
286
- }
287
- return elem.innerText;
288
- };
289
- })();
290
-
291
- /**
292
- * 去除字符串首尾空格全兼容
293
- */
294
- function trim(text) {
295
- if (text == null) {
296
- return "";
297
- }
298
- if (core_trim && !core_trim.call("\uFEFF\xA0")) {
299
- return core_trim.call(text);
300
- } else {
301
- text += "";
302
- return text.replace(/(^\s*)|(\s*$)/g, "");
303
- }
304
- }
305
-
306
- /**
307
- * 根据配置参数决定是否去除空格
308
- */
309
- function _trim(str) {
310
- return b28Cfg.trimText ? trim(str) : str;
311
- }
312
-
313
- /**
314
- * 是否是html元素
315
- */
316
- function assertElement(elem) {
317
- //支持HTMLElement
318
- if (typeof HTMLElement === "object" && elem instanceof HTMLElement) {
319
- return true;
320
- }
321
- //ie等
322
- if (typeof elem === "object" && (elem.nodeType === 1 || elem.nodeType === 9) && typeof elem.nodeName === "string") {
323
- return true;
324
- }
325
- return false;
326
- }
327
-
328
- /**
329
- * 判断是否为null,undefined或者空白字符串
330
- * @param {值} val
331
- */
332
- function notNull(val) {
333
- return val && /\S/.test(val);
334
- }
335
-
336
- /**
337
- * 寻找子元素中text
338
- * @param {元素} elem
339
- */
340
- function getTextChild(elem) {
341
- if (elem) {
342
- let first = elem.firstChild;
343
- if (first) {
344
- if (first.nodeType === 3) {
345
- return first.nodeValue;
346
- }
347
- return getTextChild(first.nextSibling);
348
- }
349
- }
350
- }
351
-
352
- function htmlEncode(str) {
353
- var encodeObj = {
354
- "&": "&amp;",
355
- "<": "&lt;",
356
- ">": "&gt;",
357
- "'": "&#39;",
358
- '"': "&quot;",
359
- " ": "&nbsp;",
360
- };
361
- if (str.length == 0) {
362
- return "";
363
- }
364
- return str.replace(/(&|\s| |<|>|\'|\")/g, function (a) {
365
- return encodeObj[a];
366
- });
367
- }
368
-
369
- function htmlDecode(str) {
370
- var decodeObj = {
371
- "&amp;": "&",
372
- "&lt;": "<",
373
- "&gt;": ">",
374
- "&#39;": "'",
375
- "&quot;": '"',
376
- "&nbsp;": " ",
377
- };
378
- if (str.length == 0) {
379
- return "";
380
- }
381
- return str.replace(/(&amp;|&lt;|&gt;|&#39;|&quot;|&nbsp;)/g, function (a) {
382
- return decodeObj[a];
383
- });
384
- }
385
- /** 文本处理相关函数 end */
386
-
387
- //翻译对象
388
- function Butterlation(cfg) {
389
- extend(b28Cfg, cfg);
390
-
391
- //若所支持的语言中没有默认语言,则将默认语言添加到支持语言数组中
392
- if (b28Cfg.idDefaultLang && b28Cfg.supportLang.indexOf(b28Cfg.defaultLang) === -1) {
393
- b28Cfg.supportLang.push(b28Cfg.defaultLang);
394
- }
395
- this.curDomain = 0;
396
- this.domainArr = [];
397
- this.options = {
398
- defaultLang: b28Cfg.defaultLang,
399
- support: b28Cfg.supportLang,
400
- fileType: b28Cfg.fileType,
401
- };
402
- this.langArr = b28Cfg.langArr;
403
- /**语言包文件是否加载完成标志 */
404
- this.b28Loaded = false;
405
- /**当前语言 */
406
- this.lang = "";
407
- /**是否记录当前语言用于无刷新翻译页面 */
408
- this.saveLang = false;
409
- /**当前语言包信息 */
410
- this.langData = {};
411
- /**记录翻译页面前的数据 */
412
- this.original = {
413
- title: doc.title,
414
- };
415
- }
416
-
417
- Butterlation.prototype = {
418
- /**
419
- * 翻译title
420
- */
421
- transTitle: function (title) {
422
- doc.title = this.gettext(_trim(title));
423
- },
424
- /**
425
- * 翻译html元素节点
426
- * @param {object} element
427
- */
428
- replaceTextNodeValue: function (element) {
429
- if (!element) {
430
- return;
431
- }
432
- if (/^SCRIPT$/i.test(element.tagName)) {
433
- if (element.nextSibling) {
434
- this.replaceTextNodeValue(element.nextSibling);
435
- }
436
- return;
437
- }
438
-
439
- let firstChild = element.firstChild,
440
- nextSibling = element.nextSibling,
441
- nodeType = element.nodeType,
442
- btnStr = "submit,reset,button",
443
- curValue,
444
- isInputButton,
445
- oldValue;
446
-
447
- //handle element node
448
- if (nodeType === 1) {
449
- //alt属性
450
- this.replaceTextNodeAttr("alt", element, "data-o-alt");
451
-
452
- //placeholder属性
453
- this.replaceTextNodeAttr("placeholder", element, "data-o-holder");
454
-
455
- //title属性
456
- this.replaceTextNodeAttr("title", element, "data-o-title");
457
-
458
- isInputButton = element.nodeName.toLowerCase() == "input" && btnStr.indexOf(element.getAttribute("type")) !== -1;
459
-
460
- if (isInputButton) {
461
- //data-lang属性具有较高优先级
462
- curValue = element.getAttribute("data-lang") || element.value;
463
- } else {
464
- if (element.getAttribute("data-nowrap") === "1") {
465
- curValue = element.innerHTML;
466
- } else {
467
- curValue = element.getAttribute("data-lang");
468
- }
469
- }
470
-
471
- if (curValue && /\S/.test(curValue)) {
472
- curValue = htmlEncode(curValue);
473
- if (this.saveLang) {
474
- let oldText = element.getAttribute("data-o-text");
475
- if (oldText === undefined || oldText === null) {
476
- if (element.getAttribute("data-nowrap") === "1") {
477
- oldText = curValue;
478
- } else {
479
- oldText = getTextChild(element);
480
- notNull(oldText) && (oldText = htmlEncode(oldText));
481
- }
482
- oldText = oldText || " ";
483
- element.setAttribute("data-o-text", oldText);
484
- }
485
-
486
- if (this.options.defaultLang === this.lang) {
487
- curValue = oldText;
488
- }
489
- }
490
-
491
- curValue = htmlDecode(curValue);
492
- if (curValue) {
493
- curValue = _trim(curValue);
494
- if (isInputButton) {
495
- element.setAttribute("value", this.gettext(curValue));
496
- } else {
497
- innerText(element, this.gettext(curValue));
498
- }
499
- }
500
- }
501
- //handle textNode
502
- } else if (nodeType === 3 && notNull(element.nodeValue)) {
503
- curValue = _trim(element.nodeValue);
504
- if (this.saveLang) {
505
- let parNode = element.parentNode;
506
- oldValue = parNode.getAttribute("data-o-text");
507
- if (oldValue) {
508
- curValue = htmlDecode(oldValue);
509
- } else {
510
- parNode.setAttribute("data-o-text", htmlEncode(curValue));
511
- }
512
- }
513
- element.nodeValue = this.gettext(curValue);
514
- }
515
- //translate siblings
516
- if (nextSibling) {
517
- this.replaceTextNodeValue(nextSibling);
518
- }
519
-
520
- //translate firstChild
521
- //stop handle elem.child if elem has attr data-lang
522
- if (firstChild && !element.getAttribute("data-lang")) {
523
- this.replaceTextNodeValue(firstChild);
524
- }
525
- },
526
- /**
527
- * 翻译html元素节点的属性
528
- * @param {object} element
529
- */
530
-
531
- replaceTextNodeAttr: function (attr, element, oldAttr) {
532
- let curValue = element.getAttribute(attr);
533
- let oldValue = element.getAttribute(oldAttr);
534
- if (this.saveLang) {
535
- if (oldValue) {
536
- curValue = oldValue;
537
- } else {
538
- notNull(curValue) && element.setAttribute(oldAttr, curValue);
539
- }
540
- }
541
- if (notNull(curValue)) {
542
- curValue = _trim(curValue);
543
- element.setAttribute(attr, this.gettext(curValue));
544
- }
545
- },
546
- /**
547
- * 获取语言包信息
548
- */
549
- getMsg: function () {
550
- return this.langData;
551
- },
552
- /**
553
- * 是否支持该语言
554
- * @param {string} lang
555
- */
556
- isSupport: function (lang) {
557
- let support = this.options.support;
558
-
559
- if (support.indexOf(lang) === -1) {
560
- return false;
561
- }
562
- return lang;
563
- },
564
-
565
- /**
566
- * 设置语言
567
- * @param {string} lang
568
- */
569
- setLang: function (lang) {
570
- if (lang !== undefined) {
571
- if (!this.isSupport(lang)) {
572
- lang = this.options.defaultLang;
573
- }
574
- doc.cookie = "bLanguage=" + lang + ";";
575
- }
576
- return lang;
577
- },
578
-
579
- /**
580
- * 获取当前设置的语言
581
- */
582
- getLang: function () {
583
- let special = {
584
- zh: "cn",
585
- "zh-chs": "cn",
586
- "zh-cn": "cn",
587
- "zh-cht": "cn",
588
- "zh-hk": "zh",
589
- "zh-mo": "zh",
590
- "zh-tw": "zh",
591
- "zh-sg": "zh",
592
- },
593
- defLang = this.options.defaultLang,
594
- local,
595
- ret,
596
- start,
597
- end;
598
-
599
- if (doc.cookie.indexOf("bLanguage=") === -1) {
600
- local = (
601
- win.navigator.language ||
602
- win.navigator.userLanguage ||
603
- win.navigator.browserLanguage ||
604
- win.navigator.systemLanguage ||
605
- defLang
606
- ).toLowerCase();
607
-
608
- ret = special[local] || special[local.split("-")[0].toString()] || local.split("-")[0].toString();
609
- } else {
610
- if (doc.cookie.indexOf("bLanguage=") === 0) {
611
- start = 10;
612
- } else if (doc.cookie.indexOf("; bLanguage=") !== -1) {
613
- start = doc.cookie.indexOf("; bLanguage=") + 12;
614
- }
615
-
616
- if (start !== undefined) {
617
- end = doc.cookie.indexOf(";", start) !== -1 ? doc.cookie.indexOf(";", start) : doc.cookie.length;
618
- ret = doc.cookie.substring(start, end);
619
- }
620
- }
621
- //语言使用优先级 1.浏览器语言是否支持 2 默认语言是否支持 3支持中的语言第一个 4.默认语言
622
- return this.isSupport(ret) || this.isSupport(defLang) || (this.options.support && this.options.support[0]) || defLang;
623
- },
624
-
625
- /**
626
- * 拼接语言文件的url
627
- * @param {string} domain 语言文件名称不包含扩展名(如:lang.json -> domain为lang)
628
- */
629
- getURL: function (domain) {
630
- return langPath + this.lang + "/" + domain + "." + this.options.fileType + "?" + b28Cfg.dateStr;
631
- },
632
-
633
- /**
634
- * 加载所需要的语言文件,并翻译页面
635
- * @param {string} domain 翻译文件的名称不包含扩展名(如:lang.json -> domain为lang)
636
- * @param {lang} lang 当前语言
637
- * @param {function} callBack 回调
638
- */
639
- setTextDomain: function (domain, lang, callBack) {
640
- let i,
641
- domainLen,
642
- htmlElem = doc.documentElement;
643
-
644
- this.domainArr = [];
645
- this.lang = lang || this.getLang();
646
- this.setLang(lang);
647
- this.curDomain = 0;
648
- if (typeof callBack === "function") {
649
- this.success = callBack;
650
- }
651
-
652
- htmlElem.style.visibility = "hidden";
653
-
654
- handleClass("lang-" + this.lang);
655
-
656
- if (Object.prototype.toString.call(domain) === "[object Array]") {
657
- domainLen = domain.length;
658
- this.domainArr = domain;
659
-
660
- for (i = 0; i < domainLen; i = i + 1) {
661
- this.loadDomain(this.getURL(domain[i]), i);
662
- }
663
- } else if (typeof domain === "string") {
664
- this.domainArr.push(domain);
665
- this.loadDomain(this.getURL(domain), 0);
666
- }
667
- },
668
-
669
- /**
670
- * 加载语言文件
671
- * @param {string} url 语言包文件地址
672
- */
673
- loadDomain: function (url) {
674
- //若当前设定语言与默认语言一样,则不加载语言文件
675
- if (b28Cfg.idDefaultLang && this.lang === b28Cfg.defaultLang) {
676
- this.b28Loaded = true;
677
- b28Cfg.initSelect &&
678
- domReady(() => {
679
- this.initSelectElem();
680
- });
681
- //重置语言对象
682
- this.langData = {};
683
- domReady(() => {
684
- this.translatePage();
685
- });
686
- } else {
687
- //加载对应文件
688
- loadData.reload(this.options.fileType, url, (data) => {
689
- this.handLangData(data);
690
- });
691
- }
692
- },
693
-
694
- /**
695
- * 处理加载的数据文件
696
- */
697
- handLangData: function (data) {
698
- extend(this.langData, data);
699
- this.loadedDict();
700
- },
701
-
702
- /**
703
- * 语言文件加载完成后的回调,界面加载完成后进入翻译工作
704
- */
705
- loadedDict: function () {
706
- let len = this.domainArr.length;
707
- if (this.curDomain + 1 === len) {
708
- this.b28Loaded = true;
709
- domReady(() => {
710
- this.translatePage();
711
- });
712
- } else {
713
- this.curDomain += 1;
714
- }
715
- },
716
-
717
- /**
718
- * 语言包文件是否加载完成
719
- */
720
- isLoaded: function () {
721
- return this.b28Loaded;
722
- },
723
-
724
- /**
725
- * 翻译纯文本
726
- * @param {string} key 需要翻译的字段
727
- */
728
- gettext: function (key) {
729
- if (key === undefined) return;
730
- if (this.options.defaultLang === this.lang) {
731
- //处理一对多的翻译时对翻译加上了唯一标识的前缀,故需要把这些前缀去掉
732
- return key.replace(/^[a-zA-Z]\#[a-zA-Z][a-zA-Z][a-zA-Z]\#/g, "");
733
- }
734
- return this.langData[key] !== undefined ? this.langData[key] : key.replace(/^[a-zA-Z]\#[a-zA-Z][a-zA-Z][a-zA-Z]\#/g, "");
735
- },
736
-
737
- /**
738
- * 翻译有%s参数的文本
739
- * @param {string} key 需要翻译的字段
740
- * @param {Array} replacements 参数
741
- */
742
- getFormatText: function (key, replacements) {
743
- let nkey = this.gettext(key);
744
-
745
- if (replacements === "" || replacements === undefined) {
746
- return nkey;
747
- }
748
- if (Object.prototype.toString.call(replacements) !== "[object Array]") {
749
- replacements = [replacements];
750
- }
751
-
752
- for (let i = 0, l = replacements.length; i < l; i++) {
753
- nkey = nkey.replace(/%s/, replacements[i]);
754
- }
755
-
756
- return nkey;
757
- },
758
-
759
- /**
760
- * 初始化语言选择框
761
- */
762
- initSelectElem: function () {
763
- let selectElem = doc.getElementById("select-lang"),
764
- len = b28Cfg.supportLang.length,
765
- newOption,
766
- lang,
767
- i;
768
-
769
- if (selectElem && selectElem.nodeName.toLowerCase() == "select") {
770
- for (i = 0; i < len; i++) {
771
- lang = b28Cfg.supportLang[i];
772
- newOption = new Option(this.langArr[lang], lang);
773
- selectElem.add(newOption, undefined);
774
- }
775
- selectElem.value = this.lang;
776
-
777
- if (doc.addEventListener) {
778
- selectElem.addEventListener(
779
- "change",
780
- function () {
781
- this.setLang(doc.getElementById("select-lang").value);
782
- setTimeout(function () {
783
- window.location.reload();
784
- }, 24);
785
- },
786
- false
787
- );
788
- } else if (doc.attachEvent) {
789
- selectElem.attachEvent("onchange", function () {
790
- this.setLang(doc.getElementById("select-lang").value);
791
- setTimeout(function () {
792
- window.location.reload();
793
- }, 24);
794
- });
795
- }
796
- }
797
- },
798
-
799
- /**
800
- * 翻译translateTarget及translateTarget里面的内容
801
- * @param {element} translateTarget 需要翻译的内容的容器
802
- */
803
- translate: function (translateTarget) {
804
- let translateElem;
805
- //确定html容器元素
806
- if (assertElement(translateTarget)) {
807
- translateElem = translateTarget;
808
- } else if (translateTarget && typeof translateTarget === "string") {
809
- translateElem = doc.getElementById(translateTarget);
810
- }
811
- translateElem = translateElem || doc.documentElement;
812
- // 隐藏页面
813
- doc.documentElement.style.visibility = "hidden";
814
- // 逐个翻译元素
815
- this.replaceTextNodeValue(translateElem);
816
-
817
- this.saveLang = false;
818
- // 显示页面
819
- doc.documentElement.style.visibility = "visible";
820
- // 执行翻译完成后的回调
821
- if (typeof this.success === "function") {
822
- this.success();
823
- }
824
- },
825
-
826
- /**
827
- * 翻译页面
828
- */
829
- translatePage: function () {
830
- let bodyElem = doc.body || doc.documentElement;
831
-
832
- // 翻译HTML页面内容
833
- this.transTitle(this.original.title);
834
-
835
- // 初始语言选择下拉框
836
- b28Cfg.initSelect && this.initSelectElem();
837
- //全局翻译时需要记录所有的信息
838
- this.saveLang = true;
839
- this.translate(bodyElem);
840
- },
841
- };
842
-
843
- let Butterlate = new Butterlation(),
844
- defaultLang;
845
-
846
- //将翻译对象挂载到window上面
847
- win.Butterlate = Butterlate;
848
- win.B = win.B || win.Butterlate;
849
- win._ = function (key, replacements) {
850
- return Butterlate.getFormatText(key, replacements);
851
- };
852
- win.Butterlate.loadScript = loadScript;
853
- if (window.beforeTranslate) {
854
- defaultLang = window.beforeTranslate();
855
- }
856
- window.B.setTextDomain("lang", defaultLang);
857
- })(window, document);
1
+ (function (window, document) {
2
+ Array.prototype.indexOf =
3
+ Array.prototype.indexOf ||
4
+ function (item) {
5
+ for (let i = 0, l = this.length; i < l; i++) {
6
+ if (this[i] === item) {
7
+ return i;
8
+ }
9
+ }
10
+ return -1;
11
+ };
12
+
13
+ Array.prototype.filter =
14
+ Array.prototype.filter ||
15
+ function (cb) {
16
+ let arr = [];
17
+ if (cb && typeof cb === "function") {
18
+ for (let i = 0, l = this.length; i < l; i++) {
19
+ cb(this[i]) && arr.push(this[i]);
20
+ }
21
+ }
22
+ return arr;
23
+ };
24
+
25
+ //翻译配置项
26
+ let b28Cfg = {
27
+ /**
28
+ * 支持的语言项,若设置的语言不在配置项中,则显示默认语言
29
+ */
30
+ supportLang: ["en", "cn"],
31
+ /**
32
+ * 默认语言,若supportLang中没有设置的默认语言,则自动添加到supportLang中去
33
+ */
34
+ defaultLang: "en",
35
+ /**
36
+ * 配置语言包文件类型 within ["xml", "json"]
37
+ */
38
+ fileType: "json",
39
+ /**
40
+ * 用默认语言做id
41
+ */
42
+ idDefaultLang: true,
43
+ /**
44
+ * 是否对要翻译文字进行trim
45
+ */
46
+ trimText: true,
47
+ /**
48
+ * 默认替换节点中的文字,将其设为true可插入html
49
+ */
50
+ insertHTML: true,
51
+ /**
52
+ * 是否初始化下拉框
53
+ */
54
+ initSelect: true,
55
+ /**
56
+ * 时间戳
57
+ */
58
+ dateStr: new Date().getTime(),
59
+
60
+ langArr: {
61
+ cn: "简体中文",
62
+ zh: "繁體中文",
63
+ de: "Deutsch", //德语
64
+ en: "English", //英语
65
+ es: "Español", //西班牙
66
+ fr: "Français", //法国
67
+ hu: "Magyar", //匈牙利
68
+ it: "Italiano", //意大利
69
+ pl: "Polski", //波兰
70
+ ro: "Română", //罗马尼亚
71
+ ar: "العربية", //阿拉伯
72
+ tr: "Türkçe", //土耳其
73
+ ru: "Русский", //Russian 俄语
74
+ pt: "Português", //Portugal 葡萄牙语
75
+ },
76
+ };
77
+
78
+ let win = window,
79
+ doc = document,
80
+ core_version = "3.0.0",
81
+ core_trim = core_version.trim,
82
+ //获取语言文件相对路径
83
+ js = document.scripts,
84
+ langJs = js[js.length - 1]["src"],
85
+ langPath = langJs.substring(0, langJs.lastIndexOf("/") + 1);
86
+
87
+ /** 工具函数 start */
88
+ //对象浅拷贝
89
+ function extend(oldObj, newObj) {
90
+ if (typeof newObj !== "object") {
91
+ return;
92
+ }
93
+
94
+ for (let key in newObj) {
95
+ if (newObj.hasOwnProperty(key)) {
96
+ oldObj[key] = newObj[key];
97
+ }
98
+ }
99
+ }
100
+ /** 工具函数 end */
101
+
102
+ /**
103
+ * 创建ajax
104
+ */
105
+ function createXHR() {
106
+ try {
107
+ return new XMLHttpRequest();
108
+ } catch (e) {
109
+ try {
110
+ return new window.ActiveXObject("Msxml2.XMLHTTP");
111
+ } catch (e) {
112
+ try {
113
+ return new window.ActiveXObject("Microsoft.XMLHTTP");
114
+ } catch (e) {
115
+ return;
116
+ }
117
+ }
118
+ }
119
+ }
120
+
121
+ /**
122
+ * 添加文档加载完成后的事件委托
123
+ */
124
+ let domReady = (function () {
125
+ let funcs = [],
126
+ already = false,
127
+ len,
128
+ i;
129
+
130
+ function handler(e) {
131
+ e = e || win.event;
132
+ if (already) {
133
+ return;
134
+ }
135
+
136
+ if (e.type === "readystatechange" && doc.readyState !== "complete") {
137
+ return;
138
+ }
139
+
140
+ for (i = 0, len = funcs.length; i < len; i++) {
141
+ funcs[i].call(doc);
142
+ }
143
+
144
+ already = true;
145
+ funcs = null;
146
+ }
147
+
148
+ if (doc.addEventListener) {
149
+ doc.addEventListener("DOMContentLoaded", handler, false);
150
+ doc.addEventListener("onreadystatechange", handler, false);
151
+ win.addEventListener("load", handler, false);
152
+ } else if (doc.attachEvent) {
153
+ doc.attachEvent("onreadystatechange", handler);
154
+ win.attachEvent("onload", handler);
155
+ }
156
+
157
+ return function ready(f) {
158
+ if (already) {
159
+ f.call(doc);
160
+ } else {
161
+ funcs.push(f);
162
+ }
163
+ };
164
+ })();
165
+
166
+ /**
167
+ * 加载script
168
+ */
169
+ let loadScript = (function () {
170
+ let scripts = doc.createElement("script"),
171
+ hasReadyState = scripts.readyState;
172
+
173
+ return hasReadyState
174
+ ? function (url, callBack) {
175
+ let scripts = doc.createElement("script");
176
+
177
+ scripts.onreadystatechange = function () {
178
+ if (scripts.readyState === "loaded" || scripts.readyState === "complete") {
179
+ scripts.onreadystatechange = null;
180
+
181
+ if (typeof callBack === "function") {
182
+ callBack();
183
+ callBack = null;
184
+ }
185
+ }
186
+ };
187
+ scripts.src = url;
188
+ doc.getElementsByTagName("head")[0].appendChild(scripts);
189
+ }
190
+ : function (url, callBack) {
191
+ let scripts = doc.createElement("script");
192
+
193
+ scripts.onload = function () {
194
+ if (typeof callBack === "function") {
195
+ callBack();
196
+ callBack = null;
197
+ }
198
+ };
199
+ scripts.src = url;
200
+ doc.getElementsByTagName("head")[0].appendChild(scripts);
201
+ };
202
+ })();
203
+
204
+ // 获取数据文件 并注入到msg中
205
+ let loadData = {
206
+ reload(type, url, callBack) {
207
+ let parseData = type === "json" ? loadData.parseJson : loadData.parseXML,
208
+ request;
209
+
210
+ request = createXHR();
211
+ request.open("GET", url + "?" + Math.random(), false);
212
+ request.send(null);
213
+
214
+ if ((request.status >= 200 && request.status < 300) || request.status === 304) {
215
+ let langData = parseData(request);
216
+
217
+ if (typeof callBack === "function") {
218
+ callBack(langData);
219
+ langData = null;
220
+ callBack = null;
221
+ }
222
+ }
223
+ },
224
+ parseXML(request) {
225
+ let i,
226
+ pos,
227
+ posLen,
228
+ langData = {};
229
+
230
+ pos = request.responseXML.documentElement.getElementsByTagName("message");
231
+ posLen = pos.length;
232
+
233
+ for (i = 0; i < posLen; i++) {
234
+ langData[pos[i].getAttribute("msgid")] = pos[i].getAttribute("msgstr");
235
+ }
236
+
237
+ return langData;
238
+ },
239
+ parseJson(request) {
240
+ return window.JSON.parse(request.responseText) || request.responseText;
241
+ },
242
+ };
243
+
244
+ /**
245
+ * 去除lang-xx类名,并添加新的类名
246
+ */
247
+ function handleClass(classname) {
248
+ let name = document.documentElement.className;
249
+ if (name) {
250
+ name = name.split(" ").filter((item) => {
251
+ return !/^lang-/.test(item);
252
+ });
253
+ name.push(classname);
254
+
255
+ document.documentElement.className = name.join(" ");
256
+ } else {
257
+ document.documentElement.className = classname;
258
+ }
259
+ }
260
+
261
+ /**
262
+ * 获取元素的文本内容 或者设置文本内容
263
+ */
264
+ let innerText = (function () {
265
+ if (b28Cfg.insertHTML) {
266
+ return function (elem, str) {
267
+ elem.innerHTML = str;
268
+ return elem;
269
+ };
270
+ }
271
+
272
+ let element = doc.createElement("p");
273
+ element.innerHTML = core_version;
274
+ return element.textContent
275
+ ? function (elem, str) {
276
+ if (str) {
277
+ elem.textContent = str;
278
+ return elem;
279
+ }
280
+ return elem.textContent;
281
+ }
282
+ : function (elem, str) {
283
+ if (str) {
284
+ elem.innerText = str;
285
+ return elem;
286
+ }
287
+ return elem.innerText;
288
+ };
289
+ })();
290
+
291
+ /**
292
+ * 去除字符串首尾空格全兼容
293
+ */
294
+ function trim(text) {
295
+ if (text == null) {
296
+ return "";
297
+ }
298
+ if (core_trim && !core_trim.call("\uFEFF\xA0")) {
299
+ return core_trim.call(text);
300
+ } else {
301
+ text += "";
302
+ return text.replace(/(^\s*)|(\s*$)/g, "");
303
+ }
304
+ }
305
+
306
+ /**
307
+ * 根据配置参数决定是否去除空格
308
+ */
309
+ function _trim(str) {
310
+ return b28Cfg.trimText ? trim(str) : str;
311
+ }
312
+
313
+ /**
314
+ * 是否是html元素
315
+ */
316
+ function assertElement(elem) {
317
+ //支持HTMLElement
318
+ if (typeof HTMLElement === "object" && elem instanceof HTMLElement) {
319
+ return true;
320
+ }
321
+ //ie等
322
+ if (typeof elem === "object" && (elem.nodeType === 1 || elem.nodeType === 9) && typeof elem.nodeName === "string") {
323
+ return true;
324
+ }
325
+ return false;
326
+ }
327
+
328
+ /**
329
+ * 判断是否为null,undefined或者空白字符串
330
+ * @param {值} val
331
+ */
332
+ function notNull(val) {
333
+ return val && /\S/.test(val);
334
+ }
335
+
336
+ /**
337
+ * 寻找子元素中text
338
+ * @param {元素} elem
339
+ */
340
+ function getTextChild(elem) {
341
+ if (elem) {
342
+ let first = elem.firstChild;
343
+ if (first) {
344
+ if (first.nodeType === 3) {
345
+ return first.nodeValue;
346
+ }
347
+ return getTextChild(first.nextSibling);
348
+ }
349
+ }
350
+ }
351
+
352
+ function htmlEncode(str) {
353
+ var encodeObj = {
354
+ "&": "&amp;",
355
+ "<": "&lt;",
356
+ ">": "&gt;",
357
+ "'": "&#39;",
358
+ '"': "&quot;",
359
+ " ": "&nbsp;",
360
+ };
361
+ if (str.length == 0) {
362
+ return "";
363
+ }
364
+ return str.replace(/(&|\s| |<|>|\'|\")/g, function (a) {
365
+ return encodeObj[a];
366
+ });
367
+ }
368
+
369
+ function htmlDecode(str) {
370
+ var decodeObj = {
371
+ "&amp;": "&",
372
+ "&lt;": "<",
373
+ "&gt;": ">",
374
+ "&#39;": "'",
375
+ "&quot;": '"',
376
+ "&nbsp;": " ",
377
+ };
378
+ if (str.length == 0) {
379
+ return "";
380
+ }
381
+ return str.replace(/(&amp;|&lt;|&gt;|&#39;|&quot;|&nbsp;)/g, function (a) {
382
+ return decodeObj[a];
383
+ });
384
+ }
385
+ /** 文本处理相关函数 end */
386
+
387
+ //翻译对象
388
+ function Butterlation(cfg) {
389
+ extend(b28Cfg, cfg);
390
+
391
+ //若所支持的语言中没有默认语言,则将默认语言添加到支持语言数组中
392
+ if (b28Cfg.idDefaultLang && b28Cfg.supportLang.indexOf(b28Cfg.defaultLang) === -1) {
393
+ b28Cfg.supportLang.push(b28Cfg.defaultLang);
394
+ }
395
+ this.curDomain = 0;
396
+ this.domainArr = [];
397
+ this.options = {
398
+ defaultLang: b28Cfg.defaultLang,
399
+ support: b28Cfg.supportLang,
400
+ fileType: b28Cfg.fileType,
401
+ };
402
+ this.langArr = b28Cfg.langArr;
403
+ /**语言包文件是否加载完成标志 */
404
+ this.b28Loaded = false;
405
+ /**当前语言 */
406
+ this.lang = "";
407
+ /**是否记录当前语言用于无刷新翻译页面 */
408
+ this.saveLang = false;
409
+ /**当前语言包信息 */
410
+ this.langData = {};
411
+ /**记录翻译页面前的数据 */
412
+ this.original = {
413
+ title: doc.title,
414
+ };
415
+ }
416
+
417
+ Butterlation.prototype = {
418
+ /**
419
+ * 翻译title
420
+ */
421
+ transTitle: function (title) {
422
+ doc.title = this.gettext(_trim(title));
423
+ },
424
+ /**
425
+ * 翻译html元素节点
426
+ * @param {object} element
427
+ */
428
+ replaceTextNodeValue: function (element) {
429
+ if (!element) {
430
+ return;
431
+ }
432
+ if (/^SCRIPT$/i.test(element.tagName)) {
433
+ if (element.nextSibling) {
434
+ this.replaceTextNodeValue(element.nextSibling);
435
+ }
436
+ return;
437
+ }
438
+
439
+ let firstChild = element.firstChild,
440
+ nextSibling = element.nextSibling,
441
+ nodeType = element.nodeType,
442
+ btnStr = "submit,reset,button",
443
+ curValue,
444
+ isInputButton,
445
+ oldValue;
446
+
447
+ //handle element node
448
+ if (nodeType === 1) {
449
+ //alt属性
450
+ this.replaceTextNodeAttr("alt", element, "data-o-alt");
451
+
452
+ //placeholder属性
453
+ this.replaceTextNodeAttr("placeholder", element, "data-o-holder");
454
+
455
+ //title属性
456
+ this.replaceTextNodeAttr("title", element, "data-o-title");
457
+
458
+ isInputButton = element.nodeName.toLowerCase() == "input" && btnStr.indexOf(element.getAttribute("type")) !== -1;
459
+
460
+ if (isInputButton) {
461
+ //data-lang属性具有较高优先级
462
+ curValue = element.getAttribute("data-lang") || element.value;
463
+ } else {
464
+ if (element.getAttribute("data-nowrap") === "1") {
465
+ curValue = element.innerHTML;
466
+ } else {
467
+ curValue = element.getAttribute("data-lang");
468
+ }
469
+ }
470
+
471
+ if (curValue && /\S/.test(curValue)) {
472
+ curValue = htmlEncode(curValue);
473
+ if (this.saveLang) {
474
+ let oldText = element.getAttribute("data-o-text");
475
+ if (oldText === undefined || oldText === null) {
476
+ if (element.getAttribute("data-nowrap") === "1") {
477
+ oldText = curValue;
478
+ } else {
479
+ oldText = getTextChild(element);
480
+ notNull(oldText) && (oldText = htmlEncode(oldText));
481
+ }
482
+ oldText = oldText || " ";
483
+ element.setAttribute("data-o-text", oldText);
484
+ }
485
+
486
+ if (this.options.defaultLang === this.lang) {
487
+ curValue = oldText;
488
+ }
489
+ }
490
+
491
+ curValue = htmlDecode(curValue);
492
+ if (curValue) {
493
+ curValue = _trim(curValue);
494
+ if (isInputButton) {
495
+ element.setAttribute("value", this.gettext(curValue));
496
+ } else {
497
+ innerText(element, this.gettext(curValue));
498
+ }
499
+ }
500
+ }
501
+ //handle textNode
502
+ } else if (nodeType === 3 && notNull(element.nodeValue)) {
503
+ curValue = _trim(element.nodeValue);
504
+ if (this.saveLang) {
505
+ let parNode = element.parentNode;
506
+ oldValue = parNode.getAttribute("data-o-text");
507
+ if (oldValue) {
508
+ curValue = htmlDecode(oldValue);
509
+ } else {
510
+ parNode.setAttribute("data-o-text", htmlEncode(curValue));
511
+ }
512
+ }
513
+ element.nodeValue = this.gettext(curValue);
514
+ }
515
+ //translate siblings
516
+ if (nextSibling) {
517
+ this.replaceTextNodeValue(nextSibling);
518
+ }
519
+
520
+ //translate firstChild
521
+ //stop handle elem.child if elem has attr data-lang
522
+ if (firstChild && !element.getAttribute("data-lang")) {
523
+ this.replaceTextNodeValue(firstChild);
524
+ }
525
+ },
526
+ /**
527
+ * 翻译html元素节点的属性
528
+ * @param {object} element
529
+ */
530
+
531
+ replaceTextNodeAttr: function (attr, element, oldAttr) {
532
+ let curValue = element.getAttribute(attr);
533
+ let oldValue = element.getAttribute(oldAttr);
534
+ if (this.saveLang) {
535
+ if (oldValue) {
536
+ curValue = oldValue;
537
+ } else {
538
+ notNull(curValue) && element.setAttribute(oldAttr, curValue);
539
+ }
540
+ }
541
+ if (notNull(curValue)) {
542
+ curValue = _trim(curValue);
543
+ element.setAttribute(attr, this.gettext(curValue));
544
+ }
545
+ },
546
+ /**
547
+ * 获取语言包信息
548
+ */
549
+ getMsg: function () {
550
+ return this.langData;
551
+ },
552
+ /**
553
+ * 是否支持该语言
554
+ * @param {string} lang
555
+ */
556
+ isSupport: function (lang) {
557
+ let support = this.options.support;
558
+
559
+ if (support.indexOf(lang) === -1) {
560
+ return false;
561
+ }
562
+ return lang;
563
+ },
564
+
565
+ /**
566
+ * 设置语言
567
+ * @param {string} lang
568
+ */
569
+ setLang: function (lang) {
570
+ if (lang !== undefined) {
571
+ if (!this.isSupport(lang)) {
572
+ lang = this.options.defaultLang;
573
+ }
574
+ doc.cookie = "bLanguage=" + lang + ";";
575
+ }
576
+ return lang;
577
+ },
578
+
579
+ /**
580
+ * 获取当前设置的语言
581
+ */
582
+ getLang: function () {
583
+ let special = {
584
+ zh: "cn",
585
+ "zh-chs": "cn",
586
+ "zh-cn": "cn",
587
+ "zh-cht": "cn",
588
+ "zh-hk": "zh",
589
+ "zh-mo": "zh",
590
+ "zh-tw": "zh",
591
+ "zh-sg": "zh",
592
+ },
593
+ defLang = this.options.defaultLang,
594
+ local,
595
+ ret,
596
+ start,
597
+ end;
598
+
599
+ if (doc.cookie.indexOf("bLanguage=") === -1) {
600
+ local = (
601
+ win.navigator.language ||
602
+ win.navigator.userLanguage ||
603
+ win.navigator.browserLanguage ||
604
+ win.navigator.systemLanguage ||
605
+ defLang
606
+ ).toLowerCase();
607
+
608
+ ret = special[local] || special[local.split("-")[0].toString()] || local.split("-")[0].toString();
609
+ } else {
610
+ if (doc.cookie.indexOf("bLanguage=") === 0) {
611
+ start = 10;
612
+ } else if (doc.cookie.indexOf("; bLanguage=") !== -1) {
613
+ start = doc.cookie.indexOf("; bLanguage=") + 12;
614
+ }
615
+
616
+ if (start !== undefined) {
617
+ end = doc.cookie.indexOf(";", start) !== -1 ? doc.cookie.indexOf(";", start) : doc.cookie.length;
618
+ ret = doc.cookie.substring(start, end);
619
+ }
620
+ }
621
+ //语言使用优先级 1.浏览器语言是否支持 2 默认语言是否支持 3支持中的语言第一个 4.默认语言
622
+ return this.isSupport(ret) || this.isSupport(defLang) || (this.options.support && this.options.support[0]) || defLang;
623
+ },
624
+
625
+ /**
626
+ * 拼接语言文件的url
627
+ * @param {string} domain 语言文件名称不包含扩展名(如:lang.json -> domain为lang)
628
+ */
629
+ getURL: function (domain) {
630
+ return langPath + this.lang + "/" + domain + "." + this.options.fileType + "?" + b28Cfg.dateStr;
631
+ },
632
+
633
+ /**
634
+ * 加载所需要的语言文件,并翻译页面
635
+ * @param {string} domain 翻译文件的名称不包含扩展名(如:lang.json -> domain为lang)
636
+ * @param {lang} lang 当前语言
637
+ * @param {function} callBack 回调
638
+ */
639
+ setTextDomain: function (domain, lang, callBack) {
640
+ let i,
641
+ domainLen,
642
+ htmlElem = doc.documentElement;
643
+
644
+ this.domainArr = [];
645
+ this.lang = lang || this.getLang();
646
+ this.setLang(lang);
647
+ this.curDomain = 0;
648
+ if (typeof callBack === "function") {
649
+ this.success = callBack;
650
+ }
651
+
652
+ htmlElem.style.visibility = "hidden";
653
+
654
+ handleClass("lang-" + this.lang);
655
+
656
+ if (Object.prototype.toString.call(domain) === "[object Array]") {
657
+ domainLen = domain.length;
658
+ this.domainArr = domain;
659
+
660
+ for (i = 0; i < domainLen; i = i + 1) {
661
+ this.loadDomain(this.getURL(domain[i]), i);
662
+ }
663
+ } else if (typeof domain === "string") {
664
+ this.domainArr.push(domain);
665
+ this.loadDomain(this.getURL(domain), 0);
666
+ }
667
+ },
668
+
669
+ /**
670
+ * 加载语言文件
671
+ * @param {string} url 语言包文件地址
672
+ */
673
+ loadDomain: function (url) {
674
+ //若当前设定语言与默认语言一样,则不加载语言文件
675
+ if (b28Cfg.idDefaultLang && this.lang === b28Cfg.defaultLang) {
676
+ this.b28Loaded = true;
677
+ b28Cfg.initSelect &&
678
+ domReady(() => {
679
+ this.initSelectElem();
680
+ });
681
+ //重置语言对象
682
+ this.langData = {};
683
+ domReady(() => {
684
+ this.translatePage();
685
+ });
686
+ } else {
687
+ //加载对应文件
688
+ loadData.reload(this.options.fileType, url, (data) => {
689
+ this.handLangData(data);
690
+ });
691
+ }
692
+ },
693
+
694
+ /**
695
+ * 处理加载的数据文件
696
+ */
697
+ handLangData: function (data) {
698
+ extend(this.langData, data);
699
+ this.loadedDict();
700
+ },
701
+
702
+ /**
703
+ * 语言文件加载完成后的回调,界面加载完成后进入翻译工作
704
+ */
705
+ loadedDict: function () {
706
+ let len = this.domainArr.length;
707
+ if (this.curDomain + 1 === len) {
708
+ this.b28Loaded = true;
709
+ domReady(() => {
710
+ this.translatePage();
711
+ });
712
+ } else {
713
+ this.curDomain += 1;
714
+ }
715
+ },
716
+
717
+ /**
718
+ * 语言包文件是否加载完成
719
+ */
720
+ isLoaded: function () {
721
+ return this.b28Loaded;
722
+ },
723
+
724
+ /**
725
+ * 翻译纯文本
726
+ * @param {string} key 需要翻译的字段
727
+ */
728
+ gettext: function (key) {
729
+ if (key === undefined) return;
730
+ if (this.options.defaultLang === this.lang) {
731
+ //处理一对多的翻译时对翻译加上了唯一标识的前缀,故需要把这些前缀去掉
732
+ return key.replace(/^[a-zA-Z]\#[a-zA-Z][a-zA-Z][a-zA-Z]\#/g, "");
733
+ }
734
+ return this.langData[key] !== undefined ? this.langData[key] : key.replace(/^[a-zA-Z]\#[a-zA-Z][a-zA-Z][a-zA-Z]\#/g, "");
735
+ },
736
+
737
+ /**
738
+ * 翻译有%s参数的文本
739
+ * @param {string} key 需要翻译的字段
740
+ * @param {Array} replacements 参数
741
+ */
742
+ getFormatText: function (key, replacements) {
743
+ let nkey = this.gettext(key);
744
+
745
+ if (replacements === "" || replacements === undefined) {
746
+ return nkey;
747
+ }
748
+ if (Object.prototype.toString.call(replacements) !== "[object Array]") {
749
+ replacements = [replacements];
750
+ }
751
+
752
+ for (let i = 0, l = replacements.length; i < l; i++) {
753
+ nkey = nkey.replace(/%s/, replacements[i]);
754
+ }
755
+
756
+ return nkey;
757
+ },
758
+
759
+ /**
760
+ * 初始化语言选择框
761
+ */
762
+ initSelectElem: function () {
763
+ let selectElem = doc.getElementById("select-lang"),
764
+ len = b28Cfg.supportLang.length,
765
+ newOption,
766
+ lang,
767
+ i;
768
+
769
+ if (selectElem && selectElem.nodeName.toLowerCase() == "select") {
770
+ for (i = 0; i < len; i++) {
771
+ lang = b28Cfg.supportLang[i];
772
+ newOption = new Option(this.langArr[lang], lang);
773
+ selectElem.add(newOption, undefined);
774
+ }
775
+ selectElem.value = this.lang;
776
+
777
+ if (doc.addEventListener) {
778
+ selectElem.addEventListener(
779
+ "change",
780
+ function () {
781
+ this.setLang(doc.getElementById("select-lang").value);
782
+ setTimeout(function () {
783
+ window.location.reload();
784
+ }, 24);
785
+ },
786
+ false
787
+ );
788
+ } else if (doc.attachEvent) {
789
+ selectElem.attachEvent("onchange", function () {
790
+ this.setLang(doc.getElementById("select-lang").value);
791
+ setTimeout(function () {
792
+ window.location.reload();
793
+ }, 24);
794
+ });
795
+ }
796
+ }
797
+ },
798
+
799
+ /**
800
+ * 翻译translateTarget及translateTarget里面的内容
801
+ * @param {element} translateTarget 需要翻译的内容的容器
802
+ */
803
+ translate: function (translateTarget) {
804
+ let translateElem;
805
+ //确定html容器元素
806
+ if (assertElement(translateTarget)) {
807
+ translateElem = translateTarget;
808
+ } else if (translateTarget && typeof translateTarget === "string") {
809
+ translateElem = doc.getElementById(translateTarget);
810
+ }
811
+ translateElem = translateElem || doc.documentElement;
812
+ // 隐藏页面
813
+ doc.documentElement.style.visibility = "hidden";
814
+ // 逐个翻译元素
815
+ this.replaceTextNodeValue(translateElem);
816
+
817
+ this.saveLang = false;
818
+ // 显示页面
819
+ doc.documentElement.style.visibility = "visible";
820
+ // 执行翻译完成后的回调
821
+ if (typeof this.success === "function") {
822
+ this.success();
823
+ }
824
+ },
825
+
826
+ /**
827
+ * 翻译页面
828
+ */
829
+ translatePage: function () {
830
+ let bodyElem = doc.body || doc.documentElement;
831
+
832
+ // 翻译HTML页面内容
833
+ this.transTitle(this.original.title);
834
+
835
+ // 初始语言选择下拉框
836
+ b28Cfg.initSelect && this.initSelectElem();
837
+ //全局翻译时需要记录所有的信息
838
+ this.saveLang = true;
839
+ this.translate(bodyElem);
840
+ },
841
+ };
842
+
843
+ let Butterlate = new Butterlation(),
844
+ defaultLang;
845
+
846
+ //将翻译对象挂载到window上面
847
+ win.Butterlate = Butterlate;
848
+ win.B = win.B || win.Butterlate;
849
+ win._ = function (key, replacements) {
850
+ return Butterlate.getFormatText(key, replacements);
851
+ };
852
+ win.Butterlate.loadScript = loadScript;
853
+ if (window.beforeTranslate) {
854
+ defaultLang = window.beforeTranslate();
855
+ }
856
+ window.B.setTextDomain("lang", defaultLang);
857
+ })(window, document);