diff --git a/packages/compiler-cli/src/ngcc/src/analysis/decoration_analyzer.ts b/packages/compiler-cli/src/ngcc/src/analysis/decoration_analyzer.ts index 69ad987677..910c2d9e71 100644 --- a/packages/compiler-cli/src/ngcc/src/analysis/decoration_analyzer.ts +++ b/packages/compiler-cli/src/ngcc/src/analysis/decoration_analyzer.ts @@ -60,7 +60,7 @@ export class DecorationAnalyzer { new BaseDefDecoratorHandler(this.typeChecker, this.host), new ComponentDecoratorHandler( this.typeChecker, this.host, this.scopeRegistry, this.isCore, this.resourceLoader, - this.rootDirs, /* defaultPreserveWhitespaces */ false), + this.rootDirs, /* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true), new DirectiveDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore), new InjectableDecoratorHandler(this.host, this.isCore), new NgModuleDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore), diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts index e859f06ce9..8e40ecfe9e 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts @@ -40,7 +40,7 @@ export class ComponentDecoratorHandler implements private checker: ts.TypeChecker, private reflector: ReflectionHost, private scopeRegistry: SelectorScopeRegistry, private isCore: boolean, private resourceLoader: ResourceLoader, private rootDirs: string[], - private defaultPreserveWhitespaces: boolean) {} + private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean) {} private literalCache = new Map(); private elementSchemaRegistry = new DomElementSchemaRegistry(); @@ -131,7 +131,7 @@ export class ComponentDecoratorHandler implements // Go through the root directories for this project, and select the one with the smallest // relative path representation. const filePath = node.getSourceFile().fileName; - const relativeFilePath = this.rootDirs.reduce((previous, rootDir) => { + const relativeContextFilePath = this.rootDirs.reduce((previous, rootDir) => { const candidate = path.posix.relative(rootDir, filePath); if (previous === undefined || candidate.length < previous.length) { return candidate; @@ -142,7 +142,7 @@ export class ComponentDecoratorHandler implements const template = parseTemplate( templateStr, `${node.getSourceFile().fileName}#${node.name!.text}/template.html`, - {preserveWhitespaces}, relativeFilePath); + {preserveWhitespaces}); if (template.errors !== undefined) { throw new Error( `Errors parsing template: ${template.errors.map(e => e.toString()).join(', ')}`); @@ -212,7 +212,8 @@ export class ComponentDecoratorHandler implements directives: EMPTY_ARRAY, wrapDirectivesAndPipesInClosure: false, // animations, - viewProviders + viewProviders, + i18nUseExternalIds: this.i18nUseExternalIds, relativeContextFilePath }, metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.isCore), parsedTemplate: template.nodes, diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts index ffa02def51..1b3bd568b1 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts @@ -40,7 +40,7 @@ describe('ComponentDecoratorHandler', () => { const host = new TypeScriptReflectionHost(checker); const handler = new ComponentDecoratorHandler( checker, host, new SelectorScopeRegistry(checker, host), false, new NoopResourceLoader(), - [''], false); + [''], false, true); const TestCmp = getDeclaration(program, 'entry.ts', 'TestCmp', ts.isClassDeclaration); const detected = handler.detect(TestCmp, host.getDecoratorsOfDeclaration(TestCmp)); if (detected === undefined) { diff --git a/packages/compiler-cli/src/ngtsc/program.ts b/packages/compiler-cli/src/ngtsc/program.ts index 9ea3ba656f..c9d53e44ac 100644 --- a/packages/compiler-cli/src/ngtsc/program.ts +++ b/packages/compiler-cli/src/ngtsc/program.ts @@ -220,7 +220,7 @@ export class NgtscProgram implements api.Program { new BaseDefDecoratorHandler(checker, this.reflector), new ComponentDecoratorHandler( checker, this.reflector, scopeRegistry, this.isCore, this.resourceLoader, this.rootDirs, - this.options.preserveWhitespaces || false), + this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false), new DirectiveDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore), new InjectableDecoratorHandler(this.reflector, this.isCore), new NgModuleDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore), diff --git a/packages/compiler-cli/src/transformers/api.ts b/packages/compiler-cli/src/transformers/api.ts index de2ea79793..419596a0c8 100644 --- a/packages/compiler-cli/src/transformers/api.ts +++ b/packages/compiler-cli/src/transformers/api.ts @@ -151,6 +151,9 @@ export interface CompilerOptions extends ts.CompilerOptions { i18nInFile?: string; // How to handle missing messages i18nInMissingTranslations?: 'error'|'warning'|'ignore'; + // Whether translation variable name should contain external message id + // (used by Closure Compiler's output of `goog.getMsg` for transition period) + i18nUseExternalIds?: boolean; // Whether to remove blank text nodes from compiled templates. It is `false` by default starting // from Angular 6. diff --git a/packages/compiler-cli/src/transformers/program.ts b/packages/compiler-cli/src/transformers/program.ts index 8a10d93529..140420e9af 100644 --- a/packages/compiler-cli/src/transformers/program.ts +++ b/packages/compiler-cli/src/transformers/program.ts @@ -935,7 +935,8 @@ function getAotCompilerOptions(options: CompilerOptions): AotCompilerOptions { return { locale: options.i18nInLocale, - i18nFormat: options.i18nInFormat || options.i18nOutFormat, translations, missingTranslation, + i18nFormat: options.i18nInFormat || options.i18nOutFormat, + i18nUseExternalIds: options.i18nUseExternalIds, translations, missingTranslation, enableSummariesForJit: options.enableSummariesForJit, preserveWhitespaces: options.preserveWhitespaces, fullTemplateTypeCheck: options.fullTemplateTypeCheck, diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts index 1713ebd4a3..1f71e3f70e 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts @@ -26,6 +26,15 @@ const htmlParser = new HtmlParser(); const diff = (a: Set, b: Set): Set => new Set([...Array.from(a)].filter(x => !b.has(x))); +const extract = (from: string, regex: any, transformFn: (match: any[]) => any) => { + const result = new Set(); + let item; + while ((item = regex.exec(from)) !== null) { + result.add(transformFn(item)); + } + return result; +}; + // verify that we extracted all the necessary translations // and their ids match the ones extracted via 'ng xi18n' const verifyTranslationIds = (source: string, output: string, exceptions = {}) => { @@ -39,11 +48,9 @@ const verifyTranslationIds = (source: string, output: string, exceptions = {}) = extractedIds.add(id); extractedIdToMsg.set(id, msg); }); - const matched = output.match(/\[BACKUP_MESSAGE_ID:(.+?)\]/g) || []; - matched.forEach(match => { - const [key, id] = match.split(':'); - generatedIds.add(id.slice(0, -1)); - }); + const regexp = /const\s*MSG_EXTERNAL_(.+?)\s*=\s*goog\.getMsg/g; + const ids = extract(output, regexp, v => v[1]); + ids.forEach(id => { generatedIds.add(id.split('$$')[0]); }); const delta = diff(extractedIds, generatedIds); if (delta.size) { // check if we have ids in exception list @@ -61,14 +68,6 @@ const verifyTranslationIds = (source: string, output: string, exceptions = {}) = // verify that placeholders in translation string match // placeholders object defined as goog.getMsg function argument const verifyPlaceholdersIntegrity = (output: string) => { - const extract = (from: string, regex: any, transformFn: (match: any[]) => any) => { - const result = new Set(); - let item; - while ((item = regex.exec(from)) !== null) { - result.add(transformFn(item)); - } - return result; - }; const extactTranslations = (from: string) => { const regex = /const\s*(.*?)\s*=\s*goog\.getMsg\("(.*?)",?\s*(.*?)\)/g; return extract(from, regex, v => [v[2], v[3]]); @@ -110,21 +109,35 @@ const getAppFilesWithTemplate = (template: string, args: any = {}) => ({ } }); -const verify = (input: string, output: string, extra: any = {}) => { - const files = getAppFilesWithTemplate(input, extra.inputArgs); - const result = compile(files, angularFiles); - if (extra.verbose) { - // tslint:disable-next-line - console.log(` +const maybePrint = (output: string, verbose: boolean) => { + if (!verbose) return; + // tslint:disable-next-line + console.log(` ========== Generated output: ========== -${result.source} +${output} ======================================= - `); - } + `); +}; + +const verify = (input: string, output: string, extra: any = {}): void => { + const files = getAppFilesWithTemplate(input, extra.inputArgs); + const opts = (i18nUseExternalIds: boolean) => + ({i18nUseExternalIds, ...(extra.compilerOptions || {})}); + + // invoke with file-based prefix translation names + let result = compile(files, angularFiles, opts(false)); + maybePrint(result.source, extra.verbose); + expect(verifyPlaceholdersIntegrity(result.source)).toBe(true); + expectEmit(result.source, output, 'Incorrect template'); + + if (extra.skipIdBasedCheck) return; + + // invoke with translation names based on external ids + result = compile(files, angularFiles, opts(true)); + maybePrint(result.source, extra.verbose); expect(verifyTranslationIds(input, result.source, extra.exceptions)).toBe(true); expect(verifyPlaceholdersIntegrity(result.source)).toBe(true); expectEmit(result.source, output, 'Incorrect template'); - return result.source; }; describe('i18n support in the view compiler', () => { @@ -138,75 +151,72 @@ describe('i18n support in the view compiler', () => {
Content D
Content E
Content F
-
Content G
+
Content G
`; const output = ` /** - * @desc [BACKUP_MESSAGE_ID:idA] descA + * @desc descA * @meaning meaningA */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("Content A"); + const $MSG_EXTERNAL_idA$ = goog.getMsg("Content A"); /** - * @desc [BACKUP_MESSAGE_ID:idB] descB + * @desc descB * @meaning meaningB */ - const $MSG_APP_SPEC_TS_1$ = goog.getMsg("Title B"); - const $_c2$ = ["title", $MSG_APP_SPEC_TS_1$]; + const $MSG_EXTERNAL_idB$ = goog.getMsg("Title B"); + const $_c0$ = ["title", $MSG_EXTERNAL_idB$]; /** - * @desc [BACKUP_MESSAGE_ID:4978592519614169666] meaningC + * @desc meaningC */ - const $MSG_APP_SPEC_TS_3$ = goog.getMsg("Title C"); - const $_c4$ = ["title", $MSG_APP_SPEC_TS_3$]; + const $MSG_EXTERNAL_4978592519614169666$ = goog.getMsg("Title C"); + const $_c1$ = ["title", $MSG_EXTERNAL_4978592519614169666$]; /** - * @desc [BACKUP_MESSAGE_ID:5200291527729162531] descD + * @desc descD * @meaning meaningD */ - const $MSG_APP_SPEC_TS_5$ = goog.getMsg("Title D"); - const $_c6$ = ["title", $MSG_APP_SPEC_TS_5$]; + const $MSG_EXTERNAL_5200291527729162531$ = goog.getMsg("Title D"); + const $_c2$ = ["title", $MSG_EXTERNAL_5200291527729162531$]; /** - * @desc [BACKUP_MESSAGE_ID:idE] meaningE + * @desc meaningE */ - const $MSG_APP_SPEC_TS_7$ = goog.getMsg("Title E"); - const $_c8$ = ["title", $MSG_APP_SPEC_TS_7$]; + const $MSG_EXTERNAL_idE$ = goog.getMsg("Title E"); + const $_c3$ = ["title", $MSG_EXTERNAL_idE$]; + const $MSG_EXTERNAL_idF$ = goog.getMsg("Title F"); + const $_c4$ = ["title", $MSG_EXTERNAL_idF$]; /** - * @desc [BACKUP_MESSAGE_ID:idF] + * @desc [BACKUP_MESSAGE_ID:idH]desc */ - const $MSG_APP_SPEC_TS_9$ = goog.getMsg("Title F"); - const $_c10$ = ["title", $MSG_APP_SPEC_TS_9$]; - /** - * @desc [BACKUP_MESSAGE_ID:idG]desc - */ - const $MSG_APP_SPEC_TS_11$ = goog.getMsg("Title G"); - const $_c12$ = ["title", $MSG_APP_SPEC_TS_11$]; + const $MSG_EXTERNAL_idG$ = goog.getMsg("Title G"); + const $_c5$ = ["title", $MSG_EXTERNAL_idG$]; … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_idA$); $r3$.ɵelementEnd(); $r3$.ɵelementStart(2, "div"); - $r3$.ɵi18nAttributes(3, $_c2$); + $r3$.ɵi18nAttributes(3, $_c0$); $r3$.ɵtext(4, "Content B"); $r3$.ɵelementEnd(); $r3$.ɵelementStart(5, "div"); - $r3$.ɵi18nAttributes(6, $_c4$); + $r3$.ɵi18nAttributes(6, $_c1$); $r3$.ɵtext(7, "Content C"); $r3$.ɵelementEnd(); $r3$.ɵelementStart(8, "div"); - $r3$.ɵi18nAttributes(9, $_c6$); + $r3$.ɵi18nAttributes(9, $_c2$); $r3$.ɵtext(10, "Content D"); $r3$.ɵelementEnd(); $r3$.ɵelementStart(11, "div"); - $r3$.ɵi18nAttributes(12, $_c8$); + $r3$.ɵi18nAttributes(12, $_c3$); $r3$.ɵtext(13, "Content E"); $r3$.ɵelementEnd(); $r3$.ɵelementStart(14, "div"); - $r3$.ɵi18nAttributes(15, $_c10$); + $r3$.ɵi18nAttributes(15, $_c4$); $r3$.ɵtext(16, "Content F"); $r3$.ɵelementEnd(); $r3$.ɵelementStart(17, "div"); - $r3$.ɵi18nAttributes(18, $_c12$); + $r3$.ɵi18nAttributes(18, $_c5$); $r3$.ɵtext(19, "Content G"); $r3$.ɵelementEnd(); } @@ -242,16 +252,16 @@ describe('i18n support in the view compiler', () => { const output = ` const $_c0$ = ["id", "static"]; /** - * @desc [BACKUP_MESSAGE_ID:8809028065680254561] d + * @desc d * @meaning m */ - const $MSG_APP_SPEC_TS_1$ = goog.getMsg("introduction"); - const $_c2$ = ["title", $MSG_APP_SPEC_TS_1$]; + const $MSG_EXTERNAL_8809028065680254561$ = goog.getMsg("introduction"); + const $_c1$ = ["title", $MSG_EXTERNAL_8809028065680254561$]; … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div", $_c0$); - $r3$.ɵi18nAttributes(1, $_c2$); + $r3$.ɵi18nAttributes(1, $_c1$); $r3$.ɵelementEnd(); } } @@ -275,45 +285,47 @@ describe('i18n support in the view compiler', () => { const output = String.raw ` const $_c0$ = ["id", "dynamic-1"]; + const $MSG_EXTERNAL_5526535577705876535$ = goog.getMsg("static text"); /** - * @desc [BACKUP_MESSAGE_ID:5526535577705876535] - */ - const $MSG_APP_SPEC_TS_1$ = goog.getMsg("static text"); - /** - * @desc [BACKUP_MESSAGE_ID:8977039798304050198] d + * @desc d * @meaning m */ - const $MSG_APP_SPEC_TS_2$ = goog.getMsg("intro {$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_8977039798304050198$ = goog.getMsg("intro {$interpolation}", { + "interpolation": "\uFFFD0\uFFFD" + }); /** - * @desc [BACKUP_MESSAGE_ID:7432761130955693041] d1 + * @desc d1 * @meaning m1 */ - const $MSG_APP_SPEC_TS_3$ = goog.getMsg("{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); - const $_c4$ = ["aria-roledescription", $MSG_APP_SPEC_TS_1$, "title", $MSG_APP_SPEC_TS_2$, "aria-label", $MSG_APP_SPEC_TS_3$]; - const $_c5$ = ["id", "dynamic-2"]; + const $MSG_EXTERNAL_7432761130955693041$ = goog.getMsg("{$interpolation}", { + "interpolation": "\uFFFD0\uFFFD" + }); + const $_c1$ = [ + "aria-roledescription", $MSG_EXTERNAL_5526535577705876535$, + "title", $MSG_EXTERNAL_8977039798304050198$, + "aria-label", $MSG_EXTERNAL_7432761130955693041$ + ]; + const $_c2$ = ["id", "dynamic-2"]; /** - * @desc [BACKUP_MESSAGE_ID:7566208596013750546] d2 + * @desc d2 * @meaning m2 */ - const $MSG_APP_SPEC_TS_6$ = goog.getMsg("{$interpolation} and {$interpolation_1} and again {$interpolation_2}", { + const $MSG_EXTERNAL_7566208596013750546$ = goog.getMsg("{$interpolation} and {$interpolation_1} and again {$interpolation_2}", { "interpolation": "\uFFFD0\uFFFD", "interpolation_1": "\uFFFD1\uFFFD", "interpolation_2": "\uFFFD2\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:6639222533406278123] - */ - const $MSG_APP_SPEC_TS_7$ = goog.getMsg("{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); - const _c8 = ["title", $MSG_APP_SPEC_TS_6$, "aria-roledescription", $MSG_APP_SPEC_TS_7$]; + const $MSG_EXTERNAL_6639222533406278123$ = goog.getMsg("{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); + const $_c3$ = ["title", $MSG_EXTERNAL_7566208596013750546$, "aria-roledescription", $MSG_EXTERNAL_6639222533406278123$]; … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div", $_c0$); $r3$.ɵpipe(1, "uppercase"); - $r3$.ɵi18nAttributes(2, $_c4$); + $r3$.ɵi18nAttributes(2, $_c1$); $r3$.ɵelementEnd(); - $r3$.ɵelementStart(3, "div", $_c5$); - $r3$.ɵi18nAttributes(4, $_c8$); + $r3$.ɵelementStart(3, "div", $_c2$); + $r3$.ɵi18nAttributes(4, $_c3$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -342,17 +354,19 @@ describe('i18n support in the view compiler', () => { const output = String.raw ` const $_c0$ = ["ngFor", "", 1, "ngForOf"]; /** - * @desc [BACKUP_MESSAGE_ID:8538466649243975456] d + * @desc d * @meaning m */ - const $MSG_APP_SPEC_TS__1$ = goog.getMsg("different scope {$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); - const $_c2$ = ["title", $MSG_APP_SPEC_TS__1$]; + const $MSG_EXTERNAL_8538466649243975456$ = goog.getMsg("different scope {$interpolation}", { + "interpolation": "\uFFFD0\uFFFD" + }); + const $_c1$ = ["title", $MSG_EXTERNAL_8538466649243975456$]; function MyComponent_div_Template_0(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵelementStart(1, "div"); $r3$.ɵpipe(2, "uppercase"); - $r3$.ɵi18nAttributes(3, $_c2$); + $r3$.ɵi18nAttributes(3, $_c1$); $r3$.ɵelementEnd(); $r3$.ɵelementEnd(); } @@ -391,45 +405,45 @@ describe('i18n support in the view compiler', () => { const output = String.raw ` const $_c0$ = ["id", "dynamic-1"]; + const $MSG_EXTERNAL_5526535577705876535$ = goog.getMsg("static text"); /** - * @desc [BACKUP_MESSAGE_ID:5526535577705876535] - */ - const $MSG_APP_SPEC_TS_1$ = goog.getMsg("static text"); - /** - * @desc [BACKUP_MESSAGE_ID:8977039798304050198] d + * @desc d * @meaning m */ - const $MSG_APP_SPEC_TS_2$ = goog.getMsg("intro {$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_8977039798304050198$ = goog.getMsg("intro {$interpolation}", { + "interpolation": "\uFFFD0\uFFFD" + }); /** - * @desc [BACKUP_MESSAGE_ID:7432761130955693041] d1 + * @desc d1 * @meaning m1 */ - const $MSG_APP_SPEC_TS_3$ = goog.getMsg("{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); - const $_c4$ = ["aria-roledescription", $MSG_APP_SPEC_TS_1$, "title", $MSG_APP_SPEC_TS_2$, "aria-label", $MSG_APP_SPEC_TS_3$]; - const $_c5$ = ["id", "dynamic-2"]; + const $MSG_EXTERNAL_7432761130955693041$ = goog.getMsg("{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); + const $_c1$ = [ + "aria-roledescription", $MSG_EXTERNAL_5526535577705876535$, + "title", $MSG_EXTERNAL_8977039798304050198$, + "aria-label", $MSG_EXTERNAL_7432761130955693041$ + ]; + const $_c2$ = ["id", "dynamic-2"]; /** - * @desc [BACKUP_MESSAGE_ID:7566208596013750546] d2 + * @desc d2 * @meaning m2 */ - const $MSG_APP_SPEC_TS_6$ = goog.getMsg("{$interpolation} and {$interpolation_1} and again {$interpolation_2}", { + const $MSG_EXTERNAL_7566208596013750546$ = goog.getMsg("{$interpolation} and {$interpolation_1} and again {$interpolation_2}", { "interpolation": "\uFFFD0\uFFFD", "interpolation_1": "\uFFFD1\uFFFD", "interpolation_2": "\uFFFD2\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:6639222533406278123] - */ - const $MSG_APP_SPEC_TS_7$ = goog.getMsg("{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); - const $_c8$ = ["title", $MSG_APP_SPEC_TS_6$, "aria-roledescription", $MSG_APP_SPEC_TS_7$]; + const $MSG_EXTERNAL_6639222533406278123$ = goog.getMsg("{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); + const $_c3$ = ["title", $MSG_EXTERNAL_7566208596013750546$, "aria-roledescription", $MSG_EXTERNAL_6639222533406278123$]; … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div", $_c0$); $r3$.ɵpipe(1, "uppercase"); - $r3$.ɵi18nAttributes(2, $_c4$); + $r3$.ɵi18nAttributes(2, $_c1$); $r3$.ɵelementEnd(); - $r3$.ɵelementStart(3, "div", $_c5$); - $r3$.ɵi18nAttributes(4, $_c8$); + $r3$.ɵelementStart(3, "div", $_c2$); + $r3$.ɵi18nAttributes(4, $_c3$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -458,17 +472,19 @@ describe('i18n support in the view compiler', () => { const output = String.raw ` const $_c0$ = ["ngFor", "", 1, "ngForOf"]; /** - * @desc [BACKUP_MESSAGE_ID:8538466649243975456] d + * @desc d * @meaning m */ - const $MSG_APP_SPEC_TS__1$ = goog.getMsg("different scope {$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); - const $_c2$ = ["title", $MSG_APP_SPEC_TS__1$]; + const $MSG_EXTERNAL_8538466649243975456$ = goog.getMsg("different scope {$interpolation}", { + "interpolation": "\uFFFD0\uFFFD" + }); + const $_c1$ = ["title", $MSG_EXTERNAL_8538466649243975456$]; function MyComponent_div_Template_0(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵelementStart(1, "div"); $r3$.ɵpipe(2, "uppercase"); - $r3$.ɵi18nAttributes(3, $_c2$); + $r3$.ɵi18nAttributes(3, $_c1$); $r3$.ɵelementEnd(); $r3$.ɵelementEnd(); } @@ -499,21 +515,18 @@ describe('i18n support in the view compiler', () => { const output = String.raw ` /** - * @desc [BACKUP_MESSAGE_ID:7727043314656808423] d + * @desc d * @meaning m */ - const $MSG_APP_SPEC_TS_1$ = goog.getMsg("Element title"); - const $_c2$ = ["title", $MSG_APP_SPEC_TS_1$]; - /** - * @desc [BACKUP_MESSAGE_ID:4969674997806975147] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("Some content"); + const $MSG_EXTERNAL_7727043314656808423$ = goog.getMsg("Element title"); + const $_c0$ = ["title", $MSG_EXTERNAL_7727043314656808423$]; + const $MSG_EXTERNAL_4969674997806975147$ = goog.getMsg("Some content"); … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); - $r3$.ɵi18nAttributes(2, $_c2$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_4969674997806975147$); + $r3$.ɵi18nAttributes(2, $_c0$); $r3$.ɵelementEnd(); } } @@ -556,10 +569,7 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:4924931801512133405] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("Some text 'with single quotes', \"with double quotes\" and without quotes."); + const $MSG_EXTERNAL_4924931801512133405$ = goog.getMsg("Some text 'with single quotes', \"with double quotes\" and without quotes."); `; verify(input, output); @@ -575,35 +585,26 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:4890179241114413722] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("My i18n block #1"); - /** - * @desc [BACKUP_MESSAGE_ID:2413150872298537152] - */ - const $MSG_APP_SPEC_TS_1$ = goog.getMsg("My i18n block #2"); - /** - * @desc [BACKUP_MESSAGE_ID:5023003143537152794] - */ - const $MSG_APP_SPEC_TS_2$ = goog.getMsg("My i18n block #3"); + const $MSG_EXTERNAL_4890179241114413722$ = goog.getMsg("My i18n block #1"); + const $MSG_EXTERNAL_2413150872298537152$ = goog.getMsg("My i18n block #2"); + const $MSG_EXTERNAL_5023003143537152794$ = goog.getMsg("My i18n block #3"); … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_4890179241114413722$); $r3$.ɵelementEnd(); $r3$.ɵelementStart(2, "div"); $r3$.ɵtext(3, "My non-i18n block #1"); $r3$.ɵelementEnd(); $r3$.ɵelementStart(4, "div"); - $r3$.ɵi18n(5, $MSG_APP_SPEC_TS_1$); + $r3$.ɵi18n(5, $MSG_EXTERNAL_2413150872298537152$); $r3$.ɵelementEnd(); $r3$.ɵelementStart(6, "div"); $r3$.ɵtext(7, "My non-i18n block #2"); $r3$.ɵelementEnd(); $r3$.ɵelementStart(8, "div"); - $r3$.ɵi18n(9, $MSG_APP_SPEC_TS_2$); + $r3$.ɵi18n(9, $MSG_EXTERNAL_5023003143537152794$); $r3$.ɵelementEnd(); } } @@ -618,15 +619,12 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:2817319788724342848] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("Some value: {$phA}", { "phA": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_2817319788724342848$ = goog.getMsg("Some value: {$phA}", { "phA": "\uFFFD0\uFFFD" }); … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_2817319788724342848$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -647,30 +645,21 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:572579892698764378] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("My i18n block #{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:609623417156596326] - */ - const $MSG_APP_SPEC_TS_1$ = goog.getMsg("My i18n block #{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:3998119318957372120] - */ - const $MSG_APP_SPEC_TS_2$ = goog.getMsg("My i18n block #{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_572579892698764378$ = goog.getMsg("My i18n block #{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_609623417156596326$ = goog.getMsg("My i18n block #{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_3998119318957372120$ = goog.getMsg("My i18n block #{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_572579892698764378$); $r3$.ɵelementEnd(); $r3$.ɵelementStart(2, "div"); - $r3$.ɵi18n(3, $MSG_APP_SPEC_TS_1$); + $r3$.ɵi18n(3, $MSG_EXTERNAL_609623417156596326$); $r3$.ɵpipe(4, "uppercase"); $r3$.ɵelementEnd(); $r3$.ɵelementStart(5, "div"); - $r3$.ɵi18n(6, $MSG_APP_SPEC_TS_2$); + $r3$.ɵi18n(6, $MSG_EXTERNAL_3998119318957372120$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -706,18 +695,12 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:7905233330103651696] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg(" My i18n block #{$interpolation} {$startTagSpan}Plain text in nested element{$closeTagSpan}", { + const $MSG_EXTERNAL_7905233330103651696$ = goog.getMsg(" My i18n block #{$interpolation} {$startTagSpan}Plain text in nested element{$closeTagSpan}", { "interpolation": "\uFFFD0\uFFFD", "startTagSpan": "\uFFFD#2\uFFFD", "closeTagSpan": "\uFFFD/#2\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:5788821996131681377] - */ - const $MSG_APP_SPEC_TS_1_RAW$ = goog.getMsg(" My i18n block #{$interpolation} {$startTagDiv}{$startTagDiv}{$startTagSpan} More bindings in more nested element: {$interpolation_1} {$closeTagSpan}{$closeTagDiv}{$closeTagDiv}", { + const $MSG_EXTERNAL_5788821996131681377_RAW$ = goog.getMsg(" My i18n block #{$interpolation} {$startTagDiv}{$startTagDiv}{$startTagSpan} More bindings in more nested element: {$interpolation_1} {$closeTagSpan}{$closeTagDiv}{$closeTagDiv}", { "interpolation": "\uFFFD0\uFFFD", "startTagDiv": "[\uFFFD#6\uFFFD|\uFFFD#7\uFFFD]", "startTagSpan": "\uFFFD#8\uFFFD", @@ -725,17 +708,17 @@ describe('i18n support in the view compiler', () => { "closeTagSpan": "\uFFFD/#8\uFFFD", "closeTagDiv": "[\uFFFD/#7\uFFFD|\uFFFD/#6\uFFFD]" }); - const $MSG_APP_SPEC_TS_1$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_1_RAW$); + const $MSG_EXTERNAL_5788821996131681377$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_5788821996131681377_RAW$); … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18nStart(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18nStart(1, $MSG_EXTERNAL_7905233330103651696$); $r3$.ɵelement(2, "span"); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); $r3$.ɵelementStart(3, "div"); - $r3$.ɵi18nStart(4, $MSG_APP_SPEC_TS_1$); + $r3$.ɵi18nStart(4, $MSG_EXTERNAL_5788821996131681377$); $r3$.ɵpipe(5, "uppercase"); $r3$.ɵelementStart(6, "div"); $r3$.ɵelementStart(7, "div"); @@ -775,31 +758,19 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:4782264005467235841] - */ - const $MSG_APP_SPEC_TS_1$ = goog.getMsg("Span title {$interpolation} and {$interpolation_1}", { + const $MSG_EXTERNAL_4782264005467235841$ = goog.getMsg("Span title {$interpolation} and {$interpolation_1}", { "interpolation": "\uFFFD0\uFFFD", "interpolation_1": "\uFFFD1\uFFFD" }); - const $_c2$ = ["title", $MSG_APP_SPEC_TS_1$]; - /** - * @desc [BACKUP_MESSAGE_ID:4446430594603971069] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg(" My i18n block #1 with value: {$interpolation} {$startTagSpan} Plain text in nested element (block #1) {$closeTagSpan}", { + const $_c0$ = ["title", $MSG_EXTERNAL_4782264005467235841$]; + const $MSG_EXTERNAL_4446430594603971069$ = goog.getMsg(" My i18n block #1 with value: {$interpolation} {$startTagSpan} Plain text in nested element (block #1) {$closeTagSpan}", { "interpolation": "\uFFFD0\uFFFD", "startTagSpan": "\uFFFD#2\uFFFD", "closeTagSpan": "\uFFFD/#2\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:2719594642740200058] - */ - const $MSG_APP_SPEC_TS_4$ = goog.getMsg("Span title {$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); - const $_c5$ = ["title", $MSG_APP_SPEC_TS_4$]; - /** - * @desc [BACKUP_MESSAGE_ID:2778714953278357902] - */ - const $MSG_APP_SPEC_TS_3$ = goog.getMsg(" My i18n block #2 with value {$interpolation} {$startTagSpan} Plain text in nested element (block #2) {$closeTagSpan}", { + const $MSG_EXTERNAL_2719594642740200058$ = goog.getMsg("Span title {$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); + const $_c1$ = ["title", $MSG_EXTERNAL_2719594642740200058$]; + const $MSG_EXTERNAL_2778714953278357902$ = goog.getMsg(" My i18n block #2 with value {$interpolation} {$startTagSpan} Plain text in nested element (block #2) {$closeTagSpan}", { "interpolation": "\uFFFD0\uFFFD", "startTagSpan": "\uFFFD#7\uFFFD", "closeTagSpan": "\uFFFD/#7\uFFFD" @@ -808,17 +779,17 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18nStart(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18nStart(1, $MSG_EXTERNAL_4446430594603971069$); $r3$.ɵelementStart(2, "span"); - $r3$.ɵi18nAttributes(3, $_c2$); + $r3$.ɵi18nAttributes(3, $_c0$); $r3$.ɵelementEnd(); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); $r3$.ɵelementStart(4, "div"); - $r3$.ɵi18nStart(5, $MSG_APP_SPEC_TS_3$); + $r3$.ɵi18nStart(5, $MSG_EXTERNAL_2778714953278357902$); $r3$.ɵpipe(6, "uppercase"); $r3$.ɵelementStart(7, "span"); - $r3$.ɵi18nAttributes(8, $_c5$); + $r3$.ɵi18nAttributes(8, $_c1$); $r3$.ɵelementEnd(); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); @@ -857,10 +828,7 @@ describe('i18n support in the view compiler', () => { const output = String.raw ` const $_c0$ = [1, "ngIf"]; - /** - * @desc [BACKUP_MESSAGE_ID:7679414751795588050] - */ - const $MSG_APP_SPEC_TS__1$ = goog.getMsg(" Some other content {$interpolation} {$startTagDiv} More nested levels with bindings {$interpolation_1} {$closeTagDiv}", { + const $MSG_EXTERNAL_7679414751795588050$ = goog.getMsg(" Some other content {$interpolation} {$startTagDiv} More nested levels with bindings {$interpolation_1} {$closeTagDiv}", { "interpolation": "\uFFFD0\uFFFD", "startTagDiv": "\uFFFD#3\uFFFD", "interpolation_1": "\uFFFD1\uFFFD", @@ -871,7 +839,7 @@ describe('i18n support in the view compiler', () => { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵelementStart(1, "div"); - $r3$.ɵi18nStart(2, $MSG_APP_SPEC_TS__1$); + $r3$.ɵi18nStart(2, $MSG_EXTERNAL_7679414751795588050$); $r3$.ɵelement(3, "div"); $r3$.ɵpipe(4, "uppercase"); $r3$.ɵi18nEnd(); @@ -912,18 +880,19 @@ describe('i18n support in the view compiler', () => { const output = String.raw ` const $_c0$ = ["src", "logo.png"]; const $_c1$ = [1, "ngIf"]; - function MyComponent_img_Template_1(rf, ctx) { if (rf & 1) { + function MyComponent_img_Template_1(rf, ctx) { + if (rf & 1) { $r3$.ɵelement(0, "img", $_c0$); - } } - /** - * @desc [BACKUP_MESSAGE_ID:2367729185105559721] - */ - const $MSG_APP_SPEC_TS__2$ = goog.getMsg("App logo #{$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); - const $_c3$ = ["title", $MSG_APP_SPEC_TS__2$]; + } + } + const $MSG_EXTERNAL_2367729185105559721$ = goog.getMsg("App logo #{$interpolation}", { + "interpolation": "\uFFFD0\uFFFD" + }); + const $_c2$ = ["title", $MSG_EXTERNAL_2367729185105559721$]; function MyComponent_img_Template_2(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "img", $_c0$); - $r3$.ɵi18nAttributes(1, $_c3$); + $r3$.ɵi18nAttributes(1, $_c2$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -975,10 +944,10 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - const $_c1$ = [1, "ngIf"]; + const $_c0$ = [1, "ngIf"]; function MyComponent_div_div_Template_4(rf, ctx) { if (rf & 1) { - $r3$.ɵi18nStart(0, $MSG_APP_SPEC_TS_0$, 2); + $r3$.ɵi18nStart(0, $MSG_EXTERNAL_1221890473527419724$, 2); $r3$.ɵelementStart(1, "div"); $r3$.ɵelement(2, "div"); $r3$.ɵelementEnd(); @@ -993,7 +962,7 @@ describe('i18n support in the view compiler', () => { } function MyComponent_div_Template_2(rf, ctx) { if (rf & 1) { - $r3$.ɵi18nStart(0, $MSG_APP_SPEC_TS_0$, 1); + $r3$.ɵi18nStart(0, $MSG_EXTERNAL_1221890473527419724$, 1); $r3$.ɵelementStart(1, "div"); $r3$.ɵelementStart(2, "div"); $r3$.ɵpipe(3, "uppercase"); @@ -1010,10 +979,7 @@ describe('i18n support in the view compiler', () => { $r3$.ɵi18nApply(0); } } - /** - * @desc [BACKUP_MESSAGE_ID:1221890473527419724] - */ - const $MSG_APP_SPEC_TS_0_RAW$ = goog.getMsg(" Some content {$startTagDiv_2} Some other content {$interpolation} {$startTagDiv} More nested levels with bindings {$interpolation_1} {$startTagDiv_1} Content inside sub-template {$interpolation_2} {$startTagDiv} Bottom level element {$interpolation_3} {$closeTagDiv}{$closeTagDiv}{$closeTagDiv}{$closeTagDiv}{$startTagDiv_3} Some other content {$interpolation_4} {$startTagDiv} More nested levels with bindings {$interpolation_5} {$closeTagDiv}{$closeTagDiv}", { + const $MSG_EXTERNAL_1221890473527419724$$RAW$ = goog.getMsg(" Some content {$startTagDiv_2} Some other content {$interpolation} {$startTagDiv} More nested levels with bindings {$interpolation_1} {$startTagDiv_1} Content inside sub-template {$interpolation_2} {$startTagDiv} Bottom level element {$interpolation_3} {$closeTagDiv}{$closeTagDiv}{$closeTagDiv}{$closeTagDiv}{$startTagDiv_3} Some other content {$interpolation_4} {$startTagDiv} More nested levels with bindings {$interpolation_5} {$closeTagDiv}{$closeTagDiv}", { "startTagDiv_2": "\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD", "closeTagDiv": "[\uFFFD/#2:2\uFFFD|\uFFFD/#1:2\uFFFD\uFFFD/*4:2\uFFFD|\uFFFD/#2:1\uFFFD|\uFFFD/#1:1\uFFFD\uFFFD/*2:1\uFFFD|\uFFFD/#2:3\uFFFD|\uFFFD/#1:3\uFFFD\uFFFD/*3:3\uFFFD]", "startTagDiv_3": "\uFFFD*3:3\uFFFD\uFFFD#1:3\uFFFD", @@ -1026,10 +992,10 @@ describe('i18n support in the view compiler', () => { "interpolation_4": "\uFFFD0:3\uFFFD", "interpolation_5": "\uFFFD1:3\uFFFD" }); - const $MSG_APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0_RAW$); + const $MSG_EXTERNAL_1221890473527419724$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_1221890473527419724$$RAW$); function MyComponent_div_Template_3(rf, ctx) { if (rf & 1) { - $r3$.ɵi18nStart(0, $MSG_APP_SPEC_TS_0$, 3); + $r3$.ɵi18nStart(0, $MSG_EXTERNAL_1221890473527419724$, 3); $r3$.ɵelementStart(1, "div"); $r3$.ɵelement(2, "div"); $r3$.ɵpipe(3, "uppercase"); @@ -1070,10 +1036,7 @@ describe('i18n support in the view compiler', () => { const output = String.raw ` const $_c0$ = [1, "ngIf"]; - /** - * @desc [BACKUP_MESSAGE_ID:119975189388320493] - */ - const $MSG_APP_SPEC_TS__1$ = goog.getMsg("Some other content {$startTagSpan}{$interpolation}{$closeTagSpan}", { + const $MSG_EXTERNAL_119975189388320493$ = goog.getMsg("Some other content {$startTagSpan}{$interpolation}{$closeTagSpan}", { "startTagSpan": "\uFFFD#2\uFFFD", "interpolation": "\uFFFD0\uFFFD", "closeTagSpan": "\uFFFD/#2\uFFFD" @@ -1082,7 +1045,7 @@ describe('i18n support in the view compiler', () => { function MyComponent_div_Template_0(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18nStart(1, $MSG_APP_SPEC_TS__1$); + $r3$.ɵi18nStart(1, $MSG_EXTERNAL_119975189388320493$); $r3$.ɵelement(2, "span"); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); @@ -1115,15 +1078,12 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:4890179241114413722] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("My i18n block #1"); + const $MSG_EXTERNAL_4890179241114413722$ = goog.getMsg("My i18n block #1"); … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_4890179241114413722$); $r3$.ɵelementEnd(); } } @@ -1138,16 +1098,15 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:8806993169187953163] - */ - const $MSG_APP_SPEC_TS_0_RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}"); - const $MSG_APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_8806993169187953163$$RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}"); + const $MSG_EXTERNAL_8806993169187953163$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_8806993169187953163$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_8806993169187953163$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -1167,17 +1126,11 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:2413150872298537152] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("My i18n block #2"); - /** - * @desc [BACKUP_MESSAGE_ID:4890179241114413722] - */ - const $MSG_APP_SPEC_TS__1$ = goog.getMsg("My i18n block #1"); + const $MSG_EXTERNAL_2413150872298537152$ = goog.getMsg("My i18n block #2"); + const $MSG_EXTERNAL_4890179241114413722$ = goog.getMsg("My i18n block #1"); function Template_0(rf, ctx) { if (rf & 1) { - $r3$.ɵi18n(0, $MSG_APP_SPEC_TS__1$); + $r3$.ɵi18n(0, $MSG_EXTERNAL_4890179241114413722$); } } … @@ -1185,7 +1138,7 @@ describe('i18n support in the view compiler', () => { if (rf & 1) { $r3$.ɵtemplate(0, Template_0, 1, 0); $r3$.ɵelementContainerStart(1); - $r3$.ɵi18n(2, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(2, $MSG_EXTERNAL_2413150872298537152$); $r3$.ɵelementContainerEnd(); } } @@ -1202,15 +1155,14 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:355394464191978948] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("Some content: {$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_355394464191978948$ = goog.getMsg("Some content: {$interpolation}", { + "interpolation": "\uFFFD0\uFFFD" + }); … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementContainerStart(0); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_355394464191978948$); $r3$.ɵpipe(2, "uppercase"); $r3$.ɵelementContainerEnd(); } @@ -1230,13 +1182,12 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:355394464191978948] - */ - const $MSG_APP_SPEC_TS__0$ = goog.getMsg("Some content: {$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_355394464191978948$ = goog.getMsg("Some content: {$interpolation}", { + "interpolation": "\uFFFD0\uFFFD" + }); function Template_0(rf, ctx) { if (rf & 1) { - $r3$.ɵi18n(0, $MSG_APP_SPEC_TS__0$); + $r3$.ɵi18n(0, $MSG_EXTERNAL_355394464191978948$); $r3$.ɵpipe(1, "uppercase"); } if (rf & 2) { const $ctx_r0$ = $r3$.ɵnextContext(); @@ -1264,10 +1215,7 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:702706566400598764] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("{$startTagNgTemplate}Template content: {$interpolation}{$closeTagNgTemplate}{$startTagNgContainer}Container content: {$interpolation_1}{$closeTagNgContainer}", { + const $MSG_EXTERNAL_702706566400598764$ = goog.getMsg("{$startTagNgTemplate}Template content: {$interpolation}{$closeTagNgTemplate}{$startTagNgContainer}Container content: {$interpolation_1}{$closeTagNgContainer}", { "startTagNgTemplate": "\uFFFD*2:1\uFFFD", "closeTagNgTemplate": "\uFFFD/*2:1\uFFFD", "startTagNgContainer": "\uFFFD#3\uFFFD", @@ -1277,7 +1225,7 @@ describe('i18n support in the view compiler', () => { }); function Template_2(rf, ctx) { if (rf & 1) { - $r3$.ɵi18n(0, $MSG_APP_SPEC_TS_0$, 1); + $r3$.ɵi18n(0, $MSG_EXTERNAL_702706566400598764$, 1); $r3$.ɵpipe(1, "uppercase"); } if (rf & 2) { @@ -1290,7 +1238,7 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18nStart(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18nStart(1, $MSG_EXTERNAL_702706566400598764$); $r3$.ɵtemplate(2, Template_2, 2, 2); $r3$.ɵelementContainerStart(3); $r3$.ɵpipe(4, "uppercase"); @@ -1315,19 +1263,17 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:8806993169187953163] - */ - const $MSG_APP_SPEC_TS_0_RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}"); - const $MSG_APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:7842238767399919809] - */ - const $MSG_APP_SPEC_TS__1_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); - const $MSG_APP_SPEC_TS__1$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS__1_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_8806993169187953163$$RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}"); + const $MSG_EXTERNAL_8806993169187953163$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_8806993169187953163$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); + const $MSG_EXTERNAL_7842238767399919809$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); + const $MSG_EXTERNAL_7842238767399919809$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_7842238767399919809$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); function Template_0(rf, ctx) { if (rf & 1) { - $r3$.ɵi18n(0, $MSG_APP_SPEC_TS__1$); + $r3$.ɵi18n(0, $MSG_EXTERNAL_7842238767399919809$); } if (rf & 2) { const $ctx_r0$ = $r3$.ɵnextContext(); @@ -1340,7 +1286,7 @@ describe('i18n support in the view compiler', () => { if (rf & 1) { $r3$.ɵtemplate(0, Template_0, 1, 0); $r3$.ɵelementContainerStart(1); - $r3$.ɵi18n(2, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(2, $MSG_EXTERNAL_8806993169187953163$); $r3$.ɵelementContainerEnd(); } if (rf & 2) { @@ -1371,7 +1317,7 @@ describe('i18n support in the view compiler', () => { const output = String.raw ` function Template_1(rf, ctx) { if (rf & 1) { - $r3$.ɵi18n(0, $MSG_APP_SPEC_TS_0$, 3); + $r3$.ɵi18n(0, $MSG_EXTERNAL_2051477021417799640$, 3); } if (rf & 2) { const $ctx_r2$ = $r3$.ɵnextContext(3); @@ -1381,7 +1327,7 @@ describe('i18n support in the view compiler', () => { } function Template_2(rf, ctx) { if (rf & 1) { - $r3$.ɵi18nStart(0, $MSG_APP_SPEC_TS_0$, 2); + $r3$.ɵi18nStart(0, $MSG_EXTERNAL_2051477021417799640$, 2); $r3$.ɵtemplate(1, Template_1, 1, 0); $r3$.ɵi18nEnd(); } @@ -1391,20 +1337,17 @@ describe('i18n support in the view compiler', () => { $r3$.ɵi18nApply(0); } } - /** - * @desc [BACKUP_MESSAGE_ID:2051477021417799640] - */ - const $MSG_APP_SPEC_TS_0_RAW$ = goog.getMsg("{$startTagNgTemplate} Template A: {$interpolation} {$startTagNgTemplate} Template B: {$interpolation_1} {$startTagNgTemplate} Template C: {$interpolation_2} {$closeTagNgTemplate}{$closeTagNgTemplate}{$closeTagNgTemplate}", { + const $MSG_EXTERNAL_2051477021417799640$$RAW$ = goog.getMsg("{$startTagNgTemplate} Template A: {$interpolation} {$startTagNgTemplate} Template B: {$interpolation_1} {$startTagNgTemplate} Template C: {$interpolation_2} {$closeTagNgTemplate}{$closeTagNgTemplate}{$closeTagNgTemplate}", { "startTagNgTemplate": "[\uFFFD*2:1\uFFFD|\uFFFD*2:2\uFFFD|\uFFFD*1:3\uFFFD]", "closeTagNgTemplate": "[\uFFFD/*1:3\uFFFD|\uFFFD/*2:2\uFFFD|\uFFFD/*2:1\uFFFD]", "interpolation": "\uFFFD0:1\uFFFD", "interpolation_1": "\uFFFD0:2\uFFFD", "interpolation_2": "\uFFFD0:3\uFFFD" }); - const MSG_APP_SPEC_TS_0 = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0_RAW$); + const $MSG_EXTERNAL_2051477021417799640$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_2051477021417799640$$RAW$); function Template_2(rf, ctx) { if (rf & 1) { - $r3$.ɵi18nStart(0, $MSG_APP_SPEC_TS_0$, 1); + $r3$.ɵi18nStart(0, $MSG_EXTERNAL_2051477021417799640$, 1); $r3$.ɵpipe(1, "uppercase"); $r3$.ɵtemplate(2, Template_2, 2, 0); $r3$.ɵi18nEnd(); @@ -1419,7 +1362,7 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18nStart(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18nStart(1, $MSG_EXTERNAL_2051477021417799640$); $r3$.ɵtemplate(2, Template_2, 3, 2); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); @@ -1437,19 +1380,17 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:7842238767399919809] - */ - const $MSG_APP_SPEC_TS_0_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); - const $MSG_APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:8806993169187953163] - */ - const $MSG_APP_SPEC_TS__1_RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}"); - const $MSG_APP_SPEC_TS__1$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS__1_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_7842238767399919809$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); + const $MSG_EXTERNAL_7842238767399919809$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_7842238767399919809$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); + const $MSG_EXTERNAL_8806993169187953163$$RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}"); + const $MSG_EXTERNAL_8806993169187953163$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_8806993169187953163$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); function Template_2(rf, ctx) { if (rf & 1) { - $r3$.ɵi18n(0, $MSG_APP_SPEC_TS__1$); + $r3$.ɵi18n(0, $MSG_EXTERNAL_8806993169187953163$); } if (rf & 2) { const $ctx_r0$ = $r3$.ɵnextContext(); @@ -1461,7 +1402,7 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementContainerStart(0); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_7842238767399919809$); $r3$.ɵelementContainerEnd(); $r3$.ɵtemplate(2, Template_2, 1, 0); } @@ -1478,27 +1419,25 @@ describe('i18n support in the view compiler', () => { it('should handle self-closing tags as content', () => { const input = ` - is my logo + is my logo #1 - is my logo + is my logo #2 `; const output = String.raw ` - const $_c1$ = ["src", "logo.png", "title", "Logo"]; - /** - * @desc [BACKUP_MESSAGE_ID:394166286969183735] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("{$tagImg} is my logo ", { "tagImg": "\uFFFD#2\uFFFD\uFFFD/#2\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:394166286969183735] - */ - const $MSG_APP_SPEC_TS__2$ = goog.getMsg("{$tagImg} is my logo ", { "tagImg": "\uFFFD#1\uFFFD\uFFFD/#1\uFFFD" }); + const $_c0$ = ["src", "logo.png", "title", "Logo"]; + const $MSG_EXTERNAL_4891196282781544695$ = goog.getMsg("{$tagImg} is my logo #1 ", { + "tagImg": "\uFFFD#2\uFFFD\uFFFD/#2\uFFFD" + }); + const $MSG_EXTERNAL_461986953980355147$ = goog.getMsg("{$tagImg} is my logo #2 ", { + "tagImg": "\uFFFD#1\uFFFD\uFFFD/#1\uFFFD" + }); function Template_3(rf, ctx) { if (rf & 1) { - $r3$.ɵi18nStart(0, $MSG_APP_SPEC_TS__2$); - $r3$.ɵelement(1, "img", $_c1$); + $r3$.ɵi18nStart(0, $MSG_EXTERNAL_461986953980355147$); + $r3$.ɵelement(1, "img", $_c0$); $r3$.ɵi18nEnd(); } } @@ -1506,8 +1445,8 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementContainerStart(0); - $r3$.ɵi18nStart(1, $MSG_APP_SPEC_TS_0$); - $r3$.ɵelement(2, "img", $_c1$); + $r3$.ɵi18nStart(1, $MSG_EXTERNAL_4891196282781544695$); + $r3$.ɵelement(2, "img", $_c0$); $r3$.ɵi18nEnd(); $r3$.ɵelementContainerEnd(); $r3$.ɵtemplate(3, Template_3, 2, 0); @@ -1529,10 +1468,7 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:963542717423364282] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("\n Some text\n {$startTagSpan}Text inside span{$closeTagSpan}\n ", { + const $MSG_EXTERNAL_963542717423364282$ = goog.getMsg("\n Some text\n {$startTagSpan}Text inside span{$closeTagSpan}\n ", { "startTagSpan": "\uFFFD#3\uFFFD", "closeTagSpan": "\uFFFD/#3\uFFFD" }); @@ -1541,7 +1477,7 @@ describe('i18n support in the view compiler', () => { if (rf & 1) { $r3$.ɵtext(0, "\n "); $r3$.ɵelementStart(1, "div"); - $r3$.ɵi18nStart(2, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18nStart(2, $MSG_EXTERNAL_963542717423364282$); $r3$.ɵelement(3, "span"); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); @@ -1561,16 +1497,15 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:7842238767399919809] - */ - const $MSG_APP_SPEC_TS_0_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); - const $MSG_APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_7842238767399919809$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); + const $MSG_EXTERNAL_7842238767399919809$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_7842238767399919809$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_7842238767399919809$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -1589,11 +1524,10 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:4166854826696768832] - */ - const $MSG_APP_SPEC_TS_0_RAW$ = goog.getMsg("{VAR_SELECT, select, single {'single quotes'} double {\"double quotes\"} other {other}}"); - const $MSG_APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_4166854826696768832$$RAW$ = goog.getMsg("{VAR_SELECT, select, single {'single quotes'} double {\"double quotes\"} other {other}}"); + const $MSG_EXTERNAL_4166854826696768832$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_4166854826696768832$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); `; verify(input, output); @@ -1611,22 +1545,20 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:7842238767399919809] - */ - const $MSG_APP_SPEC_TS_0_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); - const $MSG_APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); - const $_c1$ = [1, "ngIf"]; - const $_c2$ = ["title", "icu only"]; - /** - * @desc [BACKUP_MESSAGE_ID:8806993169187953163] - */ - const $MSG_APP_SPEC_TS__3_RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}"); - const $MSG_APP_SPEC_TS__3$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS__3_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_7842238767399919809$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); + const $MSG_EXTERNAL_7842238767399919809$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_7842238767399919809$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); + const $_c0$ = [1, "ngIf"]; + const $_c1$ = ["title", "icu only"]; + const $MSG_EXTERNAL_8806993169187953163$$RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}"); + const $MSG_EXTERNAL_8806993169187953163$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_8806993169187953163$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); function MyComponent_div_Template_2(rf, ctx) { if (rf & 1) { - $r3$.ɵelementStart(0, "div", $_c2$); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS__3$); + $r3$.ɵelementStart(0, "div", $_c1$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_8806993169187953163$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -1635,19 +1567,18 @@ describe('i18n support in the view compiler', () => { $r3$.ɵi18nApply(1); } } - const $_c4$ = ["title", "icu and text"]; - /** - * @desc [BACKUP_MESSAGE_ID:1922743304863699161] - */ - const MSG_APP_SPEC_TS__5_RAW = goog.getMsg("{VAR_SELECT, select, 0 {no emails} 1 {one email} other {{$interpolation} emails}}", { + const $_c2$ = ["title", "icu and text"]; + const $MSG_EXTERNAL_1922743304863699161$$RAW$ = goog.getMsg("{VAR_SELECT, select, 0 {no emails} 1 {one email} other {{$interpolation} emails}}", { "interpolation": "\uFFFD1\uFFFD" }); - const MSG_APP_SPEC_TS__5 = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS__5_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_1922743304863699161$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_1922743304863699161$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); function MyComponent_div_Template_3(rf, ctx) { if (rf & 1) { - $r3$.ɵelementStart(0, "div", $_c4$); + $r3$.ɵelementStart(0, "div", $_c2$); $r3$.ɵtext(1, " You have "); - $r3$.ɵi18n(2, $MSG_APP_SPEC_TS__5$); + $r3$.ɵi18n(2, $MSG_EXTERNAL_1922743304863699161$); $r3$.ɵtext(3, ". "); $r3$.ɵelementEnd(); } @@ -1662,10 +1593,10 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_7842238767399919809$); $r3$.ɵelementEnd(); - $r3$.ɵtemplate(2, MyComponent_div_Template_2, 2, 0, null, $_c1$); - $r3$.ɵtemplate(3, MyComponent_div_Template_3, 4, 0, null, $_c1$); + $r3$.ɵtemplate(2, MyComponent_div_Template_2, 2, 0, null, $_c0$); + $r3$.ɵtemplate(3, MyComponent_div_Template_3, 4, 0, null, $_c0$); } if (rf & 2) { $r3$.ɵi18nExp($r3$.ɵbind(ctx.gender)); @@ -1689,10 +1620,7 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:2417296354340576868] - */ - const $MSG_APP_SPEC_TS_1_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male - {$startBoldText}male{$closeBoldText}} female {female {$startBoldText}female{$closeBoldText}} other {{$startTagDiv}{$startItalicText}other{$closeItalicText}{$closeTagDiv}}}", { + const $MSG_EXTERNAL_2417296354340576868$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male - {$startBoldText}male{$closeBoldText}} female {female {$startBoldText}female{$closeBoldText}} other {{$startTagDiv}{$startItalicText}other{$closeItalicText}{$closeTagDiv}}}", { "startBoldText": "", "closeBoldText": "", "startItalicText": "", @@ -1700,12 +1628,11 @@ describe('i18n support in the view compiler', () => { "startTagDiv": "
", "closeTagDiv": "
" }); - const $MSG_APP_SPEC_TS_1$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_1_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); - const $_c2$ = ["other", 1, "other", true]; - /** - * @desc [BACKUP_MESSAGE_ID:9102821288363830807] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("{$icu}{$startBoldText}Other content{$closeBoldText}{$startTagDiv}{$startItalicText}Another content{$closeItalicText}{$closeTagDiv}", { + const $MSG_EXTERNAL_2417296354340576868$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_2417296354340576868$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); + const $_c0$ = ["other", 1, "other", true]; + const $MSG_EXTERNAL_5791551881115084301$ = goog.getMsg("{$icu}{$startBoldText}Other content{$closeBoldText}{$startTagDiv}{$startItalicText}Another content{$closeItalicText}{$closeTagDiv}", { "startBoldText": "\uFFFD#2\uFFFD", "closeBoldText": "\uFFFD/#2\uFFFD", "startTagDiv": "\uFFFD#3\uFFFD", @@ -1718,10 +1645,10 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18nStart(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18nStart(1, $MSG_EXTERNAL_5791551881115084301$); $r3$.ɵelement(2, "b"); $r3$.ɵelementStart(3, "div"); - $r3$.ɵelementStyling($_c2$); + $r3$.ɵelementStyling($_c0$); $r3$.ɵelement(4, "i"); $r3$.ɵelementEnd(); $r3$.ɵi18nEnd(); @@ -1743,18 +1670,17 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:6879461626778511059] - */ - const $MSG_APP_SPEC_TS_0_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male of age: {$interpolation}} female {female} other {other}}", { + const $MSG_EXTERNAL_6879461626778511059$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male of age: {$interpolation}} female {female} other {other}}", { "interpolation": "\uFFFD1\uFFFD" }); - const $MSG_APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_6879461626778511059$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_6879461626778511059$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_6879461626778511059$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -1777,28 +1703,23 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:7842238767399919809] - */ - const $MSG_APP_SPEC_TS_1_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); - const $MSG_APP_SPEC_TS_1$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_1_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:7068143081688428291] - */ - const $MSG_APP_SPEC_TS_2_RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}"); - const $MSG_APP_SPEC_TS_2$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_2_RAW$, { "VAR_SELECT": "\uFFFD1\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:2967249209167308918] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("{$icu}{$icu_1}", { - "icu": $MSG_APP_SPEC_TS_1$, - "icu_1": $MSG_APP_SPEC_TS_2$ + const $MSG_EXTERNAL_7842238767399919809$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); + const $MSG_EXTERNAL_7842238767399919809$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_7842238767399919809$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); + const $MSG_EXTERNAL_7068143081688428291$$RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}"); + const $MSG_EXTERNAL_7068143081688428291$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_7068143081688428291$$RAW$, { + "VAR_SELECT": "\uFFFD1\uFFFD" + }); + const $MSG_EXTERNAL_2967249209167308918$ = goog.getMsg("{$icu}{$icu_1}", { + "icu": $MSG_EXTERNAL_7842238767399919809$, + "icu_1": $MSG_EXTERNAL_7068143081688428291$ }); … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_2967249209167308918$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -1826,32 +1747,26 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:7842238767399919809] - */ - const $MSG_APP_SPEC_TS_1_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); - const $MSG_APP_SPEC_TS_1$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_1_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:7842238767399919809] - */ - const $MSG_APP_SPEC_TS_2_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); - const $MSG_APP_SPEC_TS_2$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_2_RAW$, { "VAR_SELECT": "\uFFFD1\uFFFD" }); + const $MSG_APP_SPEC_TS_1$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); + const $MSG_APP_SPEC_TS_1$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_1$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); + const $MSG_APP_SPEC_TS_2$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); + const $MSG_APP_SPEC_TS_2$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_2$$RAW$, { + "VAR_SELECT": "\uFFFD1\uFFFD" + }); const $_c3$ = [1, "ngIf"]; - /** - * @desc [BACKUP_MESSAGE_ID:7842238767399919809] - */ - const $MSG_APP_SPEC_TS__4_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); - const $MSG_APP_SPEC_TS__4$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS__4_RAW$, { "VAR_SELECT": "\uFFFD0:1\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:7986645988117050801] - */ - const $MSG_APP_SPEC_TS_0_RAW$ = goog.getMsg("{$icu}{$startTagDiv}{$icu}{$closeTagDiv}{$startTagDiv_1}{$icu}{$closeTagDiv}", { + const $MSG_APP_SPEC_TS__4$$RAW$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); + const $MSG_APP_SPEC_TS__4$$RAW$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS__4$$RAW$$RAW$, { + "VAR_SELECT": "\uFFFD0:1\uFFFD" + }); + const $MSG_APP_SPEC_TS_0$$RAW$$RAW$ = goog.getMsg("{$icu}{$startTagDiv}{$icu}{$closeTagDiv}{$startTagDiv_1}{$icu}{$closeTagDiv}", { "startTagDiv": "\uFFFD#2\uFFFD", "closeTagDiv": "[\uFFFD/#2\uFFFD|\uFFFD/#1:1\uFFFD\uFFFD/*3:1\uFFFD]", "startTagDiv_1": "\uFFFD*3:1\uFFFD\uFFFD#1:1\uFFFD", "icu": "\uFFFDI18N_EXP_ICU\uFFFD" }); - const $MSG_APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0_RAW$, { + const $MSG_APP_SPEC_TS_0$$RAW$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0$$RAW$$RAW$, { "ICU": [$MSG_APP_SPEC_TS_1$, $MSG_APP_SPEC_TS_2$, $MSG_APP_SPEC_TS__4$] }); function MyComponent_div_Template_3(rf, ctx) { @@ -1885,7 +1800,10 @@ describe('i18n support in the view compiler', () => { } `; - verify(input, output); + // TODO(akushnir): this use-case is currently supported with + // file-based prefix for translation const names. Translation statements + // caching is required to support this use-case (FW-635) with id-based consts. + verify(input, output, {skipIdBasedCheck: true}); }); it('should handle nested icus', () => { @@ -1900,11 +1818,8 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:343563413083115114] - */ - const $MSG_APP_SPEC_TS_0_RAW$ = goog.getMsg("{VAR_SELECT_1, select, male {male of age: {VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}} female {female} other {other}}"); - const $MSG_APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0_RAW$, { + const $MSG_EXTERNAL_3052001905251380936$$RAW$ = goog.getMsg("{VAR_SELECT_1, select, male {male of age: {VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}} female {female} other {other}}"); + const $MSG_EXTERNAL_3052001905251380936$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_3052001905251380936$$RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD", "VAR_SELECT_1": "\uFFFD1\uFFFD" }); @@ -1912,7 +1827,7 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_3052001905251380936$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -1926,7 +1841,7 @@ describe('i18n support in the view compiler', () => { const exceptions = { '3052001905251380936': 'Wrapper message generated by "ng xi18n" around ICU: " {$ICU} "' }; - verify(input, output, {exceptions}); + verify(input, output, {exceptions, verbose: true}); }); it('should handle icus in different contexts', () => { @@ -1940,29 +1855,24 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:7842238767399919809] - */ - const $MSG_APP_SPEC_TS_1_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); - const $MSG_APP_SPEC_TS_1$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_1_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); - const $_c2$ = [1, "ngIf"]; - /** - * @desc [BACKUP_MESSAGE_ID:7068143081688428291] - */ - const $MSG_APP_SPEC_TS__3_RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}"); - const $MSG_APP_SPEC_TS__3$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS__3_RAW$, { "VAR_SELECT": "\uFFFD0:1\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:1194472282609532229] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("{$icu}{$startTagSpan}{$icu_1}{$closeTagSpan}", { + const $MSG_EXTERNAL_7842238767399919809$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); + const $MSG_EXTERNAL_7842238767399919809$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_7842238767399919809$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); + const $_c0$ = [1, "ngIf"]; + const $MSG_EXTERNAL_7068143081688428291$$RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}"); + const $MSG_EXTERNAL_7068143081688428291$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_7068143081688428291$$RAW$, { + "VAR_SELECT": "\uFFFD0:1\uFFFD" + }); + const $MSG_EXTERNAL_1194472282609532229$ = goog.getMsg("{$icu}{$startTagSpan}{$icu_1}{$closeTagSpan}", { "startTagSpan": "\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD", "closeTagSpan": "\uFFFD/#1:1\uFFFD\uFFFD/*2:1\uFFFD", - "icu": MSG_APP_SPEC_TS_1, - "icu_1": MSG_APP_SPEC_TS__3 + "icu": $MSG_EXTERNAL_7842238767399919809$, + "icu_1": $MSG_EXTERNAL_7068143081688428291$ }); function MyComponent_span_Template_2(rf, ctx) { if (rf & 1) { - $r3$.ɵi18nStart(0, $MSG_APP_SPEC_TS_0$, 1); + $r3$.ɵi18nStart(0, $MSG_EXTERNAL_1194472282609532229$, 1); $r3$.ɵelement(1, "span"); $r3$.ɵi18nEnd(); } @@ -1976,7 +1886,7 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18nStart(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18nStart(1, $MSG_EXTERNAL_1194472282609532229$); $r3$.ɵtemplate(2, MyComponent_span_Template_2, 2, 0, null, $_c2$); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); @@ -2003,34 +1913,29 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:7825031864601787094] - */ - const $MSG_APP_SPEC_TS_1_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male {$interpolation}} female {female {$interpolation_1}} other {other}}", { + const $MSG_EXTERNAL_7825031864601787094$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male {$interpolation}} female {female {$interpolation_1}} other {other}}", { "interpolation": "\uFFFD1\uFFFD", "interpolation_1": "\uFFFD2\uFFFD" }); - const $MSG_APP_SPEC_TS_1$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_1_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); - const $_c2$ = [1, "ngIf"]; - /** - * @desc [BACKUP_MESSAGE_ID:2310343208266678305] - */ - const $MSG_APP_SPEC_TS__3_RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other: {$interpolation}}}", { + const $MSG_EXTERNAL_7825031864601787094$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_7825031864601787094$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); + const $_c0$ = [1, "ngIf"]; + const $MSG_EXTERNAL_2310343208266678305$$RAW$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other: {$interpolation}}}", { "interpolation": "\uFFFD1:1\uFFFD" }); - const $MSG_APP_SPEC_TS__3$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS__3_RAW$, { "VAR_SELECT": "\uFFFD0:1\uFFFD" }); - /** - * @desc [BACKUP_MESSAGE_ID:7186042105600518133] - */ - const $MSG_APP_SPEC_TS_0$ = goog.getMsg("{$icu}{$startTagSpan}{$icu_1}{$closeTagSpan}", { + const $MSG_EXTERNAL_2310343208266678305$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_2310343208266678305$$RAW$, { + "VAR_SELECT": "\uFFFD0:1\uFFFD" + }); + const $MSG_EXTERNAL_7186042105600518133$ = goog.getMsg("{$icu}{$startTagSpan}{$icu_1}{$closeTagSpan}", { "startTagSpan": "\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD", "closeTagSpan": "\uFFFD/#1:1\uFFFD\uFFFD/*2:1\uFFFD", - "icu": $MSG_APP_SPEC_TS_1$, - "icu_1": $MSG_APP_SPEC_TS__3$ + "icu": $MSG_EXTERNAL_7825031864601787094$, + "icu_1": $MSG_EXTERNAL_2310343208266678305$ }); function MyComponent_span_Template_2(rf, ctx) { if (rf & 1) { - $r3$.ɵi18nStart(0, $MSG_APP_SPEC_TS_0$, 1); + $r3$.ɵi18nStart(0, $MSG_EXTERNAL_7186042105600518133$, 1); $r3$.ɵelement(1, "span"); $r3$.ɵi18nEnd(); } @@ -2045,8 +1950,8 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18nStart(1, $MSG_APP_SPEC_TS_0$); - $r3$.ɵtemplate(2, MyComponent_span_Template_2, 2, 0, null, $_c2$); + $r3$.ɵi18nStart(1, $MSG_EXTERNAL_7186042105600518133$); + $r3$.ɵtemplate(2, MyComponent_span_Template_2, 2, 0, null, $_c0$); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); } @@ -2075,20 +1980,19 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - /** - * @desc [BACKUP_MESSAGE_ID:4853189513362404940] - */ - const $MSG_APP_SPEC_TS_0_RAW$ = goog.getMsg("{VAR_SELECT, select, male {male {$phA}} female {female {$phB}} other {other {$phC}}}", { + const $MSG_EXTERNAL_4853189513362404940$$RAW$ = goog.getMsg("{VAR_SELECT, select, male {male {$phA}} female {female {$phB}} other {other {$phC}}}", { "phA": "\uFFFD1\uFFFD", "phB": "\uFFFD2\uFFFD", "phC": "\uFFFD3\uFFFD" }); - const $MSG_APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0_RAW$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); + const $MSG_EXTERNAL_4853189513362404940$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_4853189513362404940$$RAW$, { + "VAR_SELECT": "\uFFFD0\uFFFD" + }); … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_APP_SPEC_TS_0$); + $r3$.ɵi18n(1, $MSG_EXTERNAL_4853189513362404940$); $r3$.ɵelementEnd(); } if (rf & 2) { diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index 11daa8dd8a..f6b9ebe491 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -553,6 +553,26 @@ describe('ngtsc behavioral tests', () => { expect(trim(jsContents)).toContain(trim(hostBindingsFn)); }); + it('should use proper default value for preserveWhitespaces config param', () => { + env.tsconfig(); // default is `false` + env.write(`test.ts`, ` + import {Component} from '@angular/core'; + @Component({ + selector: 'test', + preserveWhitespaces: false, + template: \` +
+ Template with whitespaces +
+ \` + }) + class FooCmp {} + `); + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('text(1, " Template with whitespaces ");'); + }); + it('should take preserveWhitespaces config option into account', () => { env.tsconfig({preserveWhitespaces: true}); env.write(`test.ts`, ` @@ -593,6 +613,36 @@ describe('ngtsc behavioral tests', () => { expect(jsContents).toContain('text(1, " Template with whitespaces ");'); }); + it('should use proper default value for i18nUseExternalIds config param', () => { + env.tsconfig(); // default is `true` + env.write(`test.ts`, ` + import {Component} from '@angular/core'; + @Component({ + selector: 'test', + template: '
Some text
' + }) + class FooCmp {} + `); + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('i18n(1, MSG_EXTERNAL_8321000940098097247);'); + }); + + it('should take i18nUseExternalIds config option into account', () => { + env.tsconfig({i18nUseExternalIds: false}); + env.write(`test.ts`, ` + import {Component} from '@angular/core'; + @Component({ + selector: 'test', + template: '
Some text
' + }) + class FooCmp {} + `); + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('i18n(1, MSG_TEST_TS_0);'); + }); + it('should correctly recognize local symbols', () => { env.tsconfig(); env.write('module.ts', ` diff --git a/packages/compiler/src/aot/compiler_options.ts b/packages/compiler/src/aot/compiler_options.ts index e4d7d1682e..f8fbdf2800 100644 --- a/packages/compiler/src/aot/compiler_options.ts +++ b/packages/compiler/src/aot/compiler_options.ts @@ -11,6 +11,7 @@ import {MissingTranslationStrategy} from '../core'; export interface AotCompilerOptions { locale?: string; i18nFormat?: string; + i18nUseExternalIds?: boolean; translations?: string; missingTranslation?: MissingTranslationStrategy; enableSummariesForJit?: boolean; diff --git a/packages/compiler/src/jit_compiler_facade.ts b/packages/compiler/src/jit_compiler_facade.ts index 3a123657ce..eab07d8423 100644 --- a/packages/compiler/src/jit_compiler_facade.ts +++ b/packages/compiler/src/jit_compiler_facade.ts @@ -104,11 +104,9 @@ export class CompilerFacadeImpl implements CompilerFacade { const constantPool = new ConstantPool(); // Parse the template and check for errors. - const template = parseTemplate( - facade.template, sourceMapUrl, { - preserveWhitespaces: facade.preserveWhitespaces || false, - }, - ''); + const template = parseTemplate(facade.template, sourceMapUrl, { + preserveWhitespaces: facade.preserveWhitespaces || false, + }); if (template.errors !== undefined) { const errors = template.errors.map(err => err.toString()).join(', '); throw new Error(`Errors during JIT compilation of template for ${facade.name}: ${errors}`); @@ -129,6 +127,8 @@ export class CompilerFacadeImpl implements CompilerFacade { animations: facade.animations != null ? new WrappedNodeExpr(facade.animations) : null, viewProviders: facade.viewProviders != null ? new WrappedNodeExpr(facade.viewProviders) : null, + relativeContextFilePath: '', + i18nUseExternalIds: true, }, constantPool, makeBindingParser()); const preStatements = [...constantPool.statements, ...res.statements]; diff --git a/packages/compiler/src/render3/view/api.ts b/packages/compiler/src/render3/view/api.ts index 9530ffabdb..9cb0ce3ef2 100644 --- a/packages/compiler/src/render3/view/api.ts +++ b/packages/compiler/src/render3/view/api.ts @@ -132,13 +132,6 @@ export interface R3ComponentMetadata extends R3DirectiveMetadata { * Selectors found in the tags in the template. */ ngContentSelectors: string[]; - - /** - * Path to the .ts file in which this template's generated code will be included, relative to - * the compilation root. This will be used to generate identifiers that need to be globally - * unique in certain contexts (such as g3). - */ - relativeContextFilePath: string; }; /** @@ -190,6 +183,20 @@ export interface R3ComponentMetadata extends R3DirectiveMetadata { * The list of view providers defined in the component. */ viewProviders: o.Expression|null; + + + /** + * Path to the .ts file in which this template's generated code will be included, relative to + * the compilation root. This will be used to generate identifiers that need to be globally + * unique in certain contexts (such as g3). + */ + relativeContextFilePath: string; + + /** + * Whether translation variable name should contain external message id + * (used by Closure Compiler's output of `goog.getMsg` for transition period) + */ + i18nUseExternalIds: boolean; } /** diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index 759e82bf0e..60f17b111f 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -254,7 +254,7 @@ export function compileComponentFromMetadata( const templateBuilder = new TemplateDefinitionBuilder( constantPool, BindingScope.ROOT_SCOPE, 0, templateTypeName, null, null, templateName, meta.viewQueries, directiveMatcher, directivesUsed, meta.pipes, pipesUsed, R3.namespaceHTML, - meta.template.relativeContextFilePath); + meta.relativeContextFilePath, meta.i18nUseExternalIds); const templateFunctionExpression = templateBuilder.buildTemplateFunction( template.nodes, [], template.hasNgContent, template.ngContentSelectors); @@ -373,7 +373,6 @@ export function compileComponentFromRender2( nodes: render3Ast.nodes, hasNgContent: render3Ast.hasNgContent, ngContentSelectors: render3Ast.ngContentSelectors, - relativeContextFilePath: '', }, directives: [], pipes: typeMapToExpressionMap(pipeTypeByName, outputCtx), @@ -384,7 +383,9 @@ export function compileComponentFromRender2( (summary.template && summary.template.encapsulation) || core.ViewEncapsulation.Emulated, animations: null, viewProviders: - component.viewProviders.length > 0 ? new o.WrappedNodeExpr(component.viewProviders) : null + component.viewProviders.length > 0 ? new o.WrappedNodeExpr(component.viewProviders) : null, + relativeContextFilePath: '', + i18nUseExternalIds: true, }; const res = compileComponentFromMetadata(meta, outputCtx.constantPool, bindingParser); diff --git a/packages/compiler/src/render3/view/i18n/util.ts b/packages/compiler/src/render3/view/i18n/util.ts index 1f49ca5eed..19ea3042e9 100644 --- a/packages/compiler/src/render3/view/i18n/util.ts +++ b/packages/compiler/src/render3/view/i18n/util.ts @@ -19,12 +19,6 @@ const TRANSLATION_PREFIX = 'MSG_'; /** Closure uses `goog.getMsg(message)` to lookup translations */ const GOOG_GET_MSG = 'goog.getMsg'; -/** String key that is used to provide backup id of translatable message in Closure */ -const BACKUP_MESSAGE_ID = 'BACKUP_MESSAGE_ID'; - -/** Regexp to identify whether backup id already provided in description */ -const BACKUP_MESSAGE_ID_REGEXP = new RegExp(BACKUP_MESSAGE_ID); - /** I18n separators for metadata **/ const I18N_MEANING_SEPARATOR = '|'; const I18N_ID_SEPARATOR = '@@'; @@ -63,15 +57,11 @@ function i18nTranslationToDeclStmt( // to a JsDoc statement formatted as expected by the Closure compiler. function i18nMetaToDocStmt(meta: I18nMeta): o.JSDocCommentStmt|null { const tags: o.JSDocTag[] = []; - const {id, description, meaning} = meta; - if (id || description) { - const hasBackupId = !!description && BACKUP_MESSAGE_ID_REGEXP.test(description); - const text = - id && !hasBackupId ? `[${BACKUP_MESSAGE_ID}:${id}] ${description || ''}` : description; - tags.push({tagName: o.JSDocTagName.Desc, text: text !.trim()}); + if (meta.description) { + tags.push({tagName: o.JSDocTagName.Desc, text: meta.description}); } - if (meaning) { - tags.push({tagName: o.JSDocTagName.Meaning, text: meaning}); + if (meta.meaning) { + tags.push({tagName: o.JSDocTagName.Meaning, text: meta.meaning}); } return tags.length == 0 ? null : new o.JSDocCommentStmt(tags); } @@ -92,9 +82,9 @@ export function hasI18nAttrs(element: html.Element): boolean { return element.attrs.some((attr: html.Attribute) => isI18nAttribute(attr.name)); } -export function metaFromI18nMessage(message: i18n.Message): I18nMeta { +export function metaFromI18nMessage(message: i18n.Message, id: string | null = null): I18nMeta { return { - id: message.id || '', + id: typeof id === 'string' ? id : message.id || '', meaning: message.meaning || '', description: message.description || '' }; @@ -222,8 +212,14 @@ export function formatI18nPlaceholderName(name: string): string { return postfix ? `${raw}_${postfix}` : raw; } -export function getTranslationConstPrefix(fileBasedSuffix: string): string { - return `${TRANSLATION_PREFIX}${fileBasedSuffix}`.toUpperCase(); +/** + * Generates a prefix for translation const name. + * + * @param extra Additional local prefix that should be injected into translation var name + * @returns Complete translation const prefix + */ +export function getTranslationConstPrefix(extra: string): string { + return `${TRANSLATION_PREFIX}${extra}`.toUpperCase(); } /** @@ -246,7 +242,7 @@ export function getTranslationDeclStmts( statements.push(docStatements); } if (transformFn) { - const raw = o.variable(`${variable.name}_RAW`); + const raw = o.variable(`${variable.name}$$RAW`); statements.push(i18nTranslationToDeclStmt(raw, message, params)); statements.push( variable.set(transformFn(raw)).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final])); diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index aed01583e0..0019f336ed 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -109,7 +109,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver private viewQueries: R3QueryMetadata[], private directiveMatcher: SelectorMatcher|null, private directives: Set, private pipeTypeByName: Map, private pipes: Set, private _namespace: o.ExternalReference, - private relativeContextFilePath: string) { + private relativeContextFilePath: string, private i18nUseExternalIds: boolean) { // view queries can take up space in data and allocation happens earlier (in the "viewQuery" // function) this._dataIndex = viewQueries.length; @@ -184,8 +184,9 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver // - this template has parent i18n context // - or the template has i18n meta associated with it, // but it's not initiated by the Element (e.g. ) - const initI18nContext = this.i18nContext || - (isI18nRootNode(i18n) && !(isSingleElementTemplate(nodes) && nodes[0].i18n === i18n)); + const initI18nContext = + this.i18nContext || (isI18nRootNode(i18n) && !isSingleI18nIcu(i18n) && + !(isSingleElementTemplate(nodes) && nodes[0].i18n === i18n)); const selfClosingI18nInstruction = hasTextChildrenOnly(nodes); if (initI18nContext) { this.i18nStart(null, i18n !, selfClosingI18nInstruction); @@ -254,8 +255,8 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver i18nTranslate( message: i18n.Message, params: {[name: string]: o.Expression} = {}, ref?: o.ReadVarExpr, - transformFn?: (raw: o.ReadVarExpr) => o.Expression): o.Expression { - const _ref = ref || this.i18nAllocateRef(); + transformFn?: (raw: o.ReadVarExpr) => o.Expression): o.ReadVarExpr { + const _ref = ref || this.i18nAllocateRef(message.id); const _params: {[key: string]: any} = {}; if (params && Object.keys(params).length) { Object.keys(params).forEach(key => _params[formatI18nPlaceholderName(key)] = params[key]); @@ -296,9 +297,16 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver return bound; } - i18nAllocateRef() { - const prefix = getTranslationConstPrefix(this.fileBasedI18nSuffix); - return o.variable(this.constantPool.uniqueName(prefix)); + i18nAllocateRef(messageId: string): o.ReadVarExpr { + let name: string; + if (this.i18nUseExternalIds) { + const prefix = getTranslationConstPrefix(`EXTERNAL_`); + name = `${prefix}${messageId}`; + } else { + const prefix = getTranslationConstPrefix(this.fileBasedI18nSuffix); + name = this.constantPool.uniqueName(prefix); + } + return o.variable(name); } i18nUpdateRef(context: I18nContext): void { @@ -350,7 +358,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver if (this.i18nContext) { this.i18n = this.i18nContext.forkChildContext(index, this.templateIndex !, meta); } else { - const ref = this.i18nAllocateRef(); + const ref = this.i18nAllocateRef((meta as i18n.Message).id); this.i18n = new I18nContext(index, ref, 0, this.templateIndex, meta); } @@ -434,7 +442,8 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver const stylingBuilder = new StylingBuilder(o.literal(elementIndex), null); let isNonBindableMode: boolean = false; - const isI18nRootElement: boolean = isI18nRootNode(element.i18n); + const isI18nRootElement: boolean = + isI18nRootNode(element.i18n) && !isSingleI18nIcu(element.i18n); if (isI18nRootElement && this.i18n) { throw new Error(`Could not mark an element as translatable inside of a translatable section`); @@ -704,7 +713,8 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver const templateVisitor = new TemplateDefinitionBuilder( this.constantPool, this._bindingScope, this.level + 1, contextName, this.i18n, templateIndex, templateName, [], this.directiveMatcher, this.directives, - this.pipeTypeByName, this.pipes, this._namespace, this.fileBasedI18nSuffix); + this.pipeTypeByName, this.pipes, this._namespace, this.fileBasedI18nSuffix, + this.i18nUseExternalIds); // Nested templates must not be visited until after their parent templates have completed // processing, so they are queued here until after the initial pass. Otherwise, we wouldn't @@ -1383,25 +1393,14 @@ function interpolate(args: o.Expression[]): o.Expression { * @param templateUrl URL to use for source mapping of the parsed template */ export function parseTemplate( - template: string, templateUrl: string, options: {preserveWhitespaces?: boolean} = {}, - relativeContextFilePath: string): { - errors?: ParseError[], - nodes: t.Node[], - hasNgContent: boolean, - ngContentSelectors: string[], - relativeContextFilePath: string -} { + template: string, templateUrl: string, options: {preserveWhitespaces?: boolean}): + {errors?: ParseError[], nodes: t.Node[], hasNgContent: boolean, ngContentSelectors: string[]} { const bindingParser = makeBindingParser(); const htmlParser = new HtmlParser(); const parseResult = htmlParser.parse(template, templateUrl, true); if (parseResult.errors && parseResult.errors.length > 0) { - return { - errors: parseResult.errors, - nodes: [], - hasNgContent: false, - ngContentSelectors: [], relativeContextFilePath - }; + return {errors: parseResult.errors, nodes: [], hasNgContent: false, ngContentSelectors: []}; } let rootNodes: html.Node[] = parseResult.rootNodes; @@ -1426,15 +1425,10 @@ export function parseTemplate( const {nodes, hasNgContent, ngContentSelectors, errors} = htmlAstToRender3Ast(rootNodes, bindingParser); if (errors && errors.length > 0) { - return { - errors, - nodes: [], - hasNgContent: false, - ngContentSelectors: [], relativeContextFilePath - }; + return {errors, nodes: [], hasNgContent: false, ngContentSelectors: []}; } - return {nodes, hasNgContent, ngContentSelectors, relativeContextFilePath}; + return {nodes, hasNgContent, ngContentSelectors}; } /** @@ -1478,4 +1472,4 @@ function hasTextChildrenOnly(children: t.Node[]): boolean { return !children.find( child => !(child instanceof t.Text || child instanceof t.BoundText || child instanceof t.Icu)); -} \ No newline at end of file +} diff --git a/packages/compiler/test/render3/view/binding_spec.ts b/packages/compiler/test/render3/view/binding_spec.ts index 90ef1f3605..85ca63f4ba 100644 --- a/packages/compiler/test/render3/view/binding_spec.ts +++ b/packages/compiler/test/render3/view/binding_spec.ts @@ -29,8 +29,7 @@ function makeSelectorMatcher(): SelectorMatcher { describe('t2 binding', () => { it('should bind a simple template', () => { - const template = - parseTemplate('
{{item.name}}
', '', {}, ''); + const template = parseTemplate('
{{item.name}}
', '', {}); const binder = new R3TargetBinder(new SelectorMatcher()); const res = binder.bind({template: template.nodes}); @@ -48,8 +47,7 @@ describe('t2 binding', () => { }); it('should match directives when binding a simple template', () => { - const template = - parseTemplate('
{{item.name}}
', '', {}, ''); + const template = parseTemplate('
{{item.name}}
', '', {}); const binder = new R3TargetBinder(makeSelectorMatcher()); const res = binder.bind({template: template.nodes}); const tmpl = template.nodes[0] as a.Template;