vite-gc-i18n-plugin 1.1.7 → 1.1.9

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/index.cjs CHANGED
@@ -924,7 +924,7 @@ function createTextSplitter(values, maxChunkSize) {
924
924
  */
925
925
  function splitByRegex(str, separatorRegex) {
926
926
  // 定义标点符号的正则表达式
927
- const punctuationRegex = /[,。?!《》,..:!?""'';'"、0-9\n\r\t\v\f]/;
927
+ const punctuationRegex = /[,。?!《》()(),..:!?""'';'"、0-9\n\r\t\v\f]/;
928
928
  // 创建一个新的正则表达式,用于分割字符串
929
929
  const splitRegex = new RegExp(`(${separatorRegex.source}|${punctuationRegex.source})`, separatorRegex.flags);
930
930
 
@@ -934,7 +934,7 @@ function splitByRegex(str, separatorRegex) {
934
934
  let currentMatch = '';
935
935
 
936
936
  // 定义连接标点符号的正则表达式
937
- const connectPunctuationRegex = /[,。?!《》,..:!?;'"、0-9]/;
937
+ const connectPunctuationRegex = /[,。?!《》()(),..:!?;'"、0-9]/;
938
938
  // 创建一个新的正则表达式,用于检测是否需要连接
939
939
  const connectRegex = new RegExp(`(${separatorRegex.source}|${connectPunctuationRegex.source})`, separatorRegex.flags);
940
940
 
@@ -981,7 +981,85 @@ function splitByRegex(str, separatorRegex) {
981
981
  if (tempStr) {
982
982
  finalResult.push(tempStr);
983
983
  }
984
- return finalResult;
984
+ return mergeInlineTextSeparatedOriginChunks(finalResult, separatorRegex);
985
+ }
986
+ function mergeInlineTextSeparatedOriginChunks(strArray, separatorRegex) {
987
+ const result = [];
988
+ for (let i = 0; i < strArray.length; i++) {
989
+ let current = strArray[i];
990
+ if (!separatorRegex.test(current) && i + 1 < strArray.length && separatorRegex.test(strArray[i + 1])) {
991
+ const {
992
+ beforeInlineText,
993
+ inlineText
994
+ } = splitTrailingInlineText(current);
995
+ if (inlineText && /[^\s\u00a0]/.test(inlineText)) {
996
+ if (beforeInlineText) {
997
+ result.push(beforeInlineText);
998
+ }
999
+ current = `${normalizeInlineTextPrefix(inlineText)}${strArray[i + 1]}`;
1000
+ i += 1;
1001
+ }
1002
+ }
1003
+ if (!separatorRegex.test(current) && isInlineTextSeparator(current) && /[^\s\u00a0]/.test(current) && i + 1 < strArray.length && separatorRegex.test(strArray[i + 1])) {
1004
+ current = `${normalizeInlineTextPrefix(current)}${strArray[i + 1]}`;
1005
+ i += 1;
1006
+ }
1007
+ if (separatorRegex.test(current)) {
1008
+ while (i + 2 < strArray.length && isInlineTextSeparator(strArray[i + 1]) && separatorRegex.test(strArray[i + 2])) {
1009
+ current += `${normalizeInlineTextSeparator(strArray[i + 1])}${strArray[i + 2]}`;
1010
+ i += 2;
1011
+ }
1012
+ if (i + 1 < strArray.length) {
1013
+ const {
1014
+ inlineText,
1015
+ rest
1016
+ } = splitLeadingInlineText(strArray[i + 1]);
1017
+ if (inlineText) {
1018
+ current += normalizeInlineTextSeparator(inlineText);
1019
+ strArray[i + 1] = rest;
1020
+ }
1021
+ }
1022
+ }
1023
+ if (current) {
1024
+ result.push(current);
1025
+ }
1026
+ }
1027
+ return result;
1028
+ }
1029
+ function isInlineTextSeparator(value) {
1030
+ return value !== '' && !/[<>]/.test(value);
1031
+ }
1032
+ function normalizeInlineTextSeparator(value) {
1033
+ return /^[\s\u00a0]+$/.test(value) ? ' ' : value.replace(/[\s\u00a0]+/g, ' ');
1034
+ }
1035
+ function normalizeInlineTextPrefix(value) {
1036
+ return value.replace(/[\s\u00a0]+/g, ' ').trimStart();
1037
+ }
1038
+ function splitLeadingInlineText(value) {
1039
+ const tagIndex = value.search(/[<>]/);
1040
+ if (tagIndex === -1) {
1041
+ return {
1042
+ inlineText: value,
1043
+ rest: ''
1044
+ };
1045
+ }
1046
+ return {
1047
+ inlineText: value.slice(0, tagIndex),
1048
+ rest: value.slice(tagIndex)
1049
+ };
1050
+ }
1051
+ function splitTrailingInlineText(value) {
1052
+ const tagEndIndex = value.lastIndexOf('>');
1053
+ if (tagEndIndex === -1) {
1054
+ return {
1055
+ beforeInlineText: '',
1056
+ inlineText: value
1057
+ };
1058
+ }
1059
+ return {
1060
+ beforeInlineText: value.slice(0, tagEndIndex + 1),
1061
+ inlineText: value.slice(tagEndIndex + 1)
1062
+ };
985
1063
  }
986
1064
 
987
1065
  /**
@@ -991,7 +1069,7 @@ function splitByRegex(str, separatorRegex) {
991
1069
  */
992
1070
  function checkNeedSplit(str) {
993
1071
  // 检查字符串中是否包含需要切割的特殊字符
994
- return str.includes('\n') || str.includes('\\') || str.includes('\r') || str.includes('\t') || str.includes('\v') || str.includes('\f') || str.includes('>') || str.includes('<');
1072
+ return str.includes('\\') || str.includes('>') || str.includes('<');
995
1073
  }
996
1074
 
997
1075
  /**
@@ -1105,71 +1183,131 @@ function initLangFile() {
1105
1183
  initTranslateBasicFnFile();
1106
1184
  }
1107
1185
  /**
1108
- * @description: 初始化翻译基础函数文件
1109
- * @returns {void}
1186
+ * Normalize a language key for runtime storage aliases.
1187
+ * Examples: zh-cn -> zhcn, en -> en.
1110
1188
  */
1111
- async function initTranslateBasicFnFile() {
1112
- // 从配置选项中获取必要的配置信息
1113
- const {
1114
- targetLangList
1115
- } = exports.option;
1116
- // 生成语言映射列表
1117
- let languages = [];
1118
- let langList = targetLangList.map(item => {
1119
- const parts = item.split('-');
1120
- const lang = parts[0] + '-' + parts[1].toUpperCase();
1121
- return _.find(allLanguage, {
1122
- code: lang
1123
- });
1124
- });
1125
- langList
1126
- // 构建语言映射项
1127
- .map(item => {
1128
- languages.push(`{
1129
- code: "${item.code}",
1130
- name: "${item.name}"
1131
- }`);
1189
+ function normalizeRuntimeLangKey(langKey) {
1190
+ return String(langKey || '').toLowerCase().replace(/[^a-z0-9]/g, '');
1191
+ }
1192
+ function resolveLanguageMeta(langKey) {
1193
+ const [lang, region] = langKey.split('-');
1194
+ const normalizedCode = region ? `${lang}-${region.toUpperCase()}` : langKey;
1195
+ const matched = _.find(allLanguage, {
1196
+ code: normalizedCode
1132
1197
  });
1133
- // 用逗号和换行符连接所有映射项
1134
- const translateBasicFnText = `
1135
- import gc_i18n from 'gc_i18n'
1136
- export const languages = [${languages.toString()}]
1137
- const gcI18nInstance = new gc_i18n({
1138
- appCode: 'TEST',
1139
- env: 'dev', // local 本地部署 dev 多语言测试环境 prod 多语言生产环境
1140
- orgCode: 'GREENCLOUD',
1141
- messages: {} // 如果你需要自己引入语言包
1142
- })
1143
- export default {
1144
- install(app, router) {
1145
- gcI18nInstance.setRouter(router)
1198
+ return {
1199
+ code: matched?.code || normalizedCode,
1200
+ name: matched?.name || langKey
1201
+ };
1202
+ }
1203
+ function getRuntimeLangKeys() {
1204
+ return Array.from(new Set([exports.option.originLang, ...exports.option.targetLangList].filter(Boolean)));
1205
+ }
1206
+
1207
+ /**
1208
+ * Create the self-contained browser runtime written to lang/index.js.
1209
+ *
1210
+ * The runtime intentionally avoids importing an external gc_i18n package so generated
1211
+ * examples/apps can translate transformed calls immediately after importing ./lang.
1212
+ */
1213
+ function createRuntimeIndexCode() {
1214
+ const namespace = exports.option.namespace || 'lang';
1215
+ const commonTranslateKey = exports.option.commonTranslateKey || '';
1216
+ const originRuntimeKey = normalizeRuntimeLangKey(exports.option.originLang);
1217
+ const languages = exports.option.targetLangList.map(resolveLanguageMeta);
1218
+ const langEntries = getRuntimeLangKeys().map(langKey => {
1219
+ const runtimeKey = normalizeRuntimeLangKey(langKey);
1220
+ return ` '${runtimeKey}': getJSONKey('${langKey}', langJSON)`;
1221
+ }).join(',\n');
1222
+ return `import langJSON from './index.json'
1223
+
1224
+ export const languages = ${JSON.stringify(languages, null, 4)}
1225
+
1226
+ const DEFAULT_NAMESPACE = '${namespace}'
1227
+ const COMMON_TRANSLATE_KEY = '${commonTranslateKey}'
1228
+ const ORIGIN_LANG = '${originRuntimeKey}'
1229
+ const root = typeof globalThis !== 'undefined' ? globalThis : window
1230
+
1231
+ function normalizeLangKey(lang) {
1232
+ return String(lang || '').toLowerCase().replace(/[^a-z0-9]/g, '')
1233
+ }
1234
+
1235
+ function getJSONKey(key, insertJSONObj = langJSON) {
1236
+ const langObj = {}
1237
+ Object.keys(insertJSONObj || {}).forEach(value => {
1238
+ langObj[value] = insertJSONObj[value] && insertJSONObj[value][key]
1239
+ })
1240
+ return langObj
1241
+ }
1242
+
1243
+ function createTranslate(defaultNamespace) {
1244
+ const translate = function (key, val, nameSpace = defaultNamespace) {
1245
+ const langPackage = translate[nameSpace] || {}
1246
+ return langPackage[key] || val
1146
1247
  }
1147
- }`;
1148
- // 构建翻译基础函数文件的路径
1149
- const indexPath = path.join(exports.option.globalPath, 'index.js');
1248
+ translate.locale = function (locale, nameSpace = defaultNamespace) {
1249
+ translate[nameSpace] = locale || {}
1250
+ }
1251
+ return translate
1252
+ }
1150
1253
 
1151
- // 文件已存在 同时 不重写配置,那么这里就结束
1152
- if (fs.existsSync(indexPath) && !exports.option.rewriteConfig) return;
1254
+ root.$t = root.$t || createTranslate(DEFAULT_NAMESPACE)
1255
+ root.$$t = root.$$t || function (val) {
1256
+ return val
1257
+ }
1258
+ root.$deepScan = root.$deepScan || function (val) {
1259
+ return val
1260
+ }
1261
+ root._getJSONKey = root._getJSONKey || getJSONKey
1153
1262
 
1154
- // 新增哈希比对逻辑
1263
+ const runtimeLangMap = {
1264
+ ${langEntries}
1265
+ }
1266
+ const existingLangMap = root.langMap || {}
1267
+ const langMap = { ...runtimeLangMap, ...existingLangMap }
1268
+ root.langMap = langMap
1155
1269
 
1156
- // 标记是否需要更新文件
1157
- let needUpdate = true;
1158
- if (fs.existsSync(indexPath)) {
1159
- // 检查文件是否已存在
1160
- // 读取现有文件内容
1161
- const existingContent = fs.readFileSync(indexPath, 'utf-8');
1162
- // 生成现有内容的哈希值
1163
- const existingHash = generateId(existingContent);
1164
- // 判断是否需要更新文件
1165
- // needUpdate = currentHash !== existingHash
1166
- needUpdate = !existingHash;
1167
- }
1270
+ function readStorageLang(key) {
1271
+ if (!key || !root.localStorage || typeof root.localStorage.getItem !== 'function') {
1272
+ return ''
1273
+ }
1274
+ return root.localStorage.getItem(key) || ''
1275
+ }
1168
1276
 
1169
- // 如果需要更新文件,则写入新内容
1170
- if (needUpdate) {
1171
- fs.writeFileSync(indexPath, translateBasicFnText);
1172
- }
1277
+ function applyLanguage(lang, nameSpace = DEFAULT_NAMESPACE) {
1278
+ const runtimeKey = normalizeLangKey(lang) || ORIGIN_LANG
1279
+ const locale = langMap[runtimeKey] || langMap[ORIGIN_LANG] || {}
1280
+ root.$t.locale(locale, nameSpace)
1281
+ return locale
1282
+ }
1283
+
1284
+ const storedCommonLang = readStorageLang(COMMON_TRANSLATE_KEY)
1285
+ const storedLang = readStorageLang('lang')
1286
+ applyLanguage(storedCommonLang || storedLang || ORIGIN_LANG)
1287
+
1288
+ root.$changeLang = function (lang, nameSpace = DEFAULT_NAMESPACE) {
1289
+ return applyLanguage(lang, nameSpace)
1290
+ }
1291
+
1292
+ export default {
1293
+ install() {
1294
+ applyLanguage(readStorageLang(COMMON_TRANSLATE_KEY) || readStorageLang('lang') || ORIGIN_LANG)
1295
+ }
1296
+ }
1297
+ `;
1298
+ }
1299
+
1300
+ /**
1301
+ * @description: 初始化翻译基础函数文件
1302
+ * @returns {void}
1303
+ */
1304
+ async function initTranslateBasicFnFile() {
1305
+ const indexPath = path.join(exports.option.globalPath, 'index.js');
1306
+
1307
+ // 项目已有 lang/index.js 时保留项目自定义运行时,不再由插件覆盖。
1308
+ if (fs.existsSync(indexPath)) return;
1309
+ const translateBasicFnText = createRuntimeIndexCode();
1310
+ fs.writeFileSync(indexPath, translateBasicFnText);
1173
1311
  }
1174
1312
  /**
1175
1313
  * @description: 生成国际化JSON文件
@@ -1294,11 +1432,13 @@ function uploadFile() {
1294
1432
 
1295
1433
  var file = /*#__PURE__*/Object.freeze({
1296
1434
  __proto__: null,
1435
+ createRuntimeIndexCode: createRuntimeIndexCode,
1297
1436
  getLangObjByJSONFileWithLangKey: getLangObjByJSONFileWithLangKey,
1298
1437
  getLangTranslateJSONFile: getLangTranslateJSONFile,
1299
1438
  initLangFile: initLangFile,
1300
1439
  initLangTranslateJSONFile: initLangTranslateJSONFile,
1301
1440
  initTranslateBasicFnFile: initTranslateBasicFnFile,
1441
+ normalizeRuntimeLangKey: normalizeRuntimeLangKey,
1302
1442
  setLangTranslateJSONFile: setLangTranslateJSONFile,
1303
1443
  uploadFile: uploadFile
1304
1444
  });
@@ -1839,6 +1979,13 @@ function createI18nTranslator(createOption) {
1839
1979
  uncodeValue: valStr,
1840
1980
  namespace: nameSpace
1841
1981
  };
1982
+ insertOption?.collector?.record?.({
1983
+ key: exports.option.useValueAsKey ? trimmedValue : generatedKey,
1984
+ value: trimmedValue,
1985
+ namespace: nameSpace,
1986
+ resourcePath: insertOption?.resourcePath,
1987
+ root: insertOption?.root
1988
+ });
1842
1989
  if (exports.option.translateExtends) {
1843
1990
  const {
1844
1991
  handleCodeCall,
@@ -2470,9 +2617,13 @@ function getExpressionPlaceholder(expression) {
2470
2617
  return getExpressionPlaceholder(expression.expression);
2471
2618
  }
2472
2619
  const generateCode = generate__namespace.default?.default || generate__namespace.default || generate__namespace;
2473
- return generateCode(expression, {
2620
+ return normalizeExpressionPlaceholder(generateCode(expression, {
2474
2621
  comments: false
2475
- }).code;
2622
+ }).code);
2623
+ }
2624
+ function normalizeExpressionPlaceholder(placeholder) {
2625
+ if (placeholder === null) return null;
2626
+ return placeholder.replace(/(^|[^\w$])(?:_vm|\$data)\s*\./g, '$1').replace(/(^|[^\w$])(?:_vm|\$data)\s*\[/g, '$1[');
2476
2627
  }
2477
2628
  function optimizeConditionalExpression(expression) {
2478
2629
  if (!types.isConditionalExpression(expression)) return null;
@@ -2718,11 +2869,11 @@ function CallExpressionFn (insertOption) {
2718
2869
  isExpression: true
2719
2870
  });
2720
2871
  path.replaceWith(replaceNode);
2721
- translateSetLang(replaceNode);
2872
+ translateSetLang(replaceNode, insertOption);
2722
2873
  }
2723
2874
  } else if (exports.option.translateType === TranslateTypeEnum.FULL_AUTO) {
2724
2875
  // 全自动模式下还是只收集 单独 $t 调用
2725
- if (callee.name === exports.option.translateKey || callee.property && callee.property.name === exports.option.translateKey) translateSetLang(node);
2876
+ if (callee.name === exports.option.translateKey || callee.property && callee.property.name === exports.option.translateKey) translateSetLang(node, insertOption);
2726
2877
  }
2727
2878
  }
2728
2879
  };
@@ -2733,7 +2884,7 @@ function CallExpressionFn (insertOption) {
2733
2884
  * @param node - 调用表达式节点
2734
2885
  * @return
2735
2886
  */
2736
- function translateSetLang(node) {
2887
+ function translateSetLang(node, insertOption) {
2737
2888
  // 获取调用表达式的参数
2738
2889
  let arg = node.arguments || [];
2739
2890
  // 提取参数作为值
@@ -2754,6 +2905,13 @@ function translateSetLang(node) {
2754
2905
  }
2755
2906
  // 调用翻译工具的 setLangObj 方法设置语言对象属性
2756
2907
  setLangObj(resolvedId, value);
2908
+ insertOption?.collector?.record?.({
2909
+ key: exports.option.useValueAsKey ? value : resolvedId,
2910
+ value,
2911
+ namespace: exports.option.namespace,
2912
+ resourcePath: insertOption?.resourcePath,
2913
+ root: insertOption?.root
2914
+ });
2757
2915
  }
2758
2916
  }
2759
2917
 
@@ -2895,10 +3053,310 @@ var index$1 = /*#__PURE__*/Object.freeze({
2895
3053
  default: index
2896
3054
  });
2897
3055
 
3056
+ const RUNTIME_MANIFEST_VERSION = 1;
3057
+ const RUNTIME_MANIFEST_GLOBAL = '__GC_I18N_RUNTIME_MANIFEST__';
3058
+ const VITE_RUNTIME_MANIFEST_ID = 'virtual:gc-i18n-runtime-manifest';
3059
+ const VITE_RUNTIME_BOOTSTRAP_ID = 'virtual:gc-i18n-runtime-bootstrap';
3060
+ const RESOLVED_VITE_RUNTIME_MANIFEST_ID = `\0${VITE_RUNTIME_MANIFEST_ID}`;
3061
+ const RESOLVED_VITE_RUNTIME_BOOTSTRAP_ID = `\0${VITE_RUNTIME_BOOTSTRAP_ID}`;
3062
+ function normalizeResourcePath(resourcePath, root) {
3063
+ if (!resourcePath) return undefined;
3064
+ if (!root) return resourcePath;
3065
+ const relativePath = path.relative(root, resourcePath);
3066
+ return relativePath && !relativePath.startsWith('..') ? relativePath : resourcePath;
3067
+ }
3068
+ function createI18nManifestCollector() {
3069
+ let root = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : process.cwd();
3070
+ const records = new Map();
3071
+ return {
3072
+ record(input) {
3073
+ if (!input.key || !input.value) return;
3074
+ const resourcePath = normalizeResourcePath(input.resourcePath, input.root || root);
3075
+ const namespace = input.namespace || 'lang';
3076
+ const dedupeKey = [namespace, resourcePath || '', input.key].join('\u0000');
3077
+ records.set(dedupeKey, {
3078
+ key: input.key,
3079
+ value: input.value,
3080
+ namespace,
3081
+ ...(resourcePath ? {
3082
+ resourcePath
3083
+ } : {})
3084
+ });
3085
+ },
3086
+ toJSON() {
3087
+ let option = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
3088
+ const recordList = Array.from(records.values()).sort((left, right) => {
3089
+ const leftPath = left.resourcePath || '';
3090
+ const rightPath = right.resourcePath || '';
3091
+ return leftPath.localeCompare(rightPath) || left.key.localeCompare(right.key);
3092
+ });
3093
+ const resourceMap = new Map();
3094
+ const allKeys = new Set();
3095
+ recordList.forEach(record => {
3096
+ const resourcePath = record.resourcePath || '<unknown>';
3097
+ const keys = resourceMap.get(resourcePath) || new Set();
3098
+ keys.add(record.key);
3099
+ allKeys.add(record.key);
3100
+ resourceMap.set(resourcePath, keys);
3101
+ });
3102
+ const byFile = Object.fromEntries(Array.from(resourceMap.entries()).map(_ref => {
3103
+ let [resourcePath, keys] = _ref;
3104
+ return [resourcePath, Array.from(keys).sort()];
3105
+ }));
3106
+ return {
3107
+ version: RUNTIME_MANIFEST_VERSION,
3108
+ namespace: option.namespace || 'lang',
3109
+ translateKey: option.translateKey || '$t',
3110
+ originLang: option.originLang || 'zh-cn',
3111
+ targetLangList: option.targetLangList || [],
3112
+ resources: Object.entries(byFile).map(_ref2 => {
3113
+ let [resourcePath, keys] = _ref2;
3114
+ return {
3115
+ path: resourcePath,
3116
+ keys
3117
+ };
3118
+ }),
3119
+ byFile,
3120
+ allKeys: Array.from(allKeys).sort(),
3121
+ records: recordList
3122
+ };
3123
+ },
3124
+ clear() {
3125
+ records.clear();
3126
+ }
3127
+ };
3128
+ }
3129
+ function serializeRuntimeManifest(manifest) {
3130
+ return `const manifest = ${JSON.stringify(manifest, null, 2)};\nexport { manifest };\nexport default manifest;\n`;
3131
+ }
3132
+ function createRuntimeBootstrapCode() {
3133
+ let manifestModuleId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : VITE_RUNTIME_MANIFEST_ID;
3134
+ return `import manifest from ${JSON.stringify(manifestModuleId)};\nconst target = typeof globalThis !== 'undefined' ? globalThis : window;\ntarget[${JSON.stringify(RUNTIME_MANIFEST_GLOBAL)}] = manifest;\nexport { manifest };\nexport default manifest;\n`;
3135
+ }
3136
+ function writeWebpackRuntimeBootstrap(root, manifestAssetName) {
3137
+ const outputDir = path.join(root, 'node_modules', '.cache', 'gc-i18n-plugin');
3138
+ fs.mkdirSync(outputDir, {
3139
+ recursive: true
3140
+ });
3141
+ const bootstrapPath = path.join(outputDir, 'runtime-bootstrap.js');
3142
+ const source = `if (typeof globalThis !== 'undefined') {\n globalThis[${JSON.stringify(RUNTIME_MANIFEST_GLOBAL)}] = globalThis[${JSON.stringify(RUNTIME_MANIFEST_GLOBAL)}] || { version: ${RUNTIME_MANIFEST_VERSION}, resources: [], records: [] };\n globalThis[${JSON.stringify(RUNTIME_MANIFEST_GLOBAL)}].asset = ${JSON.stringify(manifestAssetName)};\n}\n`;
3143
+ fs.writeFileSync(bootstrapPath, source);
3144
+ return bootstrapPath;
3145
+ }
3146
+ function prependWebpackEntry(entry, bootstrapPath) {
3147
+ if (!entry) return entry;
3148
+ if (typeof entry === 'string') return [bootstrapPath, entry];
3149
+ if (Array.isArray(entry)) return [bootstrapPath, ...entry];
3150
+ if (typeof entry === 'function') {
3151
+ return async () => prependWebpackEntry(await entry(), bootstrapPath);
3152
+ }
3153
+ if (typeof entry === 'object') {
3154
+ return Object.fromEntries(Object.entries(entry).map(_ref3 => {
3155
+ let [name, value] = _ref3;
3156
+ if (typeof value === 'string' || Array.isArray(value)) {
3157
+ return [name, prependWebpackEntry(value, bootstrapPath)];
3158
+ }
3159
+ if (value && typeof value === 'object' && 'import' in value) {
3160
+ return [name, {
3161
+ ...value,
3162
+ import: prependWebpackEntry(value.import, bootstrapPath)
3163
+ }];
3164
+ }
3165
+ return [name, value];
3166
+ }));
3167
+ }
3168
+ return entry;
3169
+ }
3170
+
3171
+ const RTL_LANGUAGES = new Set(['ar', 'fa', 'he', 'iw', 'ps', 'ur']);
3172
+ const DEFAULT_NAMESPACE = 'lang';
3173
+ const DEFAULT_HOTKEY = 'Alt+KeyI';
3174
+ function normalizeLocale(locale) {
3175
+ let fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
3176
+ return String(locale || fallback).toLowerCase().replace(/_/g, '-');
3177
+ }
3178
+ function normalizeStorageKey(locale) {
3179
+ let fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
3180
+ return normalizeLocale(locale, fallback).replace(/[^a-z0-9]/g, '');
3181
+ }
3182
+ function cloneMessages(messages) {
3183
+ return Object.keys(messages || {}).reduce((result, locale) => {
3184
+ result[normalizeStorageKey(locale)] = {
3185
+ ...(messages?.[locale] || {})
3186
+ };
3187
+ return result;
3188
+ }, {});
3189
+ }
3190
+ function mergeMessageLayers() {
3191
+ for (var _len = arguments.length, layers = new Array(_len), _key = 0; _key < _len; _key++) {
3192
+ layers[_key] = arguments[_key];
3193
+ }
3194
+ return layers.reduce((result, layer) => {
3195
+ Object.keys(layer || {}).forEach(locale => {
3196
+ const runtimeLocale = normalizeStorageKey(locale);
3197
+ result[runtimeLocale] = {
3198
+ ...(result[runtimeLocale] || {}),
3199
+ ...(layer?.[locale] || {})
3200
+ };
3201
+ });
3202
+ return result;
3203
+ }, {});
3204
+ }
3205
+ function getMessagesForLocale(messages, runtimeLocale) {
3206
+ const baseLocale = runtimeLocale.slice(0, 2);
3207
+ return {
3208
+ ...(messages[runtimeLocale] || {}),
3209
+ ...(baseLocale === runtimeLocale ? {} : messages[baseLocale] || {})
3210
+ };
3211
+ }
3212
+ function interpolate(template, params) {
3213
+ if (!params) return template;
3214
+ return template.replace(/\{\{?\s*([\w.]+)\s*\}?\}/g, (match, path) => {
3215
+ const value = String(path).split('.').reduce((current, key) => {
3216
+ if (current && typeof current === 'object' && key in current) {
3217
+ return current[key];
3218
+ }
3219
+ return undefined;
3220
+ }, params);
3221
+ return value === undefined || value === null ? match : String(value);
3222
+ });
3223
+ }
3224
+ function parseHotkey(event, hotkey) {
3225
+ const parts = hotkey.split('+');
3226
+ const code = parts.pop();
3227
+ const modifiers = new Set(parts.map(part => part.toLowerCase()));
3228
+ return (!modifiers.has('alt') || !!event.altKey) && (!modifiers.has('ctrl') || !!event.ctrlKey) && (!modifiers.has('meta') || !!event.metaKey) && (!modifiers.has('shift') || !!event.shiftKey) && (!code || event.code === code || event.key === code);
3229
+ }
3230
+ function createI18nRuntime() {
3231
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
3232
+ const namespace = options.namespace || DEFAULT_NAMESPACE;
3233
+ const fallbackLocale = normalizeStorageKey(options.fallbackLocale || options.initialLocale || 'zh-cn');
3234
+ let locale = normalizeStorageKey(options.initialLocale, fallbackLocale);
3235
+ let commonMessages = cloneMessages(options.commonMessages);
3236
+ let localMessages = cloneMessages(options.localMessages);
3237
+ let remoteMessages = cloneMessages(options.remoteMessages);
3238
+ const delta = new Map();
3239
+ const runtime = {
3240
+ namespace,
3241
+ getLocale() {
3242
+ return locale;
3243
+ },
3244
+ setRemoteMessages(messages) {
3245
+ remoteMessages = cloneMessages(messages);
3246
+ },
3247
+ mergeMessages(messages) {
3248
+ let layer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'local';
3249
+ if (layer === 'common') commonMessages = mergeMessageLayers(commonMessages, cloneMessages(messages));
3250
+ if (layer === 'local') localMessages = mergeMessageLayers(localMessages, cloneMessages(messages));
3251
+ if (layer === 'remote') remoteMessages = mergeMessageLayers(remoteMessages, cloneMessages(messages));
3252
+ },
3253
+ t(key) {
3254
+ let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
3255
+ let params = arguments.length > 2 ? arguments[2] : undefined;
3256
+ let callNamespace = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : namespace;
3257
+ const interpolationParams = typeof value === 'object' ? value : params;
3258
+ const fallbackValue = typeof value === 'string' ? value : key;
3259
+ const messages = runtime.getMergedMessages();
3260
+ const localeMessages = {
3261
+ ...getMessagesForLocale(messages, fallbackLocale),
3262
+ ...getMessagesForLocale(messages, locale)
3263
+ };
3264
+ const translated = localeMessages[key];
3265
+ if (translated === undefined) {
3266
+ const deltaKey = `${callNamespace}:${locale}:${key}`;
3267
+ if (!delta.has(deltaKey)) {
3268
+ delta.set(deltaKey, {
3269
+ key,
3270
+ value: fallbackValue,
3271
+ locale,
3272
+ namespace: callNamespace
3273
+ });
3274
+ }
3275
+ }
3276
+ return interpolate(translated || fallbackValue || key, interpolationParams);
3277
+ },
3278
+ changeLocale(nextLocale) {
3279
+ locale = normalizeStorageKey(nextLocale, fallbackLocale);
3280
+ return locale;
3281
+ },
3282
+ clearI18n() {
3283
+ remoteMessages = {};
3284
+ delta.clear();
3285
+ },
3286
+ isRTL() {
3287
+ let targetLocale = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : locale;
3288
+ const lang = normalizeLocale(targetLocale).split('-')[0];
3289
+ return RTL_LANGUAGES.has(lang);
3290
+ },
3291
+ getDelta() {
3292
+ return Array.from(delta.values());
3293
+ },
3294
+ getMergedMessages() {
3295
+ return mergeMessageLayers(commonMessages, localMessages, remoteMessages);
3296
+ },
3297
+ requestConfig() {
3298
+ const payload = {
3299
+ locale,
3300
+ namespace,
3301
+ delta: runtime.getDelta(),
3302
+ messages: runtime.getMergedMessages()
3303
+ };
3304
+ options.onConfigRequest?.(payload);
3305
+ return payload;
3306
+ },
3307
+ install() {
3308
+ let target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : options.target || (typeof globalThis !== 'undefined' ? globalThis : undefined);
3309
+ if (!target) return runtime;
3310
+ target.$t = runtime.t;
3311
+ target.$changeLocale = runtime.changeLocale;
3312
+ target.$clearI18n = runtime.clearI18n;
3313
+ target.$isRTL = runtime.isRTL;
3314
+ target.__GC_I18N_RUNTIME__ = runtime;
3315
+ return runtime;
3316
+ }
3317
+ };
3318
+ return runtime;
3319
+ }
3320
+ function installI18nRuntime(app) {
3321
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
3322
+ const runtime = createI18nRuntime({
3323
+ ...options,
3324
+ localMessages: mergeMessageLayers(options.localMessages, options.messages)
3325
+ });
3326
+ runtime.install(options.target);
3327
+ if (app && typeof app.config === 'object') {
3328
+ app.config.globalProperties = app.config.globalProperties || {};
3329
+ app.config.globalProperties.$t = runtime.t;
3330
+ app.config.globalProperties.$changeLocale = runtime.changeLocale;
3331
+ app.config.globalProperties.$clearI18n = runtime.clearI18n;
3332
+ app.config.globalProperties.$isRTL = runtime.isRTL;
3333
+ }
3334
+ const target = options.target || (typeof globalThis !== 'undefined' ? globalThis : undefined);
3335
+ const hotkey = options.hotkey === false ? false : options.hotkey || DEFAULT_HOTKEY;
3336
+ if (target && hotkey && typeof target.addEventListener === 'function') {
3337
+ target.addEventListener('keydown', event => {
3338
+ if (!parseHotkey(event, hotkey)) return;
3339
+ const payload = runtime.requestConfig();
3340
+ if (typeof target.dispatchEvent === 'function' && typeof target.CustomEvent === 'function') {
3341
+ target.dispatchEvent(new target.CustomEvent('gc-i18n-config-request', {
3342
+ detail: payload
3343
+ }));
3344
+ }
3345
+ });
3346
+ }
3347
+ return runtime;
3348
+ }
3349
+ const runtimeUtils = {
3350
+ normalizeLocale,
3351
+ normalizeStorageKey,
3352
+ mergeMessageLayers
3353
+ };
3354
+
2898
3355
  var allowedExtensions = ['.vue', '.ts', '.js', '.tsx', '.jsx'];
2899
3356
  function vitePluginsAutoI18n(optionInfo) {
2900
3357
  var name = 'vite-gc-i18n-plugin';
2901
3358
  var config;
3359
+ var collector = createI18nManifestCollector();
2902
3360
  initOption(__assign({
2903
3361
  deepScan: true,
2904
3362
  globalPath: './lang',
@@ -2923,6 +3381,27 @@ function vitePluginsAutoI18n(optionInfo) {
2923
3381
  // 存储最终解析的配置
2924
3382
  config = resolvedConfig;
2925
3383
  },
3384
+ resolveId: function (id) {
3385
+ if (id === VITE_RUNTIME_MANIFEST_ID) return RESOLVED_VITE_RUNTIME_MANIFEST_ID;
3386
+ if (id === VITE_RUNTIME_BOOTSTRAP_ID) return RESOLVED_VITE_RUNTIME_BOOTSTRAP_ID;
3387
+ },
3388
+ load: function (id) {
3389
+ if (id === RESOLVED_VITE_RUNTIME_MANIFEST_ID) {
3390
+ return serializeRuntimeManifest(collector.toJSON({
3391
+ namespace: exports.option.namespace,
3392
+ translateKey: exports.option.translateKey,
3393
+ originLang: exports.option.originLang,
3394
+ targetLangList: exports.option.targetLangList
3395
+ }));
3396
+ }
3397
+ if (id === RESOLVED_VITE_RUNTIME_BOOTSTRAP_ID) {
3398
+ return createRuntimeBootstrapCode();
3399
+ }
3400
+ },
3401
+ transformIndexHtml: function (html) {
3402
+ var bootstrap = "<script type=\"module\">import ".concat(JSON.stringify(VITE_RUNTIME_BOOTSTRAP_ID), ";</script>");
3403
+ return html.includes(VITE_RUNTIME_BOOTSTRAP_ID) ? html : html.replace('</head>', "".concat(bootstrap, "\n</head>"));
3404
+ },
2926
3405
  transform: function (code, path) {
2927
3406
  return __awaiter(this, void 0, void 0, function () {
2928
3407
  var sourceObj;
@@ -2950,7 +3429,11 @@ function vitePluginsAutoI18n(optionInfo) {
2950
3429
  case 3:
2951
3430
  return [2 /*return*/, babel__namespace.transformAsync(sourceObj.source, {
2952
3431
  configFile: false,
2953
- plugins: [index()]
3432
+ plugins: [index(__assign(__assign({}, sourceObj), {
3433
+ resourcePath: path,
3434
+ root: config === null || config === void 0 ? void 0 : config.root,
3435
+ collector: collector
3436
+ }))]
2954
3437
  }).then(function (result) {
2955
3438
  if ((config === null || config === void 0 ? void 0 : config.command) === 'serve') {
2956
3439
  autoTranslate(); // 执行前需要确保transformAsync已经完成
@@ -3011,19 +3494,33 @@ exports.FunctionFactoryOption = FunctionFactoryOption;
3011
3494
  exports.GoogleTranslator = GoogleTranslator;
3012
3495
  exports.LanguageEnum = LanguageEnum;
3013
3496
  exports.OriginLangKeyEnum = OriginLangKeyEnum;
3497
+ exports.RESOLVED_VITE_RUNTIME_BOOTSTRAP_ID = RESOLVED_VITE_RUNTIME_BOOTSTRAP_ID;
3498
+ exports.RESOLVED_VITE_RUNTIME_MANIFEST_ID = RESOLVED_VITE_RUNTIME_MANIFEST_ID;
3499
+ exports.RUNTIME_MANIFEST_GLOBAL = RUNTIME_MANIFEST_GLOBAL;
3500
+ exports.RUNTIME_MANIFEST_VERSION = RUNTIME_MANIFEST_VERSION;
3014
3501
  exports.ScanTranslator = ScanTranslator;
3015
3502
  exports.TranslateApiEnum = TranslateApiEnum;
3016
3503
  exports.TranslateTypeEnum = TranslateTypeEnum;
3017
3504
  exports.Translator = Translator;
3505
+ exports.VITE_RUNTIME_BOOTSTRAP_ID = VITE_RUNTIME_BOOTSTRAP_ID;
3506
+ exports.VITE_RUNTIME_MANIFEST_ID = VITE_RUNTIME_MANIFEST_ID;
3018
3507
  exports.VolcengineTranslator = VolcengineTranslator;
3019
3508
  exports.Vue2Extends = Vue2Extends;
3020
3509
  exports.YoudaoTranslator = YoudaoTranslator;
3021
3510
  exports.baseUtils = base;
3022
3511
  exports.checkOption = checkOption;
3512
+ exports.createI18nManifestCollector = createI18nManifestCollector;
3513
+ exports.createI18nRuntime = createI18nRuntime;
3514
+ exports.createRuntimeBootstrapCode = createRuntimeBootstrapCode;
3023
3515
  exports.default = vitePluginsAutoI18n;
3024
3516
  exports.fileUtils = file;
3025
3517
  exports.filter = index$1;
3026
3518
  exports.initOption = initOption;
3519
+ exports.installI18nRuntime = installI18nRuntime;
3520
+ exports.prependWebpackEntry = prependWebpackEntry;
3521
+ exports.runtimeUtils = runtimeUtils;
3522
+ exports.serializeRuntimeManifest = serializeRuntimeManifest;
3027
3523
  exports.translateUtils = translate;
3028
3524
  exports.uploadUtils = upload$1;
3525
+ exports.writeWebpackRuntimeBootstrap = writeWebpackRuntimeBootstrap;
3029
3526
  //# sourceMappingURL=index.cjs.map