diff --git a/packages/angular_devkit/build_angular/src/dev-server/index.ts b/packages/angular_devkit/build_angular/src/dev-server/index.ts index d69c235932d2..810867b9a70e 100644 --- a/packages/angular_devkit/build_angular/src/dev-server/index.ts +++ b/packages/angular_devkit/build_angular/src/dev-server/index.ts @@ -65,25 +65,27 @@ async function createI18nPlugins( const diagnostics = new localizeDiag.Diagnostics(); - if (translation) { - const es2015 = await import( - // tslint:disable-next-line: trailing-comma no-implicit-dependencies - '@angular/localize/src/tools/src/translate/source_files/es2015_translate_plugin' - ); - plugins.push( - // tslint:disable-next-line: no-any - es2015.makeEs2015TranslatePlugin(diagnostics, translation as any, { missingTranslation }), - ); + const es2015 = await import( + // tslint:disable-next-line: trailing-comma no-implicit-dependencies + '@angular/localize/src/tools/src/translate/source_files/es2015_translate_plugin' + ); + plugins.push( + // tslint:disable-next-line: no-any + es2015.makeEs2015TranslatePlugin(diagnostics, (translation || {}) as any, { + missingTranslation: translation === undefined ? 'ignore' : missingTranslation, + }), + ); - const es5 = await import( - // tslint:disable-next-line: trailing-comma no-implicit-dependencies - '@angular/localize/src/tools/src/translate/source_files/es5_translate_plugin' - ); - plugins.push( - // tslint:disable-next-line: no-any - es5.makeEs5TranslatePlugin(diagnostics, translation as any, { missingTranslation }), - ); - } + const es5 = await import( + // tslint:disable-next-line: trailing-comma no-implicit-dependencies + '@angular/localize/src/tools/src/translate/source_files/es5_translate_plugin' + ); + plugins.push( + // tslint:disable-next-line: no-any + es5.makeEs5TranslatePlugin(diagnostics, (translation || {}) as any, { + missingTranslation: translation === undefined ? 'ignore' : missingTranslation, + }), + ); const inlineLocale = await import( // tslint:disable-next-line: trailing-comma no-implicit-dependencies @@ -173,14 +175,29 @@ export function serveWebpackBrowser( } const locale = [...i18n.inlineLocales][0]; - const translation = i18n.locales[locale] && i18n.locales[locale].translation; + const localeDescription = i18n.locales[locale] && i18n.locales[locale]; const { plugins, diagnostics } = await createI18nPlugins( locale, - translation, + localeDescription && localeDescription.translation, browserOptions.i18nMissingTranslation, ); + // Modify main entrypoint to include locale data + if ( + localeDescription && + localeDescription.dataPath && + typeof config.entry === 'object' && + !Array.isArray(config.entry) && + config.entry['main'] + ) { + if (Array.isArray(config.entry['main'])) { + config.entry['main'].unshift(localeDescription.dataPath); + } else { + config.entry['main'] = [localeDescription.dataPath, config.entry['main']]; + } + } + // Get the insertion point for the i18n babel loader rule // This is currently dependent on the rule order/construction in common.ts // A future refactor of the webpack configuration definition will improve this situation @@ -212,7 +229,6 @@ export function serveWebpackBrowser( // Add a plugin to inject the i18n diagnostics // tslint:disable-next-line: no-non-null-assertion webpackConfig.plugins!.push({ - // tslint:disable-next-line:no-any apply: (compiler: webpack.Compiler) => { compiler.hooks.thisCompilation.tap('build-angular', compilation => { compilation.hooks.finishModules.tap('build-angular', () => { diff --git a/packages/angular_devkit/build_angular/src/utils/i18n-options.ts b/packages/angular_devkit/build_angular/src/utils/i18n-options.ts index 0ce79020f0ed..fa74888ea387 100644 --- a/packages/angular_devkit/build_angular/src/utils/i18n-options.ts +++ b/packages/angular_devkit/build_angular/src/utils/i18n-options.ts @@ -106,14 +106,6 @@ export async function configureI18nBuild 1) - ) { - throw new Error('Using the localize option for multiple locales is temporarily disabled.'); - } - const tsConfig = readTsconfig(buildOptions.tsConfig, context.workspaceRoot); const usingIvy = tsConfig.options.enableIvy !== false; const metadata = await context.getProjectMetadata(context.target); @@ -129,6 +121,13 @@ export async function configureI18nBuild 0) { const projectRoot = path.join(context.workspaceRoot, (metadata.root as string) || ''); const localeDataBasePath = findLocaleDataBasePath(projectRoot); @@ -172,8 +171,7 @@ export async function configureI18nBuild 0) { buildOptions.i18nFormat = [...usedFormats][0]; } - - // If only one locale is specified set the deprecated option to enable the webpack plugin - // transform to register the locale directly in the output bundle. - if (i18n.inlineLocales.size === 1) { - buildOptions.i18nLocale = [...i18n.inlineLocales][0]; - } } // If inlining store the output in a temporary location to facilitate post-processing diff --git a/tests/legacy-cli/e2e/tests/i18n/ivy-localize-dl.ts b/tests/legacy-cli/e2e/tests/i18n/ivy-localize-dl.ts index 997467a23fc9..d0ac318f04d2 100644 --- a/tests/legacy-cli/e2e/tests/i18n/ivy-localize-dl.ts +++ b/tests/legacy-cli/e2e/tests/i18n/ivy-localize-dl.ts @@ -14,27 +14,21 @@ export default async function() { config.angularCompilerOptions.disableTypeScriptVersionCheck = true; }); - // TODO: re-enable all locales once localeData support is added. - const tempLangTranslations = langTranslations.filter(l => l.lang == 'fr'); - // Build each locale and verify the output. - // NOTE: this should not fail in general, but multi-locale translation is currently disabled. - // TODO: remove expectToFail once localeData support is added. - await expectToFail(() => ng('build', '--localize', 'true')); await ng('build'); - for (const { lang, outputPath, translation } of tempLangTranslations) { + for (const { lang, outputPath, translation } of langTranslations) { await expectFileToMatch(`${outputPath}/main-es5.js`, translation.helloPartial); await expectFileToMatch(`${outputPath}/main-es2015.js`, translation.helloPartial); await expectToFail(() => expectFileToMatch(`${outputPath}/main-es5.js`, '$localize`')); await expectToFail(() => expectFileToMatch(`${outputPath}/main-es2015.js`, '$localize`')); // Verify the locale ID is present - await expectFileToMatch(`${outputPath}/main-es5.js`, lang); - await expectFileToMatch(`${outputPath}/main-es2015.js`, lang); + await expectFileToMatch(`${outputPath}/vendor-es5.js`, lang); + await expectFileToMatch(`${outputPath}/vendor-es2015.js`, lang); // Verify the locale data is registered using the global files - // await expectFileToMatch(`${outputPath}/main-es5.js`, '.ng.common.locales'); - // await expectFileToMatch(`${outputPath}/main-es2015.js`, '.ng.common.locales'); + await expectFileToMatch(`${outputPath}/vendor-es5.js`, '.ng.common.locales'); + await expectFileToMatch(`${outputPath}/vendor-es2015.js`, '.ng.common.locales'); // Execute Application E2E tests with dev server await ng('e2e', `--configuration=${lang}`, '--port=0'); @@ -49,9 +43,9 @@ export default async function() { } // Verify deprecated locale data registration is not present - // await ng('build', '--configuration=fr', '--optimization=false'); - // await expectToFail(() => expectFileToMatch(`${baseDir}/fr/main-es5.js`, 'registerLocaleData(')); - // await expectToFail(() => expectFileToMatch(`${baseDir}/fr/main-es2015.js`, 'registerLocaleData(')); + await ng('build', '--configuration=fr', '--optimization=false'); + await expectToFail(() => expectFileToMatch(`${baseDir}/fr/main-es5.js`, 'registerLocaleData(')); + await expectToFail(() => expectFileToMatch(`${baseDir}/fr/main-es2015.js`, 'registerLocaleData(')); // Verify missing translation behaviour. await appendToFile('src/app/app.component.html', '

Other content

'); @@ -60,7 +54,11 @@ export default async function() { await expectFileToMatch(`${baseDir}/fr/main-es2015.js`, /Other content/); await expectToFail(() => ng('build')); try { - await execAndWaitForOutputToMatch('ng', ['serve', '--port=0'], /No translation found for/); + await execAndWaitForOutputToMatch( + 'ng', + ['serve', '--configuration=fr', '--port=0'], + /No translation found for/, + ); } finally { killAllProcesses(); } diff --git a/tests/legacy-cli/e2e/tests/i18n/ivy-localize-es2015.ts b/tests/legacy-cli/e2e/tests/i18n/ivy-localize-es2015.ts index e0055f28bfaf..f5fb2a8cc30a 100644 --- a/tests/legacy-cli/e2e/tests/i18n/ivy-localize-es2015.ts +++ b/tests/legacy-cli/e2e/tests/i18n/ivy-localize-es2015.ts @@ -15,12 +15,8 @@ export default async function() { config.angularCompilerOptions.disableTypeScriptVersionCheck = true; }); - - // TODO: re-enable all locales once localeData support is added. - const tempLangTranslations = langTranslations.filter(l => l.lang == 'fr'); - await ng('build'); - for (const { lang, outputPath, translation } of tempLangTranslations) { + for (const { lang, outputPath, translation } of langTranslations) { await expectFileToMatch(`${outputPath}/main.js`, translation.helloPartial); await expectToFail(() => expectFileToMatch(`${outputPath}/main.js`, '$localize`')); await expectFileNotToExist(`${outputPath}/main-es5.js`); diff --git a/tests/legacy-cli/e2e/tests/i18n/ivy-localize-es5.ts b/tests/legacy-cli/e2e/tests/i18n/ivy-localize-es5.ts index fad15ff6f68b..99c8a408357d 100644 --- a/tests/legacy-cli/e2e/tests/i18n/ivy-localize-es5.ts +++ b/tests/legacy-cli/e2e/tests/i18n/ivy-localize-es5.ts @@ -14,12 +14,9 @@ export default async function() { config.angularCompilerOptions.disableTypeScriptVersionCheck = true; }); - // TODO: re-enable all locales once localeData support is added. - const tempLangTranslations = langTranslations.filter(l => l.lang == 'fr'); - // Build each locale and verify the output. await ng('build'); - for (const { lang, outputPath, translation } of tempLangTranslations) { + for (const { lang, outputPath, translation } of langTranslations) { await expectFileToMatch(`${outputPath}/main.js`, translation.helloPartial); await expectToFail(() => expectFileToMatch(`${outputPath}/main.js`, '$localize`')); await expectFileNotToExist(`${outputPath}/main-es2015.js`); diff --git a/tests/legacy-cli/e2e/tests/i18n/ivy-localize-server.ts b/tests/legacy-cli/e2e/tests/i18n/ivy-localize-server.ts index 07b380eb136f..7350c23a9694 100644 --- a/tests/legacy-cli/e2e/tests/i18n/ivy-localize-server.ts +++ b/tests/legacy-cli/e2e/tests/i18n/ivy-localize-server.ts @@ -32,9 +32,6 @@ export default async function () { const serverbaseDir = 'dist/test-project/server'; const serverBuildArgs = ['run', 'test-project:server']; - // TODO: re-enable all locales once localeData support is added. - const tempLangTranslations = langTranslations.filter(l => l.lang == 'fr'); - // Add server-specific config. await updateJsonFile('angular.json', workspaceJson => { const appProject = workspaceJson.projects['test-project']; @@ -106,7 +103,7 @@ export default async function () { await ng('build'); await ng(...serverBuildArgs); - for (const { lang, translation } of tempLangTranslations) { + for (const { lang, translation } of langTranslations) { await expectFileToMatch(`${serverbaseDir}/${lang}/main.js`, translation.helloPartial); await expectToFail(() => expectFileToMatch(`${serverbaseDir}/${lang}/main.js`, '$localize`')); diff --git a/tests/legacy-cli/e2e/tests/i18n/legacy.ts b/tests/legacy-cli/e2e/tests/i18n/legacy.ts index 3ac3248a713e..90c60c6f302e 100644 --- a/tests/legacy-cli/e2e/tests/i18n/legacy.ts +++ b/tests/legacy-cli/e2e/tests/i18n/legacy.ts @@ -7,12 +7,11 @@ import { updateJsonFile } from '../../utils/project'; import { expectToFail } from '../../utils/utils'; import { readNgVersion } from '../../utils/version'; - // Configurations for each locale. export const baseDir = 'dist/test-project'; export const langTranslations = [ { - lang: 'en-US', outputPath: `${baseDir}/en`, + lang: 'en-US', outputPath: `${baseDir}/en-US`, translation: { helloPartial: 'Hello', hello: 'Hello i18n!', @@ -59,7 +58,6 @@ export const langTranslations = [ ]; export const sourceLocale = langTranslations[0].lang; export const externalServer = (outputPath: string) => { - // Ivy i18n doesn't yet work with `ng serve` so we must use a separate server. const app = express(); app.use(express.static(resolve(outputPath))); @@ -142,9 +140,7 @@ export async function setupI18nConfig(useLocalize = true) { if (useLocalize) { // Enable localization for all locales - // TODO: re-enable all locales once localeData support is added. - // appArchitect['build'].options.localize = true; - appArchitect['build'].options.localize = ['fr']; + appArchitect['build'].options.localize = true; } // Add i18n config items (app, build, serve, e2e).