/** * @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 {escapeRegExp} from '@angular/compiler/src/util'; import {serializeNodes} from '../../../src/i18n/digest'; import * as i18n from '../../../src/i18n/i18n_ast'; import {Xtb} from '../../../src/i18n/serializers/xtb'; export function main(): void { describe('XTB serializer', () => { const serializer = new Xtb(); function loadAsMap(xtb: string): {[id: string]: string} { const {i18nNodesByMsgId} = serializer.load(xtb, 'url'); const msgMap: {[id: string]: string} = {}; Object.keys(i18nNodesByMsgId).forEach(id => { msgMap[id] = serializeNodes(i18nNodesByMsgId[id]).join(''); }); return msgMap; } describe('load', () => { it('should load XTB files with a doctype', () => { const XTB = ` ]> rab `; expect(loadAsMap(XTB)).toEqual({'8841459487341224498': 'rab'}); }); it('should load XTB files without placeholders', () => { const XTB = ` rab `; expect(loadAsMap(XTB)).toEqual({'8841459487341224498': 'rab'}); }); it('should return the target locale', () => { const XTB = ` rab `; expect(serializer.load(XTB, 'url').locale).toEqual('fr'); }); it('should load XTB files with placeholders', () => { const XTB = ` rab `; expect(loadAsMap(XTB)).toEqual({ '8877975308926375834': 'rab' }); }); it('should replace ICU placeholders with their translations', () => { const XTB = ` ** {VAR_PLURAL, plural, =1 {rab}} `; expect(loadAsMap(XTB)).toEqual({ '7717087045075616176': `**`, '5115002811911870583': `{VAR_PLURAL, plural, =1 {[, rab, ]}}`, }); }); it('should load complex XTB files', () => { const XTB = ` rab oof {VAR_PLURAL, plural, =1 {rab}} oof {VAR_PLURAL, plural, =1 {{VAR_GENDER, gender, male {rab}} }} `; expect(loadAsMap(XTB)).toEqual({ '8281795707202401639': `rab oof`, '5115002811911870583': `{VAR_PLURAL, plural, =1 {[, rab, ]}}`, '130772889486467622': `oof`, '4739316421648347533': `{VAR_PLURAL, plural, =1 {[{VAR_GENDER, gender, male {[, rab, ]}}, ]}}`, }); }); }); describe('errors', () => { it('should be able to parse non-angular xtb files without error', () => { const XTB = ` is great is less {count, plural, =0 {{GREAT}}} `; // Invalid messages should not cause the parser to throw let i18nNodesByMsgId: {[id: string]: i18n.Node[]} = undefined !; expect(() => { i18nNodesByMsgId = serializer.load(XTB, 'url').i18nNodesByMsgId; }).not.toThrow(); expect(Object.keys(i18nNodesByMsgId).length).toEqual(2); expect(serializeNodes(i18nNodesByMsgId['angular']).join('')).toEqual('is great'); // Messages that contain unsupported feature should throw on access expect(() => { const read = i18nNodesByMsgId['non angular']; }).toThrowError(/xtb parse errors/); }); it('should throw on nested ', () => { const XTB = ''; expect(() => { loadAsMap(XTB); }).toThrowError(/ elements can not be nested/); }); it('should throw when a has no id attribute', () => { const XTB = ` `; expect(() => { loadAsMap(XTB); }).toThrowError(/ misses the "id" attribute/); }); it('should throw when a placeholder has no name attribute', () => { const XTB = ` `; expect(() => { loadAsMap(XTB); }).toThrowError(/ misses the "name" attribute/); }); it('should throw on unknown xtb tags', () => { const XTB = ``; expect(() => { loadAsMap(XTB); }).toThrowError(new RegExp(escapeRegExp(`Unexpected tag ("[ERROR ->]")`))); }); it('should throw on unknown message tags', () => { const XTB = ` msg should contain only ph tags `; expect(() => { loadAsMap(XTB); }) .toThrowError( new RegExp(escapeRegExp(`[ERROR ->]msg should contain only ph tags`))); }); it('should throw on duplicate message id', () => { const XTB = ` msg1 msg2 `; expect(() => { loadAsMap(XTB); }).toThrowError(/Duplicated translations for msg 1186013544048295927/); }); it('should throw when trying to save an xtb file', () => { expect(() => { serializer.write([], null); }).toThrowError(/Unsupported/); }); }); }); }