Skip to content

Commit b8a2215

Browse files
clydindgp1130
authored andcommitted
fix(@angular-devkit/build-angular): allow new i18n options to work with VE
(cherry picked from commit 7987906)
1 parent 6aee3b1 commit b8a2215

File tree

3 files changed

+118
-12
lines changed

3 files changed

+118
-12
lines changed

packages/angular_devkit/build_angular/src/utils/i18n-options.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import { BuilderContext } from '@angular-devkit/architect';
9-
import { json, virtualFs } from '@angular-devkit/core';
9+
import { json } from '@angular-devkit/core';
1010
import * as fs from 'fs';
1111
import * as os from 'os';
1212
import * as path from 'path';
@@ -25,6 +25,7 @@ export interface I18nOptions {
2525
>;
2626
flatOutput?: boolean;
2727
readonly shouldInline: boolean;
28+
veCompatLocale?: string;
2829
}
2930

3031
export function createI18nOptions(
@@ -116,9 +117,32 @@ export async function configureI18nBuild<T extends BrowserBuilderSchema | Server
116117
if (buildOptions.localize === undefined && usingIvy) {
117118
mergeDeprecatedI18nOptions(i18n, buildOptions.i18nLocale, buildOptions.i18nFile);
118119
} else if (buildOptions.localize !== undefined && !usingIvy) {
119-
buildOptions.localize = undefined;
120+
if (
121+
buildOptions.localize === true ||
122+
(Array.isArray(buildOptions.localize) && buildOptions.localize.length > 1)
123+
) {
124+
throw new Error(
125+
`Localization with multiple locales in one build is not supported with View Engine.`,
126+
);
127+
}
128+
129+
for (const deprecatedOption of ['i18nLocale', 'i18nFormat', 'i18nFile']) {
130+
// tslint:disable-next-line: no-any
131+
if (typeof (buildOptions as any)[deprecatedOption] !== 'undefined') {
132+
context.logger.warn(
133+
`Option 'localize' and deprecated '${deprecatedOption}' found. Using 'localize'.`,
134+
);
135+
}
136+
}
120137

121-
context.logger.warn(`Option 'localize' is not supported with View Engine.`);
138+
if (
139+
buildOptions.localize === false ||
140+
(Array.isArray(buildOptions.localize) && buildOptions.localize.length === 0)
141+
) {
142+
buildOptions.i18nFile = undefined;
143+
buildOptions.i18nLocale = undefined;
144+
buildOptions.i18nFormat = undefined;
145+
}
122146
}
123147

124148
// Clear deprecated options when using Ivy to prevent unintended behavior
@@ -180,6 +204,21 @@ export async function configureI18nBuild<T extends BrowserBuilderSchema | Server
180204
if (usedFormats.size > 0) {
181205
buildOptions.i18nFormat = [...usedFormats][0];
182206
}
207+
208+
// Provide support for using the Ivy i18n options with VE
209+
if (!usingIvy) {
210+
i18n.veCompatLocale = buildOptions.i18nLocale = [...i18n.inlineLocales][0];
211+
212+
if (buildOptions.i18nLocale !== i18n.sourceLocale) {
213+
buildOptions.i18nFile = i18n.locales[buildOptions.i18nLocale].file;
214+
}
215+
216+
// Clear inline locales to prevent any new i18n related processing
217+
i18n.inlineLocales.clear();
218+
219+
// Update the output path to include the locale to mimic Ivy localize behavior
220+
buildOptions.outputPath = path.join(buildOptions.outputPath, buildOptions.i18nLocale);
221+
}
183222
}
184223

185224
// If inlining store the output in a temporary location to facilitate post-processing

packages/angular_devkit/build_angular/src/utils/output-paths.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,21 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
98
import { existsSync, mkdirSync } from 'fs';
109
import { join } from 'path';
1110
import { I18nOptions } from './i18n-options';
1211

1312
export function ensureOutputPaths(baseOutputPath: string, i18n: I18nOptions): string[] {
14-
const outputPaths = i18n.shouldInline && !i18n.flatOutput
15-
? [...i18n.inlineLocales].map(l => join(baseOutputPath, l))
16-
: [baseOutputPath];
13+
const outputPaths =
14+
i18n.shouldInline && !i18n.flatOutput
15+
? [...i18n.inlineLocales].map(l => join(baseOutputPath, l))
16+
: [i18n.veCompatLocale ? join(baseOutputPath, i18n.veCompatLocale) : baseOutputPath];
1717

18-
for (const outputPath of outputPaths) {
19-
if (!existsSync(outputPath)) {
20-
mkdirSync(outputPath, { recursive: true });
21-
}
18+
for (const outputPath of outputPaths) {
19+
if (!existsSync(outputPath)) {
20+
mkdirSync(outputPath, { recursive: true });
2221
}
22+
}
2323

24-
return outputPaths;
24+
return outputPaths;
2525
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { getGlobalVariable } from '../../utils/env';
2+
import { expectFileToMatch, writeFile } from '../../utils/fs';
3+
import { execAndWaitForOutputToMatch, ng, npm } from '../../utils/process';
4+
import { updateJsonFile } from '../../utils/project';
5+
import { expectToFail } from '../../utils/utils';
6+
import { readNgVersion } from '../../utils/version';
7+
import { baseDir, externalServer, langTranslations, setupI18nConfig } from './legacy';
8+
9+
export default async function() {
10+
if (!getGlobalVariable('argv')['ve']) {
11+
return;
12+
}
13+
14+
// Setup i18n tests and config.
15+
await setupI18nConfig();
16+
17+
// Using localize-based options requires the @angular/locale package
18+
let localizeVersion = '@angular/localize@' + readNgVersion();
19+
if (getGlobalVariable('argv')['ng-snapshots']) {
20+
localizeVersion = require('../../ng-snapshot/package.json').dependencies['@angular/localize'];
21+
}
22+
await npm('install', `${localizeVersion}`);
23+
24+
// Ensure a ES2015 build is used.
25+
await writeFile('browserslist', 'Chrome 65');
26+
await updateJsonFile('tsconfig.json', config => {
27+
config.compilerOptions.target = 'es2015';
28+
config.angularCompilerOptions.disableTypeScriptVersionCheck = true;
29+
});
30+
31+
// Attempts to build multiple locales with VE should fail
32+
await expectToFail(() => ng('build'));
33+
34+
for (const { lang, outputPath, translation } of langTranslations) {
35+
await ng('build', `--configuration=${lang}`);
36+
37+
await expectFileToMatch(`${outputPath}/main.js`, translation.helloPartial);
38+
await expectToFail(() => expectFileToMatch(`${outputPath}/main.js`, '$localize`'));
39+
40+
// Execute Application E2E tests with dev server
41+
await ng('e2e', `--configuration=${lang}`, '--port=0');
42+
43+
// Execute Application E2E tests for a production build without dev server
44+
const server = externalServer(outputPath);
45+
try {
46+
await ng('e2e', `--configuration=${lang}`, '--devServerTarget=');
47+
} finally {
48+
server.close();
49+
}
50+
}
51+
52+
await execAndWaitForOutputToMatch(
53+
'ng',
54+
['build', '--configuration=fr', '--i18n-locale=en-US'],
55+
/Option 'localize' and deprecated 'i18nLocale' found. Using 'localize'./,
56+
);
57+
await execAndWaitForOutputToMatch(
58+
'ng',
59+
['build', '--configuration=fr', '--i18n-format=xmb'],
60+
/Option 'localize' and deprecated 'i18nFormat' found. Using 'localize'./,
61+
);
62+
await execAndWaitForOutputToMatch(
63+
'ng',
64+
['build', '--configuration=fr', '--i18n-file=error.json'],
65+
/Option 'localize' and deprecated 'i18nFile' found. Using 'localize'./,
66+
);
67+
}

0 commit comments

Comments
 (0)