@zohodesk/client_build_tool 0.0.1-0.exp.0.0.3 → 0.0.1-0.exp.0.0.4

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.
@@ -181,18 +181,6 @@ var _default = {
181
181
  value: false,
182
182
  cli: 'i18n_idx_enable'
183
183
  },
184
- disableDefaultMerge: {
185
- value: false,
186
- cli: 'i18n_idx_disable_default_merge'
187
- },
188
- htmlTemplateLabel: {
189
- value: '{{--user-locale}}',
190
- cli: 'i18n_idx_html_template_label'
191
- },
192
- localeVarName: {
193
- value: 'window.userLangCode',
194
- cli: 'i18n_idx_locale_var_name'
195
- },
196
184
  jsResourcePath: {
197
185
  value: './deskapp/properties/JSResources.properties',
198
186
  cli: 'i18n_idx_js_resource_path'
@@ -201,20 +189,29 @@ var _default = {
201
189
  value: './deskapp/properties',
202
190
  cli: 'i18n_idx_properties_folder_path'
203
191
  },
204
- propertiesPattern: {
205
- value: ''
206
- },
207
192
  numericMapPath: {
208
193
  value: './deskapp/properties/i18n-numeric-map.json',
209
194
  cli: 'i18n_idx_numeric_map_path'
210
195
  },
196
+ numericFilenameTemplate: {
197
+ value: 'i18n-chunks/[locale]/numeric.[contenthash].js',
198
+ cli: 'i18n_idx_numeric_filename_template'
199
+ },
200
+ dynamicFilenameTemplate: {
201
+ value: 'i18n-chunks/[locale]/dynamic.[contenthash].js',
202
+ cli: 'i18n_idx_dynamic_filename_template'
203
+ },
211
204
  jsonpFunc: {
212
205
  value: 'window.loadI18nData',
213
206
  cli: 'i18n_idx_jsonp_func'
214
207
  },
215
- fallbackToHash: {
216
- value: true,
217
- cli: 'i18n_idx_fallback_to_hash'
208
+ htmlTemplateLabel: {
209
+ value: '{{--user-locale}}',
210
+ cli: 'i18n_idx_html_template_label'
211
+ },
212
+ localeVarName: {
213
+ value: 'window.userLangCode',
214
+ cli: 'i18n_idx_locale_var_name'
218
215
  }
219
216
  },
220
217
  publicFolders: ['...'],
@@ -98,16 +98,14 @@ var _default = {
98
98
  },
99
99
  i18nIndexing: {
100
100
  enable: false,
101
- disableDefaultMerge: false,
102
- htmlTemplateLabel: '{{--user-locale}}',
103
- localeVarName: 'window.userLangCode',
104
101
  jsResourcePath: './deskapp/properties/JSResources.properties',
105
102
  propertiesFolderPath: './deskapp/properties',
106
- propertiesPattern: '',
107
103
  numericMapPath: './deskapp/properties/i18n-numeric-map.json',
108
- numericJsonpFunc: 'window.loadI18nChunk',
109
- dynamicJsonpFunc: 'window.loadI18nChunk',
110
- fallbackToHash: true
104
+ numericFilenameTemplate: 'i18n-chunks/numeric/[locale]/numeric.[contenthash].js',
105
+ dynamicFilenameTemplate: 'i18n-chunks/dynamic/[locale]/dynamic.[contenthash].js',
106
+ jsonpFunc: 'window.loadI18nChunk',
107
+ htmlTemplateLabel: '{{--user-locale}}',
108
+ localeVarName: 'window.userLangCode'
111
109
  },
112
110
  publicFolders: ['...', {
113
111
  source: './deskapp/tp/',
@@ -9,20 +9,72 @@ const {
9
9
  Compilation
10
10
  } = require('webpack');
11
11
 
12
+ let createHashFunction; // Assuming "../I18nSplitPlugin/createHash" exists and exports createHash.
13
+ // If it might not, the original try-catch with a fallback was more robust.
14
+ // For this fix, I'm keeping your current simplified version.
15
+
12
16
  const {
13
17
  createHash
14
18
  } = require("../I18nSplitPlugin/createHash");
15
19
 
20
+ createHashFunction = createHash;
16
21
  const {
17
22
  RawSource
18
23
  } = sources;
19
24
  const pluginName = 'I18nNumericIndexPlugin';
20
25
 
26
+ function parseProperties(content) {
27
+ const lines = content.split(/\r?\n/);
28
+ const data = {};
29
+
30
+ for (let lineNum = 0; lineNum < lines.length; lineNum++) {
31
+ const line = lines[lineNum];
32
+ const trimmedLine = line.trim();
33
+
34
+ if (trimmedLine && !trimmedLine.startsWith('#') && !trimmedLine.startsWith('!')) {
35
+ const separatorIndex = trimmedLine.indexOf('=');
36
+
37
+ if (separatorIndex !== -1) {
38
+ // Ensure key is trimmed before use, especially if spaces can exist before '='
39
+ let key = trimmedLine.substring(0, separatorIndex).trim();
40
+ let value = trimmedLine.substring(separatorIndex + 1).trim();
41
+
42
+ if (key) {
43
+ // Decode Unicode escape sequences in both key and value
44
+ // Assumes input like "\\uXXXX" from properties file for \uXXXX
45
+ key = decodeUnicodeEscapes(key);
46
+ value = decodeUnicodeEscapes(value);
47
+ data[key] = value;
48
+ }
49
+ }
50
+ }
51
+ }
52
+
53
+ return {
54
+ data,
55
+ problematicLines: []
56
+ };
57
+ } // This function converts strings like "Hello \\u00E9" to "Hello é"
58
+
59
+
60
+ function decodeUnicodeEscapes(str) {
61
+ if (typeof str !== 'string') {
62
+ return str;
63
+ }
64
+
65
+ return str.replace(/\\u([0-9a-fA-F]{4})/g, (match, hex) => {
66
+ return String.fromCharCode(parseInt(hex, 16));
67
+ });
68
+ }
69
+
21
70
  class I18nNumericIndexPlugin {
22
- constructor(options) {
71
+ constructor(options = {}) {
23
72
  this.options = options;
24
- this.numericMap = null;
25
- this.numericMapPath = options.numericMapPath;
73
+ this.numericMap = null; // Default emitLiteralUnicode to true if not specified
74
+
75
+ if (typeof this.options.emitLiteralUnicode === 'undefined') {
76
+ this.options.emitLiteralUnicode = true;
77
+ }
26
78
  }
27
79
 
28
80
  loadNumericMapOnce(compilation) {
@@ -30,9 +82,12 @@ class I18nNumericIndexPlugin {
30
82
  return this.numericMap;
31
83
  }
32
84
 
85
+ const numericMapPathOpt = this.options.numericMapPath;
86
+ const numericMapPath = numericMapPathOpt ? path.resolve(compilation.compiler.context, numericMapPathOpt) : null;
87
+
33
88
  try {
34
- if (this.numericMapPath && fs.existsSync(this.numericMapPath)) {
35
- const fileContent = fs.readFileSync(this.numericMapPath, 'utf-8');
89
+ if (numericMapPath && fs.existsSync(numericMapPath)) {
90
+ const fileContent = fs.readFileSync(numericMapPath, 'utf-8');
36
91
  const parsedData = JSON.parse(fileContent);
37
92
 
38
93
  if (parsedData && parsedData.sortedOriginalKeys && parsedData.totalKeys !== undefined) {
@@ -40,24 +95,27 @@ class I18nNumericIndexPlugin {
40
95
  sortedOriginalKeys: parsedData.sortedOriginalKeys,
41
96
  totalKeys: parsedData.totalKeys
42
97
  };
43
- compilation.logger.info(`${pluginName}: Loaded numeric map from ${this.numericMapPath}.`);
44
98
  return this.numericMap;
45
99
  } else {
46
- compilation.logger.error(`${pluginName}: Invalid format in numeric map file at ${this.numericMapPath}.`);
100
+ compilation.warnings.push(new Error(`${pluginName}: numericMap file (${numericMapPath}) parsed but seems malformed. Using empty map.`));
47
101
  this.numericMap = {
48
102
  sortedOriginalKeys: [],
49
103
  totalKeys: 0
50
104
  };
51
105
  }
52
106
  } else {
53
- compilation.logger.warn(`${pluginName}: Numeric map path not provided or file not found at ${this.numericMapPath}.`);
107
+ if (numericMapPathOpt) {
108
+ // Only warn if a path was actually provided
109
+ compilation.warnings.push(new Error(`${pluginName}: numericMapPath (${numericMapPath}) not found. Using empty map.`));
110
+ }
111
+
54
112
  this.numericMap = {
55
113
  sortedOriginalKeys: [],
56
114
  totalKeys: 0
57
115
  };
58
116
  }
59
117
  } catch (err) {
60
- compilation.logger.error(`${pluginName}: Error loading numeric map from ${this.numericMapPath}: ${err.message}`);
118
+ compilation.errors.push(new Error(`${pluginName}: Error loading/parsing numericMapPath ${numericMapPath}: ${err.message}`));
61
119
  this.numericMap = {
62
120
  sortedOriginalKeys: [],
63
121
  totalKeys: 0
@@ -67,115 +125,258 @@ class I18nNumericIndexPlugin {
67
125
  return this.numericMap;
68
126
  }
69
127
 
70
- emitFile(compilation, baseFilenameTemplate, locale, fileContentData, jsonpFunc, typeSuffix = '') {
71
- const fileContent = `${jsonpFunc}(${JSON.stringify(fileContentData)});`;
128
+ loadAllI18nData(compilation) {
129
+ if (this.options.allI18nObject && this.options.locales) {
130
+ return {
131
+ allI18nObject: this.options.allI18nObject,
132
+ locales: this.options.locales
133
+ };
134
+ }
135
+
136
+ const allI18nObject = {};
137
+ const discoveredLocales = new Set();
138
+ const compilerContext = compilation.compiler.context;
139
+ const propertiesFolderPathOpt = this.options.propertiesFolderPath;
140
+ const jsResourcePathOpt = this.options.jsResourcePath;
141
+
142
+ if (!propertiesFolderPathOpt) {
143
+ compilation.errors.push(new Error(`${pluginName}: 'propertiesFolderPath' option is missing, cannot load translations.`));
144
+ return {
145
+ allI18nObject,
146
+ locales: []
147
+ };
148
+ }
149
+
150
+ const propertiesFolderPath = path.resolve(compilerContext, propertiesFolderPathOpt);
151
+ const baseJsResourcePath = jsResourcePathOpt ? path.resolve(compilerContext, jsResourcePathOpt) : null;
152
+
153
+ if (!fs.existsSync(propertiesFolderPath)) {
154
+ compilation.errors.push(new Error(`${pluginName}: propertiesFolderPath does not exist: ${propertiesFolderPath}`));
155
+ return {
156
+ allI18nObject,
157
+ locales: []
158
+ };
159
+ }
160
+
161
+ const baseFileName = baseJsResourcePath ? path.basename(baseJsResourcePath, path.extname(baseJsResourcePath)) : null;
162
+ const baseExtension = baseJsResourcePath ? path.extname(baseJsResourcePath) : '.properties';
163
+
164
+ try {
165
+ const files = fs.readdirSync(propertiesFolderPath);
166
+ files.forEach(file => {
167
+ const filePath = path.join(propertiesFolderPath, file);
168
+
169
+ if (fs.statSync(filePath).isFile()) {
170
+ let locale = null;
171
+ const ext = path.extname(file);
172
+ const nameWithoutExt = path.basename(file, ext);
173
+
174
+ if (baseFileName && nameWithoutExt.startsWith(baseFileName + '_')) {
175
+ locale = nameWithoutExt.substring((baseFileName + '_').length);
176
+ } else if (baseFileName && nameWithoutExt === baseFileName) {
177
+ locale = this.options.defaultLocaleForBaseFile || 'en';
178
+ } else if (!baseFileName && nameWithoutExt.includes('_')) {
179
+ // Generic pattern: messages_fr_CA.properties -> fr_CA
180
+ const parts = nameWithoutExt.split('_');
181
+
182
+ if (parts.length > 1) {
183
+ locale = parts.slice(1).join('_');
184
+ }
185
+ } else if (!baseFileName && !nameWithoutExt.includes('_') && ext.toLowerCase() === baseExtension.toLowerCase()) {
186
+ // Fallback for files like 'fr.properties' if no baseFileName is defined
187
+ locale = nameWithoutExt;
188
+ }
189
+
190
+ if (locale && ext.toLowerCase() === baseExtension.toLowerCase()) {
191
+ try {
192
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
193
+ const parseResult = parseProperties(fileContent);
194
+ allI18nObject[locale] = parseResult.data;
195
+ discoveredLocales.add(locale);
196
+ } catch (readErr) {
197
+ compilation.errors.push(new Error(`${pluginName}: Error reading/parsing properties file ${filePath}: ${readErr.message}`));
198
+ }
199
+ }
200
+ }
201
+ });
202
+ } catch (err) {
203
+ compilation.errors.push(new Error(`${pluginName}: Error reading propertiesFolderPath ${propertiesFolderPath}: ${err.message}`));
204
+ }
205
+
206
+ return {
207
+ allI18nObject,
208
+ locales: Array.from(discoveredLocales)
209
+ };
210
+ }
211
+
212
+ validateAndSanitizeData(data, chunkType, locale, compilation) {
213
+ // Placeholder for any future validation or sanitization logic
214
+ return data;
215
+ }
216
+
217
+ emitChunkFile(compilation, filenameTemplate, locale, fileContentData, jsonpFunc, chunkType) {
218
+ const dataToStringify = this.validateAndSanitizeData(fileContentData, chunkType, locale, compilation);
219
+ let stringifiedData;
220
+
221
+ try {
222
+ // JSON.stringify will escape non-ASCII characters to \uXXXX sequences
223
+ stringifiedData = JSON.stringify(dataToStringify, null, 0); // If emitLiteralUnicode is true (default), convert \uXXXX sequences back to actual Unicode characters
224
+ // This ensures the output file contains literal UTF-8 characters if desired.
225
+
226
+ if (this.options.emitLiteralUnicode) {
227
+ stringifiedData = decodeUnicodeEscapes(stringifiedData);
228
+ }
229
+ } catch (e) {
230
+ compilation.errors.push(new Error(`${pluginName}: Failed to stringify or post-process data for ${chunkType} chunk (${locale}): ${e.message}`));
231
+ return;
232
+ }
233
+
234
+ const fileContent = `${jsonpFunc}(${stringifiedData});`; // RawSource expects a string. If stringifiedData contains literal Unicode,
235
+ // fileContent will also, and Webpack handles UTF-8 output correctly.
236
+
72
237
  const source = new RawSource(fileContent);
73
- const actualContentHash = createHash({
74
- //
238
+ const actualContentHash = createHashFunction({
239
+ // Ensure createHashFunction is loaded
75
240
  outputOptions: compilation.outputOptions,
76
- content: fileContent
241
+ content: fileContent // Hash is based on the final content
242
+
77
243
  });
78
- let processedFilenameTemplate = baseFilenameTemplate.replace(/\[locale\]/g, locale).replace(/\[name\]/g, locale).replace(/\[id\]/g, locale);
244
+ let processedFilenameTemplate = filenameTemplate.replace(/\[locale\]/g, locale).replace(/\[name\]/g, locale).replace(/\[id\]/g, locale);
79
245
  const finalFileName = compilation.getAssetPath(processedFilenameTemplate, {
80
246
  locale: locale,
81
247
  contentHash: actualContentHash,
82
248
  hash: compilation.hash,
249
+ // Webpack compilation hash
83
250
  chunk: {
84
- id: `i18n-${typeSuffix || 'data'}-${locale}`,
85
- name: `${typeSuffix || 'data'}-${locale}`,
251
+ // Mock chunk object for placeholders
252
+ id: `i18n-${chunkType}-${locale}`,
253
+ name: `${chunkType}-${locale}`,
86
254
  hash: actualContentHash,
255
+ // Chunk-specific hash
87
256
  contentHash: {
88
- [this.options.moduleType || 'i18n/mini-extract']: actualContentHash
257
+ [this.options.moduleType || 'i18n/data-extract']: actualContentHash
89
258
  }
90
259
  },
91
- contentHashType: this.options.moduleType || 'i18n/mini-extract'
260
+ contentHashType: this.options.moduleType || 'i18n/data-extract'
92
261
  });
93
262
  compilation.emitAsset(finalFileName, source);
94
- compilation.logger.info(`${pluginName}: Emitted ${typeSuffix} i18n file for locale ${locale} to ${finalFileName}`);
95
263
  }
96
264
 
97
265
  apply(compiler) {
98
266
  compiler.hooks.thisCompilation.tap(pluginName, compilation => {
99
267
  compilation.hooks.processAssets.tapAsync({
100
268
  name: pluginName,
101
- stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE
269
+ stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE // Or a later stage if needed
270
+
102
271
  }, (assets, callback) => {
272
+ if (!this.options.enable) {
273
+ return callback();
274
+ }
275
+
103
276
  const {
104
- sortedOriginalKeys,
105
- totalKeys
106
- } = this.loadNumericMapOnce(compilation);
277
+ allI18nObject,
278
+ locales
279
+ } = this.loadAllI18nData(compilation);
107
280
 
108
- if (totalKeys === 0 && (!sortedOriginalKeys || sortedOriginalKeys.length === 0)) {
109
- compilation.logger.info(`${pluginName}: No numeric keys to process. Skipping numeric file emission.`);
281
+ if (!locales || locales.length === 0) {
282
+ if (this.options.propertiesFolderPath) {
283
+ // Only warn if path was given
284
+ compilation.warnings.push(new Error(`${pluginName}: No locales found or no translation data loaded from ${this.options.propertiesFolderPath}.`));
285
+ }
286
+
287
+ return callback();
110
288
  }
111
289
 
112
- const globallyUsedLiteralKeys = new Set();
290
+ const numericMapData = this.loadNumericMapOnce(compilation);
291
+ const sortedOriginalKeys = numericMapData.sortedOriginalKeys || [];
292
+ const totalKeys = numericMapData.totalKeys || 0;
113
293
  const globallyUsedCommentKeys = new Set();
114
294
 
115
295
  for (const module of compilation.modules) {
116
- if (module.buildInfo) {
117
- if (Array.isArray(module.buildInfo.loaderIdentifiedLiteralI18nKeys)) {
118
- module.buildInfo.loaderIdentifiedLiteralI18nKeys.forEach(key => globallyUsedLiteralKeys.add(key));
119
- }
120
-
121
- if (Array.isArray(module.buildInfo.loaderIdentifiedCommentI18nKeys)) {
122
- module.buildInfo.loaderIdentifiedCommentI18nKeys.forEach(key => globallyUsedCommentKeys.add(key));
123
- }
296
+ if (module.buildInfo && Array.isArray(module.buildInfo.loaderIdentifiedCommentI18nKeys)) {
297
+ module.buildInfo.loaderIdentifiedCommentI18nKeys.forEach(key => globallyUsedCommentKeys.add(key));
124
298
  }
125
299
  }
126
300
 
127
- compilation.logger.info(`${pluginName}: Globally identified Literal Keys: ${globallyUsedLiteralKeys.size}, Comment Keys: ${globallyUsedCommentKeys.size}`);
128
- const {
129
- locales,
130
- allI18nObject,
131
- numericFilenameTemplate,
132
- dynamicFilenameTemplate,
133
- numericJsonpFunc,
134
- dynamicJsonpFunc
135
- } = this.options;
136
-
137
- if (!locales || !allI18nObject || !numericFilenameTemplate || !dynamicFilenameTemplate || !numericJsonpFunc || !dynamicJsonpFunc) {
138
- compilation.errors.push(new Error(`${pluginName}: Missing some required options (locales, allI18nObject, filename templates, jsonp funcs).`));
139
- return callback();
301
+ const numericFilenameTemplate = this.options.numericFilenameTemplate;
302
+ const dynamicFilenameTemplate = this.options.dynamicFilenameTemplate;
303
+ const numericJsonpFunction = this.options.numericJsonpFunction || 'loadI18nNumericChunk';
304
+ const dynamicJsonpFunction = this.options.dynamicJsonpFunction || 'loadI18nDynamicChunk';
305
+
306
+ if (!numericFilenameTemplate) {
307
+ compilation.errors.push(new Error(`${pluginName}: Missing required option 'numericFilenameTemplate' in plugin options.`)); // return callback(); // Allow processing other chunks if one template is missing
308
+ }
309
+
310
+ if (!dynamicFilenameTemplate) {
311
+ compilation.errors.push(new Error(`${pluginName}: Missing required option 'dynamicFilenameTemplate' in plugin options.`)); // return callback();
312
+ }
313
+
314
+ if (typeof numericFilenameTemplate === 'string' && !numericFilenameTemplate.includes('[locale]') && !numericFilenameTemplate.includes('[name]') && !numericFilenameTemplate.includes('[id]')) {
315
+ compilation.warnings.push(new Error( // Changed to warning as it might be intentional for a single combined file not per-locale
316
+ `${pluginName}: The 'numericFilenameTemplate' ("${numericFilenameTemplate}") ` + `does not include '[locale]', '[name]', or '[id]'. All locales will overwrite the same file if multiple locales exist.`));
140
317
  }
141
318
 
142
- if (totalKeys > 0 && sortedOriginalKeys && sortedOriginalKeys.length > 0) {
143
- for (const locale of locales) {
144
- const localeTranslations = allI18nObject[locale] || {};
145
- const orderedNumericTranslations = new Array(totalKeys);
319
+ if (typeof dynamicFilenameTemplate === 'string' && !dynamicFilenameTemplate.includes('[locale]') && !dynamicFilenameTemplate.includes('[name]') && !dynamicFilenameTemplate.includes('[id]')) {
320
+ compilation.warnings.push(new Error(`${pluginName}: The 'dynamicFilenameTemplate' ("${dynamicFilenameTemplate}") ` + `does not include '[locale]', '[name]', or '[id]'. All locales will overwrite the same file if multiple locales exist.`));
321
+ }
322
+
323
+ const numericKeysSet = new Set(sortedOriginalKeys);
324
+
325
+ for (const locale of locales) {
326
+ const localeTranslations = allI18nObject[locale] || {};
327
+ const numericDataForLocale = []; // Fill numericDataForLocale based on sortedOriginalKeys
146
328
 
329
+ if (totalKeys > 0 && sortedOriginalKeys.length > 0) {
147
330
  for (let i = 0; i < totalKeys; i++) {
148
- const originalKey = sortedOriginalKeys[i];
331
+ // Iterate up to totalKeys (max expected length)
332
+ const originalKey = sortedOriginalKeys[i]; // Get key if available
333
+ // If originalKey is undefined (i < sortedOriginalKeys.length but originalKey is not there due to sparse array or shorter sortedKeys)
334
+ // or if the translation is missing, push null.
149
335
 
150
- if (globallyUsedLiteralKeys.has(originalKey)) {
151
- orderedNumericTranslations[i] = localeTranslations[originalKey] !== undefined ? localeTranslations[originalKey] : 0; // Use 0 or null as placeholder for missing keys
152
- } else {
153
- orderedNumericTranslations[i] = 0; // Placeholder for keys not identified as literals or not used
154
- }
336
+ const value = originalKey !== undefined && localeTranslations[originalKey] !== undefined ? localeTranslations[originalKey] : null;
337
+ numericDataForLocale.push(value);
155
338
  }
156
-
157
- this.emitFile(compilation, numericFilenameTemplate, locale, orderedNumericTranslations, numericJsonpFunc, 'numeric');
158
339
  }
159
- }
160
340
 
161
- if (globallyUsedCommentKeys.size > 0) {
162
- for (const locale of locales) {
163
- const localeTranslations = allI18nObject[locale] || {};
164
- const dynamicKeyTranslations = {};
165
- globallyUsedCommentKeys.forEach(originalKey => {
166
- if (localeTranslations[originalKey] !== undefined) {
167
- dynamicKeyTranslations[originalKey] = localeTranslations[originalKey];
168
- } else {
169
- dynamicKeyTranslations[originalKey] = null;
170
- }
171
- });
172
-
173
- if (Object.keys(dynamicKeyTranslations).length > 0) {
174
- this.emitFile(compilation, dynamicFilenameTemplate, locale, dynamicKeyTranslations, dynamicJsonpFunc, 'dynamic');
341
+ const dynamicDataForLocale = {}; // Process globally used comment keys first
342
+
343
+ globallyUsedCommentKeys.forEach(originalKey => {
344
+ if (!numericKeysSet.has(originalKey)) {
345
+ // Only if not already in numeric set
346
+ dynamicDataForLocale[originalKey] = localeTranslations[originalKey] !== undefined ? localeTranslations[originalKey] : null; // Explicitly null for missing keys referenced in comments
175
347
  }
348
+ }); // Process remaining keys from localeTranslations
349
+
350
+ Object.keys(localeTranslations).forEach(originalKey => {
351
+ // Add if not in numeric set AND not already added from globallyUsedCommentKeys
352
+ if (!numericKeysSet.has(originalKey) && !dynamicDataForLocale.hasOwnProperty(originalKey)) {
353
+ dynamicDataForLocale[originalKey] = localeTranslations[originalKey];
354
+ }
355
+ });
356
+
357
+ if (this.options.logKeyCounts && locale === (this.options.logKeyCountsForLocale || 'en_US')) {
358
+ const numericKeysWithValues = numericDataForLocale.filter(v => v !== null).length;
359
+ const numericKeysWithNullValues = numericDataForLocale.length - numericKeysWithValues;
360
+ const totalDynamicKeys = Object.keys(dynamicDataForLocale).length;
361
+ const dynamicKeysWithNullValues = Object.values(dynamicDataForLocale).filter(v => v === null).length;
362
+ const commentKeysInDynamic = Array.from(globallyUsedCommentKeys).filter(key => !numericKeysSet.has(key) && dynamicDataForLocale.hasOwnProperty(key)).length;
363
+ const jsResourceKeysInDynamic = totalDynamicKeys - commentKeysInDynamic;
364
+ console.log(`\n=== ${pluginName} KEY COUNTS FOR ${locale} ===`);
365
+ console.log(`📊 NUMERIC MAPPING: ${totalKeys} map size, ${sortedOriginalKeys.length} sorted keys provided`);
366
+ console.log(`📊 LOCALE TRANSLATIONS: ${Object.keys(localeTranslations).length} total keys for this locale`);
367
+ console.log(`📊 GLOBALLY USED COMMENT KEYS: ${globallyUsedCommentKeys.size} total, ${Array.from(globallyUsedCommentKeys).filter(k => numericKeysSet.has(k)).length} in numeric`);
368
+ console.log(`📊 NUMERIC CHUNK (${locale}): ${numericDataForLocale.length} items (${numericKeysWithValues} values, ${numericKeysWithNullValues} nulls)`);
369
+ console.log(`📊 DYNAMIC CHUNK (${locale}): ${totalDynamicKeys} items (${commentKeysInDynamic} from comments, ${jsResourceKeysInDynamic} from JS resources only, ${dynamicKeysWithNullValues} nulls)`);
370
+ console.log(`=== END KEY COUNTS ===\n`);
371
+ }
372
+
373
+ if (numericFilenameTemplate && numericDataForLocale.length > 0) {
374
+ this.emitChunkFile(compilation, numericFilenameTemplate, locale, numericDataForLocale, numericJsonpFunction, 'numeric');
375
+ }
376
+
377
+ if (dynamicFilenameTemplate && Object.keys(dynamicDataForLocale).length > 0) {
378
+ this.emitChunkFile(compilation, dynamicFilenameTemplate, locale, dynamicDataForLocale, dynamicJsonpFunction, 'dynamic');
176
379
  }
177
- } else {
178
- compilation.logger.info(`${pluginName}: No globally used comment keys found. Skipping dynamic file emission.`);
179
380
  }
180
381
 
181
382
  callback();
@@ -11,18 +11,20 @@ function loadJSResourcesOnce(options) {
11
11
  return allI18nDataFromPropertiesCache;
12
12
  }
13
13
 
14
- let resourcePathToLoad = '';
15
-
16
- if (options.i18nIndexing && options.i18nIndexing.enable && options.i18nIndexing.jsResourcePath) {
17
- resourcePathToLoad = options.i18nIndexing.jsResourcePath;
18
- } else if (options.i18nChunkSplit && options.i18nChunkSplit.jsResource) {
19
- resourcePathToLoad = options.i18nChunkSplit.jsResource;
20
- } else {
21
- allI18nDataFromPropertiesCache = {};
22
- return allI18nDataFromPropertiesCache;
14
+ if (!options.i18nIndexing || !options.i18nIndexing.enable) {
15
+ throw new Error('i18nIdReplaceLoader requires i18nIndexing to be enabled');
16
+ }
17
+
18
+ if (!options.i18nIndexing.jsResourcePath) {
19
+ throw new Error('Missing required jsResourcePath in i18nIndexing options');
20
+ }
21
+
22
+ const propertiesFilePath = path.resolve(process.cwd(), options.i18nIndexing.jsResourcePath);
23
+
24
+ if (!fs.existsSync(propertiesFilePath)) {
25
+ throw new Error(`JSResource file not found at: ${propertiesFilePath}`);
23
26
  }
24
27
 
25
- const propertiesFilePath = path.resolve(process.cwd(), resourcePathToLoad);
26
28
  const i18nData = {};
27
29
 
28
30
  try {
@@ -56,7 +58,12 @@ function loadJSResourcesOnce(options) {
56
58
  }
57
59
  }
58
60
  });
59
- } catch (err) {// Silent error handling
61
+ } catch (err) {
62
+ throw new Error(`Error reading JSResource file ${propertiesFilePath}: ${err.message}`);
63
+ }
64
+
65
+ if (Object.keys(i18nData).length === 0) {
66
+ throw new Error(`No i18n data found in JSResource file: ${propertiesFilePath}`);
60
67
  }
61
68
 
62
69
  allI18nDataFromPropertiesCache = i18nData;
@@ -64,25 +71,25 @@ function loadJSResourcesOnce(options) {
64
71
  }
65
72
 
66
73
  function i18nIdReplaceLoaderConfig(options) {
74
+ if (!options.i18nIndexing || !options.i18nIndexing.enable) {
75
+ throw new Error('i18nIdReplaceLoader requires i18nIndexing to be enabled');
76
+ }
77
+
78
+ if (!options.i18nIndexing.numericMapPath) {
79
+ throw new Error('Missing required numericMapPath in i18nIndexing options');
80
+ }
81
+
67
82
  const allI18nData = loadJSResourcesOnce(options);
68
83
 
69
84
  const i18nKeyReplaceLoaderPath = require.resolve('../loaders/i18nIdReplaceLoader.js');
70
85
 
71
86
  const loaderOptions = {
72
87
  allI18nData: allI18nData,
73
- sourceMaps: !!options.devtool && options.devtool.includes('source-map'),
74
- isDebug: options.mode === 'development'
88
+ sourceMaps: !!(options.devtool && options.devtool.includes('source-map')),
89
+ isDebug: options.mode === 'development',
90
+ useNumericIndexing: true,
91
+ numericMapPath: options.i18nIndexing.numericMapPath
75
92
  };
76
-
77
- if (options.i18nIndexing && options.i18nIndexing.enable) {
78
- loaderOptions.useNumericIndexing = true;
79
- loaderOptions.numericMapPath = options.i18nIndexing.numericMapPath;
80
- loaderOptions.fallbackToHash = options.i18nIndexing.fallbackToHash !== undefined ? options.i18nIndexing.fallbackToHash : true;
81
- } else {
82
- loaderOptions.useNumericIndexing = false;
83
- loaderOptions.fallbackToHash = true;
84
- }
85
-
86
93
  return {
87
94
  loader: i18nKeyReplaceLoaderPath,
88
95
  options: loaderOptions
@@ -16,18 +16,12 @@ const {
16
16
  getOptions
17
17
  } = require('loader-utils');
18
18
 
19
- let collectAndCategorizeUsedI18nKeys, generateShortHash;
19
+ let collectAndCategorizeUsedI18nKeys;
20
20
 
21
21
  try {
22
22
  collectAndCategorizeUsedI18nKeys = require('../custom_plugins/I18nSplitPlugin/utils/collectAstKeys').collectAndCategorizeUsedI18nKeys;
23
- generateShortHash = require('../common/hashUtils').generateShortHash;
24
23
  } catch (e) {
25
- collectAndCategorizeUsedI18nKeys = () => ({
26
- literalKeys: new Set(),
27
- commentKeys: new Set()
28
- });
29
-
30
- generateShortHash = key => key;
24
+ throw new Error('[i18nIdReplaceLoader] Required dependency not found: ' + e.message);
31
25
  }
32
26
 
33
27
  const LOADER_PREFIX = '[i18nIdReplaceLoader]';
@@ -36,34 +30,32 @@ let mapLoadAttemptedForPath = {};
36
30
 
37
31
  function loadNumericIdMap(loaderContext, mapPath) {
38
32
  if (!mapPath) {
39
- loaderContext.emitWarning(new Error(`${LOADER_PREFIX} Numeric map path not provided in loader options.`));
40
- return null;
33
+ throw new Error(`${LOADER_PREFIX} Numeric map path not provided in loader options.`);
41
34
  }
42
35
 
43
- if (numericIdMapDataCache && mapLoadAttemptedForPath[mapPath]) {
36
+ const absoluteMapPath = path.isAbsolute(mapPath) ? mapPath : path.resolve(loaderContext.rootContext || process.cwd(), mapPath);
37
+
38
+ if (numericIdMapDataCache && mapLoadAttemptedForPath[absoluteMapPath]) {
44
39
  return numericIdMapDataCache;
45
40
  }
46
41
 
47
- mapLoadAttemptedForPath[mapPath] = true;
42
+ mapLoadAttemptedForPath[absoluteMapPath] = true;
43
+
44
+ if (!fs.existsSync(absoluteMapPath)) {
45
+ throw new Error(`${LOADER_PREFIX} Pre-generated i18n numeric map file NOT FOUND at: ${absoluteMapPath}.`);
46
+ }
48
47
 
49
48
  try {
50
- if (fs.existsSync(mapPath)) {
51
- const fileContent = fs.readFileSync(mapPath, 'utf-8');
52
- const parsedData = JSON.parse(fileContent);
53
-
54
- if (parsedData && parsedData.originalKeyToNumericId && typeof parsedData.originalKeyToNumericId === 'object') {
55
- numericIdMapDataCache = parsedData.originalKeyToNumericId;
56
- } else {
57
- loaderContext.emitError(new Error(`${LOADER_PREFIX} Pre-generated map file (${mapPath}) is invalid or does not contain 'originalKeyToNumericId'.`));
58
- numericIdMapDataCache = null;
59
- }
60
- } else {
61
- loaderContext.emitError(new Error(`${LOADER_PREFIX} Pre-generated i18n numeric map file NOT FOUND at: ${mapPath}.`));
62
- numericIdMapDataCache = null;
49
+ const fileContent = fs.readFileSync(absoluteMapPath, 'utf-8');
50
+ const parsedData = JSON.parse(fileContent);
51
+
52
+ if (!parsedData || !parsedData.originalKeyToNumericId || typeof parsedData.originalKeyToNumericId !== 'object') {
53
+ throw new Error(`${LOADER_PREFIX} Pre-generated map file (${absoluteMapPath}) is invalid or does not contain 'originalKeyToNumericId'.`);
63
54
  }
55
+
56
+ numericIdMapDataCache = parsedData.originalKeyToNumericId;
64
57
  } catch (err) {
65
- loaderContext.emitError(new Error(`${LOADER_PREFIX} Error loading or parsing pre-generated i18n map from ${mapPath}: ${err.message}`));
66
- numericIdMapDataCache = null;
58
+ throw new Error(`${LOADER_PREFIX} Error loading or parsing pre-generated i18n map from ${absoluteMapPath}: ${err.message}`);
67
59
  }
68
60
 
69
61
  return numericIdMapDataCache;
@@ -77,23 +69,19 @@ module.exports = function i18nIdReplaceLoader(source, map, meta) {
77
69
  const loaderContext = this;
78
70
 
79
71
  if (!options.allI18nData || typeof options.allI18nData !== 'object' || Object.keys(options.allI18nData).length === 0) {
80
- this.emitWarning(new Error(`${LOADER_PREFIX} [${resourcePath}] 'allI18nData' option is missing or empty. No replacements will be made.`));
81
- return callback(null, source, map);
72
+ throw new Error(`${LOADER_PREFIX} [${resourcePath}] 'allI18nData' option is missing or empty.`);
82
73
  }
83
74
 
84
- let useNumericIndexing = options.useNumericIndexing !== undefined ? options.useNumericIndexing : true;
85
- let localOriginalKeyToNumericIdMap = null;
86
-
87
- if (useNumericIndexing) {
88
- localOriginalKeyToNumericIdMap = loadNumericIdMap(this, options.numericMapPath);
75
+ if (!options.useNumericIndexing) {
76
+ throw new Error(`${LOADER_PREFIX} [${resourcePath}] 'useNumericIndexing' must be enabled.`);
89
77
  }
90
78
 
91
- const fallbackToHash = options.fallbackToHash !== undefined ? options.fallbackToHash : true;
79
+ const numericIdMap = loadNumericIdMap(this, options.numericMapPath);
92
80
 
93
81
  try {
94
82
  const parserOptions = {
95
83
  sourceType: 'module',
96
- plugins: ['jsx', 'typescript', 'classProperties', 'optionalChaining', 'nullishCoalescingOperator'],
84
+ plugins: ['jsx', 'typescript', 'classProperties', 'optionalChaining', 'nullishCoalescingOperator', 'objectRestSpread', 'dynamicImport'],
97
85
  attachComment: true,
98
86
  sourceFilename: resourcePath
99
87
  };
@@ -119,9 +107,7 @@ module.exports = function i18nIdReplaceLoader(source, map, meta) {
119
107
  }
120
108
  }
121
109
 
122
- const keysToReplaceInLiterals = literalKeys;
123
-
124
- if (keysToReplaceInLiterals.size === 0) {
110
+ if (literalKeys.size === 0) {
125
111
  return callback(null, source, map);
126
112
  }
127
113
 
@@ -133,44 +119,25 @@ module.exports = function i18nIdReplaceLoader(source, map, meta) {
133
119
  if ((node.type === 'Literal' || node.type === 'StringLiteral') && typeof node.value === 'string') {
134
120
  const originalValue = node.value;
135
121
 
136
- if (keysToReplaceInLiterals.has(originalValue)) {
137
- let replaced = false;
122
+ if (literalKeys.has(originalValue)) {
123
+ const numericId = numericIdMap[originalValue];
138
124
 
139
- if (useNumericIndexing && localOriginalKeyToNumericIdMap) {
140
- const numericId = localOriginalKeyToNumericIdMap[originalValue];
125
+ if (numericId !== undefined) {
126
+ const numericLiteralNode = {
127
+ type: 'NumericLiteral',
128
+ value: numericId
129
+ };
130
+ let replacementNode = numericLiteralNode;
141
131
 
142
- if (numericId !== undefined) {
143
- const numericLiteralNode = {
144
- type: 'NumericLiteral',
145
- value: numericId
132
+ if (parent && parent.type === 'JSXAttribute' && parent.value === node) {
133
+ replacementNode = {
134
+ type: 'JSXExpressionContainer',
135
+ expression: numericLiteralNode
146
136
  };
147
- let replacementNode = numericLiteralNode;
148
-
149
- if (parent && parent.type === 'JSXAttribute' && parent.value === node) {
150
- replacementNode = {
151
- type: 'JSXExpressionContainer',
152
- expression: numericLiteralNode
153
- };
154
- }
155
-
156
- walkerControl.replace(replacementNode);
157
- replacementMade = true;
158
- replaced = true;
159
137
  }
160
- }
161
138
 
162
- if (!replaced && fallbackToHash) {
163
- try {
164
- const hashValue = generateShortHash(originalValue);
165
- const hashedStringLiteralNode = {
166
- type: 'StringLiteral',
167
- value: hashValue
168
- };
169
- walkerControl.replace(hashedStringLiteralNode);
170
- replacementMade = true;
171
- } catch (hashError) {
172
- loaderContext.emitError(new Error(`${LOADER_PREFIX} [${resourcePath}] Error hashing key "${originalValue}": ${hashError.message}`));
173
- }
139
+ walkerControl.replace(replacementNode);
140
+ replacementMade = true;
174
141
  }
175
142
  }
176
143
  }
@@ -179,7 +146,7 @@ module.exports = function i18nIdReplaceLoader(source, map, meta) {
179
146
 
180
147
  if (replacementMade) {
181
148
  const generateOptions = {
182
- sourceMaps: options.sourceMaps,
149
+ sourceMaps: !!options.sourceMaps,
183
150
  sourceFileName: resourcePath,
184
151
  retainLines: false,
185
152
  comments: true
@@ -192,7 +159,7 @@ module.exports = function i18nIdReplaceLoader(source, map, meta) {
192
159
  } catch (err) {
193
160
  const detailedError = new Error(`${LOADER_PREFIX} [${resourcePath}] AST Processing Error: ${err.message} (Stack: ${err.stack})`);
194
161
 
195
- if (err.loc) {
162
+ if (err.loc && err.loc.line) {
196
163
  detailedError.message += ` at line ${err.loc.line}, column ${err.loc.column}`;
197
164
  }
198
165
 
@@ -31,6 +31,18 @@ function urlJoin(...args) {
31
31
  return args.map(part => typeof part === 'string' ? part.replace(/(^\/+|\/+$)/g, '') : '').filter(part => part !== '').join('/');
32
32
  }
33
33
 
34
+ function validateAndGetFilenameTemplate(template, chunkType) {
35
+ if (!template || typeof template !== 'string') {
36
+ throw new Error(`Missing required ${chunkType} filename template in i18nIndexing options`);
37
+ }
38
+
39
+ if (!template.includes('[locale]')) {
40
+ throw new Error(`${chunkType} filename template must include '[locale]' placeholder: ${template}`);
41
+ }
42
+
43
+ return template;
44
+ }
45
+
34
46
  function configI18nNumericIndexPlugin(options) {
35
47
  if (!(options.i18nIndexing && options.i18nIndexing.enable)) {
36
48
  return null;
@@ -38,43 +50,52 @@ function configI18nNumericIndexPlugin(options) {
38
50
 
39
51
  const i18nOpts = options.i18nIndexing;
40
52
  const cdnConfig = options.cdnMapping || {};
53
+
54
+ if (!i18nOpts.jsResourcePath) {
55
+ throw new Error('Missing required jsResourcePath in i18nIndexing options');
56
+ }
57
+
58
+ if (!i18nOpts.propertiesFolderPath) {
59
+ throw new Error('Missing required propertiesFolderPath in i18nIndexing options');
60
+ }
61
+
62
+ if (!i18nOpts.numericMapPath) {
63
+ throw new Error('Missing required numericMapPath in i18nIndexing options');
64
+ }
65
+
66
+ if (!i18nOpts.jsonpFunc) {
67
+ throw new Error('Missing required jsonpFunc in i18nIndexing options');
68
+ }
69
+
70
+ if (!i18nOpts.htmlTemplateLabel) {
71
+ throw new Error('Missing required htmlTemplateLabel in i18nIndexing options');
72
+ }
73
+
74
+ if (!i18nOpts.localeVarName) {
75
+ throw new Error('Missing required localeVarName in i18nIndexing options');
76
+ }
77
+
78
+ console.log('I18n Indexing Options:', {
79
+ enable: i18nOpts.enable,
80
+ jsResourcePath: i18nOpts.jsResourcePath,
81
+ propertiesFolderPath: i18nOpts.propertiesFolderPath,
82
+ numericMapPath: i18nOpts.numericMapPath,
83
+ numericFilenameTemplate: i18nOpts.numericFilenameTemplate,
84
+ dynamicFilenameTemplate: i18nOpts.dynamicFilenameTemplate,
85
+ jsonpFunc: i18nOpts.jsonpFunc,
86
+ htmlTemplateLabel: i18nOpts.htmlTemplateLabel,
87
+ localeVarName: i18nOpts.localeVarName
88
+ });
41
89
  const {
42
90
  locales,
43
91
  allI18nObject
44
92
  } = readI18nValues({
45
93
  jsResource: i18nOpts.jsResourcePath,
46
94
  propertiesFolder: i18nOpts.propertiesFolderPath,
47
- disableDefault: i18nOpts.disableDefaultMerge !== undefined ? i18nOpts.disableDefaultMerge : false
95
+ disableDefault: false
48
96
  });
49
- const hardcodedDefaultNumericTemplate = 'i18n-chunks/[locale]/numeric.i18n.js';
50
- const hardcodedDefaultDynamicTemplate = 'i18n-chunks/[locale]/dynamic.i18n.js';
51
- let numericFilenameTemplate = i18nOpts.numericFilenameTemplate || hardcodedDefaultNumericTemplate;
52
- let dynamicFilenameTemplate = i18nOpts.dynamicFilenameTemplate || hardcodedDefaultDynamicTemplate;
53
-
54
- if (i18nOpts.numericFilenameTemplate === undefined) {
55
- // Check if explicitly undefined or missing
56
- const i18nSplitFilename = options.i18nChunkSplit && options.i18nChunkSplit.filename;
57
-
58
- if (i18nSplitFilename && typeof i18nSplitFilename === 'string') {
59
- // This adaptation logic might need to be more robust
60
- numericFilenameTemplate = `i18n-chunks/[locale]/${path.basename(i18nSplitFilename).replace(/(\.i18n)?\.js$/, '.numeric.i18n.js')}`;
61
- } else {
62
- numericFilenameTemplate = hardcodedDefaultNumericTemplate;
63
- }
64
- }
65
-
66
- if (i18nOpts.dynamicFilenameTemplate === undefined) {
67
- const i18nSplitFilename = options.i18nChunkSplit && options.i18nChunkSplit.filename;
68
-
69
- if (i18nSplitFilename && typeof i18nSplitFilename === 'string') {
70
- dynamicFilenameTemplate = `i18n-chunks/[locale]/${path.basename(i18nSplitFilename).replace(/(\.i18n)?\.js$/, '.dynamic.i18n.js')}`;
71
- } else {
72
- dynamicFilenameTemplate = hardcodedDefaultDynamicTemplate;
73
- }
74
- }
75
-
76
- const htmlTemplateLabel = i18nOpts.htmlTemplateLabel || '{{--user-locale}}';
77
- const defaultJsonpFunc = options.i18nChunkSplit && options.i18nChunkSplit.jsonpFunc || 'window.loadI18nChunk';
97
+ const numericFilenameTemplate = validateAndGetFilenameTemplate(i18nOpts.numericFilenameTemplate, 'numericFilenameTemplate');
98
+ const dynamicFilenameTemplate = validateAndGetFilenameTemplate(i18nOpts.dynamicFilenameTemplate, 'dynamicFilenameTemplate');
78
99
  let i18nAssetsPublicPathPrefix = '';
79
100
 
80
101
  if (cdnConfig.isCdnEnabled) {
@@ -90,24 +111,32 @@ function configI18nNumericIndexPlugin(options) {
90
111
  i18nAssetsPublicPathPrefix = urlConcat(options.publicPath === undefined ? '' : options.publicPath);
91
112
  }
92
113
 
93
- const pluginBaseOptions = {
114
+ const numericIndexPluginOptions = {
115
+ enable: i18nOpts.enable,
116
+ jsResourcePath: i18nOpts.jsResourcePath,
117
+ propertiesFolderPath: i18nOpts.propertiesFolderPath,
118
+ numericMapPath: i18nOpts.numericMapPath,
94
119
  locales,
95
120
  allI18nObject,
96
- numericMapPath: i18nOpts.numericMapPath,
97
- numericJsonpFunc: i18nOpts.numericJsonpFunc || defaultJsonpFunc,
98
- dynamicJsonpFunc: i18nOpts.dynamicJsonpFunc || defaultJsonpFunc,
99
- numericFilenameTemplate,
100
- // This will now include "i18n-chunks/[locale]/"
101
- dynamicFilenameTemplate,
102
- // This will now include "i18n-chunks/[locale]/"
103
- moduleType: 'i18n/mini-extract',
104
- mainChunkName: options.i18nChunkSplit && options.i18nChunkSplit.mainChunkName || 'main',
105
- htmlTemplateLabel,
106
- localeVarName: i18nOpts.localeVarName
121
+ numericFilenameTemplate: numericFilenameTemplate,
122
+ dynamicFilenameTemplate: dynamicFilenameTemplate,
123
+ numericJsonpFunction: i18nOpts.jsonpFunc,
124
+ dynamicJsonpFunction: i18nOpts.jsonpFunc,
125
+ moduleType: 'i18n/mini-extract'
107
126
  };
108
- const htmlInjectorOptions = { ...pluginBaseOptions,
127
+ const htmlInjectorOptions = {
128
+ locales,
129
+ numericFilenameTemplate: numericFilenameTemplate,
130
+ numericJsonpFunc: i18nOpts.jsonpFunc,
131
+ dynamicFilenameTemplate: dynamicFilenameTemplate,
132
+ dynamicJsonpFunc: i18nOpts.jsonpFunc,
133
+ mainChunkName: options.i18nChunkSplit && options.i18nChunkSplit.mainChunkName || 'main',
134
+ htmlTemplateLabel: i18nOpts.htmlTemplateLabel,
135
+ localeVarName: i18nOpts.localeVarName,
109
136
  i18nAssetsPublicPathPrefix: i18nAssetsPublicPathPrefix,
110
137
  cspNoncePlaceholder: i18nOpts.cspNoncePlaceholder || '{{--CSP-nonce}}'
111
138
  };
112
- return [new I18nNumericIndexPlugin(pluginBaseOptions), new I18nNumericIndexHtmlInjectorPlugin(htmlInjectorOptions)];
139
+ const i18nNumericPluginInstance = new I18nNumericIndexPlugin(numericIndexPluginOptions);
140
+ const htmlInjectorPluginInstance = new I18nNumericIndexHtmlInjectorPlugin(htmlInjectorOptions);
141
+ return [i18nNumericPluginInstance, htmlInjectorPluginInstance];
113
142
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zohodesk/client_build_tool",
3
- "version": "0.0.10.exp.0.0.3",
3
+ "version": "0.0.10.exp.0.0.4",
4
4
  "description": "A CLI tool to build web applications and client libraries",
5
5
  "main": "lib/index.js",
6
6
  "bin": {