From 881dce841fa517e3f0eb3e62355b3e185f2a7e52 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Wed, 8 Feb 2017 11:35:16 -0800 Subject: [PATCH] refactor(compiler): Load the translation bundle only once in the i18n html parser (#14362) fixes #14322 --- .../compiler/src/i18n/i18n_html_parser.ts | 56 ++++++++++--------- .../test/i18n/i18n_html_parser_spec.ts | 47 ++++++++++++++++ .../compiler/test/i18n/i18n_parser_spec.ts | 8 +-- 3 files changed, 79 insertions(+), 32 deletions(-) create mode 100644 modules/@angular/compiler/test/i18n/i18n_html_parser_spec.ts diff --git a/modules/@angular/compiler/src/i18n/i18n_html_parser.ts b/modules/@angular/compiler/src/i18n/i18n_html_parser.ts index 4e994967ca..57bcff2c87 100644 --- a/modules/@angular/compiler/src/i18n/i18n_html_parser.ts +++ b/modules/@angular/compiler/src/i18n/i18n_html_parser.ts @@ -24,11 +24,18 @@ export class I18NHtmlParser implements HtmlParser { // @override getTagDefinition: any; + private _translationBundle: TranslationBundle; + constructor( - private _htmlParser: HtmlParser, private _translations?: string, - private _translationsFormat?: string, - private _missingTranslation: MissingTranslationStrategy = MissingTranslationStrategy.Warning, - private _console?: Console) {} + private _htmlParser: HtmlParser, translations?: string, translationsFormat?: string, + missingTranslation: MissingTranslationStrategy = MissingTranslationStrategy.Warning, + console?: Console) { + if (translations) { + const serializer = createSerializer(translationsFormat); + this._translationBundle = + TranslationBundle.load(translations, 'i18n', serializer, missingTranslation, console); + } + } parse( source: string, url: string, parseExpansionForms: boolean = false, @@ -36,36 +43,31 @@ export class I18NHtmlParser implements HtmlParser { const parseResult = this._htmlParser.parse(source, url, parseExpansionForms, interpolationConfig); - if (!this._translations || this._translations === '') { + if (!this._translationBundle) { // Do not enable i18n when no translation bundle is provided return parseResult; } - // TODO(vicb): add support for implicit tags / attributes - if (parseResult.errors.length) { return new ParseTreeResult(parseResult.rootNodes, parseResult.errors); } - const serializer = this._createSerializer(); - const translationBundle = TranslationBundle.load( - this._translations, url, serializer, this._missingTranslation, this._console); - - return mergeTranslations(parseResult.rootNodes, translationBundle, interpolationConfig, [], {}); - } - - private _createSerializer(): Serializer { - const format = (this._translationsFormat || 'xlf').toLowerCase(); - - switch (format) { - case 'xmb': - return new Xmb(); - case 'xtb': - return new Xtb(); - case 'xliff': - case 'xlf': - default: - return new Xliff(); - } + return mergeTranslations( + parseResult.rootNodes, this._translationBundle, interpolationConfig, [], {}); + } +} + +function createSerializer(format?: string): Serializer { + format = (format || 'xlf').toLowerCase(); + + switch (format) { + case 'xmb': + return new Xmb(); + case 'xtb': + return new Xtb(); + case 'xliff': + case 'xlf': + default: + return new Xliff(); } } diff --git a/modules/@angular/compiler/test/i18n/i18n_html_parser_spec.ts b/modules/@angular/compiler/test/i18n/i18n_html_parser_spec.ts new file mode 100644 index 0000000000..fc3f22c1b6 --- /dev/null +++ b/modules/@angular/compiler/test/i18n/i18n_html_parser_spec.ts @@ -0,0 +1,47 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {I18NHtmlParser} from '@angular/compiler/src/i18n/i18n_html_parser'; +import {TranslationBundle} from '@angular/compiler/src/i18n/translation_bundle'; +import {HtmlParser} from '@angular/compiler/src/ml_parser/html_parser'; +import {ParseTreeResult} from '@angular/compiler/src/ml_parser/parser'; + +export function main() { + describe('I18N html parser', () => { + + it('should return the html nodes when no translations are given', () => { + const htmlParser = new HtmlParser(); + const i18nHtmlParser = new I18NHtmlParser(htmlParser); + const ptResult = new ParseTreeResult([], []); + + spyOn(htmlParser, 'parse').and.returnValue(ptResult); + spyOn(i18nHtmlParser, 'parse').and.callThrough(); + + expect(i18nHtmlParser.parse('source', 'url')).toBe(ptResult); + + expect(htmlParser.parse).toHaveBeenCalledTimes(1); + expect(htmlParser.parse) + .toHaveBeenCalledWith('source', 'url', jasmine.anything(), jasmine.anything()); + }); + + // https://github.com/angular/angular/issues/14322 + it('should parse the translations only once', () => { + const transBundle = new TranslationBundle({}, () => 'id'); + spyOn(TranslationBundle, 'load').and.returnValue(transBundle); + const htmlParser = new HtmlParser(); + const i18nHtmlParser = new I18NHtmlParser(htmlParser, 'translations'); + + expect(TranslationBundle.load).toHaveBeenCalledTimes(1); + + i18nHtmlParser.parse('source', 'url'); + i18nHtmlParser.parse('source', 'url'); + expect(TranslationBundle.load).toHaveBeenCalledTimes(1); + }); + + }); +} diff --git a/modules/@angular/compiler/test/i18n/i18n_parser_spec.ts b/modules/@angular/compiler/test/i18n/i18n_parser_spec.ts index 22e140dfdf..070871fa0e 100644 --- a/modules/@angular/compiler/test/i18n/i18n_parser_spec.ts +++ b/modules/@angular/compiler/test/i18n/i18n_parser_spec.ts @@ -6,13 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {digest} from '@angular/compiler/src/i18n/digest'; +import {digest, serializeNodes} from '@angular/compiler/src/i18n/digest'; import {extractMessages} from '@angular/compiler/src/i18n/extractor_merger'; import {Message} from '@angular/compiler/src/i18n/i18n_ast'; - -import {serializeNodes} from '../../src/i18n/digest'; -import {HtmlParser} from '../../src/ml_parser/html_parser'; -import {DEFAULT_INTERPOLATION_CONFIG} from '../../src/ml_parser/interpolation_config'; +import {HtmlParser} from '@angular/compiler/src/ml_parser/html_parser'; +import {DEFAULT_INTERPOLATION_CONFIG} from '@angular/compiler/src/ml_parser/interpolation_config'; export function main() { describe('I18nParser', () => {