@zohodesk/client_build_tool 0.0.11-exp.26.0 → 0.0.11-exp.28.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/README.md +0 -102
- package/README_backup.md +0 -102
- package/lib/schemas/defaultConfigValues.js +13 -29
- package/lib/schemas/defaultConfigValuesOnly.js +10 -14
- package/lib/shared/bundler/webpack/common/i18nOptionsValidator.js +144 -0
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nGroupRuntimeModule.js +130 -169
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexHtmlInjectorPlugin.js +47 -35
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexPlugin.js +200 -128
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/utils/i18nDataLoader.js +33 -59
- package/lib/shared/bundler/webpack/loaderConfigs/i18nIdReplaceLoaderConfig.js +28 -39
- package/lib/shared/bundler/webpack/loaders/i18nIdReplaceLoader.js +24 -60
- package/lib/shared/bundler/webpack/optimizationConfig.js +1 -4
- package/lib/shared/bundler/webpack/pluginConfigs/configI18nNumericIndexPlugin.js +40 -61
- package/lib/shared/bundler/webpack/plugins.js +1 -4
- package/package.json +1 -1
- package/docs/DYNAMIC_TEMPLATE_EXAMPLE.md +0 -129
- package/docs/I18N_NUMERIC_INDEXING_PLUGIN.md +0 -225
- package/docs/I18N_SINGLE_FILE_MODE.md +0 -126
- package/docs/client_build_tool_source_doc.md +0 -390
package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexPlugin.js
CHANGED
|
@@ -15,15 +15,34 @@ 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
|
|
|
22
22
|
const {
|
|
23
23
|
RawSource
|
|
24
24
|
} = _webpack.sources;
|
|
25
|
+
const assetStoreKey = Symbol.for('I18nNumericIndexPluginAssets');
|
|
25
26
|
const pluginName = 'I18nNumericIndexPlugin';
|
|
26
27
|
|
|
28
|
+
function buildChunkMappingFromGroups(customGroups) {
|
|
29
|
+
if (!customGroups) {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const mapping = {};
|
|
34
|
+
Object.entries(customGroups).forEach(([groupName, config]) => {
|
|
35
|
+
if (config && Array.isArray(config.chunks)) {
|
|
36
|
+
config.chunks.forEach(chunkName => {
|
|
37
|
+
if (chunkName && typeof chunkName === 'string') {
|
|
38
|
+
mapping[chunkName] = groupName;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return mapping;
|
|
44
|
+
}
|
|
45
|
+
|
|
27
46
|
class I18nNumericIndexPlugin {
|
|
28
47
|
constructor(options) {
|
|
29
48
|
this.options = { ...options,
|
|
@@ -33,40 +52,45 @@ class I18nNumericIndexPlugin {
|
|
|
33
52
|
generateManifest: options.generateManifest || false,
|
|
34
53
|
outputFolder: options.outputFolder || 'i18n-chunk',
|
|
35
54
|
manifestPath: options.manifestPath || null,
|
|
36
|
-
emitFiles: options.emitFiles !== undefined ? options.emitFiles : true
|
|
55
|
+
emitFiles: options.emitFiles !== undefined ? options.emitFiles : true,
|
|
56
|
+
chunkToGroupMapping: options.chunkToGroupMapping || {}
|
|
37
57
|
};
|
|
38
58
|
this.numericMap = {};
|
|
39
59
|
this.customGroups = {};
|
|
40
60
|
this.manifest = {};
|
|
61
|
+
this.groupAssetUrls = {};
|
|
62
|
+
this.preparedAssets = [];
|
|
63
|
+
this.assetsPrepared = false;
|
|
64
|
+
this.assetsEmitted = false;
|
|
65
|
+
this.groupChunkMapping = buildChunkMappingFromGroups(this.options.customGroups);
|
|
41
66
|
}
|
|
42
67
|
|
|
43
68
|
apply(compiler) {
|
|
44
|
-
//
|
|
69
|
+
// Build-time validation for critical file paths
|
|
70
|
+
this.validateCriticalFilePaths(compiler); // Detect webpackI18nGroup comments in code
|
|
71
|
+
|
|
45
72
|
this.detectI18nGroupComments(compiler);
|
|
46
73
|
compiler.hooks.thisCompilation.tap(pluginName, compilation => {
|
|
47
|
-
|
|
48
|
-
|
|
74
|
+
this.groupAssetUrls = {};
|
|
75
|
+
this.detectedGroups = {};
|
|
76
|
+
this.preparedAssets = [];
|
|
77
|
+
this.assetsPrepared = false;
|
|
78
|
+
this.assetsEmitted = false; // Add runtime module for group-based loading
|
|
49
79
|
|
|
50
80
|
if (this.options.customGroups) {
|
|
51
81
|
compilation.hooks.additionalTreeRuntimeRequirements.tap(pluginName, (chunk, set) => {
|
|
52
82
|
// Only add to the main/entry chunk to avoid duplication
|
|
53
83
|
if (chunk.name === 'main' || chunk.hasRuntime()) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const hasMapping = Object.keys(chunkMapping).length > 0;
|
|
57
|
-
|
|
58
|
-
if (hasMapping || !this._hasLoggedRuntime) {
|
|
59
|
-
console.log('[I18nNumericIndexPlugin] Adding runtime module to chunk:', chunk.name);
|
|
60
|
-
console.log('[I18nNumericIndexPlugin] Chunk mapping for runtime:', chunkMapping);
|
|
61
|
-
this._hasLoggedRuntime = true;
|
|
62
|
-
}
|
|
63
|
-
|
|
84
|
+
this.ensureAssetsPrepared(compilation);
|
|
85
|
+
const chunkMapping = this.getChunkIdToGroupMapping(compilation);
|
|
64
86
|
compilation.addRuntimeModule(chunk, new _I18nGroupRuntimeModule.I18nGroupRuntimeModule({
|
|
65
87
|
customGroups: this.options.customGroups,
|
|
66
88
|
chunkIdToGroupMapping: chunkMapping,
|
|
67
89
|
localeVarName: this.options.localeVarName,
|
|
68
90
|
jsonpFunc: this.options.jsonpFunc,
|
|
69
|
-
i18nPublicPathVar: this.options.i18nPublicPathVar
|
|
91
|
+
i18nPublicPathVar: this.options.i18nPublicPathVar,
|
|
92
|
+
groupAssetUrls: this.groupAssetUrls,
|
|
93
|
+
includeContentHash: this.options.includeContentHash
|
|
70
94
|
}));
|
|
71
95
|
}
|
|
72
96
|
});
|
|
@@ -76,49 +100,96 @@ class I18nNumericIndexPlugin {
|
|
|
76
100
|
name: pluginName,
|
|
77
101
|
stage: compilation.PROCESS_ASSETS_STAGE_OPTIMIZE
|
|
78
102
|
}, () => {
|
|
79
|
-
this.
|
|
103
|
+
this.ensureAssetsPrepared(compilation);
|
|
104
|
+
this.emitPreparedAssets(compilation);
|
|
80
105
|
});
|
|
81
106
|
});
|
|
82
107
|
}
|
|
83
108
|
|
|
109
|
+
validateCriticalFilePaths(compiler) {
|
|
110
|
+
const {
|
|
111
|
+
jsResourcePath,
|
|
112
|
+
propertiesFolderPath,
|
|
113
|
+
numericMapPath
|
|
114
|
+
} = this.options;
|
|
115
|
+
const missingPaths = [];
|
|
116
|
+
const resolvedPaths = []; // Check jsResourcePath (must exist)
|
|
117
|
+
|
|
118
|
+
if (jsResourcePath) {
|
|
119
|
+
const resolvedJsPath = _path.default.resolve(compiler.context, jsResourcePath);
|
|
120
|
+
|
|
121
|
+
resolvedPaths.push(`jsResourcePath: ${resolvedJsPath}`);
|
|
122
|
+
|
|
123
|
+
if (!_fs.default.existsSync(resolvedJsPath)) {
|
|
124
|
+
missingPaths.push(`jsResourcePath: ${resolvedJsPath}`);
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
missingPaths.push('jsResourcePath: [not configured]');
|
|
128
|
+
} // Check propertiesFolderPath (must exist)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
if (propertiesFolderPath) {
|
|
132
|
+
const resolvedPropsPath = _path.default.resolve(compiler.context, propertiesFolderPath);
|
|
133
|
+
|
|
134
|
+
resolvedPaths.push(`propertiesFolderPath: ${resolvedPropsPath}`);
|
|
135
|
+
|
|
136
|
+
if (!_fs.default.existsSync(resolvedPropsPath)) {
|
|
137
|
+
missingPaths.push(`propertiesFolderPath: ${resolvedPropsPath}`);
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
missingPaths.push('propertiesFolderPath: [not configured]');
|
|
141
|
+
} // Check numericMapPath (must exist)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
if (numericMapPath) {
|
|
145
|
+
const resolvedMapPath = _path.default.resolve(compiler.context, numericMapPath);
|
|
146
|
+
|
|
147
|
+
resolvedPaths.push(`numericMapPath: ${resolvedMapPath}`);
|
|
148
|
+
|
|
149
|
+
if (!_fs.default.existsSync(resolvedMapPath)) {
|
|
150
|
+
missingPaths.push(`numericMapPath: ${resolvedMapPath}`);
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
missingPaths.push('numericMapPath: [not configured]');
|
|
154
|
+
} // If any critical files are missing, fail the build immediately
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
if (missingPaths.length > 0) {
|
|
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
|
+
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
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
84
169
|
detectI18nGroupComments(compiler) {
|
|
85
|
-
console.log('[I18nNumericIndexPlugin] Setting up i18n group comment detection');
|
|
86
170
|
compiler.hooks.normalModuleFactory.tap(pluginName, factory => {
|
|
87
171
|
factory.hooks.parser.for('javascript/auto').tap(pluginName, parser => {
|
|
88
172
|
parser.hooks.importCall.tap(pluginName, expr => {
|
|
89
|
-
// Only log if comments exist to reduce noise
|
|
90
173
|
const comments = expr.leadingComments || [];
|
|
91
174
|
|
|
92
175
|
if (comments.length > 0) {
|
|
93
|
-
|
|
94
|
-
console.log('[I18nNumericIndexPlugin] Leading comments count:', comments.length);
|
|
95
|
-
comments.forEach((comment, index) => {
|
|
96
|
-
console.log(`[I18nNumericIndexPlugin] Comment ${index}:`, comment.value);
|
|
97
|
-
|
|
176
|
+
comments.forEach(comment => {
|
|
98
177
|
if (comment.value && comment.value.includes('webpackI18nGroup')) {
|
|
99
|
-
console.log('[I18nNumericIndexPlugin] Found webpackI18nGroup comment:', comment.value);
|
|
100
178
|
const match = comment.value.match(/webpackI18nGroup:\s*["']([^"']+)["']/);
|
|
101
179
|
|
|
102
180
|
if (match) {
|
|
103
181
|
const groupName = match[1];
|
|
104
|
-
console.log('[I18nNumericIndexPlugin] Extracted group name:', groupName); // Store this information for later use
|
|
105
182
|
|
|
106
183
|
if (!this.detectedGroups) {
|
|
107
184
|
this.detectedGroups = {};
|
|
108
|
-
}
|
|
109
|
-
|
|
185
|
+
}
|
|
110
186
|
|
|
111
187
|
const chunkNameMatch = comment.value.match(/webpackChunkName:\s*["']([^"']+)["']/);
|
|
112
188
|
|
|
113
189
|
if (chunkNameMatch) {
|
|
114
190
|
const chunkName = chunkNameMatch[1];
|
|
115
|
-
console.log('[I18nNumericIndexPlugin] Mapping chunk:', chunkName, '→', groupName);
|
|
116
191
|
this.detectedGroups[chunkName] = groupName;
|
|
117
|
-
} else {
|
|
118
|
-
console.log('[I18nNumericIndexPlugin] No webpackChunkName found in comment');
|
|
119
192
|
}
|
|
120
|
-
} else {
|
|
121
|
-
console.log('[I18nNumericIndexPlugin] webpackI18nGroup pattern did not match');
|
|
122
193
|
}
|
|
123
194
|
}
|
|
124
195
|
});
|
|
@@ -129,53 +200,33 @@ class I18nNumericIndexPlugin {
|
|
|
129
200
|
}
|
|
130
201
|
|
|
131
202
|
getChunkIdToGroupMapping(compilation) {
|
|
132
|
-
const chunkIdToGroup = {};
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
'preferencePopup': 'setup',
|
|
137
|
-
'auditloglist': 'setup'
|
|
138
|
-
};
|
|
139
|
-
let foundAnyMapping = false;
|
|
140
|
-
let hasRelevantChunks = false; // Process chunks to get their actual IDs and map to groups
|
|
203
|
+
const chunkIdToGroup = {};
|
|
204
|
+
const configuredMappings = { ...this.groupChunkMapping,
|
|
205
|
+
...(this.options.chunkToGroupMapping || {})
|
|
206
|
+
}; // Process chunks to get their actual IDs and map to groups
|
|
141
207
|
|
|
142
208
|
for (const chunk of compilation.chunks) {
|
|
143
|
-
const chunkName = chunk.name; //
|
|
144
|
-
|
|
145
|
-
if (chunkName && (chunkName.toLowerCase().includes('setup') || chunkName.toLowerCase().includes('preference') || chunkName.toLowerCase().includes('audit'))) {
|
|
146
|
-
hasRelevantChunks = true;
|
|
147
|
-
} // First try detected groups, then fallback to hardcoded mappings
|
|
148
|
-
|
|
209
|
+
const chunkName = chunk.name; // First try detected groups, then fall back to configured mappings
|
|
149
210
|
|
|
150
211
|
let groupName = null;
|
|
151
212
|
|
|
152
213
|
if (this.detectedGroups && this.detectedGroups[chunkName]) {
|
|
153
214
|
groupName = this.detectedGroups[chunkName];
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
} else if (hardcodedMappings[chunkName]) {
|
|
157
|
-
groupName = hardcodedMappings[chunkName];
|
|
158
|
-
console.log(`[I18nNumericIndexPlugin] Found hardcoded mapping: ${chunkName} → ${groupName} (ID: ${chunk.id})`);
|
|
159
|
-
foundAnyMapping = true;
|
|
215
|
+
} else if (configuredMappings[chunkName]) {
|
|
216
|
+
groupName = configuredMappings[chunkName];
|
|
160
217
|
}
|
|
161
218
|
|
|
162
219
|
if (groupName) {
|
|
163
220
|
chunkIdToGroup[chunk.id] = groupName;
|
|
164
221
|
}
|
|
165
|
-
} // Only log summary if we found mappings or relevant chunks
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (foundAnyMapping || hasRelevantChunks || compilation.chunks.size > 0) {
|
|
169
|
-
console.log('[I18nNumericIndexPlugin] Building chunk ID to group mapping');
|
|
170
|
-
console.log('[I18nNumericIndexPlugin] Detected groups:', this.detectedGroups);
|
|
171
|
-
console.log('[I18nNumericIndexPlugin] Total chunks in compilation:', compilation.chunks.size);
|
|
172
|
-
console.log('[I18nNumericIndexPlugin] Final chunk ID to group mapping:', chunkIdToGroup);
|
|
173
222
|
}
|
|
174
223
|
|
|
175
224
|
return chunkIdToGroup;
|
|
176
225
|
}
|
|
177
226
|
|
|
178
227
|
processI18nFiles(compilation) {
|
|
228
|
+
this.preparedAssets = [];
|
|
229
|
+
this.groupAssetUrls = {};
|
|
179
230
|
const {
|
|
180
231
|
jsResourcePath,
|
|
181
232
|
propertiesFolderPath,
|
|
@@ -188,14 +239,17 @@ class I18nNumericIndexPlugin {
|
|
|
188
239
|
|
|
189
240
|
if (!jsResourcePath || !propertiesFolderPath) {
|
|
190
241
|
return;
|
|
191
|
-
} //
|
|
242
|
+
} // Reset build-scoped caches so incremental builds don't carry stale data
|
|
243
|
+
|
|
192
244
|
|
|
245
|
+
this.numericMap = {};
|
|
246
|
+
this.manifest = {};
|
|
247
|
+
this.customGroups = {}; // Load existing numeric map if available
|
|
193
248
|
|
|
194
249
|
if (numericMapPath) {
|
|
195
250
|
const mapData = (0, _i18nDataLoader.loadNumericMap)(numericMapPath, compilation);
|
|
196
251
|
|
|
197
252
|
if (mapData && mapData.sortedKeys) {
|
|
198
|
-
// Initialize numericMap from existing data
|
|
199
253
|
mapData.sortedKeys.forEach((key, id) => {
|
|
200
254
|
if (key) {
|
|
201
255
|
this.numericMap[key] = id;
|
|
@@ -221,15 +275,9 @@ class I18nNumericIndexPlugin {
|
|
|
221
275
|
|
|
222
276
|
Object.keys(allI18nObject).forEach(loc => {
|
|
223
277
|
allI18nObject[loc] = this.normalizeObjectValues(allI18nObject[loc]);
|
|
224
|
-
}); // For en_US, use only JSResources
|
|
225
|
-
|
|
226
|
-
if (allI18nObject['en_US']) {
|
|
227
|
-
allI18nObject['en_US'] = jsResourceKeys;
|
|
228
|
-
} else {
|
|
229
|
-
// If en_US doesn't exist in the folder, create it from JSResources
|
|
230
|
-
allI18nObject['en_US'] = jsResourceKeys;
|
|
231
|
-
} // If requested, restrict all locales to base (English) keys only
|
|
278
|
+
}); // For en_US, use only JSResources
|
|
232
279
|
|
|
280
|
+
allI18nObject['en_US'] = jsResourceKeys; // If requested, restrict all locales to base (English) keys only
|
|
233
281
|
|
|
234
282
|
if (this.options.restrictToBaseKeys) {
|
|
235
283
|
const baseKeys = Object.keys(jsResourceKeys);
|
|
@@ -260,8 +308,11 @@ class I18nNumericIndexPlugin {
|
|
|
260
308
|
Object.keys(localeData).forEach(key => {
|
|
261
309
|
const value = localeData[key]; // Simple logic: if has numeric ID use it, otherwise it's dynamic
|
|
262
310
|
|
|
263
|
-
|
|
264
|
-
|
|
311
|
+
const numericId = this.numericMap[key];
|
|
312
|
+
const hasNumericId = numericId !== undefined && numericId !== null;
|
|
313
|
+
|
|
314
|
+
if (hasNumericId) {
|
|
315
|
+
const numericKey = String(numericId); // Check if belongs to a custom group
|
|
265
316
|
|
|
266
317
|
const belongsToGroup = this.getKeyGroup(key);
|
|
267
318
|
|
|
@@ -271,31 +322,29 @@ class I18nNumericIndexPlugin {
|
|
|
271
322
|
numericData[numericKey] = value;
|
|
272
323
|
}
|
|
273
324
|
} else {
|
|
274
|
-
// No numeric ID = dynamic key
|
|
325
|
+
// No numeric ID = dynamic key
|
|
275
326
|
dynamicData[key] = value;
|
|
276
327
|
}
|
|
277
328
|
}); // Handle single-file mode or separate files
|
|
278
329
|
|
|
279
330
|
if (this.options.singleFile) {
|
|
280
|
-
// Combine numeric and dynamic data into a single file
|
|
281
331
|
const combinedData = { ...numericData,
|
|
282
332
|
...dynamicData
|
|
283
333
|
};
|
|
284
334
|
|
|
285
335
|
if (Object.keys(combinedData).length > 0) {
|
|
286
|
-
// Use singleFileTemplate for combined file - no fileType suffix needed
|
|
287
336
|
const singleFileTemplate = this.options.singleFileTemplate || '[locale].js';
|
|
288
|
-
this.
|
|
337
|
+
this.prepareChunkAsset(compilation, singleFileTemplate, locale, combinedData, jsonpFunc, null, null);
|
|
289
338
|
}
|
|
290
339
|
} else {
|
|
291
340
|
// Emit numeric chunk
|
|
292
341
|
if (Object.keys(numericData).length > 0) {
|
|
293
|
-
this.
|
|
342
|
+
this.prepareChunkAsset(compilation, numericFilenameTemplate, locale, numericData, jsonpFunc, null, 'numeric');
|
|
294
343
|
} // Emit dynamic chunk
|
|
295
344
|
|
|
296
345
|
|
|
297
346
|
if (Object.keys(dynamicData).length > 0) {
|
|
298
|
-
this.
|
|
347
|
+
this.prepareChunkAsset(compilation, dynamicFilenameTemplate, locale, dynamicData, jsonpFunc, null, 'dynamic');
|
|
299
348
|
}
|
|
300
349
|
} // Emit custom group chunks (always separate)
|
|
301
350
|
|
|
@@ -305,7 +354,7 @@ class I18nNumericIndexPlugin {
|
|
|
305
354
|
|
|
306
355
|
if (groupConfig && Object.keys(data).length > 0) {
|
|
307
356
|
const groupTemplate = groupConfig.filenameTemplate || `[locale]/${groupName}.i18n.js`;
|
|
308
|
-
this.
|
|
357
|
+
this.prepareChunkAsset(compilation, groupTemplate, locale, data, jsonpFunc, groupName, `group-${groupName}`);
|
|
309
358
|
}
|
|
310
359
|
});
|
|
311
360
|
}); // Generate manifest file if enabled
|
|
@@ -314,9 +363,34 @@ class I18nNumericIndexPlugin {
|
|
|
314
363
|
const manifestPath = this.options.manifestPath || _path.default.join(this.options.outputFolder, 'manifest.json');
|
|
315
364
|
|
|
316
365
|
const manifestContent = JSON.stringify(this.manifest, null, 2);
|
|
317
|
-
|
|
318
|
-
|
|
366
|
+
this.preparedAssets.push({
|
|
367
|
+
outputPath: manifestPath,
|
|
368
|
+
source: new RawSource(manifestContent),
|
|
369
|
+
shouldEmit: true
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
ensureAssetsPrepared(compilation) {
|
|
375
|
+
if (this.assetsPrepared) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
this.processI18nFiles(compilation);
|
|
380
|
+
this.assetsPrepared = true;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
emitPreparedAssets(compilation) {
|
|
384
|
+
if (this.assetsEmitted) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
319
387
|
|
|
388
|
+
this.preparedAssets.forEach(asset => {
|
|
389
|
+
if (asset.shouldEmit !== false) {
|
|
390
|
+
compilation.emitAsset(asset.outputPath, asset.source);
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
this.assetsEmitted = true;
|
|
320
394
|
}
|
|
321
395
|
|
|
322
396
|
parseCustomGroups(jsResourcePath, customGroups) {
|
|
@@ -357,16 +431,6 @@ class I18nNumericIndexPlugin {
|
|
|
357
431
|
return null;
|
|
358
432
|
}
|
|
359
433
|
|
|
360
|
-
isDynamicKey(value) {
|
|
361
|
-
// Check if value contains placeholders like {0}, {1}, etc.
|
|
362
|
-
return /\{\d+\}/.test(value);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
getNumericKey(key) {
|
|
366
|
-
// Return numeric ID if it exists, null otherwise
|
|
367
|
-
return this.numericMap[key] ? String(this.numericMap[key]) : null;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
434
|
generateContentHash(content, compilation) {
|
|
371
435
|
const {
|
|
372
436
|
hashFunction,
|
|
@@ -382,31 +446,22 @@ class I18nNumericIndexPlugin {
|
|
|
382
446
|
|
|
383
447
|
constructFilePath(template, locale) {
|
|
384
448
|
const {
|
|
385
|
-
outputFolder
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
let filePath = template.replace(/\[locale\]/g, locale); // If template already contains outputFolder or starts with a path separator, use as-is
|
|
449
|
+
outputFolder
|
|
450
|
+
} = this.options;
|
|
451
|
+
const filePath = template.replace(/\[locale\]/g, locale); // If template already contains outputFolder or starts with path separator, use as-is
|
|
390
452
|
|
|
391
453
|
if (filePath.includes(outputFolder) || filePath.startsWith('/')) {
|
|
392
|
-
return filePath
|
|
393
|
-
} //
|
|
394
|
-
// put it directly in outputFolder without subdirectories
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
if (singleFile && !filePath.includes('/')) {
|
|
398
|
-
return _path.default.join(outputFolder, filePath).replace(/\\/g, '/');
|
|
399
|
-
} // For other cases, if template contains subdirectories, preserve them
|
|
454
|
+
return filePath;
|
|
455
|
+
} // Otherwise, join with outputFolder
|
|
400
456
|
|
|
401
457
|
|
|
402
458
|
return _path.default.join(outputFolder, filePath).replace(/\\/g, '/');
|
|
403
459
|
}
|
|
404
460
|
|
|
405
|
-
|
|
461
|
+
prepareChunkAsset(compilation, filenameTemplate, locale, data, jsonpFunc, groupName = null, fileType = null) {
|
|
406
462
|
if (!filenameTemplate || Object.keys(data).length === 0) {
|
|
407
463
|
return null;
|
|
408
|
-
}
|
|
409
|
-
|
|
464
|
+
}
|
|
410
465
|
|
|
411
466
|
const content = this.generateChunkContent(data, jsonpFunc, groupName);
|
|
412
467
|
let outputPath = this.constructFilePath(filenameTemplate, locale); // Handle [contenthash] placeholder in template
|
|
@@ -415,42 +470,59 @@ class I18nNumericIndexPlugin {
|
|
|
415
470
|
const contentHash = this.generateContentHash(content, compilation);
|
|
416
471
|
outputPath = outputPath.replace(/\[contenthash\]/g, contentHash);
|
|
417
472
|
} else if (this.options.includeContentHash) {
|
|
418
|
-
// Legacy: Add content hash before .js extension if includeContentHash is true
|
|
419
473
|
const contentHash = this.generateContentHash(content, compilation);
|
|
420
474
|
outputPath = outputPath.replace(/\.js$/, `.${contentHash}.js`);
|
|
421
475
|
} // Track in manifest if enabled
|
|
422
476
|
|
|
423
477
|
|
|
424
478
|
if (this.options.generateManifest) {
|
|
425
|
-
|
|
426
|
-
let manifestKey;
|
|
427
|
-
|
|
428
|
-
if (this.options.singleFile) {
|
|
429
|
-
// Just use locale.js without path or type suffix
|
|
430
|
-
manifestKey = `${locale}.js`;
|
|
431
|
-
} else {
|
|
432
|
-
// For multi-file mode, include the full path
|
|
433
|
-
const cleanName = this.constructFilePath(filenameTemplate, locale);
|
|
434
|
-
manifestKey = fileType ? cleanName.replace(/\.js$/, `.${fileType}.js`) : cleanName;
|
|
435
|
-
}
|
|
436
|
-
|
|
479
|
+
const manifestKey = this.options.singleFile ? `${locale}.js` : outputPath;
|
|
437
480
|
this.manifest[manifestKey] = _path.default.basename(outputPath);
|
|
438
|
-
}
|
|
481
|
+
}
|
|
439
482
|
|
|
483
|
+
const source = new RawSource(content);
|
|
484
|
+
const assetInfo = {
|
|
485
|
+
locale,
|
|
486
|
+
fileType,
|
|
487
|
+
outputPath,
|
|
488
|
+
filenameTemplate
|
|
489
|
+
};
|
|
490
|
+
this.registerEmittedAsset(compilation, assetInfo);
|
|
491
|
+
this.preparedAssets.push({
|
|
492
|
+
outputPath,
|
|
493
|
+
source,
|
|
494
|
+
shouldEmit: this.options.emitFiles,
|
|
495
|
+
info: assetInfo
|
|
496
|
+
});
|
|
497
|
+
return outputPath;
|
|
498
|
+
}
|
|
440
499
|
|
|
441
|
-
|
|
442
|
-
|
|
500
|
+
registerEmittedAsset(compilation, assetInfo) {
|
|
501
|
+
if (!Object.prototype.hasOwnProperty.call(compilation, assetStoreKey)) {
|
|
502
|
+
Object.defineProperty(compilation, assetStoreKey, {
|
|
503
|
+
configurable: true,
|
|
504
|
+
enumerable: false,
|
|
505
|
+
value: []
|
|
506
|
+
});
|
|
443
507
|
}
|
|
444
508
|
|
|
445
|
-
|
|
509
|
+
compilation[assetStoreKey].push(assetInfo);
|
|
510
|
+
|
|
511
|
+
if (assetInfo.fileType && assetInfo.fileType.startsWith('group-')) {
|
|
512
|
+
const groupName = assetInfo.fileType.slice('group-'.length);
|
|
513
|
+
|
|
514
|
+
if (!this.groupAssetUrls[groupName]) {
|
|
515
|
+
this.groupAssetUrls[groupName] = {};
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
this.groupAssetUrls[groupName][assetInfo.locale] = assetInfo.outputPath;
|
|
519
|
+
}
|
|
446
520
|
}
|
|
447
521
|
|
|
448
522
|
generateChunkContent(data, jsonpFunc, groupName) {
|
|
449
|
-
// Decode Unicode escapes to convert \uXXXX to actual characters
|
|
450
523
|
const jsonString = (0, _propertiesUtils.decodeUnicodeEscapes)(JSON.stringify(data));
|
|
451
524
|
|
|
452
525
|
if (groupName) {
|
|
453
|
-
// Include group name for lazy loading identification
|
|
454
526
|
return `${jsonpFunc}(${jsonString}, "${groupName}");`;
|
|
455
527
|
}
|
|
456
528
|
|
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,30 +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
|
|
33
|
+
const fileContent = _fs.default.readFileSync(numericMapPath, 'utf-8');
|
|
48
34
|
|
|
49
|
-
|
|
50
|
-
const
|
|
35
|
+
const parsedData = JSON.parse(fileContent);
|
|
36
|
+
const numericMap = parsedData.originalKeyToNumericId || parsedData;
|
|
37
|
+
const totalKeys = parsedData.totalKeysInMap || Object.keys(numericMap).length;
|
|
38
|
+
const values = Object.values(numericMap);
|
|
39
|
+
const maxId = Math.max(...values.map(id => typeof id === 'number' ? id : Number(id)));
|
|
51
40
|
const sortedKeys = new Array(maxId + 1);
|
|
52
41
|
Object.entries(numericMap).forEach(([key, id]) => {
|
|
53
42
|
sortedKeys[id] = key;
|
|
@@ -67,30 +56,26 @@ function loadNumericMap(numericMapPath, compilation) {
|
|
|
67
56
|
};
|
|
68
57
|
}
|
|
69
58
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Load all locale files from properties directory
|
|
72
|
-
*/
|
|
73
|
-
|
|
74
59
|
|
|
75
60
|
function loadAllLocaleFiles(propertiesPath, compilation, jsResourceBase) {
|
|
76
|
-
const allI18n = {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
locales.push('en_US');
|
|
61
|
+
const allI18n = {
|
|
62
|
+
en_US: jsResourceBase
|
|
63
|
+
};
|
|
64
|
+
const locales = ['en_US'];
|
|
81
65
|
|
|
82
66
|
try {
|
|
83
|
-
const files =
|
|
84
|
-
files.forEach(file => {
|
|
85
|
-
if (!file.endsWith('.properties')) return; // Match locale-specific property files
|
|
67
|
+
const files = _fs.default.readdirSync(propertiesPath);
|
|
86
68
|
|
|
69
|
+
files.forEach(file => {
|
|
70
|
+
if (!file.endsWith('.properties')) return;
|
|
87
71
|
const match = file.match(/^ApplicationResources_([a-z]{2}_[A-Z]{2})\.properties$/);
|
|
88
72
|
|
|
89
73
|
if (match) {
|
|
90
74
|
const locale = match[1];
|
|
91
|
-
const filePath = path.join(propertiesPath, file);
|
|
92
|
-
const localeData = loadPropertiesFile(filePath, compilation, `locale ${locale}`); // Merge with base resources
|
|
93
75
|
|
|
76
|
+
const filePath = _path.default.join(propertiesPath, file);
|
|
77
|
+
|
|
78
|
+
const localeData = loadPropertiesFile(filePath, compilation, `locale ${locale}`);
|
|
94
79
|
allI18n[locale] = { ...jsResourceBase,
|
|
95
80
|
...localeData
|
|
96
81
|
};
|
|
@@ -111,17 +96,13 @@ function loadAllLocaleFiles(propertiesPath, compilation, jsResourceBase) {
|
|
|
111
96
|
locales
|
|
112
97
|
};
|
|
113
98
|
}
|
|
114
|
-
/**
|
|
115
|
-
* Main loader function for i18n data
|
|
116
|
-
*/
|
|
117
|
-
|
|
118
99
|
|
|
119
100
|
function loadI18nData(options, compilation) {
|
|
120
|
-
const jsResourcePath =
|
|
121
|
-
const propertiesPath = path.resolve(compilation.compiler.context, options.propertiesFolderPath); // Load base JS resources
|
|
101
|
+
const jsResourcePath = _path.default.resolve(compilation.compiler.context, options.jsResourcePath);
|
|
122
102
|
|
|
123
|
-
const
|
|
103
|
+
const propertiesPath = _path.default.resolve(compilation.compiler.context, options.propertiesFolderPath);
|
|
124
104
|
|
|
105
|
+
const jsResourceBase = loadPropertiesFile(jsResourcePath, compilation, 'JS resources');
|
|
125
106
|
const {
|
|
126
107
|
allI18n,
|
|
127
108
|
locales
|
|
@@ -131,11 +112,4 @@ function loadI18nData(options, compilation) {
|
|
|
131
112
|
allI18n,
|
|
132
113
|
locales
|
|
133
114
|
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
module.exports = {
|
|
137
|
-
loadPropertiesFile,
|
|
138
|
-
loadNumericMap,
|
|
139
|
-
loadAllLocaleFiles,
|
|
140
|
-
loadI18nData
|
|
141
|
-
};
|
|
115
|
+
}
|