Skip to content

Commit 0d3c988

Browse files
committed
fix(@angular-devkit/build-angular): correctly set i18n subPath in webpack browser builder
The `subPath` option was not being properly applied when using the webpack-based browser builder. Closes #30247
1 parent c560d44 commit 0d3c988

File tree

2 files changed

+84
-4
lines changed

2 files changed

+84
-4
lines changed

packages/angular_devkit/build_angular/src/utils/process-bundle.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -192,10 +192,10 @@ export async function inlineLocales(options: InlineOptions) {
192192
if (!transformResult || !transformResult.code) {
193193
throw new Error(`Unknown error occurred processing bundle for "${options.filename}".`);
194194
}
195-
195+
const subPath = i18n.locales[locale].subPath;
196196
const outputPath = path.join(
197197
options.outputPath,
198-
i18n.flatOutput ? '' : locale,
198+
i18n.flatOutput ? '' : subPath,
199199
options.filename,
200200
);
201201
await fs.writeFile(outputPath, transformResult.code);
@@ -284,9 +284,10 @@ async function inlineLocalesDirect(ast: ParseResult, options: InlineOptions) {
284284
source: string;
285285
map: { file: string; sourceRoot?: string };
286286
};
287+
const subPath = i18n.locales[locale].subPath;
287288
const outputPath = path.join(
288289
options.outputPath,
289-
i18n.flatOutput ? '' : locale,
290+
i18n.flatOutput ? '' : subPath,
290291
options.filename,
291292
);
292293
await fs.writeFile(outputPath, outputCode);
@@ -308,10 +309,11 @@ async function inlineCopyOnly(options: InlineOptions) {
308309
throw new Error('i18n options are missing');
309310
}
310311

312+
const subPath = i18n.locales[locale].subPath;
311313
for (const locale of i18n.inlineLocales) {
312314
const outputPath = path.join(
313315
options.outputPath,
314-
i18n.flatOutput ? '' : locale,
316+
i18n.flatOutput ? '' : subPath,
315317
options.filename,
316318
);
317319
await fs.writeFile(outputPath, options.code);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import { join } from 'path';
10+
import { expectFileToMatch } from '../../utils/fs';
11+
import { ng } from '../../utils/process';
12+
import { updateJsonFile } from '../../utils/project';
13+
import { baseDir, baseHrefs, externalServer, langTranslations, setupI18nConfig } from './setup';
14+
15+
export default async function () {
16+
// Setup i18n tests and config.
17+
await setupI18nConfig();
18+
19+
const URL_SUB_PATH: Record<string, string> = {
20+
'en-US': '',
21+
'fr': 'fr',
22+
'de': 'deutsche',
23+
};
24+
25+
// Update angular.json
26+
await updateJsonFile('angular.json', (workspaceJson) => {
27+
const appProject = workspaceJson.projects['test-project'];
28+
// tslint:disable-next-line: no-any
29+
const i18n: Record<string, any> = appProject.i18n;
30+
31+
i18n.sourceLocale = {
32+
subPath: URL_SUB_PATH['en-US'],
33+
};
34+
35+
i18n.locales['fr'] = {
36+
translation: i18n.locales['fr'],
37+
subPath: URL_SUB_PATH['fr'],
38+
};
39+
40+
i18n.locales['de'] = {
41+
translation: i18n.locales['de'],
42+
subPath: URL_SUB_PATH['de'],
43+
};
44+
});
45+
46+
// Build each locale and verify the output.
47+
await ng('build');
48+
for (const { lang } of langTranslations) {
49+
if (baseHrefs[lang] === undefined) {
50+
throw new Error('Invalid E2E test setup: unexpected locale ' + lang);
51+
}
52+
53+
const outputPath = join(baseDir, URL_SUB_PATH[lang]);
54+
55+
// Verify the HTML lang attribute is present
56+
await expectFileToMatch(`${outputPath}/index.html`, `lang="${lang}"`);
57+
58+
// Verify the HTML base HREF attribute is present
59+
await expectFileToMatch(`${outputPath}/index.html`, `href="${baseHrefs[lang] || '/'}"`);
60+
61+
// Execute Application E2E tests for a production build without dev server
62+
const { server, port, url } = await externalServer(
63+
outputPath,
64+
(baseHrefs[lang] as string) || '/',
65+
);
66+
try {
67+
await ng(
68+
'e2e',
69+
`--port=${port}`,
70+
`--configuration=${lang}`,
71+
'--dev-server-target=',
72+
`--base-url=${url}`,
73+
);
74+
} finally {
75+
server.close();
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)