Skip to content

Commit e746369

Browse files
ocombehansl
authored andcommitted
feat(@angular/cli): add AOT parameter missingTranslation
This adds the new parameter `missingTranslation` for AoT that was added in angular/angular/pull/15987 and that lets you define the MissingTranslationStrategy
1 parent 47e9c7b commit e746369

File tree

10 files changed

+98
-11
lines changed

10 files changed

+98
-11
lines changed

docs/documentation/build.md

+13
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,19 @@ Note: service worker support is experimental and subject to change.
201201
</p>
202202
</details>
203203

204+
<details>
205+
<summary>missing-translation</summary>
206+
<p>
207+
<code>--missing-translation</code>
208+
</p>
209+
<p>
210+
How to handle missing translations for i18n.
211+
</p>
212+
<p>
213+
Values: <code>error</code>, <code>warning</code>, <code>ignore</code>
214+
</p>
215+
</details>
216+
204217
<details>
205218
<summary>output-hashing</summary>
206219
<p>

docs/documentation/eject.md

+13
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,19 @@ ng eject
112112
</p>
113113
</details>
114114

115+
<details>
116+
<summary>missing-translation</summary>
117+
<p>
118+
<code>--missing-translation</code>
119+
</p>
120+
<p>
121+
How to handle missing translations for i18n.
122+
</p>
123+
<p>
124+
Values: <code>error</code>, <code>warning</code>, <code>ignore</code>
125+
</p>
126+
</details>
127+
115128
<details>
116129
<summary>output-hashing</summary>
117130
<p>

docs/documentation/serve.md

+13
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,19 @@ All the build Options are available in serve, below are the additional options.
188188
</p>
189189
</details>
190190

191+
<details>
192+
<summary>missing-translation</summary>
193+
<p>
194+
<code>--missing-translation</code>
195+
</p>
196+
<p>
197+
How to handle missing translations for i18n.
198+
</p>
199+
<p>
200+
Values: <code>error</code>, <code>warning</code>, <code>ignore</code>
201+
</p>
202+
</details>
203+
191204
<details>
192205
<summary>output-hashing</summary>
193206
<p>

docs/documentation/stories/internationalization.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@ ng xi18n --output-path src/locale
2525
Now that you have generated a messages bundle source file, you can translate it.
2626
Let's say that your file containing the french translations is named `messages.fr.xlf`
2727
and is located in the `src/locale` folder.
28-
If you want to use it when you serve your application you can use the 3 following commands:
28+
If you want to use it when you serve your application you can use the 4 following commands:
2929
- `--i18n-file` Localization file to use for i18n.
3030
- `--i18n-format` Format of the localization file specified with --i18n-file.
3131
- `--locale` Locale to use for i18n.
32+
- `--missing-translation` Defines the strategy to use for missing i18n translations.
3233

3334
In our case we can load the french translations with the following command:
3435
```sh
35-
ng serve --aot --locale fr --i18n-format xlf --i18n-file src/locale/messages.fr.xlf
36+
ng serve --aot --locale fr --i18n-format xlf --i18n-file src/locale/messages.fr.xlf --missing-translation error
3637
```
3738

3839
Our application is exactly the same but the `LOCALE_ID` has been provided with "fr",
@@ -46,14 +47,14 @@ your bootstrap file yourself.
4647
To build your application with a specific locale you can use the exact same commands
4748
that you used for `serve`:
4849
```sh
49-
ng build --aot --locale fr --i18n-format xlf --i18n-file src/i18n/messages.fr.xlf
50+
ng build --aot --locale fr --i18n-format xlf --i18n-file src/i18n/messages.fr.xlf --missing-translation error
5051
```
5152

5253
When you build your application for a specific locale, it is probably a good idea to change
5354
the output path with the command `--output-path` in order to save the files to a different location.
5455

5556
```sh
56-
ng build --aot --output-path dist/fr --locale fr --i18n-format xlf --i18n-file src/i18n/messages.fr.xlf
57+
ng build --aot --output-path dist/fr --locale fr --i18n-format xlf --i18n-file src/i18n/messages.fr.xlf --missing-translation error
5758
```
5859

5960
If you end up serving this specific version from a subdirectory, you can also change
@@ -63,7 +64,7 @@ For example if the french version of your application is served from https://mya
6364
then you would build the french version like this:
6465

6566
```sh
66-
ng build --aot --output-path dist/fr --base-href fr --locale fr --i18n-format xlf --i18n-file src/i18n/messages.fr.xlf
67+
ng build --aot --output-path dist/fr --base-href fr --locale fr --i18n-format xlf --i18n-file src/i18n/messages.fr.xlf --missing-translation error
6768
```
6869

6970
If you need more details about how to create scripts to generate the app in multiple

packages/@angular/cli/commands/build.ts

+5
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ export const baseBuildCommandOptions: any = [
100100
type: String,
101101
description: 'Locale to use for i18n.'
102102
},
103+
{
104+
name: 'missing-translation',
105+
type: String,
106+
description: 'How to handle missing translations for i18n.'
107+
},
103108
{
104109
name: 'extract-css',
105110
type: Boolean,

packages/@angular/cli/models/build-options.ts

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface BuildOptions {
1313
i18nFile?: string;
1414
i18nFormat?: string;
1515
locale?: string;
16+
missingTranslation?: string;
1617
extractCss?: boolean;
1718
watch?: boolean;
1819
outputHashing?: string;

packages/@angular/cli/models/webpack-configs/typescript.ts

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ function _createAotPlugin(wco: WebpackConfigOptions, options: any) {
6969
i18nFormat: buildOptions.i18nFormat,
7070
locale: buildOptions.locale,
7171
replaceExport: appConfig.platform === 'server',
72+
missingTranslation: buildOptions.missingTranslation,
7273
hostReplacementPaths,
7374
// If we don't explicitely list excludes, it will default to `['**/*.spec.ts']`.
7475
exclude: []

packages/@ngtools/webpack/src/plugin.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as path from 'path';
44
import * as ts from 'typescript';
55
import * as SourceMap from 'source-map';
66

7-
const {__NGTOOLS_PRIVATE_API_2} = require('@angular/compiler-cli');
7+
const {__NGTOOLS_PRIVATE_API_2, VERSION} = require('@angular/compiler-cli');
88
const ContextElementDependency = require('webpack/lib/dependencies/ContextElementDependency');
99

1010
import {WebpackResourceLoader} from './resource_loader';
@@ -31,6 +31,7 @@ export interface AotPluginOptions {
3131
i18nFile?: string;
3232
i18nFormat?: string;
3333
locale?: string;
34+
missingTranslation?: string;
3435

3536
// Use tsconfig to include path globs.
3637
exclude?: string | string[];
@@ -68,6 +69,7 @@ export class AotPlugin implements Tapable {
6869
private _i18nFile: string;
6970
private _i18nFormat: string;
7071
private _locale: string;
72+
private _missingTranslation: string;
7173

7274
private _diagnoseFiles: { [path: string]: boolean } = {};
7375
private _firstRun = true;
@@ -97,6 +99,7 @@ export class AotPlugin implements Tapable {
9799
get i18nFile() { return this._i18nFile; }
98100
get i18nFormat() { return this._i18nFormat; }
99101
get locale() { return this._locale; }
102+
get missingTranslation() { return this._missingTranslation; }
100103
get firstRun() { return this._firstRun; }
101104
get lazyRoutes() { return this._lazyRoutes; }
102105
get discoveredLazyRoutes() { return this._discoveredLazyRoutes; }
@@ -246,6 +249,15 @@ export class AotPlugin implements Tapable {
246249
if (options.hasOwnProperty('replaceExport')) {
247250
this._replaceExport = options.replaceExport || this._replaceExport;
248251
}
252+
if (options.hasOwnProperty('missingTranslation')) {
253+
const [MAJOR, MINOR, PATCH] = VERSION.full.split('.').map((x: string) => parseInt(x, 10));
254+
if (MAJOR < 4 || (MINOR == 2 && PATCH < 2)) {
255+
console.warn((`The --missing-translation parameter will be ignored because it is only `
256+
+ `compatible with Angular version 4.2.0 or higher. If you want to use it, please `
257+
+ `upgrade your Angular version.\n`));
258+
}
259+
this._missingTranslation = options.missingTranslation;
260+
}
249261
}
250262

251263
private _findLazyRoutesInAst(): LazyRouteMap {
@@ -483,6 +495,7 @@ export class AotPlugin implements Tapable {
483495
i18nFile: this.i18nFile,
484496
i18nFormat: this.i18nFormat,
485497
locale: this.locale,
498+
missingTranslation: this.missingTranslation,
486499

487500
readResource: (path: string) => this._resourceLoader.get(path)
488501
});

tests/e2e/tests/build/aot/aot-i18n.ts

+31-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import {ng} from '../../../utils/process';
2-
import {expectFileToMatch, writeFile, createDir, appendToFile} from '../../../utils/fs';
2+
import {expectFileToMatch, writeFile, createDir, appendToFile, readFile} from '../../../utils/fs';
33
import {expectToFail} from '../../../utils/utils';
4+
import {Version} from '../../../../../packages/@angular/cli/upgrade/version';
5+
import {SemVer} from 'semver';
46

57
export default function() {
68
return Promise.resolve()
@@ -22,10 +24,35 @@ export default function() {
2224
'<h1 i18n="An introduction header for this sample">Hello i18n!</h1>'))
2325
.then(() => ng('build', '--aot', '--i18n-file', 'src/locale/messages.fr.xlf', '--i18n-format',
2426
'xlf', '--locale', 'fr'))
25-
.then(() => ng('build', '--aot', '--i18nFile', 'src/locale/messages.fr.xlf', '--i18nFormat',
26-
'xlf', '--locale', 'fr'))
2727
.then(() => expectFileToMatch('dist/main.bundle.js', /Bonjour i18n!/))
2828
.then(() => ng('build', '--aot'))
2929
.then(() => expectToFail(() => expectFileToMatch('dist/main.bundle.js', /Bonjour i18n!/)))
30-
.then(() => expectFileToMatch('dist/main.bundle.js', /Hello i18n!/));
30+
.then(() => expectFileToMatch('dist/main.bundle.js', /Hello i18n!/))
31+
.then(() => appendToFile('src/app/app.component.html',
32+
'<p i18n>Other content</p>'))
33+
.then(() => readFile('node_modules/@angular/compiler-cli/package.json')
34+
.then((compilerCliPackage): any => {
35+
const version = new Version(JSON.parse(compilerCliPackage).version);
36+
if (version.major === 2) {
37+
return expectToFail(() => ng('build', '--aot', '--i18nFile', 'src/locale/messages.fr.xlf',
38+
'--i18nFormat', 'xlf', '--locale', 'fr', '--missingTranslation', 'ignore'));
39+
} else {
40+
return ng('build', '--aot', '--i18nFile', 'src/locale/messages.fr.xlf', '--i18nFormat',
41+
'xlf', '--locale', 'fr', '--missingTranslation', 'ignore')
42+
.then(() => expectFileToMatch('dist/main.bundle.js', /Other content/));
43+
}
44+
})
45+
)
46+
.then(() => readFile('node_modules/@angular/compiler-cli/package.json')
47+
.then((compilerCliPackage): any => {
48+
const version = new Version(JSON.parse(compilerCliPackage).version);
49+
if (version.isGreaterThanOrEqualTo(new SemVer('4.2.0-beta.0')) || version.major === 2) {
50+
return expectToFail(() => ng('build', '--aot', '--i18nFile', 'src/locale/messages.fr.xlf',
51+
'--i18nFormat', 'xlf', '--locale', 'fr', '--missingTranslation', 'error'));
52+
} else {
53+
return ng('build', '--aot', '--i18nFile', 'src/locale/messages.fr.xlf',
54+
'--i18nFormat', 'xlf', '--locale', 'fr', '--missingTranslation', 'error');
55+
}
56+
})
57+
);
3158
}

tests/e2e/tests/i18n/extract-locale.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default function() {
1515
.then((output) => {
1616
if (!output.stdout.match(/starting from Angular v4/)) {
1717
expectFileToExist(join('src', 'messages.xlf'));
18-
expectFileToMatch(join('src', 'messages.xlf'), /source-language="fr"/)
18+
expectFileToMatch(join('src', 'messages.xlf'), /source-language="fr"/);
1919
}
2020
});
2121
}

0 commit comments

Comments
 (0)