diff --git a/packages/compiler-cli/ngcc/main-ngcc.ts b/packages/compiler-cli/ngcc/main-ngcc.ts index fe33eb9565..3864c70496 100644 --- a/packages/compiler-cli/ngcc/main-ngcc.ts +++ b/packages/compiler-cli/ngcc/main-ngcc.ts @@ -52,6 +52,17 @@ if (require.main === module) { 'The Angular CLI does this already, so it is safe to use this option if the project is being built via the CLI.', type: 'boolean', }) + .option('legacy-message-ids', { + describe: 'Render `$localize` messages with legacy format ids.\n' + + 'The default value is `true`. Only set this to `false` if you do not want legacy message ids to\n' + + 'be rendered. For example, if you are not using legacy message ids in your translation files\n' + + 'AND are not doing compile-time inlining of translations, in which case the extra message ids\n' + + 'would add unwanted size to the final source bundle.\n' + + 'It is safe to leave this set to true if you are doing compile-time inlining because the extra\n' + + 'legacy message ids will all be stripped during translation.', + type: 'boolean', + default: true, + }) .option('async', { describe: 'Whether to compile asynchronously. This is enabled by default as it allows compilations to be parallelized.\n' + @@ -81,6 +92,7 @@ if (require.main === module) { const compileAllFormats = !options['first-only']; const createNewEntryPointFormats = options['create-ivy-entry-points']; const logLevel = options['l'] as keyof typeof LogLevel | undefined; + const enableI18nLegacyMessageIdFormat = options['legacy-message-ids']; (async() => { try { @@ -93,6 +105,7 @@ if (require.main === module) { compileAllFormats, createNewEntryPointFormats, logger, + enableI18nLegacyMessageIdFormat, async: options['async'], }); diff --git a/packages/compiler-cli/ngcc/src/main.ts b/packages/compiler-cli/ngcc/src/main.ts index 1937eda373..0eafd2d247 100644 --- a/packages/compiler-cli/ngcc/src/main.ts +++ b/packages/compiler-cli/ngcc/src/main.ts @@ -97,6 +97,19 @@ export interface SyncNgccOptions { * Default: `false` (i.e. run synchronously) */ async?: false; + + /** + * Render `$localize` messages with legacy format ids. + * + * The default value is `true`. Only set this to `false` if you do not want legacy message ids to + * be rendered. For example, if you are not using legacy message ids in your translation files + * AND are not doing compile-time inlining of translations, in which case the extra message ids + * would add unwanted size to the final source bundle. + * + * It is safe to leave this set to true if you are doing compile-time inlining because the extra + * legacy message ids will all be stripped during translation. + */ + enableI18nLegacyMessageIdFormat?: boolean; } /** @@ -124,8 +137,8 @@ export function mainNgcc(options: SyncNgccOptions): void; export function mainNgcc( {basePath, targetEntryPointPath, propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES, compileAllFormats = true, createNewEntryPointFormats = false, - logger = new ConsoleLogger(LogLevel.info), pathMappings, async = false}: NgccOptions): void| - Promise { + logger = new ConsoleLogger(LogLevel.info), pathMappings, async = false, + enableI18nLegacyMessageIdFormat = true}: NgccOptions): void|Promise { // Execute in parallel, if async execution is acceptable and there are more than 1 CPU cores. const inParallel = async && (os.cpus().length > 1); @@ -242,7 +255,7 @@ export function mainNgcc( const bundle = makeEntryPointBundle( fileSystem, entryPoint, formatPath, isCore, format, processDts, pathMappings, true, - false); + enableI18nLegacyMessageIdFormat); logger.info(`Compiling ${entryPoint.name} : ${formatProperty} as ${format}`); diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index 13fe6d0a5d..0f7496d273 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -312,7 +312,7 @@ runInEachFileSystem(() => { expect(jsContents).not.toMatch(/\$localize\s*`/); expect(jsContents) .toMatch( - /\$localize\(ɵngcc\d+\.__makeTemplateObject\(\[":some:`description`:A message"], \[":some\\\\:\\\\`description\\\\`:A message"]\)\);/); + /\$localize\(ɵngcc\d+\.__makeTemplateObject\(\[":some:`description`\\u241Fefc92f285b3c24b083a8a594f62c7fccf3118766\\u241F3806630072763809030:A message"], \[":some\\\\:\\\\`description\\\\`\\u241Fefc92f285b3c24b083a8a594f62c7fccf3118766\\u241F3806630072763809030:A message"]\)\);/); }); describe('in async mode', () => { @@ -1219,6 +1219,62 @@ runInEachFileSystem(() => { }); }); + describe('legacy message ids', () => { + it('should render legacy message ids when compiling i18n tags in component templates', () => { + compileIntoApf('test-package', { + '/index.ts': ` + import {Component} from '@angular/core'; + + @Component({ + selector: '[base]', + template: '
Some message
' + }) + export class AppComponent {} + `, + }); + + mainNgcc({ + basePath: '/node_modules', + targetEntryPointPath: 'test-package', + propertiesToConsider: ['esm2015'], + }); + + + const jsContents = fs.readFile(_(`/node_modules/test-package/esm2015/src/index.js`)); + expect(jsContents) + .toContain( + '$localize `:␟888aea0e46f7e9dddbd95fc1ef380a3ff70ada9d␟1812794354835616626:Some message'); + }); + + it('should not render legacy message ids when compiling i18n tags in component templates if `enableI18nLegacyMessageIdFormat` is false', + () => { + compileIntoApf('test-package', { + '/index.ts': ` + import {Component} from '@angular/core'; + + @Component({ + selector: '[base]', + template: '
Some message
' + }) + export class AppComponent {} + `, + }); + + mainNgcc({ + basePath: '/node_modules', + targetEntryPointPath: 'test-package', + propertiesToConsider: ['esm2015'], + enableI18nLegacyMessageIdFormat: false, + }); + + + const jsContents = fs.readFile(_(`/node_modules/test-package/esm2015/src/index.js`)); + expect(jsContents).not.toContain('␟888aea0e46f7e9dddbd95fc1ef380a3ff70ada9d'); + expect(jsContents).not.toContain('␟1812794354835616626'); + expect(jsContents).not.toContain('␟'); + }); + }); + function loadPackage( packageName: string, basePath: AbsoluteFsPath = _('/node_modules')): EntryPointPackageJson { return JSON.parse(fs.readFile(fs.resolve(basePath, packageName, 'package.json')));