@rushstack/webpack4-localization-plugin 0.14.5

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.
Files changed (53) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +292 -0
  3. package/dist/tsdoc-metadata.json +11 -0
  4. package/dist/webpack4-localization-plugin.d.ts +324 -0
  5. package/lib/AssetProcessor.d.ts +36 -0
  6. package/lib/AssetProcessor.d.ts.map +1 -0
  7. package/lib/AssetProcessor.js +306 -0
  8. package/lib/AssetProcessor.js.map +1 -0
  9. package/lib/LocalizationPlugin.d.ts +77 -0
  10. package/lib/LocalizationPlugin.d.ts.map +1 -0
  11. package/lib/LocalizationPlugin.js +597 -0
  12. package/lib/LocalizationPlugin.js.map +1 -0
  13. package/lib/WebpackConfigurationUpdater.d.ts +22 -0
  14. package/lib/WebpackConfigurationUpdater.d.ts.map +1 -0
  15. package/lib/WebpackConfigurationUpdater.js +136 -0
  16. package/lib/WebpackConfigurationUpdater.js.map +1 -0
  17. package/lib/index.d.ts +4 -0
  18. package/lib/index.d.ts.map +1 -0
  19. package/lib/index.js +8 -0
  20. package/lib/index.js.map +1 -0
  21. package/lib/interfaces.d.ts +219 -0
  22. package/lib/interfaces.d.ts.map +1 -0
  23. package/lib/interfaces.js +5 -0
  24. package/lib/interfaces.js.map +1 -0
  25. package/lib/loaders/InPlaceLocFileLoader.d.ts +4 -0
  26. package/lib/loaders/InPlaceLocFileLoader.d.ts.map +1 -0
  27. package/lib/loaders/InPlaceLocFileLoader.js +17 -0
  28. package/lib/loaders/InPlaceLocFileLoader.js.map +1 -0
  29. package/lib/loaders/LoaderFactory.d.ts +13 -0
  30. package/lib/loaders/LoaderFactory.d.ts.map +1 -0
  31. package/lib/loaders/LoaderFactory.js +41 -0
  32. package/lib/loaders/LoaderFactory.js.map +1 -0
  33. package/lib/loaders/LocLoader.d.ts +9 -0
  34. package/lib/loaders/LocLoader.d.ts.map +1 -0
  35. package/lib/loaders/LocLoader.js +36 -0
  36. package/lib/loaders/LocLoader.js.map +1 -0
  37. package/lib/utilities/Constants.d.ts +14 -0
  38. package/lib/utilities/Constants.d.ts.map +1 -0
  39. package/lib/utilities/Constants.js +44 -0
  40. package/lib/utilities/Constants.js.map +1 -0
  41. package/lib/utilities/EntityMarker.d.ts +13 -0
  42. package/lib/utilities/EntityMarker.d.ts.map +1 -0
  43. package/lib/utilities/EntityMarker.js +19 -0
  44. package/lib/utilities/EntityMarker.js.map +1 -0
  45. package/lib/utilities/LoaderTerminalProvider.d.ts +6 -0
  46. package/lib/utilities/LoaderTerminalProvider.d.ts.map +1 -0
  47. package/lib/utilities/LoaderTerminalProvider.js +28 -0
  48. package/lib/utilities/LoaderTerminalProvider.js.map +1 -0
  49. package/lib/webpackInterfaces.d.ts +10 -0
  50. package/lib/webpackInterfaces.d.ts.map +1 -0
  51. package/lib/webpackInterfaces.js +5 -0
  52. package/lib/webpackInterfaces.js.map +1 -0
  53. package/package.json +51 -0
@@ -0,0 +1,306 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
3
+ // See LICENSE in the project root for license information.
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
17
+ }) : function(o, v) {
18
+ o["default"] = v;
19
+ });
20
+ var __importStar = (this && this.__importStar) || function (mod) {
21
+ if (mod && mod.__esModule) return mod;
22
+ var result = {};
23
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
24
+ __setModuleDefault(result, mod);
25
+ return result;
26
+ };
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.AssetProcessor = exports.PLACEHOLDER_REGEX = void 0;
29
+ const lodash = __importStar(require("lodash"));
30
+ const Constants_1 = require("./utilities/Constants");
31
+ exports.PLACEHOLDER_REGEX = new RegExp(`${Constants_1.Constants.STRING_PLACEHOLDER_PREFIX}_(\\\\*)_([A-C])(\\+[^+]+\\+)?_(\\d+)`, 'g');
32
+ class AssetProcessor {
33
+ static processLocalizedAsset(options) {
34
+ const assetSource = options.asset.source();
35
+ const parsedAsset = AssetProcessor._parseStringToReconstructionSequence(options.plugin, assetSource, this._getJsonpFunction(options.chunk, options.chunkHasLocalizedModules, options.noStringsLocaleName));
36
+ const reconstructedAsset = AssetProcessor._reconstructLocalized(parsedAsset.reconstructionSeries, options.locales, options.fillMissingTranslationStrings, options.defaultLocale, options.asset.size());
37
+ const parsedAssetName = AssetProcessor._parseStringToReconstructionSequence(options.plugin, options.assetName, () => {
38
+ throw new Error('unsupported');
39
+ });
40
+ const reconstructedAssetName = AssetProcessor._reconstructLocalized(parsedAssetName.reconstructionSeries, options.locales, options.fillMissingTranslationStrings, options.defaultLocale, options.assetName.length);
41
+ const result = new Map();
42
+ for (const [locale, { source, size }] of reconstructedAsset.result) {
43
+ const newAsset = lodash.clone(options.asset);
44
+ newAsset.source = () => source;
45
+ newAsset.size = () => size;
46
+ result.set(locale, {
47
+ filename: reconstructedAssetName.result.get(locale).source,
48
+ asset: newAsset
49
+ });
50
+ }
51
+ const issues = [
52
+ ...parsedAsset.issues,
53
+ ...reconstructedAsset.issues,
54
+ ...parsedAssetName.issues,
55
+ ...reconstructedAssetName.issues
56
+ ];
57
+ if (issues.length > 0) {
58
+ options.compilation.errors.push(Error(`localization:\n${issues.map((issue) => ` ${issue}`).join('\n')}`));
59
+ }
60
+ return result;
61
+ }
62
+ static processNonLocalizedAsset(options) {
63
+ const assetSource = options.asset.source();
64
+ const parsedAsset = AssetProcessor._parseStringToReconstructionSequence(options.plugin, assetSource, this._getJsonpFunction(options.chunk, options.chunkHasLocalizedModules, options.noStringsLocaleName));
65
+ const reconstructedAsset = AssetProcessor._reconstructNonLocalized(parsedAsset.reconstructionSeries, options.asset.size(), options.noStringsLocaleName);
66
+ const parsedAssetName = AssetProcessor._parseStringToReconstructionSequence(options.plugin, options.assetName, () => {
67
+ throw new Error('unsupported');
68
+ });
69
+ const reconstructedAssetName = AssetProcessor._reconstructNonLocalized(parsedAssetName.reconstructionSeries, options.assetName.length, options.noStringsLocaleName);
70
+ const issues = [
71
+ ...parsedAsset.issues,
72
+ ...reconstructedAsset.issues,
73
+ ...parsedAssetName.issues,
74
+ ...reconstructedAssetName.issues
75
+ ];
76
+ if (issues.length > 0) {
77
+ options.compilation.errors.push(Error(`localization:\n${issues.map((issue) => ` ${issue}`).join('\n')}`));
78
+ }
79
+ const newAsset = lodash.clone(options.asset);
80
+ newAsset.source = () => reconstructedAsset.result.source;
81
+ newAsset.size = () => reconstructedAsset.result.size;
82
+ return {
83
+ filename: reconstructedAssetName.result.source,
84
+ asset: newAsset
85
+ };
86
+ }
87
+ static _reconstructLocalized(reconstructionSeries, locales, fillMissingTranslationStrings, defaultLocale, initialSize) {
88
+ const localizedResults = new Map();
89
+ const issues = [];
90
+ for (const locale of locales) {
91
+ const reconstruction = [];
92
+ let sizeDiff = 0;
93
+ for (const element of reconstructionSeries) {
94
+ switch (element.kind) {
95
+ case 'static': {
96
+ reconstruction.push(element.staticString);
97
+ break;
98
+ }
99
+ case 'localized': {
100
+ const localizedElement = element;
101
+ let newValue = localizedElement.values[locale];
102
+ if (!newValue) {
103
+ if (fillMissingTranslationStrings) {
104
+ newValue = localizedElement.values[defaultLocale];
105
+ }
106
+ else {
107
+ issues.push(`The string "${localizedElement.stringName}" in "${localizedElement.locFilePath}" is missing in ` +
108
+ `the locale ${locale}`);
109
+ newValue = '-- MISSING STRING --';
110
+ }
111
+ }
112
+ const escapedBackslash = localizedElement.escapedBackslash || '\\';
113
+ // Replace backslashes with the properly escaped backslash
114
+ newValue = newValue.replace(/\\/g, escapedBackslash);
115
+ // @todo: look into using JSON.parse(...) to get the escaping characters
116
+ const escapingCharacterSequence = escapedBackslash.substr(escapedBackslash.length / 2);
117
+ // Ensure the the quotemark, apostrophe, tab, and newline characters are properly escaped
118
+ newValue = newValue.replace(/\r/g, `${escapingCharacterSequence}r`);
119
+ newValue = newValue.replace(/\n/g, `${escapingCharacterSequence}n`);
120
+ newValue = newValue.replace(/\t/g, `${escapingCharacterSequence}t`);
121
+ newValue = newValue.replace(/\"/g, `${escapingCharacterSequence}u0022`);
122
+ newValue = newValue.replace(/\'/g, `${escapingCharacterSequence}u0027`);
123
+ reconstruction.push(newValue);
124
+ sizeDiff += newValue.length - localizedElement.size;
125
+ break;
126
+ }
127
+ case 'dynamic': {
128
+ const dynamicElement = element;
129
+ const newValue = dynamicElement.valueFn(locale, dynamicElement.token);
130
+ reconstruction.push(newValue);
131
+ sizeDiff += newValue.length - dynamicElement.size;
132
+ break;
133
+ }
134
+ }
135
+ }
136
+ const newAssetSource = reconstruction.join('');
137
+ localizedResults.set(locale, {
138
+ source: newAssetSource,
139
+ size: initialSize + sizeDiff
140
+ });
141
+ }
142
+ return {
143
+ issues,
144
+ result: localizedResults
145
+ };
146
+ }
147
+ static _reconstructNonLocalized(reconstructionSeries, initialSize, noStringsLocaleName) {
148
+ const issues = [];
149
+ const reconstruction = [];
150
+ let sizeDiff = 0;
151
+ for (const element of reconstructionSeries) {
152
+ switch (element.kind) {
153
+ case 'static': {
154
+ reconstruction.push(element.staticString);
155
+ break;
156
+ }
157
+ case 'localized': {
158
+ const localizedElement = element;
159
+ issues.push(`The string "${localizedElement.stringName}" in "${localizedElement.locFilePath}" appeared in an asset ` +
160
+ 'that is not expected to contain localized resources.');
161
+ const newValue = '-- NOT EXPECTED TO BE LOCALIZED --';
162
+ reconstruction.push(newValue);
163
+ sizeDiff += newValue.length - localizedElement.size;
164
+ break;
165
+ }
166
+ case 'dynamic': {
167
+ const dynamicElement = element;
168
+ const newValue = dynamicElement.valueFn(noStringsLocaleName, dynamicElement.token);
169
+ reconstruction.push(newValue);
170
+ sizeDiff += newValue.length - dynamicElement.size;
171
+ break;
172
+ }
173
+ }
174
+ }
175
+ const newAssetSource = reconstruction.join('');
176
+ return {
177
+ issues,
178
+ result: {
179
+ source: newAssetSource,
180
+ size: initialSize + sizeDiff
181
+ }
182
+ };
183
+ }
184
+ static _parseStringToReconstructionSequence(plugin, source, jsonpFunction) {
185
+ const issues = [];
186
+ const reconstructionSeries = [];
187
+ let lastIndex = 0;
188
+ let regexResult;
189
+ while ((regexResult = exports.PLACEHOLDER_REGEX.exec(source))) {
190
+ // eslint-disable-line no-cond-assign
191
+ const staticElement = {
192
+ kind: 'static',
193
+ staticString: source.substring(lastIndex, regexResult.index)
194
+ };
195
+ reconstructionSeries.push(staticElement);
196
+ const [placeholder, escapedBackslash, elementLabel, token, placeholderSerialNumber] = regexResult;
197
+ let localizedReconstructionElement;
198
+ switch (elementLabel) {
199
+ case Constants_1.Constants.STRING_PLACEHOLDER_LABEL: {
200
+ const stringData = plugin.getDataForSerialNumber(placeholderSerialNumber);
201
+ if (!stringData) {
202
+ issues.push(`Missing placeholder ${placeholder}`);
203
+ const brokenLocalizedElement = {
204
+ kind: 'static',
205
+ staticString: placeholder
206
+ };
207
+ localizedReconstructionElement = brokenLocalizedElement;
208
+ }
209
+ else {
210
+ const localizedElement = {
211
+ kind: 'localized',
212
+ values: stringData.values,
213
+ size: placeholder.length,
214
+ locFilePath: stringData.locFilePath,
215
+ escapedBackslash: escapedBackslash,
216
+ stringName: stringData.stringName
217
+ };
218
+ localizedReconstructionElement = localizedElement;
219
+ }
220
+ break;
221
+ }
222
+ case Constants_1.Constants.LOCALE_NAME_PLACEHOLDER_LABEL: {
223
+ const dynamicElement = {
224
+ kind: 'dynamic',
225
+ valueFn: (locale) => locale,
226
+ size: placeholder.length,
227
+ escapedBackslash: escapedBackslash
228
+ };
229
+ localizedReconstructionElement = dynamicElement;
230
+ break;
231
+ }
232
+ case Constants_1.Constants.JSONP_PLACEHOLDER_LABEL: {
233
+ const dynamicElement = {
234
+ kind: 'dynamic',
235
+ valueFn: jsonpFunction,
236
+ size: placeholder.length,
237
+ escapedBackslash: escapedBackslash,
238
+ token: token.substring(1, token.length - 1)
239
+ };
240
+ localizedReconstructionElement = dynamicElement;
241
+ break;
242
+ }
243
+ default: {
244
+ throw new Error(`Unexpected label ${elementLabel}`);
245
+ }
246
+ }
247
+ reconstructionSeries.push(localizedReconstructionElement);
248
+ lastIndex = regexResult.index + placeholder.length;
249
+ }
250
+ const lastElement = {
251
+ kind: 'static',
252
+ staticString: source.substr(lastIndex)
253
+ };
254
+ reconstructionSeries.push(lastElement);
255
+ return {
256
+ issues,
257
+ reconstructionSeries
258
+ };
259
+ }
260
+ static _getJsonpFunction(chunk, chunkHasLocalizedModules, noStringsLocaleName) {
261
+ const idsWithStrings = new Set();
262
+ const idsWithoutStrings = new Set();
263
+ const asyncChunks = chunk.getAllAsyncChunks();
264
+ for (const asyncChunk of asyncChunks) {
265
+ const chunkId = asyncChunk.id;
266
+ if (chunkId === null || chunkId === undefined) {
267
+ throw new Error(`Chunk "${asyncChunk.name}"'s ID is null or undefined.`);
268
+ }
269
+ if (chunkHasLocalizedModules(asyncChunk)) {
270
+ idsWithStrings.add(chunkId);
271
+ }
272
+ else {
273
+ idsWithoutStrings.add(chunkId);
274
+ }
275
+ }
276
+ if (idsWithStrings.size === 0) {
277
+ return () => JSON.stringify(noStringsLocaleName);
278
+ }
279
+ else if (idsWithoutStrings.size === 0) {
280
+ return (locale) => JSON.stringify(locale);
281
+ }
282
+ else {
283
+ // Generate an array [<locale>, <nostrings locale>] and an object that is used as an indexer into that
284
+ // object that maps chunk IDs to 0s for chunks with localized strings and 1s for chunks without localized
285
+ // strings
286
+ //
287
+ // This can be improved in the future. We can maybe sort the chunks such that the chunks below a certain ID
288
+ // number are localized and the those above are not.
289
+ const chunkMapping = {};
290
+ for (const idWithStrings of idsWithStrings) {
291
+ chunkMapping[idWithStrings] = 0;
292
+ }
293
+ for (const idWithoutStrings of idsWithoutStrings) {
294
+ chunkMapping[idWithoutStrings] = 1;
295
+ }
296
+ return (locale, chunkIdToken) => {
297
+ if (!locale) {
298
+ throw new Error('Missing locale name.');
299
+ }
300
+ return `(${JSON.stringify([locale, noStringsLocaleName])})[${JSON.stringify(chunkMapping)}[${chunkIdToken}]]`;
301
+ };
302
+ }
303
+ }
304
+ }
305
+ exports.AssetProcessor = AssetProcessor;
306
+ //# sourceMappingURL=AssetProcessor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetProcessor.js","sourceRoot":"","sources":["../src/AssetProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as Webpack from 'webpack';\nimport * as lodash from 'lodash';\n\nimport { Constants } from './utilities/Constants';\nimport { ILocaleElementMap } from './interfaces';\nimport { LocalizationPlugin, IStringSerialNumberData as IStringData } from './LocalizationPlugin';\n\ninterface IReconstructionElement {\n kind: 'static' | 'localized' | 'dynamic';\n}\n\ninterface IStaticReconstructionElement extends IReconstructionElement {\n kind: 'static';\n staticString: string;\n}\n\ninterface ILocalizedReconstructionElement extends IReconstructionElement {\n kind: 'localized';\n values: ILocaleElementMap;\n size: number;\n stringName: string;\n escapedBackslash: string;\n locFilePath: string;\n}\n\ninterface IDynamicReconstructionElement extends IReconstructionElement {\n kind: 'dynamic';\n valueFn: (locale: string, token: string | undefined) => string;\n size: number;\n escapedBackslash: string;\n token?: string;\n}\n\ninterface IParseResult {\n issues: string[];\n reconstructionSeries: IReconstructionElement[];\n}\n\ninterface IReconstructedString {\n source: string;\n size: number;\n}\n\ninterface ILocalizedReconstructionResult {\n result: Map<string, IReconstructedString>;\n issues: string[];\n}\n\ninterface INonLocalizedReconstructionResult {\n result: IReconstructedString;\n issues: string[];\n}\n\nexport interface IProcessAssetOptionsBase {\n plugin: LocalizationPlugin;\n compilation: Webpack.compilation.Compilation;\n assetName: string;\n asset: IAsset;\n chunk: Webpack.compilation.Chunk;\n noStringsLocaleName: string;\n chunkHasLocalizedModules: (chunk: Webpack.compilation.Chunk) => boolean;\n}\n\nexport interface IProcessNonLocalizedAssetOptions extends IProcessAssetOptionsBase {}\n\nexport interface IProcessLocalizedAssetOptions extends IProcessAssetOptionsBase {\n locales: Set<string>;\n fillMissingTranslationStrings: boolean;\n defaultLocale: string;\n}\n\nexport interface IAsset {\n size(): number;\n source(): string;\n}\n\nexport interface IProcessAssetResult {\n filename: string;\n asset: IAsset;\n}\n\nexport const PLACEHOLDER_REGEX: RegExp = new RegExp(\n `${Constants.STRING_PLACEHOLDER_PREFIX}_(\\\\\\\\*)_([A-C])(\\\\+[^+]+\\\\+)?_(\\\\d+)`,\n 'g'\n);\n\nexport class AssetProcessor {\n public static processLocalizedAsset(\n options: IProcessLocalizedAssetOptions\n ): Map<string, IProcessAssetResult> {\n const assetSource: string = options.asset.source();\n\n const parsedAsset: IParseResult = AssetProcessor._parseStringToReconstructionSequence(\n options.plugin,\n assetSource,\n this._getJsonpFunction(options.chunk, options.chunkHasLocalizedModules, options.noStringsLocaleName)\n );\n const reconstructedAsset: ILocalizedReconstructionResult = AssetProcessor._reconstructLocalized(\n parsedAsset.reconstructionSeries,\n options.locales,\n options.fillMissingTranslationStrings,\n options.defaultLocale,\n options.asset.size()\n );\n\n const parsedAssetName: IParseResult = AssetProcessor._parseStringToReconstructionSequence(\n options.plugin,\n options.assetName,\n () => {\n throw new Error('unsupported');\n }\n );\n const reconstructedAssetName: ILocalizedReconstructionResult = AssetProcessor._reconstructLocalized(\n parsedAssetName.reconstructionSeries,\n options.locales,\n options.fillMissingTranslationStrings,\n options.defaultLocale,\n options.assetName.length\n );\n\n const result: Map<string, IProcessAssetResult> = new Map<string, IProcessAssetResult>();\n for (const [locale, { source, size }] of reconstructedAsset.result) {\n const newAsset: IAsset = lodash.clone(options.asset);\n newAsset.source = () => source;\n newAsset.size = () => size;\n\n result.set(locale, {\n filename: reconstructedAssetName.result.get(locale)!.source,\n asset: newAsset\n });\n }\n\n const issues: string[] = [\n ...parsedAsset.issues,\n ...reconstructedAsset.issues,\n ...parsedAssetName.issues,\n ...reconstructedAssetName.issues\n ];\n\n if (issues.length > 0) {\n options.compilation.errors.push(\n Error(`localization:\\n${issues.map((issue) => ` ${issue}`).join('\\n')}`)\n );\n }\n\n return result;\n }\n\n public static processNonLocalizedAsset(options: IProcessNonLocalizedAssetOptions): IProcessAssetResult {\n const assetSource: string = options.asset.source();\n\n const parsedAsset: IParseResult = AssetProcessor._parseStringToReconstructionSequence(\n options.plugin,\n assetSource,\n this._getJsonpFunction(options.chunk, options.chunkHasLocalizedModules, options.noStringsLocaleName)\n );\n const reconstructedAsset: INonLocalizedReconstructionResult = AssetProcessor._reconstructNonLocalized(\n parsedAsset.reconstructionSeries,\n options.asset.size(),\n options.noStringsLocaleName\n );\n\n const parsedAssetName: IParseResult = AssetProcessor._parseStringToReconstructionSequence(\n options.plugin,\n options.assetName,\n () => {\n throw new Error('unsupported');\n }\n );\n const reconstructedAssetName: INonLocalizedReconstructionResult = AssetProcessor._reconstructNonLocalized(\n parsedAssetName.reconstructionSeries,\n options.assetName.length,\n options.noStringsLocaleName\n );\n\n const issues: string[] = [\n ...parsedAsset.issues,\n ...reconstructedAsset.issues,\n ...parsedAssetName.issues,\n ...reconstructedAssetName.issues\n ];\n\n if (issues.length > 0) {\n options.compilation.errors.push(\n Error(`localization:\\n${issues.map((issue) => ` ${issue}`).join('\\n')}`)\n );\n }\n\n const newAsset: IAsset = lodash.clone(options.asset);\n newAsset.source = () => reconstructedAsset.result.source;\n newAsset.size = () => reconstructedAsset.result.size;\n return {\n filename: reconstructedAssetName.result.source,\n asset: newAsset\n };\n }\n\n private static _reconstructLocalized(\n reconstructionSeries: IReconstructionElement[],\n locales: Set<string>,\n fillMissingTranslationStrings: boolean,\n defaultLocale: string,\n initialSize: number\n ): ILocalizedReconstructionResult {\n const localizedResults: Map<string, IReconstructedString> = new Map<string, IReconstructedString>();\n const issues: string[] = [];\n\n for (const locale of locales) {\n const reconstruction: string[] = [];\n\n let sizeDiff: number = 0;\n for (const element of reconstructionSeries) {\n switch (element.kind) {\n case 'static': {\n reconstruction.push((element as IStaticReconstructionElement).staticString);\n break;\n }\n\n case 'localized': {\n const localizedElement: ILocalizedReconstructionElement =\n element as ILocalizedReconstructionElement;\n let newValue: string | undefined = localizedElement.values[locale];\n if (!newValue) {\n if (fillMissingTranslationStrings) {\n newValue = localizedElement.values[defaultLocale];\n } else {\n issues.push(\n `The string \"${localizedElement.stringName}\" in \"${localizedElement.locFilePath}\" is missing in ` +\n `the locale ${locale}`\n );\n\n newValue = '-- MISSING STRING --';\n }\n }\n\n const escapedBackslash: string = localizedElement.escapedBackslash || '\\\\';\n\n // Replace backslashes with the properly escaped backslash\n newValue = newValue.replace(/\\\\/g, escapedBackslash);\n\n // @todo: look into using JSON.parse(...) to get the escaping characters\n const escapingCharacterSequence: string = escapedBackslash.substr(escapedBackslash.length / 2);\n\n // Ensure the the quotemark, apostrophe, tab, and newline characters are properly escaped\n newValue = newValue.replace(/\\r/g, `${escapingCharacterSequence}r`);\n newValue = newValue.replace(/\\n/g, `${escapingCharacterSequence}n`);\n newValue = newValue.replace(/\\t/g, `${escapingCharacterSequence}t`);\n newValue = newValue.replace(/\\\"/g, `${escapingCharacterSequence}u0022`);\n newValue = newValue.replace(/\\'/g, `${escapingCharacterSequence}u0027`);\n\n reconstruction.push(newValue);\n sizeDiff += newValue.length - localizedElement.size;\n break;\n }\n\n case 'dynamic': {\n const dynamicElement: IDynamicReconstructionElement = element as IDynamicReconstructionElement;\n const newValue: string = dynamicElement.valueFn(locale, dynamicElement.token);\n reconstruction.push(newValue);\n sizeDiff += newValue.length - dynamicElement.size;\n break;\n }\n }\n }\n\n const newAssetSource: string = reconstruction.join('');\n localizedResults.set(locale, {\n source: newAssetSource,\n size: initialSize + sizeDiff\n });\n }\n\n return {\n issues,\n result: localizedResults\n };\n }\n\n private static _reconstructNonLocalized(\n reconstructionSeries: IReconstructionElement[],\n initialSize: number,\n noStringsLocaleName: string\n ): INonLocalizedReconstructionResult {\n const issues: string[] = [];\n\n const reconstruction: string[] = [];\n\n let sizeDiff: number = 0;\n for (const element of reconstructionSeries) {\n switch (element.kind) {\n case 'static': {\n reconstruction.push((element as IStaticReconstructionElement).staticString);\n break;\n }\n\n case 'localized': {\n const localizedElement: ILocalizedReconstructionElement =\n element as ILocalizedReconstructionElement;\n issues.push(\n `The string \"${localizedElement.stringName}\" in \"${localizedElement.locFilePath}\" appeared in an asset ` +\n 'that is not expected to contain localized resources.'\n );\n\n const newValue: string = '-- NOT EXPECTED TO BE LOCALIZED --';\n reconstruction.push(newValue);\n sizeDiff += newValue.length - localizedElement.size;\n break;\n }\n\n case 'dynamic': {\n const dynamicElement: IDynamicReconstructionElement = element as IDynamicReconstructionElement;\n const newValue: string = dynamicElement.valueFn(noStringsLocaleName, dynamicElement.token);\n reconstruction.push(newValue);\n sizeDiff += newValue.length - dynamicElement.size;\n break;\n }\n }\n }\n\n const newAssetSource: string = reconstruction.join('');\n return {\n issues,\n result: {\n source: newAssetSource,\n size: initialSize + sizeDiff\n }\n };\n }\n\n private static _parseStringToReconstructionSequence(\n plugin: LocalizationPlugin,\n source: string,\n jsonpFunction: (locale: string, chunkIdToken: string | undefined) => string\n ): IParseResult {\n const issues: string[] = [];\n const reconstructionSeries: IReconstructionElement[] = [];\n\n let lastIndex: number = 0;\n let regexResult: RegExpExecArray | null;\n while ((regexResult = PLACEHOLDER_REGEX.exec(source))) {\n // eslint-disable-line no-cond-assign\n const staticElement: IStaticReconstructionElement = {\n kind: 'static',\n staticString: source.substring(lastIndex, regexResult.index)\n };\n reconstructionSeries.push(staticElement);\n\n const [placeholder, escapedBackslash, elementLabel, token, placeholderSerialNumber] = regexResult;\n\n let localizedReconstructionElement: IReconstructionElement;\n switch (elementLabel) {\n case Constants.STRING_PLACEHOLDER_LABEL: {\n const stringData: IStringData | undefined = plugin.getDataForSerialNumber(placeholderSerialNumber);\n if (!stringData) {\n issues.push(`Missing placeholder ${placeholder}`);\n const brokenLocalizedElement: IStaticReconstructionElement = {\n kind: 'static',\n staticString: placeholder\n };\n localizedReconstructionElement = brokenLocalizedElement;\n } else {\n const localizedElement: ILocalizedReconstructionElement = {\n kind: 'localized',\n values: stringData.values,\n size: placeholder.length,\n locFilePath: stringData.locFilePath,\n escapedBackslash: escapedBackslash,\n stringName: stringData.stringName\n };\n localizedReconstructionElement = localizedElement;\n }\n break;\n }\n\n case Constants.LOCALE_NAME_PLACEHOLDER_LABEL: {\n const dynamicElement: IDynamicReconstructionElement = {\n kind: 'dynamic',\n valueFn: (locale: string) => locale,\n size: placeholder.length,\n escapedBackslash: escapedBackslash\n };\n localizedReconstructionElement = dynamicElement;\n break;\n }\n\n case Constants.JSONP_PLACEHOLDER_LABEL: {\n const dynamicElement: IDynamicReconstructionElement = {\n kind: 'dynamic',\n valueFn: jsonpFunction,\n size: placeholder.length,\n escapedBackslash: escapedBackslash,\n token: token.substring(1, token.length - 1)\n };\n localizedReconstructionElement = dynamicElement;\n break;\n }\n\n default: {\n throw new Error(`Unexpected label ${elementLabel}`);\n }\n }\n\n reconstructionSeries.push(localizedReconstructionElement);\n lastIndex = regexResult.index + placeholder.length;\n }\n\n const lastElement: IStaticReconstructionElement = {\n kind: 'static',\n staticString: source.substr(lastIndex)\n };\n reconstructionSeries.push(lastElement);\n\n return {\n issues,\n reconstructionSeries\n };\n }\n\n private static _getJsonpFunction(\n chunk: Webpack.compilation.Chunk,\n chunkHasLocalizedModules: (chunk: Webpack.compilation.Chunk) => boolean,\n noStringsLocaleName: string\n ): (locale: string, chunkIdToken: string | undefined) => string {\n const idsWithStrings: Set<number | string> = new Set<number | string>();\n const idsWithoutStrings: Set<number | string> = new Set<number | string>();\n\n const asyncChunks: Set<Webpack.compilation.Chunk> = chunk.getAllAsyncChunks();\n for (const asyncChunk of asyncChunks) {\n const chunkId: number | string | null = asyncChunk.id;\n\n if (chunkId === null || chunkId === undefined) {\n throw new Error(`Chunk \"${asyncChunk.name}\"'s ID is null or undefined.`);\n }\n\n if (chunkHasLocalizedModules(asyncChunk)) {\n idsWithStrings.add(chunkId);\n } else {\n idsWithoutStrings.add(chunkId);\n }\n }\n\n if (idsWithStrings.size === 0) {\n return () => JSON.stringify(noStringsLocaleName);\n } else if (idsWithoutStrings.size === 0) {\n return (locale: string) => JSON.stringify(locale);\n } else {\n // Generate an array [<locale>, <nostrings locale>] and an object that is used as an indexer into that\n // object that maps chunk IDs to 0s for chunks with localized strings and 1s for chunks without localized\n // strings\n //\n // This can be improved in the future. We can maybe sort the chunks such that the chunks below a certain ID\n // number are localized and the those above are not.\n const chunkMapping: { [chunkId: string]: number } = {};\n for (const idWithStrings of idsWithStrings) {\n chunkMapping[idWithStrings] = 0;\n }\n\n for (const idWithoutStrings of idsWithoutStrings) {\n chunkMapping[idWithoutStrings] = 1;\n }\n\n return (locale: string, chunkIdToken: string | undefined) => {\n if (!locale) {\n throw new Error('Missing locale name.');\n }\n\n return `(${JSON.stringify([locale, noStringsLocaleName])})[${JSON.stringify(\n chunkMapping\n )}[${chunkIdToken}]]`;\n };\n }\n }\n}\n"]}
@@ -0,0 +1,77 @@
1
+ import { ITerminal } from '@rushstack/node-core-library';
2
+ import * as Webpack from 'webpack';
3
+ import { ILocalizationFile } from '@rushstack/localization-utilities';
4
+ import { ILocalizationPluginOptions, ILocaleElementMap } from './interfaces';
5
+ /**
6
+ * @internal
7
+ */
8
+ export interface IStringPlaceholder {
9
+ value: string;
10
+ suffix: string;
11
+ }
12
+ /**
13
+ * @internal
14
+ */
15
+ export interface IAddDefaultLocFileResult {
16
+ /**
17
+ * A list of paths to translation files that were loaded
18
+ */
19
+ additionalLoadedFilePaths: string[];
20
+ errors: Error[];
21
+ }
22
+ /**
23
+ * @internal
24
+ */
25
+ export interface IStringSerialNumberData {
26
+ values: ILocaleElementMap;
27
+ locFilePath: string;
28
+ stringName: string;
29
+ }
30
+ /**
31
+ * This plugin facilitates localization in webpack.
32
+ *
33
+ * @public
34
+ */
35
+ export declare class LocalizationPlugin implements Webpack.Plugin {
36
+ /**
37
+ * @internal
38
+ */
39
+ stringKeys: Map<string, IStringPlaceholder>;
40
+ private _options;
41
+ private _resolvedTranslatedStringsFromOptions;
42
+ private _globsToIgnore;
43
+ private _stringPlaceholderCounter;
44
+ private _stringPlaceholderMap;
45
+ private _locales;
46
+ private _passthroughLocaleName;
47
+ private _defaultLocale;
48
+ private _noStringsLocaleName;
49
+ private _fillMissingTranslationStrings;
50
+ private _pseudolocalizers;
51
+ private _resxNewlineNormalization;
52
+ private _ignoreMissingResxComments;
53
+ /**
54
+ * The outermost map's keys are the locale names.
55
+ * The middle map's keys are the resolved, file names.
56
+ * The innermost map's keys are the string identifiers and its values are the string values.
57
+ */
58
+ private _resolvedLocalizedStrings;
59
+ constructor(options: ILocalizationPluginOptions);
60
+ apply(compiler: Webpack.Compiler): void;
61
+ /**
62
+ * @internal
63
+ *
64
+ * @returns
65
+ */
66
+ addDefaultLocFile(terminal: ITerminal, localizedResourcePath: string, localizedResourceData: ILocalizationFile): IAddDefaultLocFileResult;
67
+ /**
68
+ * @internal
69
+ */
70
+ getDataForSerialNumber(serialNumber: string): IStringSerialNumberData | undefined;
71
+ private _addLocFile;
72
+ private _initializeAndValidateOptions;
73
+ private _getPlaceholderString;
74
+ private _chunkHasLocalizedModules;
75
+ private _convertLocalizationFileToLocData;
76
+ }
77
+ //# sourceMappingURL=LocalizationPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocalizationPlugin.d.ts","sourceRoot":"","sources":["../src/LocalizationPlugin.ts"],"names":[],"mappings":"AAGA,OAAO,EAAwB,SAAS,EAAe,MAAM,8BAA8B,CAAC;AAC5F,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAGnC,OAAO,EAEL,iBAAiB,EAGlB,MAAM,mCAAmC,CAAC;AAO3C,OAAO,EACL,0BAA0B,EAG1B,iBAAiB,EAGlB,MAAM,cAAc,CAAC;AAKtB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,yBAAyB,EAAE,MAAM,EAAE,CAAC;IAEpC,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AA0BD;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAID;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,OAAO,CAAC,MAAM;IACvD;;OAEG;IACI,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAyC;IAE3F,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,qCAAqC,CAAqB;IAClE,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,yBAAyB,CAAa;IAC9C,OAAO,CAAC,qBAAqB,CAGzB;IACJ,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,sBAAsB,CAAU;IACxC,OAAO,CAAC,cAAc,CAAU;IAChC,OAAO,CAAC,oBAAoB,CAAU;IACtC,OAAO,CAAC,8BAA8B,CAAW;IACjD,OAAO,CAAC,iBAAiB,CAGrB;IACJ,OAAO,CAAC,yBAAyB,CAA0B;IAC3D,OAAO,CAAC,0BAA0B,CAAsB;IAExD;;;;OAIG;IACH,OAAO,CAAC,yBAAyB,CAG7B;gBAEe,OAAO,EAAE,0BAA0B;IAe/C,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,GAAG,IAAI;IA6U9C;;;;OAIG;IACI,iBAAiB,CACtB,QAAQ,EAAE,SAAS,EACnB,qBAAqB,EAAE,MAAM,EAC7B,qBAAqB,EAAE,iBAAiB,GACvC,wBAAwB;IA0E3B;;OAEG;IACI,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS;IAIxF,OAAO,CAAC,WAAW;IAkCnB,OAAO,CAAC,6BAA6B;IAiNrC,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,yBAAyB;IA+BjC,OAAO,CAAC,iCAAiC;CAQ1C"}