/** * @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 {serializeAst} from '@angular/compiler/src/i18n/catalog'; import {extractI18nMessages} from '@angular/compiler/src/i18n/i18n_parser'; import {ddescribe, describe, expect, it} from '@angular/core/testing/testing_internal'; import {HtmlParser} from '../../src/html_parser/html_parser'; import {DEFAULT_INTERPOLATION_CONFIG} from '../../src/html_parser/interpolation_config'; export function main() { ddescribe('I18nParser', () => { describe('elements', () => { it('should extract from elements', () => { expect(extract('
text
')).toEqual([ [['text'], 'm', 'd'], ]); }); it('should extract from nested elements', () => { expect(extract('
textnested
')).toEqual([ [ [ 'text', 'nested' ], 'm', 'd' ], ]); }); it('should not create a message for empty elements', () => { expect(extract('
')).toEqual([]); }); it('should not create a message for plain elements', () => { expect(extract('
')).toEqual([]); }); it('should suppoprt void elements', () => { expect(extract('


')).toEqual([ [ [ '' ], 'm', 'd' ], ]); }); }); describe('attributes', () => { it('should extract from attributes outside of translatable section', () => { expect(extract('
')).toEqual([ [['msg'], 'm', 'd'], ]); }); it('should extract from attributes in translatable element', () => { expect(extract('

')).toEqual([ [ [ '' ], '', '' ], [['msg'], 'm', 'd'], ]); }); it('should extract from attributes in translatable block', () => { expect(extract('

')) .toEqual([ [['msg'], 'm', 'd'], [ [ '' ], '', '' ], ]); }); it('should extract from attributes in translatable ICU', () => { expect( extract( '{count, plural, =0 {

}}')) .toEqual([ [['msg'], 'm', 'd'], [ [ '{count, plural, =0 {[]}}' ], '', '' ], ]); }); it('should extract from attributes in non translatable ICU', () => { expect(extract('{count, plural, =0 {

}}')) .toEqual([ [['msg'], 'm', 'd'], ]); }); it('should not create a message for empty attributes', () => { expect(extract('
')).toEqual([]); }); }); describe('interpolation', () => { it('should replace interpolation with placeholder', () => { expect(extract('
before{{ exp }}after
')).toEqual([ [['[before, exp , after]'], 'm', 'd'], ]); }); it('should support named interpolation', () => { expect(extract('
before{{ exp //i18n(ph="teSt") }}after
')).toEqual([ [['[before, exp //i18n(ph="teSt") , after]'], 'm', 'd'], ]); }) }); describe('blocks', () => { it('should extract from blocks', () => { expect(extract(`message1 message2 message3`)) .toEqual([ [['message1'], 'meaning1', 'desc1'], [['message2'], 'meaning2', ''], [['message3'], '', ''], ]); }); it('should extract all siblings', () => { expect(extract(`text

htmlnested

`)).toEqual([ [ [ 'text', 'html, nested' ], '', '' ], ]); }); }); describe('ICU messages', () => { it('should extract as ICU when single child of an element', () => { expect(extract('
{count, plural, =0 {zero}}
')).toEqual([ [['{count, plural, =0 {[zero]}}'], 'm', 'd'], ]); }); it('should extract as ICU + ph when not single child of an element', () => { expect(extract('
b{count, plural, =0 {zero}}a
')).toEqual([ [['b', '{count, plural, =0 {[zero]}}', 'a'], 'm', 'd'], [['{count, plural, =0 {[zero]}}'], '', ''], ]); }); it('should extract as ICU when single child of a block', () => { expect(extract('{count, plural, =0 {zero}}')).toEqual([ [['{count, plural, =0 {[zero]}}'], 'm', 'd'], ]); }); it('should extract as ICU + ph when not single child of a block', () => { expect(extract('b{count, plural, =0 {zero}}a')).toEqual([ [['{count, plural, =0 {[zero]}}'], '', ''], [['b', '{count, plural, =0 {[zero]}}', 'a'], 'm', 'd'], ]); }); it('should not extract nested ICU messages', () => { expect(extract('
b{count, plural, =0 {{sex, gender, =m {m}}}}a
')) .toEqual([ [ [ 'b', '{count, plural, =0 {[{sex, gender, =m {[m]}}]}}', 'a' ], 'm', 'd' ], [['{count, plural, =0 {[{sex, gender, =m {[m]}}]}}'], '', ''], ]); }); }); describe('implicit elements', () => { it('should extract from implicit elements', () => { expect(extract('bolditalic', ['b'])).toEqual([ [['bold'], '', ''], ]); }); }); describe('implicit attributes', () => { it('should extract implicit attributes', () => { expect(extract('bolditalic', [], {'b': ['title']})) .toEqual([ [['bb'], '', ''], ]); }); }); describe('placeholders', () => { it('should reuse the same placeholder name for tags', () => { expect(extract('

one

two

three

')).toEqual([ [ [ 'one', 'two', 'three', ], 'm', 'd' ], ]); }); it('should reuse the same placeholder name for interpolations', () => { expect(extract('
{{ a }}{{ a }}{{ b }}
')).toEqual([ [ [ '[ a , a , b ]' ], 'm', 'd' ], ]); }); it('should reuse the same placeholder name for icu messages', () => { expect( extract( '
{count, plural, =0 {0}}{count, plural, =0 {0}}{count, plural, =1 {1}}
')) .toEqual([ [ [ '{count, plural, =0 {[0]}}', '{count, plural, =0 {[0]}}', '{count, plural, =1 {[1]}}', ], 'm', 'd' ], [['{count, plural, =0 {[0]}}'], '', ''], [['{count, plural, =0 {[0]}}'], '', ''], [['{count, plural, =1 {[1]}}'], '', ''], ]); }); }); }); } function extract( html: string, implicitTags: string[] = [], implicitAttrs: {[k: string]: string[]} = {}): [string[], string, string][] { const htmlParser = new HtmlParser(); const parseResult = htmlParser.parse(html, 'extractor spec', true); if (parseResult.errors.length > 1) { throw Error(`unexpected parse errors: ${parseResult.errors.join('\n')}`); } const messages = extractI18nMessages( parseResult.rootNodes, DEFAULT_INTERPOLATION_CONFIG, implicitTags, implicitAttrs); // clang-format off // https://github.com/angular/clang-format/issues/35 return messages.map( message => [serializeAst(message.nodes), message.meaning, message.description, ]) as [string[], string, string][]; // clang-format on }