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