@zohodesk/client_build_tool 0.0.1-0.exp.0.0.3 → 0.0.1-0.exp.0.0.8
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/schemas/defaultConfigValues.js +39 -19
- package/lib/schemas/defaultConfigValuesOnly.js +14 -8
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/CLAUDE.md +0 -0
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexPlugin.js +382 -75
- package/lib/shared/bundler/webpack/custom_plugins/I18nSplitPlugin/I18nFilesEmitPlugin.js +66 -5
- package/lib/shared/bundler/webpack/custom_plugins/I18nSplitPlugin/optionsHandler.js +3 -0
- package/lib/shared/bundler/webpack/custom_plugins/getInitialI18nAssetsArrayStr.js +6 -1
- package/lib/shared/bundler/webpack/loaderConfigs/i18nIdReplaceLoaderConfig.js +92 -61
- package/lib/shared/bundler/webpack/loaders/i18nIdReplaceLoader.js +151 -123
- package/lib/shared/bundler/webpack/pluginConfigs/configI18nNumericIndexPlugin.js +74 -45
- package/lib/shared/bundler/webpack/pluginConfigs/configI18nSplitPlugin.js +4 -1
- package/lib/shared/bundler/webpack/utils/propertiesParser.js +103 -0
- package/npm-shrinkwrap.json +8086 -21
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@ exports.configI18nNumericIndexPlugin = configI18nNumericIndexPlugin;
|
|
|
7
7
|
|
|
8
8
|
var {
|
|
9
9
|
I18nNumericIndexPlugin
|
|
10
|
-
} = require("
|
|
10
|
+
} = require("../custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexPlugin");
|
|
11
11
|
|
|
12
12
|
var {
|
|
13
13
|
I18nNumericIndexHtmlInjectorPlugin
|
|
@@ -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:
|
|
95
|
+
disableDefault: false
|
|
48
96
|
});
|
|
49
|
-
const
|
|
50
|
-
const
|
|
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
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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 = {
|
|
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
|
-
|
|
139
|
+
const i18nNumericPluginInstance = new I18nNumericIndexPlugin(numericIndexPluginOptions);
|
|
140
|
+
const htmlInjectorPluginInstance = new I18nNumericIndexHtmlInjectorPlugin(htmlInjectorOptions);
|
|
141
|
+
return [i18nNumericPluginInstance, htmlInjectorPluginInstance];
|
|
113
142
|
}
|
|
@@ -36,6 +36,9 @@ function configI18nSplitPlugin(options) {
|
|
|
36
36
|
publicPath: i18nPublicPath,
|
|
37
37
|
i18nManifestFileName: (0, _nameTemplates.nameTemplates)('i18nmanifest', options),
|
|
38
38
|
// template: (object, locale) => `window.loadI18n(${JSON.stringify(object)}, ${JSON.stringify(locale)})`,
|
|
39
|
-
propertiesFolder: i18nChunkSplit.propertiesFolder
|
|
39
|
+
propertiesFolder: i18nChunkSplit.propertiesFolder,
|
|
40
|
+
// NEW OPTIONS FOR NUMERIC INDEXING
|
|
41
|
+
useNumericIndexing: i18nChunkSplit.useNumericIndexing,
|
|
42
|
+
numericMapPath: i18nChunkSplit.numericMapPath
|
|
40
43
|
});
|
|
41
44
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared properties file parsing utility
|
|
4
|
+
* Handles consistent parsing across all i18n tools
|
|
5
|
+
*/
|
|
6
|
+
// Decode Unicode escape sequences (for values only)
|
|
7
|
+
|
|
8
|
+
function decodeUnicodeEscapes(str) {
|
|
9
|
+
if (typeof str !== 'string') {
|
|
10
|
+
return str;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return str.replace(/\\u([0-9a-fA-F]{4})/g, (match, hex) => {
|
|
14
|
+
return String.fromCharCode(parseInt(hex, 16));
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parse properties file content into key-value pairs
|
|
19
|
+
* @param {string} content - Properties file content
|
|
20
|
+
* @returns {Object} Parsed key-value pairs
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
function parseProperties(content) {
|
|
25
|
+
const lines = content.split(/\r?\n/);
|
|
26
|
+
const data = {};
|
|
27
|
+
lines.forEach(line => {
|
|
28
|
+
const trimmedLine = line.trim();
|
|
29
|
+
|
|
30
|
+
if (trimmedLine.startsWith('#') || trimmedLine.startsWith('!') || trimmedLine === '') {
|
|
31
|
+
return;
|
|
32
|
+
} // Find unescaped separator (= or :)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
let separatorIndex = -1;
|
|
36
|
+
|
|
37
|
+
for (let i = 0; i < trimmedLine.length; i++) {
|
|
38
|
+
if ((trimmedLine[i] === '=' || trimmedLine[i] === ':') && (i === 0 || trimmedLine[i - 1] !== '\\')) {
|
|
39
|
+
separatorIndex = i;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (separatorIndex > 0) {
|
|
45
|
+
let key = trimmedLine.substring(0, separatorIndex).trim();
|
|
46
|
+
let value = trimmedLine.substring(separatorIndex + 1).trim();
|
|
47
|
+
|
|
48
|
+
if (key) {
|
|
49
|
+
// Handle escaped spaces in keys only
|
|
50
|
+
key = key.replace(/\\ /g, ' '); // Decode Unicode escape sequences ONLY in values, not keys
|
|
51
|
+
|
|
52
|
+
value = decodeUnicodeEscapes(value);
|
|
53
|
+
data[key] = value;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return data;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Parse properties file content into a Set of keys only
|
|
61
|
+
* @param {string} content - Properties file content
|
|
62
|
+
* @returns {Set<string>} Set of keys
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
function parsePropertiesToKeySet(content) {
|
|
67
|
+
const lines = content.split(/\r?\n/);
|
|
68
|
+
const keys = new Set();
|
|
69
|
+
lines.forEach(line => {
|
|
70
|
+
const trimmedLine = line.trim();
|
|
71
|
+
|
|
72
|
+
if (trimmedLine.startsWith('#') || trimmedLine.startsWith('!') || trimmedLine === '') {
|
|
73
|
+
return;
|
|
74
|
+
} // Find unescaped separator (= or :)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
let separatorIndex = -1;
|
|
78
|
+
|
|
79
|
+
for (let i = 0; i < trimmedLine.length; i++) {
|
|
80
|
+
if ((trimmedLine[i] === '=' || trimmedLine[i] === ':') && (i === 0 || trimmedLine[i - 1] !== '\\')) {
|
|
81
|
+
separatorIndex = i;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (separatorIndex > 0) {
|
|
87
|
+
let key = trimmedLine.substring(0, separatorIndex).trim();
|
|
88
|
+
|
|
89
|
+
if (key) {
|
|
90
|
+
// Handle escaped spaces in keys only
|
|
91
|
+
key = key.replace(/\\ /g, ' ');
|
|
92
|
+
keys.add(key);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
return keys;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = {
|
|
100
|
+
parseProperties,
|
|
101
|
+
parsePropertiesToKeySet,
|
|
102
|
+
decodeUnicodeEscapes
|
|
103
|
+
};
|