| 
									
										
										
										
											2016-07-21 13:56:58 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @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 {Xtb} from '@angular/compiler/src/i18n/serializers/xtb'; | 
					
						
							|  |  |  | import {escapeRegExp} from '@angular/core/src/facade/lang'; | 
					
						
							|  |  |  | import {beforeEach, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {HtmlParser} from '../../../src/html_parser/html_parser'; | 
					
						
							|  |  |  | import {DEFAULT_INTERPOLATION_CONFIG} from '../../../src/html_parser/interpolation_config'; | 
					
						
							|  |  |  | import {serializeAst} from '../../html_parser/ast_serializer_spec'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function main(): void { | 
					
						
							|  |  |  |   describe('XTB serializer', () => { | 
					
						
							|  |  |  |     let serializer: Xtb; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function loadAsText(content: string, placeholders: {[id: string]: {[name: string]: string}}): | 
					
						
							|  |  |  |         {[id: string]: string} { | 
					
						
							|  |  |  |       const asAst = serializer.load(content, 'url', placeholders); | 
					
						
							|  |  |  |       let asText: {[id: string]: string} = {}; | 
					
						
							| 
									
										
										
										
											2016-08-04 19:35:41 +02:00
										 |  |  |       Object.keys(asAst).forEach(id => { asText[id] = serializeAst(asAst[id]).join(''); }); | 
					
						
							| 
									
										
										
										
											2016-07-21 13:56:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return asText; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     beforeEach(() => { serializer = new Xtb(new HtmlParser(), DEFAULT_INTERPOLATION_CONFIG); }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('load', () => { | 
					
						
							| 
									
										
										
										
											2016-07-29 13:07:01 -07:00
										 |  |  |       it('should load XTB files with a doctype', () => { | 
					
						
							|  |  |  |         const XTB = `<?xml version="1.0" encoding="UTF-8"?>
 | 
					
						
							|  |  |  | <!DOCTYPE translationbundle [<!ELEMENT translationbundle (translation)*> | 
					
						
							|  |  |  | <!ATTLIST translationbundle lang CDATA #REQUIRED> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <!ELEMENT translation (#PCDATA|ph)*> | 
					
						
							|  |  |  | <!ATTLIST translation id CDATA #REQUIRED> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <!ELEMENT ph EMPTY> | 
					
						
							|  |  |  | <!ATTLIST ph name CDATA #REQUIRED> | 
					
						
							|  |  |  | ]> | 
					
						
							|  |  |  | <translationbundle> | 
					
						
							|  |  |  |   <translation id="foo">bar</translation> | 
					
						
							|  |  |  | </translationbundle>`;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(loadAsText(XTB, {})).toEqual({foo: 'bar'}); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-21 13:56:58 -07:00
										 |  |  |       it('should load XTB files without placeholders', () => { | 
					
						
							| 
									
										
										
										
											2016-07-29 13:07:01 -07:00
										 |  |  |         const XTB = `<?xml version="1.0" encoding="UTF-8"?>
 | 
					
						
							| 
									
										
										
										
											2016-07-21 13:56:58 -07:00
										 |  |  | <translationbundle> | 
					
						
							|  |  |  |   <translation id="foo">bar</translation> | 
					
						
							|  |  |  | </translationbundle>`;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(loadAsText(XTB, {})).toEqual({foo: 'bar'}); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should load XTB files with placeholders', () => { | 
					
						
							| 
									
										
										
										
											2016-07-29 13:07:01 -07:00
										 |  |  |         const XTB = `<?xml version="1.0" encoding="UTF-8"?>
 | 
					
						
							| 
									
										
										
										
											2016-07-21 13:56:58 -07:00
										 |  |  | <translationbundle> | 
					
						
							|  |  |  |   <translation id="foo">bar<ph name="PLACEHOLDER"/><ph name="PLACEHOLDER"/></translation> | 
					
						
							|  |  |  | </translationbundle>`;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(loadAsText(XTB, {foo: {PLACEHOLDER: '!'}})).toEqual({foo: 'bar!!'}); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should load complex XTB files', () => { | 
					
						
							| 
									
										
										
										
											2016-07-29 13:07:01 -07:00
										 |  |  |         const XTB = `<? xml version="1.0" encoding="UTF-8" ?>
 | 
					
						
							| 
									
										
										
										
											2016-07-21 13:56:58 -07:00
										 |  |  | <translationbundle> | 
					
						
							|  |  |  |   <translation id="a">translatable element <ph name="START_BOLD_TEXT"><ex><b></ex></ph>with placeholders<ph name="CLOSE_BOLD_TEXT"><ex></b></ex></ph> <ph name="INTERPOLATION"/></translation> | 
					
						
							|  |  |  |   <translation id="b">{ count, plural, =0 {<ph name="START_PARAGRAPH"><ex><p></ex></ph>test<ph name="CLOSE_PARAGRAPH"><ex></p></ex></ph>}}</translation> | 
					
						
							|  |  |  |   <translation id="c" desc="d" meaning="m">foo</translation> | 
					
						
							|  |  |  |   <translation id="d">{ count, plural, =0 {{ sex, gender, other {<ph name="START_PARAGRAPH"><ex><p></ex></ph>deeply nested<ph name="CLOSE_PARAGRAPH"><ex></p></ex></ph>}} }}</translation> | 
					
						
							|  |  |  | </translationbundle>`;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const PLACEHOLDERS = { | 
					
						
							|  |  |  |           a: { | 
					
						
							|  |  |  |             START_BOLD_TEXT: '<b>', | 
					
						
							|  |  |  |             CLOSE_BOLD_TEXT: '</b>', | 
					
						
							|  |  |  |             INTERPOLATION: '{{ a + b }}', | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           b: { | 
					
						
							|  |  |  |             START_PARAGRAPH: '<p translated=true>', | 
					
						
							|  |  |  |             CLOSE_PARAGRAPH: '</p>', | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           d: { | 
					
						
							|  |  |  |             START_PARAGRAPH: '<p>', | 
					
						
							|  |  |  |             CLOSE_PARAGRAPH: '</p>', | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(loadAsText(XTB, PLACEHOLDERS)).toEqual({ | 
					
						
							|  |  |  |           a: 'translatable element <b>with placeholders</b> {{ a + b }}', | 
					
						
							|  |  |  |           b: '{ count, plural, =0 {<p translated="true">test</p>}}', | 
					
						
							|  |  |  |           c: 'foo', | 
					
						
							|  |  |  |           d: '{ count, plural, =0 {{ sex, gender, other {<p>deeply nested</p>}} }}', | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('errors', () => { | 
					
						
							|  |  |  |       it('should throw on nested <translationbundle>', () => { | 
					
						
							|  |  |  |         const XTB = | 
					
						
							|  |  |  |             '<translationbundle><translationbundle></translationbundle></translationbundle>'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(() => { | 
					
						
							|  |  |  |           serializer.load(XTB, 'url', {}); | 
					
						
							|  |  |  |         }).toThrowError(/<translationbundle> elements can not be nested/); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should throw on nested <translation>', () => { | 
					
						
							| 
									
										
										
										
											2016-07-29 13:07:01 -07:00
										 |  |  |         const XTB = `<translationbundle>
 | 
					
						
							| 
									
										
										
										
											2016-07-21 13:56:58 -07:00
										 |  |  |   <translation id="outer"> | 
					
						
							|  |  |  |     <translation id="inner"> | 
					
						
							|  |  |  |     </translation> | 
					
						
							|  |  |  |   </translation> | 
					
						
							|  |  |  | </translationbundle>`;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(() => { | 
					
						
							|  |  |  |           serializer.load(XTB, 'url', {}); | 
					
						
							|  |  |  |         }).toThrowError(/<translation> elements can not be nested/); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should throw when a <translation> has no id attribute', () => { | 
					
						
							| 
									
										
										
										
											2016-07-29 13:07:01 -07:00
										 |  |  |         const XTB = `<translationbundle>
 | 
					
						
							| 
									
										
										
										
											2016-07-21 13:56:58 -07:00
										 |  |  |   <translation></translation> | 
					
						
							|  |  |  | </translationbundle>`;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(() => { | 
					
						
							|  |  |  |           serializer.load(XTB, 'url', {}); | 
					
						
							|  |  |  |         }).toThrowError(/<translation> misses the "id" attribute/); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should throw when a placeholder has no name attribute', () => { | 
					
						
							| 
									
										
										
										
											2016-07-29 13:07:01 -07:00
										 |  |  |         const XTB = `<translationbundle>
 | 
					
						
							| 
									
										
										
										
											2016-07-21 13:56:58 -07:00
										 |  |  |   <translation id="fail"><ph /></translation> | 
					
						
							|  |  |  | </translationbundle>`;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(() => { | 
					
						
							|  |  |  |           serializer.load(XTB, 'url', {}); | 
					
						
							|  |  |  |         }).toThrowError(/<ph> misses the "name" attribute/); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should throw when a placeholder is not present in the source message', () => { | 
					
						
							| 
									
										
										
										
											2016-07-29 13:07:01 -07:00
										 |  |  |         const XTB = `<translationbundle>
 | 
					
						
							| 
									
										
										
										
											2016-07-21 13:56:58 -07:00
										 |  |  |   <translation id="fail"><ph name="UNKNOWN"/></translation> | 
					
						
							|  |  |  | </translationbundle>`;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(() => { | 
					
						
							|  |  |  |           serializer.load(XTB, 'url', {}); | 
					
						
							|  |  |  |         }).toThrowError(/The placeholder "UNKNOWN" does not exists in the source message/); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should throw when the translation results in invalid html', () => { | 
					
						
							| 
									
										
										
										
											2016-07-29 13:07:01 -07:00
										 |  |  |       const XTB = `<translationbundle>
 | 
					
						
							| 
									
										
										
										
											2016-07-21 13:56:58 -07:00
										 |  |  |   <translation id="fail">foo<ph name="CLOSE_P"/>bar</translation> | 
					
						
							|  |  |  | </translationbundle>`;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(() => { | 
					
						
							|  |  |  |         serializer.load(XTB, 'url', {fail: {CLOSE_P: '</p>'}}); | 
					
						
							|  |  |  |       }).toThrowError(/xtb parse errors:\nUnexpected closing tag "p"/); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should throw on unknown tags', () => { | 
					
						
							|  |  |  |       const XTB = `<what></what>`; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(() => { | 
					
						
							|  |  |  |         serializer.load(XTB, 'url', {}); | 
					
						
							|  |  |  |       }).toThrowError(new RegExp(escapeRegExp(`Unexpected tag ("[ERROR ->]<what></what>")`))); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should throw when trying to save an xmb file', | 
					
						
							|  |  |  |        () => { expect(() => { serializer.write({}); }).toThrow(); }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-08-04 19:35:41 +02:00
										 |  |  | } |