10000 Add support for referencing loc in translations. · rbuckton/rushstack@60409ae · GitHub
[go: up one dir, main page]

Skip to content

Commit 60409ae

Browse files
committed
Add support for referencing loc in translations.
1 parent 19ff1a4 commit 60409ae

File tree

8 files changed

+109
-34
lines changed

8 files changed

+109
-34
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<root>
3+
<data name="string1" xml:space="preserve">
4+
<value>La primera cadena RESX</value>
5+
</data>
6+
<data name="stringWithQuotes" xml:space="preserve">
7+
<value>"Cadena RESX con comillas"</value>
8+
</data>
9+
</root>

build-tests/localization-plugin-test-02/webpack.config.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,7 @@ module.exports = function(env) {
6060
"./src/strings4.loc.json": {
6161
"string1": "\"Cadena con comillas\""
6262
},
63-
"./src/strings5.resx": {
64-
"string1": "La primera cadena RESX",
65-
"stringWithQuotes": "\"Cadena RESX con comillas\""
66-
}
63+
"./src/strings5.resx": "./localization/es-es/strings5.resx"
6764
}
6865
},
6966
passthroughLocale: {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"string1": {
3+
"value": "la segunda cadena"
4+
}
5+
}

build-tests/localization-plugin-test-03/webpack.config.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,7 @@ module.exports = function(env) {
5454
"./src/strings1.loc.json": {
5555
"string1": "la primera cadena"
5656
},
57-
"./src/chunks/strings2.loc.json": {
58-
"string1": "la segunda cadena"
59-
},
57+
"./src/chunks/strings2.loc.json": "./localization/es-es/chunks/strings2.loc.json",
6058
"./src/strings3.loc.json": {
6159
"string1": "la tercera cadena",
6260
"string2": "cuerda cuatro con un ' apóstrofe",

common/reviews/api/localization-plugin.api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export interface IDefaultLocaleOptions {
1717
// @public (undocumented)
1818
export interface ILocaleData {
1919
// (undocumented)
20-
[locFilePath: string]: ILocaleFileData;
20+
[locFilePath: string]: string | ILocaleFileData;
2121
}
2222

2323
// @public (undocumented)

webpack/localization-plugin/README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ resources
2727
directly references two `.loc.json` files
2828
- [`indexC.ts`](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-02/src/indexC.ts)
2929
directly references no localized resources, and dynamically imports an async chunk without localized data
30-
- The webpack config contains Spanish translations for most of the English strings in the resource files
30+
- The webpack config contains and references Spanish translations for most of the English strings in the resource files
3131
- The output contains English, Spanish, and "passthrough" localized variants of files that contain
3232
localized data, and a non-localized variant of the files that do not contain localized data
3333
- [Project 3](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-03)
@@ -41,7 +41,7 @@ resources
4141
directly references no localized resources, and dynamically imports an async chunk with localized data
4242
- [`indexD.ts`](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-03/src/indexD.ts)
4343
directly references no localized resources, and dynamically imports an async chunk without localized data
44-
- The webpack config contains Spanish translations for all of the English strings in the resource files
44+
- The webpack config contains or references Spanish translations for some of the English strings in the resource files
4545
- The output contains English, Spanish, "passthrough," and two pseudo-localized variants of files that contain
4646
localized data, and a non-localized variant of the files that do not contain localized data
4747

@@ -122,6 +122,20 @@ translatedStrings: {
122122
}
123123
```
124124

125+
Alternatively, instead of directly specifying the translations, a path to a translated resource file can be
126+
specified. For example:
127+
128+
```JavaScript
129+
translatedStrings: {
130+
"en-us": {
131+
"./src/strings1.loc.json": "./localization/en-us/strings1.loc.json"
132+
},
133+
"es-es": {
134+
"./src/strings1.loc.json": "./localization/es-es/strings1.loc.json"
135+
}
136+
}
137+
```
138+
125139
#### `localizedData.passthroughLocale = { }`
126140

127141
This option is used to specify how and if a passthrough locale should be generated. A passthrough locale

webpack/localization-plugin/src/LocalizationPlugin.ts

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
22
// See LICENSE in the project root for license information.
33< EF56 /td>

4-
import { JsonFile } from '@rushstack/node-core-library';
4+
import {
5+
JsonFile,
6+
FileSystem,
7+
ITerminalProvider,
8+
TerminalProviderSeverity,
9+
Terminal
10+
} from '@rushstack/node-core-library';
511
import * as Webpack from 'webpack';
612
import * as path from 'path';
713
import * as Tapable from 'tapable';
@@ -27,6 +33,7 @@ import { LocFileTypingsGenerator } from './LocFileTypingsGenerator';
2733
import { Pseudolocalization } from './Pseudolocalization';
2834
import { EntityMarker } from './utilities/EntityMarker';
2935
import { IAsset, IProcessAssetResult, AssetProcessor } from './AssetProcessor';
36+
import { LocFileParser } from './utilities/LocFileParser';
3037

3138
/**
3239
* @internal
@@ -135,7 +142,7 @@ export class LocalizationPlugin implements Webpack.Plugin {
135142
// https://github.com/webpack/webpack-dev-server/pull/1929/files#diff-15fb51940da53816af13330d8ce69b4eR66
136143
const isWebpackDevServer: boolean = process.env.WEBPACK_DEV_SERVER === 'true';
137144

138-
const errors: Error[] = this._initializeAndValidateOptions(compiler.options, isWebpackDevServer);
145+
const { errors, warnings } = this._initializeAndValidateOptions(compiler.options, isWebpackDevServer);
139146

140147
let typingsPreprocessor: LocFileTypingsGenerator | undefined;
141148
if (this._options.typingsOptions) {
@@ -156,14 +163,18 @@ export class LocalizationPlugin implements Webpack.Plugin {
156163
localeNameOrPlaceholder: Constants.LOCALE_NAME_PLACEHOLDER
157164
};
158165

159-
if (errors.length > 0) {
166+
if (errors.length > 0 || warnings.length > 0) {
160167
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation: Webpack.compilation.Compilation) => {
161168
compilation.errors.push(...errors);
169+
compilation.warnings.push(...warnings);
162170
});
163171

164-
WebpackConfigurationUpdater.amendWebpackConfigurationForInPlaceLocFiles(webpackConfigurationUpdaterOptions);
165-
166-
return;
172+
if (errors.length > 0) {
173+
// If there are any errors, just pass through the resources in source and don't do any
174+
// additional configuration
175+
WebpackConfigurationUpdater.amendWebpackConfigurationForInPlaceLocFiles(webpackConfigurationUpdaterOptions);
176+
return;
177+
}
167178
}
168179

169180
if (isWebpackDevServer) {
@@ -390,11 +401,7 @@ export class LocalizationPlugin implements Webpack.Plugin {
390401
* @internal
391402
*/
392403
public addDefaultLocFile(locFilePath: string, locFile: ILocalizationFile): void {
393-
const locFileData: ILocaleFileData = {};
394-
for (const stringName in locFile) { // eslint-disable-line guard-for-in
395-
locFileData[stringName] = locFile[stringName].value;
396-
}
397-
404+
const locFileData: ILocaleFileData = this._convertLocalizationFileToLocData(locFile);
398405
this._addLocFile(this._defaultLocale, locFilePath, locFileData);
399406

400407
this._pseudolocalizers.forEach((pseudolocalizer: (str: string) => string, pseudolocaleName: string) => {
@@ -454,8 +461,12 @@ export class LocalizationPlugin implements Webpack.Plugin {
454461
}
455462
}
456463

457-
private _initializeAndValidateOptions(configuration: Webpack.Configuration, isWebpackDevServer: boolean): Error[] {
464+
private _initializeAndValidateOptions(
465+
configuration: Webpack.Configuration,
466+
isWebpackDevServer: boolean
467+
): { errors: Error[], warnings: Error[] } {
458468
const errors: Error[] = [];
469+
const warnings: Error[] = [];
459470

460471
function ensureValidLocaleName(localeName: string): boolean {
461472
const LOCALE_NAME_REGEX: RegExp = /[a-z-]/i;
@@ -510,18 +521,37 @@ export class LocalizationPlugin implements Webpack.Plugin {
510521
// START options.localizedData.translatedStrings
511522
const { translatedStrings } = this._options.localizedData;
512523
if (translatedStrings) {
524+
const terminalProvider: ITerminalProvider = {
525+
supportsColor: false,
526+
eolCharacter: '\n',
527+
write: (data: string, severity: TerminalProviderSeverity) => {
528+
switch (severity) {
529+
case TerminalProviderSeverity.error: {
530+
errors.push(new Error(data));
531+
break;
532+
}
533+
534+
case TerminalProviderSeverity.warning: {
535+
warnings.push(new Error(data));
536+
break;
537+
}
538+
}
539+
}
540+
};
541+
const terminal: Terminal = new Terminal(terminalProvider);
542+
513543
for (const localeName in translatedStrings) {
514544
if (translatedStrings.hasOwnProperty(localeName)) {
515545
if (this._locales.has(localeName)) {
516546
errors.push(Error(
517547
`The locale "${localeName}" appears multiple times. ` +
518548
'There may be multiple instances with different casing.'
519549
));
520-
return errors;
550+
return { errors, warnings };
521551
}
522552

523553
if (!ensureValidLocaleName(localeName)) {
524-
return errors;
554+
return { errors, warnings };
525555
}
526556

527557
this._locales.add(localeName);
@@ -540,12 +570,25 @@ export class LocalizationPlugin implements Webpack.Plugin {
540570
`The localization file path "${locFilePath}" appears multiple times in locale ${localeName}. ` +
541571
'There may be multiple instances with different casing.'
542572
));
543-
return errors;
573+
return { errors, warnings };
544574
}
545575

546576
locFilePathsInLocale.add(normalizedLocFilePath);
547577

548-
const locFileData: ILocaleFileData = locale[locFilePath];
578+
let locFileData: ILocaleFileData;
579+
const locFileDataFromOptions: ILocaleFileData | string = locale[locFilePath];
580+
if (typeof locFileDataFromOptions === 'string') {
581+
const normalizedTranslatedFilePath: string = path.resolve(configuration.context!, locFileDataFromOptions);
582+
const localizationFile: ILocalizationFile = LocFileParser.parseLocFile({
583+
filePath: normalizedTranslatedFilePath,
584+
content: FileSystem.readFile(normalizedTranslatedFilePath),
585+
terminal: terminal
586+
});
587+
588+
locFileData = this._convertLocalizationFileToLocData(localizationFile);
589+
} else {
590+
locFileData = locFileDataFromOptions;
591+
}
549592
this._addLocFile(localeName, normalizedLocFilePath, locFileData);
550593
}
551594
}
@@ -560,9 +603,9 @@ export class LocalizationPlugin implements Webpack.Plugin {
560603
if (this._options.localizedData.defaultLocale.localeName) {
561604
if (this._locales.has(localeName)) {
562605
errors.push(new Error('The default locale is also specified in the translated strings.'));
563-
return errors;
606+
return { errors, warnings };
564607
} else if (!ensureValidLocaleName(localeName)) {
565-
return errors;
608+
return { errors, warnings };
566609
}
567610

568611
this._locales.add(localeName);
@@ -571,11 +614,11 @@ export class LocalizationPlugin implements Webpack.Plugin {
571614
this._fillMissingTranslationStrings = !!fillMissingTranslationStrings;
572615
} else {
573616
errors.push(new Error('Missing default locale name'));
574-
return errors;
617+
return { errors, warnings };
575618
}
576619
} else {
577620
errors.push(new Error('Missing default locale options.'));
578-
return errors;
621+
return { errors, warnings };
579622
}
580623
// END options.localizedData.defaultLocale
581624

@@ -585,14 +628,14 @@ export class LocalizationPlugin implements Webpack.Plugin {
585628
if (this._options.localizedData.pseudolocales.hasOwnProperty(pseudolocaleName)) {
586629
if (this._defaultLocale === pseudolocaleName) {
587630
errors.push(new Error(`A pseudolocale (${pseudolocaleName}) name is also the default locale name.`));
588-
return errors;
631+
return { errors, warnings };
589632
}
590633

591634
if (this._locales.has(pseudolocaleName)) {
592635
errors.push(new Error(
593636
`A pseudolocale (${pseudolocaleName}) name is also specified in the translated strings.`
594637
));
595-
return errors;
638+
return { errors, warnings };
596639
}
597640

598641
const pseudoLocaleOpts: IPseudolocaleOptions = this._options.localizedData.pseudolocales[pseudolocaleName];
@@ -620,7 +663,7 @@ export class LocalizationPlugin implements Webpack.Plugin {
620663
}
621664
// END options.noStringsLocaleName
622665

623-
return errors;
666+
return { errors, warnings };
624667
}
625668

626669
/**
@@ -661,4 +704,13 @@ export class LocalizationPlugin implements Webpack.Plugin {
661704

662705
return EntityMarker.getMark(chunk)!;
663706
}
707+
708+
private _convertLocalizationFileToLocData(locFile: ILocalizationFile): ILocaleFileData {
709+
const locFileData: ILocaleFileData = {};
710+
for (const stringName in locFile) { // eslint-disable-line guard-for-in
711+
locFileData[stringName] = locFile[stringName].value;
712+
}
713+
714+
return locFileData;
715+
}
664716
}

webpack/localization-plugin/src/interfaces.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ export interface ILocaleFileData {
188188
* @public
189189
*/
190190
export interface ILocaleData {
191-
[locFilePath: string]: ILocaleFileData;
191+
[locFilePath: string]: string | ILocaleFileData;
192192
}
193193

194194
/**

0 commit comments

Comments
 (0)
0