From 6f76d7484eba5e8616d55fcc7ffe9c59c24086e0 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Sun, 8 Dec 2019 19:47:11 -0500 Subject: [PATCH] fix(@angular-devkit/build-angular): ensure source locale data is injected when localizing Fixes #16389 --- .../build_angular/src/utils/i18n-options.ts | 60 ++++++++++--------- .../tests/i18n/ivy-localize-sourcelocale.ts | 46 ++++++++++++++ 2 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 tests/legacy-cli/e2e/tests/i18n/ivy-localize-sourcelocale.ts 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 42a031e52787..d2eade0b36aa 100644 --- a/packages/angular_devkit/build_angular/src/utils/i18n-options.ts +++ b/packages/angular_devkit/build_angular/src/utils/i18n-options.ts @@ -202,40 +202,46 @@ export async function configureI18nBuild(); for (const [locale, desc] of Object.entries(i18n.locales)) { - if (i18n.inlineLocales.has(locale) && desc.file) { - const result = loader(path.join(context.workspaceRoot, desc.file)); - - for (const diagnostics of result.diagnostics.messages) { - if (diagnostics.type === 'error') { - throw new Error( - `Error parsing translation file '${desc.file}': ${diagnostics.message}`, - ); - } else { - context.logger.warn(`WARNING [${desc.file}]: ${diagnostics.message}`); - } - } + if (!i18n.inlineLocales.has(locale)) { + continue; + } - usedFormats.add(result.format); - if (usedFormats.size > 1 && tsConfig.options.enableI18nLegacyMessageIdFormat !== false) { - // This limitation is only for legacy message id support (defaults to true as of 9.0) - throw new Error( - 'Localization currently only supports using one type of translation file format for the entire application.', - ); - } + const localeDataPath = findLocaleDataPath(locale, localeDataBasePath); + if (!localeDataPath) { + context.logger.warn( + `Locale data for '${locale}' cannot be found. No locale data will be included for this locale.`, + ); + } else { + desc.dataPath = localeDataPath; + } - desc.format = result.format; - desc.translation = result.translation; - desc.integrity = result.integrity; + if (!desc.file) { + continue; + } + + const result = loader(path.join(context.workspaceRoot, desc.file)); - const localeDataPath = findLocaleDataPath(locale, localeDataBasePath); - if (!localeDataPath) { - context.logger.warn( - `Locale data for '${locale}' cannot be found. No locale data will be included for this locale.`, + for (const diagnostics of result.diagnostics.messages) { + if (diagnostics.type === 'error') { + throw new Error( + `Error parsing translation file '${desc.file}': ${diagnostics.message}`, ); } else { - desc.dataPath = localeDataPath; + context.logger.warn(`WARNING [${desc.file}]: ${diagnostics.message}`); } } + + usedFormats.add(result.format); + if (usedFormats.size > 1 && tsConfig.options.enableI18nLegacyMessageIdFormat !== false) { + // This limitation is only for legacy message id support (defaults to true as of 9.0) + throw new Error( + 'Localization currently only supports using one type of translation file format for the entire application.', + ); + } + + desc.format = result.format; + desc.translation = result.translation; + desc.integrity = result.integrity; } // Legacy message id's require the format of the translations diff --git a/tests/legacy-cli/e2e/tests/i18n/ivy-localize-sourcelocale.ts b/tests/legacy-cli/e2e/tests/i18n/ivy-localize-sourcelocale.ts new file mode 100644 index 000000000000..7b8609a0852f --- /dev/null +++ b/tests/legacy-cli/e2e/tests/i18n/ivy-localize-sourcelocale.ts @@ -0,0 +1,46 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { expectFileToMatch } from '../../utils/fs'; +import { ng } from '../../utils/process'; +import { updateJsonFile } from '../../utils/project'; +import { externalServer, langTranslations, setupI18nConfig } from './legacy'; + +export default async function() { + // Setup i18n tests and config. + await setupI18nConfig(true); + + // Update angular.json + await updateJsonFile('angular.json', workspaceJson => { + const appProject = workspaceJson.projects['test-project']; + // tslint:disable-next-line: no-any + const i18n: Record = appProject.i18n; + + i18n.sourceLocale = 'fr'; + + delete i18n.locales['fr']; + }); + + // Build each locale and verify the output. + await ng('build'); + for (const { lang, outputPath } of langTranslations) { + // does not exist in this test due to the source locale change + if (lang === 'en-US') { + continue; + } + + 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}/vendor-es5.js`, '.ng.common.locales'); + await expectFileToMatch(`${outputPath}/vendor-es2015.js`, '.ng.common.locales'); + + // Verify the HTML lang attribute is present + await expectFileToMatch(`${outputPath}/index.html`, `lang="${lang}"`); + } +}