Skip to content

Re-enable global locale data support for Ivy #16196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 37 additions & 21 deletions packages/angular_devkit/build_angular/src/dev-server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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', () => {
Expand Down
24 changes: 8 additions & 16 deletions packages/angular_devkit/build_angular/src/utils/i18n-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,6 @@ export async function configureI18nBuild<T extends BrowserBuilderSchema | Server
}

const buildOptions = { ...options };

if (
buildOptions.localize === true ||
(Array.isArray(buildOptions.localize) && buildOptions.localize.length > 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);
Expand All @@ -129,6 +121,13 @@ export async function configureI18nBuild<T extends BrowserBuilderSchema | Server
context.logger.warn(`Option 'localize' is not supported with View Engine.`);
}

// Clear deprecated options when using Ivy to prevent unintended behavior
if (usingIvy) {
buildOptions.i18nFile = undefined;
buildOptions.i18nFormat = undefined;
buildOptions.i18nLocale = undefined;
}

if (i18n.inlineLocales.size > 0) {
const projectRoot = path.join(context.workspaceRoot, (metadata.root as string) || '');
const localeDataBasePath = findLocaleDataBasePath(projectRoot);
Expand Down Expand Up @@ -172,8 +171,7 @@ export async function configureI18nBuild<T extends BrowserBuilderSchema | Server
`Locale data for '${locale}' cannot be found. No locale data will be included for this locale.`,
);
} else {
// Temporarily disable pending FW locale data fix
// desc.dataPath = localeDataPath;
desc.dataPath = localeDataPath;
}
}
}
Expand All @@ -182,12 +180,6 @@ export async function configureI18nBuild<T extends BrowserBuilderSchema | Server
if (usedFormats.size > 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
Expand Down
28 changes: 13 additions & 15 deletions tests/legacy-cli/e2e/tests/i18n/ivy-localize-dl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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', '<p i18n>Other content</p>');
Expand All @@ -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();
}
Expand Down
6 changes: 1 addition & 5 deletions tests/legacy-cli/e2e/tests/i18n/ivy-localize-es2015.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`);
Expand Down
5 changes: 1 addition & 4 deletions tests/legacy-cli/e2e/tests/i18n/ivy-localize-es5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`);
Expand Down
5 changes: 1 addition & 4 deletions tests/legacy-cli/e2e/tests/i18n/ivy-localize-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'];
Expand Down Expand Up @@ -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`'));

Expand Down
8 changes: 2 additions & 6 deletions tests/legacy-cli/e2e/tests/i18n/legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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!',
Expand Down Expand Up @@ -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)));

Expand Down Expand Up @@ -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).
Expand Down