@zohodesk/client_build_tool 0.0.11-exp.27.0 → 0.0.11-exp.29.0
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/lib/shared/bundler/webpack/common/i18nOptionsValidator.js +146 -0
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nGroupRuntimeModule.js +59 -20
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexHtmlInjectorPlugin.js +18 -21
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexPlugin.js +1 -7
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/utils/i18nDataLoader.js +32 -75
- package/lib/shared/bundler/webpack/loaderConfigs/i18nIdReplaceLoaderConfig.js +29 -38
- package/lib/shared/bundler/webpack/loaders/i18nIdReplaceLoader.js +13 -10
- package/lib/shared/bundler/webpack/pluginConfigs/configI18nNumericIndexPlugin.js +39 -62
- package/package.json +1 -1
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.validateI18nChunkSplitOptions = validateI18nChunkSplitOptions;
|
|
7
|
+
exports.validateI18nIndexingOptions = validateI18nIndexingOptions;
|
|
8
|
+
exports.validateI18nOptions = validateI18nOptions;
|
|
9
|
+
exports.validatePathSecurity = validatePathSecurity;
|
|
10
|
+
exports.validateRequiredFields = validateRequiredFields;
|
|
11
|
+
exports.validateTemplateFormat = validateTemplateFormat;
|
|
12
|
+
const LOCALE_PLACEHOLDER = '[locale]';
|
|
13
|
+
const REQUIRED_OPTIONS = ['jsResourcePath', 'propertiesFolderPath', 'numericMapPath', 'jsonpFunc', 'htmlTemplateLabel'];
|
|
14
|
+
|
|
15
|
+
function validatePathSecurity(path, fieldName) {
|
|
16
|
+
if (!path || typeof path !== 'string') {
|
|
17
|
+
return;
|
|
18
|
+
} // Allow relative paths within project structure (../assets, etc.)
|
|
19
|
+
// Block dangerous patterns like ../../etc/passwd
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
if (path.includes('../..') || path.startsWith('/') && path.includes('..')) {
|
|
23
|
+
throw new Error(`[I18nOptionsValidator] Invalid ${fieldName} contains suspicious path: ${path}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function validateRequiredFields(options, requiredFields) {
|
|
28
|
+
const missingOptions = requiredFields.filter(opt => {
|
|
29
|
+
const value = options[opt];
|
|
30
|
+
return value === undefined || value === null || typeof value === 'string' && value.trim() === '';
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (missingOptions.length > 0) {
|
|
34
|
+
throw new Error(`[I18nOptionsValidator] Missing required i18n options: ${missingOptions.join(', ')}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function validateTemplateFormat(template, templateName) {
|
|
39
|
+
if (!template || typeof template !== 'string') {
|
|
40
|
+
throw new Error(`[I18nOptionsValidator] ${templateName} must be a non-empty string`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!template.includes(LOCALE_PLACEHOLDER)) {
|
|
44
|
+
throw new Error(`[I18nOptionsValidator] ${templateName} must include ${LOCALE_PLACEHOLDER} placeholder`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
validatePathSecurity(template, templateName);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function validateI18nIndexingOptions(i18nOpts) {
|
|
51
|
+
if (!i18nOpts || typeof i18nOpts !== 'object') {
|
|
52
|
+
throw new Error('[I18nOptionsValidator] i18nIndexing configuration must be a valid object');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!i18nOpts.enable) {
|
|
56
|
+
return {
|
|
57
|
+
skipValidation: true
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
validateRequiredFields(i18nOpts, REQUIRED_OPTIONS);
|
|
62
|
+
validatePathSecurity(i18nOpts.jsResourcePath, 'jsResourcePath');
|
|
63
|
+
validatePathSecurity(i18nOpts.propertiesFolderPath, 'propertiesFolderPath');
|
|
64
|
+
validatePathSecurity(i18nOpts.numericMapPath, 'numericMapPath');
|
|
65
|
+
const numericTemplate = i18nOpts.numericFilenameTemplate || '[locale]/numeric.i18n.js';
|
|
66
|
+
const dynamicTemplate = i18nOpts.dynamicFilenameTemplate || '[locale]/dynamic.i18n.js';
|
|
67
|
+
validateTemplateFormat(numericTemplate, 'numericFilenameTemplate');
|
|
68
|
+
validateTemplateFormat(dynamicTemplate, 'dynamicFilenameTemplate');
|
|
69
|
+
|
|
70
|
+
if (i18nOpts.singleFileTemplate) {
|
|
71
|
+
validateTemplateFormat(i18nOpts.singleFileTemplate, 'singleFileTemplate');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (i18nOpts.outputFolder) {
|
|
75
|
+
validatePathSecurity(i18nOpts.outputFolder, 'outputFolder');
|
|
76
|
+
} // Validate conflicting options
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
const includeContentHash = i18nOpts.includeContentHash;
|
|
80
|
+
const injectHtml = i18nOpts.injectI18nUrlInIndex !== undefined ? i18nOpts.injectI18nUrlInIndex : true;
|
|
81
|
+
|
|
82
|
+
if (includeContentHash && injectHtml) {
|
|
83
|
+
throw new Error('[I18nOptionsValidator] includeContentHash and injectI18nUrlInIndex cannot both be true - content hash changes filenames dynamically but HTML injection needs static filenames');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
skipValidation: false
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function validateI18nChunkSplitOptions(chunkSplitOpts) {
|
|
92
|
+
if (!chunkSplitOpts || typeof chunkSplitOpts !== 'object') {
|
|
93
|
+
throw new Error('[I18nOptionsValidator] i18nChunkSplit configuration must be a valid object');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!chunkSplitOpts.chunkSplitEnable || !chunkSplitOpts.useNumericIndexing) {
|
|
97
|
+
return {
|
|
98
|
+
skipValidation: true
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!chunkSplitOpts.jsResource) {
|
|
103
|
+
throw new Error('[I18nOptionsValidator] Missing required jsResource in i18nChunkSplit options');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!chunkSplitOpts.numericMapPath) {
|
|
107
|
+
throw new Error('[I18nOptionsValidator] Missing required numericMapPath in i18nChunkSplit options');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
validatePathSecurity(chunkSplitOpts.jsResource, 'jsResource');
|
|
111
|
+
validatePathSecurity(chunkSplitOpts.numericMapPath, 'numericMapPath');
|
|
112
|
+
return {
|
|
113
|
+
skipValidation: false
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function validateI18nOptions(options) {
|
|
118
|
+
if (!options || typeof options !== 'object') {
|
|
119
|
+
throw new Error('[I18nOptionsValidator] Options must be a valid object');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const hasIndexing = options.i18nIndexing && options.i18nIndexing.enable;
|
|
123
|
+
const hasChunkSplit = options.i18nChunkSplit && options.i18nChunkSplit.chunkSplitEnable && options.i18nChunkSplit.useNumericIndexing;
|
|
124
|
+
|
|
125
|
+
if (!hasIndexing && !hasChunkSplit) {
|
|
126
|
+
throw new Error('[I18nOptionsValidator] i18n validation requires either i18nIndexing to be enabled or i18nChunkSplit with useNumericIndexing');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (hasIndexing) {
|
|
130
|
+
const result = validateI18nIndexingOptions(options.i18nIndexing);
|
|
131
|
+
|
|
132
|
+
if (result.skipValidation) {
|
|
133
|
+
throw new Error('[I18nOptionsValidator] i18nIndexing is not properly enabled');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (hasChunkSplit) {
|
|
138
|
+
const result = validateI18nChunkSplitOptions(options.i18nChunkSplit);
|
|
139
|
+
|
|
140
|
+
if (result.skipValidation) {
|
|
141
|
+
throw new Error('[I18nOptionsValidator] i18nChunkSplit is not properly configured');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return true;
|
|
146
|
+
}
|
package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nGroupRuntimeModule.js
CHANGED
|
@@ -22,11 +22,13 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
|
|
|
22
22
|
localeVarName,
|
|
23
23
|
i18nPublicPathVar,
|
|
24
24
|
groupAssetUrls,
|
|
25
|
-
includeContentHash
|
|
25
|
+
includeContentHash,
|
|
26
|
+
mode
|
|
26
27
|
} = this.options;
|
|
27
28
|
const chunkIdToGroup = chunkIdToGroupMapping || {};
|
|
28
29
|
const hasGroupAssetOverrides = !!groupAssetUrls && Object.values(groupAssetUrls).some(localeMap => localeMap && Object.keys(localeMap).length > 0);
|
|
29
30
|
const hashAware = includeContentHash || hasGroupAssetOverrides;
|
|
31
|
+
const isDevelopment = mode === 'development';
|
|
30
32
|
return `
|
|
31
33
|
// I18n Group Loading Runtime
|
|
32
34
|
(function() {
|
|
@@ -34,7 +36,9 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
|
|
|
34
36
|
var chunkIdToGroup = ${JSON.stringify(chunkIdToGroup)};
|
|
35
37
|
var groupAssetUrls = ${JSON.stringify(groupAssetUrls || {})};
|
|
36
38
|
var hashAware = ${hashAware ? 'true' : 'false'};
|
|
39
|
+
var isDev = ${isDevelopment ? 'true' : 'false'};
|
|
37
40
|
var cachedI18nBase;
|
|
41
|
+
var scriptCache = null;
|
|
38
42
|
|
|
39
43
|
function ensureTrailingSlash(path) {
|
|
40
44
|
if (!path) return '';
|
|
@@ -61,9 +65,11 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
|
|
|
61
65
|
var base = resolveConfiguredBase();
|
|
62
66
|
|
|
63
67
|
if (!base && typeof document !== 'undefined') {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
if (!scriptCache) {
|
|
69
|
+
scriptCache = Array.from(document.getElementsByTagName('script'));
|
|
70
|
+
}
|
|
71
|
+
for (var i = 0; i < scriptCache.length; i++) {
|
|
72
|
+
var src = scriptCache[i].getAttribute('data-src') || scriptCache[i].getAttribute('src') || '';
|
|
67
73
|
var markerIndex = src.indexOf('i18n-chunk/');
|
|
68
74
|
if (markerIndex !== -1) {
|
|
69
75
|
base = src.slice(0, markerIndex);
|
|
@@ -126,15 +132,28 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
|
|
|
126
132
|
script.src = i18nUrl;
|
|
127
133
|
script.async = true;
|
|
128
134
|
|
|
135
|
+
var cleanup = function() {
|
|
136
|
+
if (script.parentNode) {
|
|
137
|
+
script.parentNode.removeChild(script);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
129
141
|
script.onload = function() {
|
|
130
142
|
loadedGroups[groupName] = true;
|
|
131
|
-
|
|
143
|
+
if (isDev) {
|
|
144
|
+
console.log('[i18n-group:loaded]', groupName, i18nUrl);
|
|
145
|
+
}
|
|
146
|
+
cleanup();
|
|
132
147
|
resolve();
|
|
133
148
|
};
|
|
134
149
|
|
|
135
150
|
script.onerror = function() {
|
|
136
|
-
|
|
137
|
-
|
|
151
|
+
if (isDev) {
|
|
152
|
+
console.error('[i18n-group:error]', groupName, i18nUrl);
|
|
153
|
+
}
|
|
154
|
+
cleanup();
|
|
155
|
+
loadedGroups[groupName] = true;
|
|
156
|
+
resolve();
|
|
138
157
|
};
|
|
139
158
|
|
|
140
159
|
document.head.appendChild(script);
|
|
@@ -159,8 +178,10 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
|
|
|
159
178
|
return i18nPromise.then(function() {
|
|
160
179
|
return originalEnsureChunk.apply(self, args);
|
|
161
180
|
}).catch(function(err) {
|
|
162
|
-
|
|
163
|
-
|
|
181
|
+
if (isDev) {
|
|
182
|
+
console.error('[i18n-group:critical] i18n failed, proceeding without:', err);
|
|
183
|
+
}
|
|
184
|
+
return originalEnsureChunk.apply(self, args);
|
|
164
185
|
});
|
|
165
186
|
} else {
|
|
166
187
|
return originalEnsureChunk.apply(this, arguments);
|
|
@@ -180,7 +201,7 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
|
|
|
180
201
|
if (config.urlPatterns && Array.isArray(config.urlPatterns)) {
|
|
181
202
|
for (var i = 0; i < config.urlPatterns.length; i++) {
|
|
182
203
|
var pattern = config.urlPatterns[i];
|
|
183
|
-
if (url.
|
|
204
|
+
if (url.includes(pattern)) {
|
|
184
205
|
return groupName;
|
|
185
206
|
}
|
|
186
207
|
}
|
|
@@ -191,12 +212,22 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
|
|
|
191
212
|
}
|
|
192
213
|
|
|
193
214
|
function checkAndLoadGroupFromUrl() {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
215
|
+
try {
|
|
216
|
+
var detectedGroup = detectGroupFromUrl();
|
|
217
|
+
if (detectedGroup && !loadedGroups[detectedGroup]) {
|
|
218
|
+
if (isDev) {
|
|
219
|
+
console.log('[i18n-group:url-detect]', detectedGroup, 'loading for current URL');
|
|
220
|
+
}
|
|
221
|
+
loadI18nGroup(detectedGroup, 'url-detection').catch(function(err) {
|
|
222
|
+
if (isDev) {
|
|
223
|
+
console.error('[i18n-group:url-detect] Failed to load', detectedGroup, ':', err);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
} catch (err) {
|
|
228
|
+
if (isDev) {
|
|
229
|
+
console.error('[i18n-group:url-detect] Error in URL detection:', err);
|
|
230
|
+
}
|
|
200
231
|
}
|
|
201
232
|
}
|
|
202
233
|
|
|
@@ -210,9 +241,13 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
|
|
|
210
241
|
for (var groupName in groupConfig) {
|
|
211
242
|
var config = groupConfig[groupName];
|
|
212
243
|
if (config.preload === true && !loadedGroups[groupName]) {
|
|
213
|
-
|
|
244
|
+
if (isDev) {
|
|
245
|
+
console.log('[i18n-group:preload]', groupName, 'loading immediately');
|
|
246
|
+
}
|
|
214
247
|
loadI18nGroup(groupName, 'preload').catch(function(err) {
|
|
215
|
-
|
|
248
|
+
if (isDev) {
|
|
249
|
+
console.error('[i18n-group:preload] Failed to preload', groupName, ':', err);
|
|
250
|
+
}
|
|
216
251
|
});
|
|
217
252
|
}
|
|
218
253
|
}
|
|
@@ -222,9 +257,13 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
|
|
|
222
257
|
for (var groupName in groupConfig) {
|
|
223
258
|
var config = groupConfig[groupName];
|
|
224
259
|
if (config.prefetch === true && !loadedGroups[groupName] && config.preload !== true) {
|
|
225
|
-
|
|
260
|
+
if (isDev) {
|
|
261
|
+
console.log('[i18n-group:prefetch]', groupName, 'scheduling background load');
|
|
262
|
+
}
|
|
226
263
|
loadI18nGroup(groupName, 'prefetch').catch(function(err) {
|
|
227
|
-
|
|
264
|
+
if (isDev) {
|
|
265
|
+
console.error('[i18n-group:prefetch] Failed to prefetch', groupName, ':', err);
|
|
266
|
+
}
|
|
228
267
|
});
|
|
229
268
|
}
|
|
230
269
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.I18nNumericIndexHtmlInjectorPlugin = void 0;
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
var _htmlWebpackPlugin = _interopRequireDefault(require("html-webpack-plugin"));
|
|
9
|
+
|
|
10
|
+
var _path = _interopRequireDefault(require("path"));
|
|
11
|
+
|
|
12
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
6
13
|
|
|
7
14
|
const pluginName = 'I18nNumericIndexHtmlInjectorPlugin';
|
|
8
15
|
const assetStoreKey = Symbol.for('I18nNumericIndexPluginAssets');
|
|
@@ -17,8 +24,7 @@ class I18nNumericIndexHtmlInjectorPlugin {
|
|
|
17
24
|
|
|
18
25
|
apply(compiler) {
|
|
19
26
|
compiler.hooks.thisCompilation.tap(pluginName, compilation => {
|
|
20
|
-
|
|
21
|
-
// Skip HTML injection if disabled
|
|
27
|
+
_htmlWebpackPlugin.default.getHooks(compilation).beforeAssetTagGeneration.tapAsync(pluginName, (hookData, cb) => {
|
|
22
28
|
if (!this.options.injectI18nUrlInIndex) {
|
|
23
29
|
return cb(null, hookData);
|
|
24
30
|
}
|
|
@@ -37,30 +43,26 @@ class I18nNumericIndexHtmlInjectorPlugin {
|
|
|
37
43
|
} = this.options;
|
|
38
44
|
const newI18nAssetUrlsToAdd = [];
|
|
39
45
|
const emittedAssetNames = compilation.getAssets().map(asset => asset.name);
|
|
40
|
-
const recordedAssets = compilation[assetStoreKey] || [];
|
|
46
|
+
const recordedAssets = compilation[assetStoreKey] || [];
|
|
41
47
|
|
|
42
48
|
const resolveAssetPath = (template, fileType) => {
|
|
43
|
-
if (!template) return null;
|
|
44
|
-
|
|
49
|
+
if (!template) return null;
|
|
45
50
|
const recorded = recordedAssets.find(asset => {
|
|
46
51
|
if (fileType === 'single') return !asset.fileType;
|
|
47
52
|
return asset.fileType === fileType;
|
|
48
53
|
});
|
|
49
54
|
|
|
50
55
|
if (recorded) {
|
|
51
|
-
// Use recorded asset with correct locale
|
|
52
56
|
const assetPath = recorded.outputPath.replace(recorded.locale, htmlTemplateLabel);
|
|
53
57
|
return i18nAssetsPublicPathPrefix + assetPath;
|
|
54
|
-
}
|
|
55
|
-
|
|
58
|
+
}
|
|
56
59
|
|
|
57
60
|
const filePath = template.replace(/\[locale\]/g, htmlTemplateLabel);
|
|
58
|
-
const fullPath = filePath.includes(outputFolder) || filePath.startsWith('/') ? filePath :
|
|
61
|
+
const fullPath = filePath.includes(outputFolder) || filePath.startsWith('/') ? filePath : _path.default.join(outputFolder, filePath);
|
|
59
62
|
|
|
60
63
|
if (emittedAssetNames.includes(fullPath)) {
|
|
61
64
|
return i18nAssetsPublicPathPrefix + fullPath;
|
|
62
|
-
}
|
|
63
|
-
|
|
65
|
+
}
|
|
64
66
|
|
|
65
67
|
if (fullPath.includes('[contenthash]')) {
|
|
66
68
|
const pattern = fullPath.replace('[contenthash]', '*');
|
|
@@ -69,15 +71,13 @@ class I18nNumericIndexHtmlInjectorPlugin {
|
|
|
69
71
|
if (matchingAsset) {
|
|
70
72
|
return i18nAssetsPublicPathPrefix + matchingAsset;
|
|
71
73
|
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
+
}
|
|
74
75
|
|
|
75
76
|
return i18nAssetsPublicPathPrefix + fullPath;
|
|
76
77
|
};
|
|
77
78
|
|
|
78
79
|
if (singleFile) {
|
|
79
|
-
const
|
|
80
|
-
const combinedFilename = resolveAssetPath(singleTemplate, 'single');
|
|
80
|
+
const combinedFilename = resolveAssetPath(singleFileTemplate, 'single');
|
|
81
81
|
|
|
82
82
|
if (combinedFilename) {
|
|
83
83
|
newI18nAssetUrlsToAdd.push(combinedFilename);
|
|
@@ -97,7 +97,6 @@ class I18nNumericIndexHtmlInjectorPlugin {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
if (newI18nAssetUrlsToAdd.length > 0) {
|
|
100
|
-
// Add i18n assets to the beginning of JS assets for early loading
|
|
101
100
|
assets.js = [...newI18nAssetUrlsToAdd, ...assets.js];
|
|
102
101
|
}
|
|
103
102
|
|
|
@@ -108,6 +107,4 @@ class I18nNumericIndexHtmlInjectorPlugin {
|
|
|
108
107
|
|
|
109
108
|
}
|
|
110
109
|
|
|
111
|
-
|
|
112
|
-
I18nNumericIndexHtmlInjectorPlugin
|
|
113
|
-
};
|
|
110
|
+
exports.I18nNumericIndexHtmlInjectorPlugin = I18nNumericIndexHtmlInjectorPlugin;
|
package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexPlugin.js
CHANGED
|
@@ -15,7 +15,7 @@ var _propertiesUtils = require("../I18nSplitPlugin/utils/propertiesUtils");
|
|
|
15
15
|
|
|
16
16
|
var _I18nGroupRuntimeModule = require("./I18nGroupRuntimeModule");
|
|
17
17
|
|
|
18
|
-
var _i18nDataLoader = require("./utils/i18nDataLoader");
|
|
18
|
+
var _i18nDataLoader = require("./utils/i18nDataLoader.js");
|
|
19
19
|
|
|
20
20
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
21
21
|
|
|
@@ -157,12 +157,6 @@ class I18nNumericIndexPlugin {
|
|
|
157
157
|
if (missingPaths.length > 0) {
|
|
158
158
|
const errorMessage = ['', '🚨 I18N BUILD FAILURE: Critical i18n files are missing!', '', 'The following required files could not be found:', ...missingPaths.map(path => ` ❌ ${path}`), '', 'These files are essential for i18n functionality. Please ensure they exist before building.', '', 'Resolved paths checked:', ...resolvedPaths.map(path => ` 📁 ${path}`), ''].join('\n');
|
|
159
159
|
throw new Error(errorMessage);
|
|
160
|
-
} // Log successful validation in development mode
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (compiler.options.mode === 'development') {
|
|
164
|
-
console.log('✅ I18n critical file validation passed:');
|
|
165
|
-
resolvedPaths.forEach(path => console.log(` 📁 ${path}`));
|
|
166
160
|
}
|
|
167
161
|
}
|
|
168
162
|
|
package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/utils/i18nDataLoader.js
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.loadAllLocaleFiles = loadAllLocaleFiles;
|
|
7
|
+
exports.loadI18nData = loadI18nData;
|
|
8
|
+
exports.loadNumericMap = loadNumericMap;
|
|
9
|
+
exports.loadPropertiesFile = loadPropertiesFile;
|
|
4
10
|
|
|
5
|
-
|
|
11
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
getPropertiesAsJSON
|
|
9
|
-
} = require('../../I18nSplitPlugin/utils/propertiesUtils');
|
|
10
|
-
/**
|
|
11
|
-
* Load and parse a properties file
|
|
12
|
-
*/
|
|
13
|
+
var _path = _interopRequireDefault(require("path"));
|
|
13
14
|
|
|
15
|
+
var _propertiesUtils = require("../../I18nSplitPlugin/utils/propertiesUtils.js");
|
|
16
|
+
|
|
17
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
18
|
|
|
15
19
|
function loadPropertiesFile(filePath, compilation, description) {
|
|
16
20
|
try {
|
|
17
|
-
|
|
18
|
-
return parsed;
|
|
21
|
+
return (0, _propertiesUtils.getPropertiesAsJSON)(filePath);
|
|
19
22
|
} catch (err) {
|
|
20
23
|
if (compilation) {
|
|
21
24
|
compilation.errors.push(new Error(`I18nNumericIndexPlugin: Error loading ${description}: ${err.message}`));
|
|
@@ -24,47 +27,16 @@ function loadPropertiesFile(filePath, compilation, description) {
|
|
|
24
27
|
return {};
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
|
-
/**
|
|
28
|
-
* Load numeric mapping from JSON file
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
30
|
|
|
32
31
|
function loadNumericMap(numericMapPath, compilation) {
|
|
33
32
|
try {
|
|
34
|
-
const fileContent =
|
|
35
|
-
const parsedData = JSON.parse(fileContent);
|
|
36
|
-
let numericMap;
|
|
37
|
-
let totalKeys; // Handle both wrapped and flat formats
|
|
38
|
-
|
|
39
|
-
if (parsedData.originalKeyToNumericId) {
|
|
40
|
-
// New format with metadata
|
|
41
|
-
numericMap = parsedData.originalKeyToNumericId;
|
|
42
|
-
totalKeys = parsedData.totalKeysInMap || Object.keys(numericMap).length;
|
|
43
|
-
} else {
|
|
44
|
-
// Flat format - use directly
|
|
45
|
-
numericMap = parsedData;
|
|
46
|
-
totalKeys = Object.keys(numericMap).length;
|
|
47
|
-
} // Create sorted array for numeric ID lookups
|
|
48
|
-
|
|
33
|
+
const fileContent = _fs.default.readFileSync(numericMapPath, 'utf-8');
|
|
49
34
|
|
|
35
|
+
const parsedData = JSON.parse(fileContent);
|
|
36
|
+
const numericMap = parsedData.originalKeyToNumericId || parsedData;
|
|
37
|
+
const totalKeys = parsedData.totalKeysInMap || Object.keys(numericMap).length;
|
|
50
38
|
const values = Object.values(numericMap);
|
|
51
|
-
|
|
52
|
-
if (values.length === 0) {
|
|
53
|
-
throw new Error('numeric map is empty');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
let maxId = 0;
|
|
57
|
-
values.forEach(id => {
|
|
58
|
-
const numericId = typeof id === 'number' ? id : Number(id);
|
|
59
|
-
|
|
60
|
-
if (Number.isNaN(numericId)) {
|
|
61
|
-
throw new Error(`invalid numeric map entry value: ${id}`);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (numericId > maxId) {
|
|
65
|
-
maxId = numericId;
|
|
66
|
-
}
|
|
67
|
-
});
|
|
39
|
+
const maxId = Math.max(...values.map(id => typeof id === 'number' ? id : Number(id)));
|
|
68
40
|
const sortedKeys = new Array(maxId + 1);
|
|
69
41
|
Object.entries(numericMap).forEach(([key, id]) => {
|
|
70
42
|
sortedKeys[id] = key;
|
|
@@ -84,30 +56,26 @@ function loadNumericMap(numericMapPath, compilation) {
|
|
|
84
56
|
};
|
|
85
57
|
}
|
|
86
58
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Load all locale files from properties directory
|
|
89
|
-
*/
|
|
90
|
-
|
|
91
59
|
|
|
92
60
|
function loadAllLocaleFiles(propertiesPath, compilation, jsResourceBase) {
|
|
93
|
-
const allI18n = {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
locales.push('en_US');
|
|
61
|
+
const allI18n = {
|
|
62
|
+
en_US: jsResourceBase
|
|
63
|
+
};
|
|
64
|
+
const locales = ['en_US'];
|
|
98
65
|
|
|
99
66
|
try {
|
|
100
|
-
const files =
|
|
101
|
-
files.forEach(file => {
|
|
102
|
-
if (!file.endsWith('.properties')) return; // Match locale-specific property files
|
|
67
|
+
const files = _fs.default.readdirSync(propertiesPath);
|
|
103
68
|
|
|
69
|
+
files.forEach(file => {
|
|
70
|
+
if (!file.endsWith('.properties')) return;
|
|
104
71
|
const match = file.match(/^ApplicationResources_([a-z]{2}_[A-Z]{2})\.properties$/);
|
|
105
72
|
|
|
106
73
|
if (match) {
|
|
107
74
|
const locale = match[1];
|
|
108
|
-
const filePath = path.join(propertiesPath, file);
|
|
109
|
-
const localeData = loadPropertiesFile(filePath, compilation, `locale ${locale}`); // Merge with base resources
|
|
110
75
|
|
|
76
|
+
const filePath = _path.default.join(propertiesPath, file);
|
|
77
|
+
|
|
78
|
+
const localeData = loadPropertiesFile(filePath, compilation, `locale ${locale}`);
|
|
111
79
|
allI18n[locale] = { ...jsResourceBase,
|
|
112
80
|
...localeData
|
|
113
81
|
};
|
|
@@ -128,17 +96,13 @@ function loadAllLocaleFiles(propertiesPath, compilation, jsResourceBase) {
|
|
|
128
96
|
locales
|
|
129
97
|
};
|
|
130
98
|
}
|
|
131
|
-
/**
|
|
132
|
-
* Main loader function for i18n data
|
|
133
|
-
*/
|
|
134
|
-
|
|
135
99
|
|
|
136
100
|
function loadI18nData(options, compilation) {
|
|
137
|
-
const jsResourcePath =
|
|
138
|
-
const propertiesPath = path.resolve(compilation.compiler.context, options.propertiesFolderPath); // Load base JS resources
|
|
101
|
+
const jsResourcePath = _path.default.resolve(compilation.compiler.context, options.jsResourcePath);
|
|
139
102
|
|
|
140
|
-
const
|
|
103
|
+
const propertiesPath = _path.default.resolve(compilation.compiler.context, options.propertiesFolderPath);
|
|
141
104
|
|
|
105
|
+
const jsResourceBase = loadPropertiesFile(jsResourcePath, compilation, 'JS resources');
|
|
142
106
|
const {
|
|
143
107
|
allI18n,
|
|
144
108
|
locales
|
|
@@ -148,11 +112,4 @@ function loadI18nData(options, compilation) {
|
|
|
148
112
|
allI18n,
|
|
149
113
|
locales
|
|
150
114
|
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
module.exports = {
|
|
154
|
-
loadPropertiesFile,
|
|
155
|
-
loadNumericMap,
|
|
156
|
-
loadAllLocaleFiles,
|
|
157
|
-
loadI18nData
|
|
158
|
-
};
|
|
115
|
+
}
|
|
@@ -1,37 +1,32 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.i18nIdReplaceLoaderConfig = i18nIdReplaceLoaderConfig;
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
var _propertiesUtils = require("../custom_plugins/I18nSplitPlugin/utils/propertiesUtils.js");
|
|
9
|
+
|
|
10
|
+
var _i18nOptionsValidator = require("../common/i18nOptionsValidator.js");
|
|
11
|
+
|
|
12
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
13
|
+
|
|
14
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
8
15
|
|
|
9
16
|
function loadJSResourcesOnce(options) {
|
|
10
|
-
let jsResourcePath;
|
|
17
|
+
let jsResourcePath;
|
|
11
18
|
|
|
12
19
|
if (options.i18nIndexing && options.i18nIndexing.enable) {
|
|
13
20
|
jsResourcePath = options.i18nIndexing.jsResourcePath;
|
|
14
21
|
} else if (options.i18nChunkSplit && options.i18nChunkSplit.chunkSplitEnable && options.i18nChunkSplit.useNumericIndexing) {
|
|
15
22
|
jsResourcePath = options.i18nChunkSplit.jsResource;
|
|
16
|
-
} else {
|
|
17
|
-
throw new Error('i18nIdReplaceLoader requires either i18nIndexing to be enabled or i18nChunkSplit with useNumericIndexing');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (!jsResourcePath) {
|
|
21
|
-
throw new Error('Missing required jsResourcePath in i18n options');
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
try {
|
|
25
|
-
const i18nData = getPropertiesAsJSON(jsResourcePath);
|
|
26
|
-
|
|
27
|
-
if (Object.keys(i18nData).length === 0) {
|
|
28
|
-
console.warn(`[i18nIdReplaceLoaderConfig] Warning: No i18n data found in JSResource file: ${jsResourcePath}`);
|
|
29
|
-
return {};
|
|
30
|
-
}
|
|
31
|
-
|
|
26
|
+
const i18nData = (0, _propertiesUtils.getPropertiesAsJSON)(jsResourcePath);
|
|
32
27
|
return i18nData;
|
|
33
28
|
} catch (err) {
|
|
34
|
-
throw new Error(`Error reading JSResource file ${jsResourcePath}: ${err.message}`);
|
|
29
|
+
throw new Error(`[I18nIdReplaceLoaderConfig] Error reading JSResource file ${jsResourcePath}: ${err.message}`);
|
|
35
30
|
}
|
|
36
31
|
}
|
|
37
32
|
|
|
@@ -39,37 +34,37 @@ function readNumericMapOnce(numericMapPath) {
|
|
|
39
34
|
if (!numericMapPath) return null;
|
|
40
35
|
|
|
41
36
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
const fileContent = _fs.default.readFileSync(numericMapPath, 'utf-8');
|
|
38
|
+
|
|
44
39
|
const parsed = JSON.parse(fileContent);
|
|
45
|
-
if (!parsed) return null;
|
|
46
40
|
return parsed.originalKeyToNumericId ? parsed.originalKeyToNumericId : parsed;
|
|
47
41
|
} catch (err) {
|
|
48
|
-
|
|
42
|
+
throw new Error(`[I18nIdReplaceLoaderConfig] Failed to read numeric map from ${numericMapPath}: ${err.message}`);
|
|
49
43
|
}
|
|
50
44
|
}
|
|
51
45
|
|
|
52
|
-
function i18nIdReplaceLoaderConfig(options
|
|
53
|
-
|
|
46
|
+
function i18nIdReplaceLoaderConfig(options) {
|
|
47
|
+
(0, _i18nOptionsValidator.validateI18nOptions)(options);
|
|
48
|
+
let numericMapPath;
|
|
54
49
|
|
|
55
50
|
if (options.i18nIndexing && options.i18nIndexing.enable) {
|
|
56
51
|
numericMapPath = options.i18nIndexing.numericMapPath;
|
|
57
52
|
} else if (options.i18nChunkSplit && options.i18nChunkSplit.chunkSplitEnable && options.i18nChunkSplit.useNumericIndexing) {
|
|
58
53
|
numericMapPath = options.i18nChunkSplit.numericMapPath;
|
|
59
|
-
} else {
|
|
60
|
-
throw new Error('i18nIdReplaceLoader requires either i18nIndexing to be enabled or i18nChunkSplit with useNumericIndexing');
|
|
61
54
|
}
|
|
62
55
|
|
|
63
|
-
if (!numericMapPath) {
|
|
64
|
-
throw new Error('numericMapPath is required in i18nIndexing or i18nChunkSplit config');
|
|
65
|
-
} // Load all i18n data for key detection
|
|
66
|
-
|
|
67
|
-
|
|
68
56
|
const allI18nData = loadJSResourcesOnce(options);
|
|
69
57
|
|
|
70
58
|
const i18nKeyReplaceLoaderPath = require.resolve('../loaders/i18nIdReplaceLoader.js');
|
|
71
59
|
|
|
72
|
-
|
|
60
|
+
let numericIdMap;
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
numericIdMap = readNumericMapOnce(numericMapPath);
|
|
64
|
+
} catch (err) {
|
|
65
|
+
throw new Error(`[I18nIdReplaceLoaderConfig] Failed to load numeric map: ${err.message}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
73
68
|
const loaderOptions = {
|
|
74
69
|
allI18nData: allI18nData,
|
|
75
70
|
sourceMaps: false,
|
|
@@ -83,8 +78,4 @@ function i18nIdReplaceLoaderConfig(options, webpackContext) {
|
|
|
83
78
|
loader: i18nKeyReplaceLoaderPath,
|
|
84
79
|
options: loaderOptions
|
|
85
80
|
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
module.exports = {
|
|
89
|
-
i18nIdReplaceLoaderConfig
|
|
90
|
-
};
|
|
81
|
+
}
|
|
@@ -22,8 +22,8 @@ module.exports = function i18nIdReplaceLoader(source, map) {
|
|
|
22
22
|
const options = getOptions(this) || {};
|
|
23
23
|
const callback = this.async(); // Skip files in excluded paths
|
|
24
24
|
|
|
25
|
-
if (options.excludePaths) {
|
|
26
|
-
const shouldExclude = options.excludePaths.some(excludePath => resourcePath.includes(excludePath));
|
|
25
|
+
if (options.excludePaths && Array.isArray(options.excludePaths)) {
|
|
26
|
+
const shouldExclude = options.excludePaths.some(excludePath => typeof excludePath === 'string' && resourcePath.includes(excludePath));
|
|
27
27
|
|
|
28
28
|
if (shouldExclude) {
|
|
29
29
|
return callback(null, source, map);
|
|
@@ -31,18 +31,18 @@ module.exports = function i18nIdReplaceLoader(source, map) {
|
|
|
31
31
|
} // Only process files in included paths if specified
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
if (options.includePaths && options.includePaths.length > 0) {
|
|
35
|
-
const shouldInclude = options.includePaths.some(includePath => resourcePath.includes(includePath));
|
|
34
|
+
if (options.includePaths && Array.isArray(options.includePaths) && options.includePaths.length > 0) {
|
|
35
|
+
const shouldInclude = options.includePaths.some(includePath => typeof includePath === 'string' && resourcePath.includes(includePath));
|
|
36
36
|
|
|
37
37
|
if (!shouldInclude) {
|
|
38
38
|
return callback(null, source, map);
|
|
39
39
|
}
|
|
40
|
-
} //
|
|
40
|
+
} // Basic runtime validation - options should already be validated by config
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
if (!options.allI18nData || Object.keys(options.allI18nData).length === 0) {
|
|
44
44
|
return callback(new Error(`i18nIdReplaceLoader: 'allI18nData' option is missing or empty`));
|
|
45
|
-
} // Load numeric ID mapping
|
|
45
|
+
} // Load numeric ID mapping - paths already validated by config
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
let numericIdMap = options.numericIdMap;
|
|
@@ -57,7 +57,8 @@ module.exports = function i18nIdReplaceLoader(source, map) {
|
|
|
57
57
|
const parsed = JSON.parse(mapContent);
|
|
58
58
|
numericIdMap = parsed.originalKeyToNumericId || parsed;
|
|
59
59
|
}
|
|
60
|
-
} catch (e) {
|
|
60
|
+
} catch (e) {
|
|
61
|
+
return callback(new Error(`i18nIdReplaceLoader: Failed to load numeric map from ${options.numericMapPath}: ${e.message}`));
|
|
61
62
|
}
|
|
62
63
|
} // If no numeric map available, return source as-is
|
|
63
64
|
|
|
@@ -70,10 +71,11 @@ module.exports = function i18nIdReplaceLoader(source, map) {
|
|
|
70
71
|
// Parse the JavaScript/TypeScript source code
|
|
71
72
|
const ast = parser.parse(source, {
|
|
72
73
|
sourceType: 'module',
|
|
73
|
-
plugins: ['jsx', 'typescript'],
|
|
74
|
+
plugins: ['jsx', 'typescript', 'classProperties', 'optionalChaining', 'nullishCoalescingOperator'],
|
|
74
75
|
sourceFilename: resourcePath
|
|
75
76
|
});
|
|
76
|
-
let hasTransformations = false;
|
|
77
|
+
let hasTransformations = false;
|
|
78
|
+
let transformationCount = 0; // Traverse AST and replace i18n keys with numeric IDs
|
|
77
79
|
|
|
78
80
|
traverse(ast, {
|
|
79
81
|
StringLiteral(path) {
|
|
@@ -85,6 +87,7 @@ module.exports = function i18nIdReplaceLoader(source, map) {
|
|
|
85
87
|
const numericId = String(numericIdMap[node.value]);
|
|
86
88
|
path.replaceWith(t.stringLiteral(numericId));
|
|
87
89
|
hasTransformations = true;
|
|
90
|
+
transformationCount++;
|
|
88
91
|
}
|
|
89
92
|
}
|
|
90
93
|
|
|
@@ -102,6 +105,6 @@ module.exports = function i18nIdReplaceLoader(source, map) {
|
|
|
102
105
|
callback(null, source, map);
|
|
103
106
|
}
|
|
104
107
|
} catch (err) {
|
|
105
|
-
callback(err);
|
|
108
|
+
callback(new Error(`i18nIdReplaceLoader: Failed to process ${resourcePath}: ${err.message}`));
|
|
106
109
|
}
|
|
107
110
|
};
|
|
@@ -11,17 +11,26 @@ var _I18nNumericIndexHtmlInjectorPlugin = require("../custom_plugins/I18nNumeric
|
|
|
11
11
|
|
|
12
12
|
var _readI18nValues = require("../custom_plugins/I18nSplitPlugin/readI18nValues");
|
|
13
13
|
|
|
14
|
+
var _i18nOptionsValidator = require("../common/i18nOptionsValidator.js");
|
|
15
|
+
|
|
14
16
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
17
|
|
|
16
18
|
function configI18nNumericIndexPlugin(options) {
|
|
17
|
-
if (!
|
|
19
|
+
if (!options.i18nIndexing) {
|
|
18
20
|
return null;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
const i18nOpts = options.i18nIndexing;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const result = (0, _i18nOptionsValidator.validateI18nIndexingOptions)(i18nOpts);
|
|
27
|
+
|
|
28
|
+
if (result.skipValidation) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
} catch (error) {
|
|
32
|
+
throw new Error(`[I18nNumericIndexPlugin] ${error.message}`);
|
|
33
|
+
}
|
|
25
34
|
|
|
26
35
|
const emitFiles = i18nOpts.emitFiles !== undefined ? i18nOpts.emitFiles : true;
|
|
27
36
|
const injectHtml = i18nOpts.injectI18nUrlInIndex !== undefined ? i18nOpts.injectI18nUrlInIndex : true;
|
|
@@ -29,87 +38,55 @@ function configI18nNumericIndexPlugin(options) {
|
|
|
29
38
|
|
|
30
39
|
if (!emitFiles && !injectHtml && !hasCustomGroups) {
|
|
31
40
|
return [];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const requiredOptions = ['jsResourcePath', 'propertiesFolderPath', 'numericMapPath', 'jsonpFunc', 'htmlTemplateLabel', 'localeVarName'];
|
|
36
|
-
const missingOptions = requiredOptions.filter(opt => !i18nOpts[opt]);
|
|
41
|
+
}
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
console.warn(`[I18nNumericIndexPlugin] Missing required options: ${missingOptions.join(', ')}`);
|
|
40
|
-
return null;
|
|
41
|
-
} // Read i18n values
|
|
43
|
+
let i18nData;
|
|
42
44
|
|
|
45
|
+
try {
|
|
46
|
+
i18nData = (0, _readI18nValues.readI18nValues)({
|
|
47
|
+
jsResource: i18nOpts.jsResourcePath,
|
|
48
|
+
propertiesFolder: i18nOpts.propertiesFolderPath,
|
|
49
|
+
disableDefault: false
|
|
50
|
+
});
|
|
51
|
+
} catch (error) {
|
|
52
|
+
throw new Error(`[I18nNumericIndexPlugin] Failed to read i18n data: ${error.message}`);
|
|
53
|
+
}
|
|
43
54
|
|
|
44
55
|
const {
|
|
45
56
|
locales,
|
|
46
57
|
allI18nObject
|
|
47
|
-
} =
|
|
48
|
-
jsResource: i18nOpts.jsResourcePath,
|
|
49
|
-
propertiesFolder: i18nOpts.propertiesFolderPath,
|
|
50
|
-
disableDefault: false
|
|
51
|
-
}); // Ensure templates have [locale] placeholder
|
|
52
|
-
|
|
58
|
+
} = i18nData;
|
|
53
59
|
const numericTemplate = i18nOpts.numericFilenameTemplate || '[locale]/numeric.i18n.js';
|
|
54
60
|
const dynamicTemplate = i18nOpts.dynamicFilenameTemplate || '[locale]/dynamic.i18n.js';
|
|
55
|
-
|
|
56
|
-
if (!numericTemplate.includes('[locale]')) {
|
|
57
|
-
console.warn('[I18nNumericIndexPlugin] numericFilenameTemplate must include [locale] placeholder');
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (!dynamicTemplate.includes('[locale]')) {
|
|
62
|
-
console.warn('[I18nNumericIndexPlugin] dynamicFilenameTemplate must include [locale] placeholder');
|
|
63
|
-
return null;
|
|
64
|
-
} // Resolve singleFileTemplate if it's a function
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
let resolvedSingleFileTemplate = i18nOpts.singleFileTemplate || '[locale].js';
|
|
68
|
-
|
|
69
|
-
if (typeof i18nOpts.singleFileTemplate === 'function') {
|
|
70
|
-
resolvedSingleFileTemplate = i18nOpts.singleFileTemplate(isDevelopment);
|
|
71
|
-
} // Plugin options
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const numericIndexPluginOptions = {
|
|
75
|
-
enable: i18nOpts.enable,
|
|
61
|
+
const sharedOptions = {
|
|
76
62
|
outputFolder: i18nOpts.outputFolder || 'i18n-chunk',
|
|
63
|
+
numericFilenameTemplate: numericTemplate,
|
|
64
|
+
dynamicFilenameTemplate: dynamicTemplate,
|
|
65
|
+
singleFileTemplate: i18nOpts.singleFileTemplate,
|
|
66
|
+
singleFile: i18nOpts.singleFile || false,
|
|
67
|
+
includeContentHash: i18nOpts.includeContentHash || false
|
|
68
|
+
};
|
|
69
|
+
const numericIndexPluginOptions = { ...sharedOptions,
|
|
70
|
+
enable: i18nOpts.enable,
|
|
77
71
|
jsResourcePath: i18nOpts.jsResourcePath,
|
|
78
72
|
propertiesFolderPath: i18nOpts.propertiesFolderPath,
|
|
79
73
|
numericMapPath: i18nOpts.numericMapPath,
|
|
80
74
|
locales,
|
|
81
75
|
allI18nObject,
|
|
82
|
-
numericFilenameTemplate: numericTemplate,
|
|
83
|
-
dynamicFilenameTemplate: dynamicTemplate,
|
|
84
|
-
singleFileTemplate: resolvedSingleFileTemplate,
|
|
85
76
|
jsonpFunc: i18nOpts.jsonpFunc,
|
|
86
77
|
localeVarName: i18nOpts.localeVarName,
|
|
87
|
-
singleFile: i18nOpts.singleFile || false,
|
|
88
78
|
restrictToBaseKeys: i18nOpts.restrictToBaseKeys || false,
|
|
89
|
-
includeContentHash: i18nOpts.includeContentHash || false,
|
|
90
79
|
generateManifest: i18nOpts.generateManifest || false,
|
|
91
80
|
manifestPath: i18nOpts.manifestPath || null,
|
|
92
81
|
customGroups: i18nOpts.customGroups || null,
|
|
93
82
|
chunkToGroupMapping: i18nOpts.chunkToGroupMapping || {},
|
|
94
|
-
emitFiles
|
|
95
|
-
isDevelopment: isDevelopment,
|
|
83
|
+
emitFiles,
|
|
96
84
|
i18nPublicPathVar: i18nOpts.i18nPublicPathVar
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const htmlInjectorOptions = {
|
|
100
|
-
outputFolder: i18nOpts.outputFolder || 'i18n-chunk',
|
|
101
|
-
numericFilenameTemplate: numericTemplate,
|
|
102
|
-
dynamicFilenameTemplate: dynamicTemplate,
|
|
103
|
-
singleFileTemplate: resolvedSingleFileTemplate,
|
|
85
|
+
};
|
|
86
|
+
const htmlInjectorOptions = { ...sharedOptions,
|
|
104
87
|
htmlTemplateLabel: i18nOpts.htmlTemplateLabel,
|
|
105
|
-
singleFile: i18nOpts.singleFile || false,
|
|
106
88
|
i18nAssetsPublicPathPrefix: '',
|
|
107
|
-
injectI18nUrlInIndex:
|
|
108
|
-
// Control HTML injection
|
|
109
|
-
isDevelopment: isDevelopment,
|
|
110
|
-
includeContentHash: i18nOpts.includeContentHash || false
|
|
89
|
+
injectI18nUrlInIndex: injectHtml
|
|
111
90
|
};
|
|
112
|
-
|
|
113
|
-
const htmlInjectorPluginInstance = new _I18nNumericIndexHtmlInjectorPlugin.I18nNumericIndexHtmlInjectorPlugin(htmlInjectorOptions);
|
|
114
|
-
return [i18nNumericPluginInstance, htmlInjectorPluginInstance];
|
|
91
|
+
return [new _I18nNumericIndexPlugin.default(numericIndexPluginOptions), new _I18nNumericIndexHtmlInjectorPlugin.I18nNumericIndexHtmlInjectorPlugin(htmlInjectorOptions)];
|
|
115
92
|
}
|