webpack-gc-i18n-plugin 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/customLoader/index.cjs +361 -206
- package/dist/customLoader/index.cjs.map +1 -1
- package/dist/customLoader/index.mjs +361 -206
- package/dist/customLoader/index.mjs.map +1 -1
- package/dist/index.cjs +1259 -1089
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.mjs +1259 -1089
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -382,6 +382,219 @@ const REGEX_MAP = {
|
|
|
382
382
|
[OriginLangKeyEnum.RU]: /[йцукенгшщзхъфывапролджэячсмитьбюё .-]{1,}/ // 俄语字母
|
|
383
383
|
};
|
|
384
384
|
|
|
385
|
+
/*
|
|
386
|
+
* @Date: 2025-03-26 20:28:21
|
|
387
|
+
* @LastEditors: xiaoshan
|
|
388
|
+
* @LastEditTime: 2025-03-31 10:29:49
|
|
389
|
+
* @FilePath: /i18n_translation_vite/packages/autoI18nPluginCore/src/utils/split.ts
|
|
390
|
+
*/
|
|
391
|
+
// 插件核心文件
|
|
392
|
+
// 字符串切割与转换函数
|
|
393
|
+
// import generate from '@babel/generator'
|
|
394
|
+
|
|
395
|
+
// todo 这个切割函数可以优化,性能可能很差
|
|
396
|
+
/**
|
|
397
|
+
* 根据正则表达式分割字符串,并将符合正则的连续字符拼接起来。
|
|
398
|
+
* @param str - 要分割的字符串。
|
|
399
|
+
* @param separatorRegex - 用于分割字符串的正则表达式。
|
|
400
|
+
* @returns 分割并拼接后的字符串数组。
|
|
401
|
+
*/
|
|
402
|
+
/**
|
|
403
|
+
* 这个函数的主要功能是根据给定的正则表达式分割字符串,并对分割结果进行特殊处理。
|
|
404
|
+
* 处理过程分为三个主要步骤:
|
|
405
|
+
*
|
|
406
|
+
* 1. 首先根据分隔符正则和标点符号正则进行初步分割
|
|
407
|
+
* 2. 然后将连续的标点符号和符合分隔符正则的部分重新连接
|
|
408
|
+
* 3. 最后将不符合分隔符正则的相邻部分合并
|
|
409
|
+
*
|
|
410
|
+
* @param str - 需要分割的源字符串
|
|
411
|
+
* @param separatorRegex - 用于分割的正则表达式
|
|
412
|
+
* @returns 处理后的字符串数组
|
|
413
|
+
*/
|
|
414
|
+
function splitByRegex(str, separatorRegex) {
|
|
415
|
+
// 定义标点符号的正则表达式
|
|
416
|
+
const punctuationRegex = /[,。?!《》,..:!?""'';'"、0-9\n\r\t\v\f]/;
|
|
417
|
+
// 创建一个新的正则表达式,用于分割字符串
|
|
418
|
+
const splitRegex = new RegExp(`(${separatorRegex.source}|${punctuationRegex.source})`, separatorRegex.flags);
|
|
419
|
+
|
|
420
|
+
// 使用正则表达式分割字符串,并过滤掉空字符串
|
|
421
|
+
const splitArr = str.split(splitRegex).filter(Boolean);
|
|
422
|
+
const result = [];
|
|
423
|
+
let currentMatch = '';
|
|
424
|
+
|
|
425
|
+
// 定义连接标点符号的正则表达式
|
|
426
|
+
const connectPunctuationRegex = /[,。?!《》,..:!?;'"、0-9]/;
|
|
427
|
+
// 创建一个新的正则表达式,用于检测是否需要连接
|
|
428
|
+
const connectRegex = new RegExp(`(${separatorRegex.source}|${connectPunctuationRegex.source})`, separatorRegex.flags);
|
|
429
|
+
|
|
430
|
+
// 遍历分割后的数组
|
|
431
|
+
for (const item of splitArr) {
|
|
432
|
+
if (connectRegex.test(item)) {
|
|
433
|
+
// 如果当前项符合连接条件,则将其添加到当前匹配字符串中
|
|
434
|
+
currentMatch += item;
|
|
435
|
+
} else {
|
|
436
|
+
// 如果当前匹配字符串不为空,则将其添加到结果数组中
|
|
437
|
+
if (currentMatch) {
|
|
438
|
+
result.push(currentMatch);
|
|
439
|
+
currentMatch = '';
|
|
440
|
+
}
|
|
441
|
+
// 将当前项添加到结果数组中
|
|
442
|
+
result.push(item);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// 如果最后一个匹配字符串不为空,则将其添加到结果数组中
|
|
447
|
+
if (currentMatch) {
|
|
448
|
+
result.push(currentMatch);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// 再遍历一次,把不符合separatorRegex 这个正则的拼起来
|
|
452
|
+
const finalResult = [];
|
|
453
|
+
let tempStr = '';
|
|
454
|
+
for (let i = 0; i < result.length; i++) {
|
|
455
|
+
const item = result[i];
|
|
456
|
+
if (separatorRegex.test(item)) {
|
|
457
|
+
if (tempStr) {
|
|
458
|
+
finalResult.push(tempStr);
|
|
459
|
+
tempStr = '';
|
|
460
|
+
}
|
|
461
|
+
finalResult.push(item);
|
|
462
|
+
} else {
|
|
463
|
+
tempStr += item;
|
|
464
|
+
if (i === result.length - 1 || separatorRegex.test(result[i + 1])) {
|
|
465
|
+
finalResult.push(tempStr);
|
|
466
|
+
tempStr = '';
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (tempStr) {
|
|
471
|
+
finalResult.push(tempStr);
|
|
472
|
+
}
|
|
473
|
+
return finalResult;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* 检查字符串是否需要切割。
|
|
478
|
+
* @param str - 要检查的字符串。
|
|
479
|
+
* @returns 如果字符串需要切割,则返回 true,否则返回 false。
|
|
480
|
+
*/
|
|
481
|
+
function checkNeedSplit(str) {
|
|
482
|
+
// 检查字符串中是否包含需要切割的特殊字符
|
|
483
|
+
return str.includes('\n') || str.includes('\\') || str.includes('\r') || str.includes('\t') || str.includes('\v') || str.includes('\f') || str.includes('>') || str.includes('<');
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* @description: 将字符串数组转换为babel的模板字符串节点
|
|
488
|
+
* @param {string[]} strArray - 字符串数组
|
|
489
|
+
* @return {types.CallExpression} - babel的深度扫描的表达式
|
|
490
|
+
*/
|
|
491
|
+
function convertToTemplateLiteral(strArray, option) {
|
|
492
|
+
const quasis = [];
|
|
493
|
+
const expressions = [];
|
|
494
|
+
strArray.forEach((str, index) => {
|
|
495
|
+
if (index === 0) {
|
|
496
|
+
if (getOriginRegex().test(str)) {
|
|
497
|
+
quasis.push(types__namespace.templateElement({
|
|
498
|
+
raw: '',
|
|
499
|
+
cooked: ''
|
|
500
|
+
}, false));
|
|
501
|
+
expressions.push(createI18nTranslator({
|
|
502
|
+
value: str,
|
|
503
|
+
isExpression: true,
|
|
504
|
+
insertOption: option
|
|
505
|
+
}));
|
|
506
|
+
} else {
|
|
507
|
+
quasis.push(types__namespace.templateElement({
|
|
508
|
+
raw: str,
|
|
509
|
+
cooked: str
|
|
510
|
+
}, false));
|
|
511
|
+
}
|
|
512
|
+
} else {
|
|
513
|
+
if (getOriginRegex().test(str)) {
|
|
514
|
+
expressions.push(createI18nTranslator({
|
|
515
|
+
value: str,
|
|
516
|
+
isExpression: true,
|
|
517
|
+
insertOption: option
|
|
518
|
+
}));
|
|
519
|
+
} else {
|
|
520
|
+
quasis.push(types__namespace.templateElement({
|
|
521
|
+
raw: str,
|
|
522
|
+
cooked: str
|
|
523
|
+
}, false));
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
if (quasis.length === expressions.length) {
|
|
528
|
+
quasis.push(types__namespace.templateElement({
|
|
529
|
+
raw: '',
|
|
530
|
+
cooked: ''
|
|
531
|
+
}, true));
|
|
532
|
+
} else if (quasis.length > expressions.length) {
|
|
533
|
+
quasis[quasis.length - 1].tail = true;
|
|
534
|
+
}
|
|
535
|
+
const templateLiteral = types__namespace.templateLiteral(quasis, expressions);
|
|
536
|
+
const deepScanCall = types__namespace.callExpression(types__namespace.identifier('$deepScan'), [templateLiteral]);
|
|
537
|
+
// 打印转换结果
|
|
538
|
+
// console.log('deepScanCall', (generate as any).default(deepScanCall).code)
|
|
539
|
+
return deepScanCall;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/*
|
|
543
|
+
* @Author: xiaoshanwen
|
|
544
|
+
* @Date: 2023-10-30 18:23:03
|
|
545
|
+
* @LastEditTime: 2025-03-16 19:12:54
|
|
546
|
+
* @FilePath: /i18n_translation_vite/packages/autoI18nPluginCore/src/utils/translate.ts
|
|
547
|
+
*/
|
|
548
|
+
|
|
549
|
+
let langObj = {};
|
|
550
|
+
function getLangKeyByValue(value) {
|
|
551
|
+
return Object.entries(langObj).find(_ref => {
|
|
552
|
+
let [, oldValue] = _ref;
|
|
553
|
+
return oldValue === value;
|
|
554
|
+
})?.[0];
|
|
555
|
+
}
|
|
556
|
+
function resolveLangKey(key, value) {
|
|
557
|
+
return getLangKeyByValue(value) || key;
|
|
558
|
+
}
|
|
559
|
+
function isTemplateValue(value) {
|
|
560
|
+
return /\$\{[^}]+}/.test(value);
|
|
561
|
+
}
|
|
562
|
+
function getTemplateStaticSegments(value) {
|
|
563
|
+
return value.split(/\$\{[^}]+}/g).filter(item => item);
|
|
564
|
+
}
|
|
565
|
+
function isTemplateStaticSegment(value) {
|
|
566
|
+
return Object.values(langObj).some(oldValue => isTemplateValue(oldValue) && getTemplateStaticSegments(oldValue).includes(value));
|
|
567
|
+
}
|
|
568
|
+
function removeTemplateStaticSegments(value) {
|
|
569
|
+
const segments = new Set(getTemplateStaticSegments(value));
|
|
570
|
+
Object.keys(langObj).forEach(key => {
|
|
571
|
+
if (segments.has(langObj[key])) {
|
|
572
|
+
delete langObj[key];
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* @description: 设置翻译对象属性
|
|
579
|
+
* @param {string} key
|
|
580
|
+
* @param {string} value
|
|
581
|
+
* @return {*}
|
|
582
|
+
*/
|
|
583
|
+
function setLangObj(key, value) {
|
|
584
|
+
if (isTemplateValue(value)) {
|
|
585
|
+
removeTemplateStaticSegments(value);
|
|
586
|
+
} else if (isTemplateStaticSegment(value)) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
const existingKey = getLangKeyByValue(value);
|
|
590
|
+
if (existingKey && existingKey !== key) {
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
if (!langObj[key]) {
|
|
594
|
+
langObj[key] = value;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
385
598
|
/*
|
|
386
599
|
* @Author: xiaoshanwen
|
|
387
600
|
* @Date: 2023-10-11 10:01:43
|
|
@@ -503,7 +716,7 @@ function createI18nTranslator(createOption) {
|
|
|
503
716
|
valStr
|
|
504
717
|
} = normalizeTranslateValue(value);
|
|
505
718
|
// 若 key 存在则使用 key,否则调用 generateId 函数根据 valStr 生成唯一的键
|
|
506
|
-
const generatedKey = key || generateId(valStr);
|
|
719
|
+
const generatedKey = key || resolveLangKey(generateId(valStr), trimmedValue);
|
|
507
720
|
// 提取公共配置对象,避免重复代码
|
|
508
721
|
const config = {
|
|
509
722
|
option: option,
|
|
@@ -760,186 +973,6 @@ let option = {
|
|
|
760
973
|
...DEFAULT_OPTION
|
|
761
974
|
};
|
|
762
975
|
|
|
763
|
-
/*
|
|
764
|
-
* @Author: xiaoshanwen
|
|
765
|
-
* @Date: 2023-10-30 18:23:03
|
|
766
|
-
* @LastEditTime: 2025-03-16 19:12:54
|
|
767
|
-
* @FilePath: /i18n_translation_vite/packages/autoI18nPluginCore/src/utils/translate.ts
|
|
768
|
-
*/
|
|
769
|
-
|
|
770
|
-
let langObj = {};
|
|
771
|
-
|
|
772
|
-
/**
|
|
773
|
-
* @description: 设置翻译对象属性
|
|
774
|
-
* @param {string} key
|
|
775
|
-
* @param {string} value
|
|
776
|
-
* @return {*}
|
|
777
|
-
*/
|
|
778
|
-
function setLangObj(key, value) {
|
|
779
|
-
if (!langObj[key]) {
|
|
780
|
-
langObj[key] = value;
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
/*
|
|
785
|
-
* @Date: 2025-03-26 20:28:21
|
|
786
|
-
* @LastEditors: xiaoshan
|
|
787
|
-
* @LastEditTime: 2025-03-31 10:29:49
|
|
788
|
-
* @FilePath: /i18n_translation_vite/packages/autoI18nPluginCore/src/utils/split.ts
|
|
789
|
-
*/
|
|
790
|
-
// 插件核心文件
|
|
791
|
-
// 字符串切割与转换函数
|
|
792
|
-
// import generate from '@babel/generator'
|
|
793
|
-
|
|
794
|
-
// todo 这个切割函数可以优化,性能可能很差
|
|
795
|
-
/**
|
|
796
|
-
* 根据正则表达式分割字符串,并将符合正则的连续字符拼接起来。
|
|
797
|
-
* @param str - 要分割的字符串。
|
|
798
|
-
* @param separatorRegex - 用于分割字符串的正则表达式。
|
|
799
|
-
* @returns 分割并拼接后的字符串数组。
|
|
800
|
-
*/
|
|
801
|
-
/**
|
|
802
|
-
* 这个函数的主要功能是根据给定的正则表达式分割字符串,并对分割结果进行特殊处理。
|
|
803
|
-
* 处理过程分为三个主要步骤:
|
|
804
|
-
*
|
|
805
|
-
* 1. 首先根据分隔符正则和标点符号正则进行初步分割
|
|
806
|
-
* 2. 然后将连续的标点符号和符合分隔符正则的部分重新连接
|
|
807
|
-
* 3. 最后将不符合分隔符正则的相邻部分合并
|
|
808
|
-
*
|
|
809
|
-
* @param str - 需要分割的源字符串
|
|
810
|
-
* @param separatorRegex - 用于分割的正则表达式
|
|
811
|
-
* @returns 处理后的字符串数组
|
|
812
|
-
*/
|
|
813
|
-
function splitByRegex(str, separatorRegex) {
|
|
814
|
-
if (str.includes('\n')) console.log(str, separatorRegex);
|
|
815
|
-
|
|
816
|
-
// 定义标点符号的正则表达式
|
|
817
|
-
const punctuationRegex = /[,。?!《》,..:!?""'';'"、0-9\n\r\t\v\f]/;
|
|
818
|
-
// 创建一个新的正则表达式,用于分割字符串
|
|
819
|
-
const splitRegex = new RegExp(`(${separatorRegex.source}|${punctuationRegex.source})`, separatorRegex.flags);
|
|
820
|
-
|
|
821
|
-
// 使用正则表达式分割字符串,并过滤掉空字符串
|
|
822
|
-
const splitArr = str.split(splitRegex).filter(Boolean);
|
|
823
|
-
const result = [];
|
|
824
|
-
let currentMatch = '';
|
|
825
|
-
|
|
826
|
-
// 定义连接标点符号的正则表达式
|
|
827
|
-
const connectPunctuationRegex = /[,。?!《》,..:!?;'"、0-9]/;
|
|
828
|
-
// 创建一个新的正则表达式,用于检测是否需要连接
|
|
829
|
-
const connectRegex = new RegExp(`(${separatorRegex.source}|${connectPunctuationRegex.source})`, separatorRegex.flags);
|
|
830
|
-
|
|
831
|
-
// 遍历分割后的数组
|
|
832
|
-
for (const item of splitArr) {
|
|
833
|
-
if (connectRegex.test(item)) {
|
|
834
|
-
// 如果当前项符合连接条件,则将其添加到当前匹配字符串中
|
|
835
|
-
currentMatch += item;
|
|
836
|
-
} else {
|
|
837
|
-
// 如果当前匹配字符串不为空,则将其添加到结果数组中
|
|
838
|
-
if (currentMatch) {
|
|
839
|
-
result.push(currentMatch);
|
|
840
|
-
currentMatch = '';
|
|
841
|
-
}
|
|
842
|
-
// 将当前项添加到结果数组中
|
|
843
|
-
result.push(item);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
// 如果最后一个匹配字符串不为空,则将其添加到结果数组中
|
|
848
|
-
if (currentMatch) {
|
|
849
|
-
result.push(currentMatch);
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
// 再遍历一次,把不符合separatorRegex 这个正则的拼起来
|
|
853
|
-
const finalResult = [];
|
|
854
|
-
let tempStr = '';
|
|
855
|
-
for (let i = 0; i < result.length; i++) {
|
|
856
|
-
const item = result[i];
|
|
857
|
-
if (separatorRegex.test(item)) {
|
|
858
|
-
if (tempStr) {
|
|
859
|
-
finalResult.push(tempStr);
|
|
860
|
-
tempStr = '';
|
|
861
|
-
}
|
|
862
|
-
finalResult.push(item);
|
|
863
|
-
} else {
|
|
864
|
-
tempStr += item;
|
|
865
|
-
if (i === result.length - 1 || separatorRegex.test(result[i + 1])) {
|
|
866
|
-
finalResult.push(tempStr);
|
|
867
|
-
tempStr = '';
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
if (tempStr) {
|
|
872
|
-
finalResult.push(tempStr);
|
|
873
|
-
}
|
|
874
|
-
return finalResult;
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
/**
|
|
878
|
-
* 检查字符串是否需要切割。
|
|
879
|
-
* @param str - 要检查的字符串。
|
|
880
|
-
* @returns 如果字符串需要切割,则返回 true,否则返回 false。
|
|
881
|
-
*/
|
|
882
|
-
function checkNeedSplit(str) {
|
|
883
|
-
// 检查字符串中是否包含需要切割的特殊字符
|
|
884
|
-
return str.includes('\n') || str.includes('\\') || str.includes('\r') || str.includes('\t') || str.includes('\v') || str.includes('\f') || str.includes('>') || str.includes('<');
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
/**
|
|
888
|
-
* @description: 将字符串数组转换为babel的模板字符串节点
|
|
889
|
-
* @param {string[]} strArray - 字符串数组
|
|
890
|
-
* @return {types.CallExpression} - babel的深度扫描的表达式
|
|
891
|
-
*/
|
|
892
|
-
function convertToTemplateLiteral(strArray, option) {
|
|
893
|
-
const quasis = [];
|
|
894
|
-
const expressions = [];
|
|
895
|
-
strArray.forEach((str, index) => {
|
|
896
|
-
if (index === 0) {
|
|
897
|
-
if (getOriginRegex().test(str)) {
|
|
898
|
-
quasis.push(types__namespace.templateElement({
|
|
899
|
-
raw: '',
|
|
900
|
-
cooked: ''
|
|
901
|
-
}, false));
|
|
902
|
-
expressions.push(createI18nTranslator({
|
|
903
|
-
value: str,
|
|
904
|
-
isExpression: true,
|
|
905
|
-
insertOption: option
|
|
906
|
-
}));
|
|
907
|
-
} else {
|
|
908
|
-
quasis.push(types__namespace.templateElement({
|
|
909
|
-
raw: str,
|
|
910
|
-
cooked: str
|
|
911
|
-
}, false));
|
|
912
|
-
}
|
|
913
|
-
} else {
|
|
914
|
-
if (getOriginRegex().test(str)) {
|
|
915
|
-
expressions.push(createI18nTranslator({
|
|
916
|
-
value: str,
|
|
917
|
-
isExpression: true,
|
|
918
|
-
insertOption: option
|
|
919
|
-
}));
|
|
920
|
-
} else {
|
|
921
|
-
quasis.push(types__namespace.templateElement({
|
|
922
|
-
raw: str,
|
|
923
|
-
cooked: str
|
|
924
|
-
}, false));
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
});
|
|
928
|
-
if (quasis.length === expressions.length) {
|
|
929
|
-
quasis.push(types__namespace.templateElement({
|
|
930
|
-
raw: '',
|
|
931
|
-
cooked: ''
|
|
932
|
-
}, true));
|
|
933
|
-
} else if (quasis.length > expressions.length) {
|
|
934
|
-
quasis[quasis.length - 1].tail = true;
|
|
935
|
-
}
|
|
936
|
-
const templateLiteral = types__namespace.templateLiteral(quasis, expressions);
|
|
937
|
-
const deepScanCall = types__namespace.callExpression(types__namespace.identifier('$deepScan'), [templateLiteral]);
|
|
938
|
-
// 打印转换结果
|
|
939
|
-
// console.log('deepScanCall', (generate as any).default(deepScanCall).code)
|
|
940
|
-
return deepScanCall;
|
|
941
|
-
}
|
|
942
|
-
|
|
943
976
|
/*
|
|
944
977
|
* @Author: xiaoshanwen
|
|
945
978
|
* @Date: 2023-11-01 16:35:38
|
|
@@ -976,8 +1009,17 @@ function TemplateLiteral (insertOption) {
|
|
|
976
1009
|
};
|
|
977
1010
|
}
|
|
978
1011
|
function handleTemplateLiteralWithExpressions(node, path) {
|
|
979
|
-
|
|
980
|
-
|
|
1012
|
+
let hasOptimizedExpression = false;
|
|
1013
|
+
const expressionLabels = node.expressions.map((expression, index) => {
|
|
1014
|
+
const optimizedExpression = optimizeConditionalExpression(expression);
|
|
1015
|
+
if (optimizedExpression) {
|
|
1016
|
+
hasOptimizedExpression = true;
|
|
1017
|
+
node.expressions[index] = optimizedExpression.expression;
|
|
1018
|
+
return optimizedExpression.label;
|
|
1019
|
+
}
|
|
1020
|
+
return getExpressionPlaceholder(expression);
|
|
1021
|
+
});
|
|
1022
|
+
if (expressionLabels.some(placeholder => placeholder === null)) {
|
|
981
1023
|
return false;
|
|
982
1024
|
}
|
|
983
1025
|
const fullValue = node.quasis.reduce((result, quasi, index) => {
|
|
@@ -989,32 +1031,26 @@ function handleTemplateLiteralWithExpressions(node, path) {
|
|
|
989
1031
|
console.log('转换异常');
|
|
990
1032
|
}
|
|
991
1033
|
}
|
|
992
|
-
return result + value + (index < node.expressions.length ?
|
|
1034
|
+
return result + value + (index < node.expressions.length ? formatExpressionPlaceholder(expressionLabels[index]) : '');
|
|
993
1035
|
}, '');
|
|
994
1036
|
if (!fullValue || !hasOriginSymbols(fullValue) || !option.excludedPattern.length || checkAgainstRegexArray(fullValue, [...option.excludedPattern])) {
|
|
1037
|
+
if (hasOptimizedExpression) {
|
|
1038
|
+
path.skip();
|
|
1039
|
+
return true;
|
|
1040
|
+
}
|
|
995
1041
|
return false;
|
|
996
1042
|
}
|
|
997
1043
|
const {
|
|
998
1044
|
trimmedValue,
|
|
999
1045
|
valStr
|
|
1000
1046
|
} = normalizeTranslateValue(fullValue);
|
|
1001
|
-
const id = generateId(valStr);
|
|
1002
|
-
const translateNode = createTranslateNode(path, id, valStr,
|
|
1047
|
+
const id = resolveLangKey(generateId(valStr), trimmedValue);
|
|
1048
|
+
const translateNode = createTranslateNode(path, id, valStr, expressionLabels, node.expressions);
|
|
1003
1049
|
path.replaceWith(translateNode);
|
|
1004
|
-
path.skip();
|
|
1005
1050
|
setLangObj(id, trimmedValue);
|
|
1006
1051
|
return true;
|
|
1007
1052
|
}
|
|
1008
1053
|
function getExpressionPlaceholder(expression) {
|
|
1009
|
-
if (types.isIdentifier(expression)) {
|
|
1010
|
-
return expression.name;
|
|
1011
|
-
}
|
|
1012
|
-
if (types.isMemberExpression(expression)) {
|
|
1013
|
-
const objectName = getExpressionPlaceholder(expression.object);
|
|
1014
|
-
const propertyName = expression.computed ? getExpressionPlaceholder(expression.property) : types.isIdentifier(expression.property) ? expression.property.name : '';
|
|
1015
|
-
const value = [objectName, propertyName].filter(Boolean).join('.');
|
|
1016
|
-
return cleanVueRuntimePrefix(value);
|
|
1017
|
-
}
|
|
1018
1054
|
if (types.isStringLiteral(expression) || types.isNumericLiteral(expression)) {
|
|
1019
1055
|
return String(expression.value);
|
|
1020
1056
|
}
|
|
@@ -1025,21 +1061,142 @@ function getExpressionPlaceholder(expression) {
|
|
|
1025
1061
|
return getExpressionPlaceholder(expression.expression);
|
|
1026
1062
|
}
|
|
1027
1063
|
const generateCode = generate__namespace.default?.default || generate__namespace.default || generate__namespace;
|
|
1028
|
-
return
|
|
1064
|
+
return generateCode(expression, {
|
|
1065
|
+
comments: false
|
|
1066
|
+
}).code;
|
|
1067
|
+
}
|
|
1068
|
+
function optimizeConditionalExpression(expression) {
|
|
1069
|
+
if (!types.isConditionalExpression(expression)) return null;
|
|
1070
|
+
const consequent = translateConditionalStringBranch(expression.consequent);
|
|
1071
|
+
const alternate = translateConditionalStringBranch(expression.alternate);
|
|
1072
|
+
if (!consequent.changed && !alternate.changed) return null;
|
|
1073
|
+
return {
|
|
1074
|
+
label: getConditionalExpressionLabel(expression),
|
|
1075
|
+
expression: types.conditionalExpression(types.cloneNode(expression.test), consequent.expression, alternate.expression)
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
function translateConditionalStringBranch(expression) {
|
|
1079
|
+
if (types.isStringLiteral(expression) && hasOriginSymbols(expression.value)) {
|
|
1080
|
+
return {
|
|
1081
|
+
changed: true,
|
|
1082
|
+
expression: createTrackedTranslateCall(expression.value)
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
if (types.isTemplateLiteral(expression)) {
|
|
1086
|
+
const translateCall = createTemplateLiteralTranslateCall(expression);
|
|
1087
|
+
if (translateCall) {
|
|
1088
|
+
return {
|
|
1089
|
+
changed: true,
|
|
1090
|
+
expression: translateCall
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
if (types.isConditionalExpression(expression)) {
|
|
1095
|
+
const optimizedExpression = optimizeConditionalExpression(expression);
|
|
1096
|
+
if (optimizedExpression) {
|
|
1097
|
+
return {
|
|
1098
|
+
changed: true,
|
|
1099
|
+
expression: optimizedExpression.expression
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
return {
|
|
1104
|
+
changed: false,
|
|
1105
|
+
expression: types.cloneNode(expression)
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
function createTrackedTranslateCall(value) {
|
|
1109
|
+
const translateCall = createI18nTranslator({
|
|
1110
|
+
value,
|
|
1111
|
+
isExpression: true
|
|
1112
|
+
});
|
|
1113
|
+
const {
|
|
1114
|
+
trimmedValue,
|
|
1115
|
+
valStr
|
|
1116
|
+
} = normalizeTranslateValue(value);
|
|
1117
|
+
const id = resolveLangKey(generateId(valStr), trimmedValue);
|
|
1118
|
+
if (id && trimmedValue) {
|
|
1119
|
+
setLangObj(id, trimmedValue);
|
|
1120
|
+
}
|
|
1121
|
+
return translateCall;
|
|
1122
|
+
}
|
|
1123
|
+
function createTemplateLiteralTranslateCall(node) {
|
|
1124
|
+
const expressions = node.expressions.map(expression => {
|
|
1125
|
+
const optimizedExpression = optimizeConditionalExpression(expression);
|
|
1126
|
+
return optimizedExpression ? optimizedExpression.expression : expression;
|
|
1127
|
+
});
|
|
1128
|
+
const expressionLabels = expressions.map(expression => getExpressionPlaceholder(expression));
|
|
1129
|
+
if (expressionLabels.some(placeholder => placeholder === null)) {
|
|
1130
|
+
return null;
|
|
1131
|
+
}
|
|
1132
|
+
const fullValue = node.quasis.reduce((result, quasi, index) => {
|
|
1133
|
+
let value = quasi.value.raw || quasi.value.cooked || '';
|
|
1134
|
+
if (asianLangs.some(lang => option.originLang.includes(lang) || option.originLang === lang)) {
|
|
1135
|
+
try {
|
|
1136
|
+
value = unicodeToString(value);
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
console.log('转换异常');
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
return result + value + (index < expressions.length ? formatExpressionPlaceholder(expressionLabels[index]) : '');
|
|
1142
|
+
}, '');
|
|
1143
|
+
if (!fullValue || !hasOriginSymbols(fullValue) || !option.excludedPattern.length || checkAgainstRegexArray(fullValue, [...option.excludedPattern])) {
|
|
1144
|
+
return null;
|
|
1145
|
+
}
|
|
1146
|
+
const {
|
|
1147
|
+
trimmedValue,
|
|
1148
|
+
valStr
|
|
1149
|
+
} = normalizeTranslateValue(fullValue);
|
|
1150
|
+
const id = resolveLangKey(generateId(valStr), trimmedValue);
|
|
1151
|
+
if (id && trimmedValue) {
|
|
1152
|
+
setLangObj(id, trimmedValue);
|
|
1153
|
+
}
|
|
1154
|
+
return createTranslateCall(id, valStr, expressionLabels, expressions);
|
|
1155
|
+
}
|
|
1156
|
+
function getConditionalExpressionLabel(expression) {
|
|
1157
|
+
const test = expression.test;
|
|
1158
|
+
if (types.isBinaryExpression(test) || types.isLogicalExpression(test)) {
|
|
1159
|
+
return getExpressionPlaceholder(test.left);
|
|
1160
|
+
}
|
|
1161
|
+
return getExpressionPlaceholder(test);
|
|
1162
|
+
}
|
|
1163
|
+
function formatExpressionPlaceholder(placeholder) {
|
|
1164
|
+
if (placeholder === null) return '';
|
|
1165
|
+
return placeholder.trim() ? `\${${placeholder}}` : placeholder;
|
|
1029
1166
|
}
|
|
1030
1167
|
function createTranslateNode(path, id, valStr) {
|
|
1031
1168
|
let placeholders = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
|
|
1032
1169
|
let expressions = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [];
|
|
1033
|
-
const
|
|
1034
|
-
if (placeholders.length) {
|
|
1035
|
-
args.push(types.objectExpression(placeholders.map((placeholder, index) => types.objectProperty(types.stringLiteral(placeholder), types.cloneNode(expressions[index])))));
|
|
1036
|
-
}
|
|
1037
|
-
const translateCall = types.callExpression(types.identifier(option.translateKey), args);
|
|
1170
|
+
const translateCall = createTranslateCall(id, valStr, placeholders, expressions);
|
|
1038
1171
|
if (!isVueTemplateRender(path)) {
|
|
1039
1172
|
return translateCall;
|
|
1040
1173
|
}
|
|
1041
1174
|
return types.sequenceExpression([createVueTemplateLanguageDependency(), translateCall]);
|
|
1042
1175
|
}
|
|
1176
|
+
function createTranslateCall(id, valStr) {
|
|
1177
|
+
let placeholders = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
|
|
1178
|
+
let expressions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
|
|
1179
|
+
const args = [types.stringLiteral(id), types.stringLiteral(valStr)];
|
|
1180
|
+
if (placeholders.length) {
|
|
1181
|
+
const placeholderEntries = placeholders.map((placeholder, index) => ({
|
|
1182
|
+
placeholder,
|
|
1183
|
+
expression: expressions[index]
|
|
1184
|
+
})).filter(_ref => {
|
|
1185
|
+
let {
|
|
1186
|
+
placeholder
|
|
1187
|
+
} = _ref;
|
|
1188
|
+
return placeholder && placeholder.trim();
|
|
1189
|
+
});
|
|
1190
|
+
args.push(types.objectExpression(placeholderEntries.map(_ref2 => {
|
|
1191
|
+
let {
|
|
1192
|
+
placeholder,
|
|
1193
|
+
expression
|
|
1194
|
+
} = _ref2;
|
|
1195
|
+
return types.objectProperty(types.stringLiteral(placeholder), types.cloneNode(expression));
|
|
1196
|
+
})));
|
|
1197
|
+
}
|
|
1198
|
+
return types.callExpression(types.identifier(option.translateKey), args);
|
|
1199
|
+
}
|
|
1043
1200
|
function isVueTemplateRender(path) {
|
|
1044
1201
|
return Boolean(path.scope?.getBinding('_vm'));
|
|
1045
1202
|
}
|
|
@@ -1053,9 +1210,6 @@ function createVueTemplateLanguageDependency() {
|
|
|
1053
1210
|
const i18nLocale = types.logicalExpression('&&', types.cloneNode(i18n), types.memberExpression(types.cloneNode(i18n), types.identifier('locale')));
|
|
1054
1211
|
return types.logicalExpression('||', storeLanguage, i18nLocale);
|
|
1055
1212
|
}
|
|
1056
|
-
function cleanVueRuntimePrefix(value) {
|
|
1057
|
-
return value.replace(/^(?:\$setup|_ctx|_vm|this)\./, '').replace(/([^\w$.])(?:\$setup|_ctx|_vm|this)\./g, '$1');
|
|
1058
|
-
}
|
|
1059
1213
|
|
|
1060
1214
|
// 处理模板元素
|
|
1061
1215
|
function handleTemplateElement(node, insertOption) {
|
|
@@ -1078,9 +1232,10 @@ function handleTemplateElement(node, insertOption) {
|
|
|
1078
1232
|
// 替换为字符类型翻译节点
|
|
1079
1233
|
node.value.raw = node.value.cooked = `\${${newNode}}`;
|
|
1080
1234
|
const {
|
|
1235
|
+
trimmedValue,
|
|
1081
1236
|
valStr
|
|
1082
1237
|
} = normalizeTranslateValue(value);
|
|
1083
|
-
let id = generateId(valStr);
|
|
1238
|
+
let id = resolveLangKey(generateId(valStr), trimmedValue);
|
|
1084
1239
|
if (id && value) {
|
|
1085
1240
|
setLangObj(id, value);
|
|
1086
1241
|
}
|