| 
									
										
										
										
											2019-05-06 15:33:34 +02: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
 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-08-10 12:51:30 +01:00
										 |  |  | // Make the `$localize()` global function available to the compiled templates, and the direct calls
 | 
					
						
							|  |  |  | // below. This would normally be done inside the application `polyfills.ts` file.
 | 
					
						
							|  |  |  | import '@angular/localize/init'; | 
					
						
							| 
									
										
										
										
											2019-12-02 13:58:32 -08:00
										 |  |  | import {CommonModule, registerLocaleData} from '@angular/common'; | 
					
						
							| 
									
										
										
										
											2019-05-17 16:13:31 +02:00
										 |  |  | import localeRo from '@angular/common/locales/ro'; | 
					
						
							| 
									
										
										
										
											2019-12-16 11:55:50 -08:00
										 |  |  | import {Component, ContentChild, ElementRef, ContentChildren, Directive, HostBinding, Input, LOCALE_ID, QueryList, TemplateRef, Type, ViewChild, ViewContainerRef, Pipe, PipeTransform, NO_ERRORS_SCHEMA} from '@angular/core'; | 
					
						
							| 
									
										
										
										
											2019-05-31 17:11:57 +02:00
										 |  |  | import {setDelayProjection} from '@angular/core/src/render3/instructions/projection'; | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  | import {TestBed} from '@angular/core/testing'; | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  | import {loadTranslations, clearTranslations} from '@angular/localize'; | 
					
						
							| 
									
										
										
										
											2019-06-07 18:20:35 +02:00
										 |  |  | import {By} from '@angular/platform-browser'; | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  | import {expect} from '@angular/platform-browser/testing/src/matchers'; | 
					
						
							|  |  |  | import {onlyInIvy} from '@angular/private/testing'; | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  | import {computeMsgId} from '@angular/compiler'; | 
					
						
							| 
									
										
										
										
											2019-12-02 13:58:32 -08:00
										 |  |  | import {BehaviorSubject} from 'rxjs'; | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  | onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { | 
					
						
							|  |  |  |   beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2019-10-26 12:44:03 +02:00
										 |  |  |     TestBed.configureTestingModule({ | 
					
						
							|  |  |  |       declarations: [AppComp, DirectiveWithTplRef, UppercasePipe], | 
					
						
							|  |  |  |       // In some of the tests we use made-up tag names for better readability, however they'll
 | 
					
						
							|  |  |  |       // cause validation errors. Add the `NO_ERRORS_SCHEMA` so that we don't have to declare
 | 
					
						
							|  |  |  |       // dummy components for each one of them.
 | 
					
						
							|  |  |  |       schemas: [NO_ERRORS_SCHEMA], | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |   afterEach(() => { | 
					
						
							|  |  |  |     setDelayProjection(false); | 
					
						
							|  |  |  |     clearTranslations(); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   it('should translate text', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |     loadTranslations({[computeMsgId('text')]: 'texte'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     const fixture = initWithTemplate(AppComp, `<div i18n>text</div>`); | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML).toEqual(`<div>texte</div>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support interpolations', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |     loadTranslations({[computeMsgId('Hello {$INTERPOLATION}!')]: 'Bonjour {$INTERPOLATION}!'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     const fixture = initWithTemplate(AppComp, `<div i18n>Hello {{name}}!</div>`); | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML).toEqual(`<div>Bonjour Angular!</div>`); | 
					
						
							|  |  |  |     fixture.componentRef.instance.name = `John`; | 
					
						
							|  |  |  |     fixture.detectChanges(); | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML).toEqual(`<div>Bonjour John!</div>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support named interpolations', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |     loadTranslations({ | 
					
						
							|  |  |  |       [computeMsgId(' Hello {$USER_NAME}! Emails: {$AMOUNT_OF_EMAILS_RECEIVED} ')]: | 
					
						
							|  |  |  |           ' Bonjour {$USER_NAME}! Emails: {$AMOUNT_OF_EMAILS_RECEIVED} ' | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-07-08 17:37:26 -07:00
										 |  |  |       <div i18n> | 
					
						
							|  |  |  |         Hello {{ name // i18n(ph="user_name") }}!
 | 
					
						
							|  |  |  |         Emails: {{ count // i18n(ph="amount of emails received") }}
 | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     `);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     expect(fixture.nativeElement.innerHTML).toEqual(`<div> Bonjour Angular! Emails: 0 </div>`); | 
					
						
							|  |  |  |     fixture.componentRef.instance.name = `John`; | 
					
						
							|  |  |  |     fixture.componentRef.instance.count = 5; | 
					
						
							|  |  |  |     fixture.detectChanges(); | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML).toEqual(`<div> Bonjour John! Emails: 5 </div>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support interpolations with custom interpolation config', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |     loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     const interpolation = ['{%', '%}'] as[string, string]; | 
					
						
							|  |  |  |     TestBed.overrideComponent(AppComp, {set: {interpolation}}); | 
					
						
							|  |  |  |     const fixture = initWithTemplate(AppComp, `<div i18n>Hello {% name %}</div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML).toBe('<div>Bonjour Angular</div>'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support &ngsp; in translatable sections', () => { | 
					
						
							|  |  |  |     // note: the `` unicode symbol represents the `&ngsp;` in translations
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |     loadTranslations({[computeMsgId('text ||')]: 'texte ||'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     const fixture = initWithTemplate(AppCompWithWhitespaces, `<div i18n>text |&ngsp;|</div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML).toEqual(`<div>texte | |</div>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support interpolations with complex expressions', () => { | 
					
						
							|  |  |  |     loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       [computeMsgId(' {$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} ')]: | 
					
						
							|  |  |  |           ' {$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} (fr) ' | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  |     const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-08-24 14:02:30 -07:00
										 |  |  |       <div i18n> | 
					
						
							|  |  |  |         {{ name | uppercase }} - | 
					
						
							|  |  |  |         {{ obj?.a?.b }} - | 
					
						
							|  |  |  |         {{ obj?.getA()?.b }} | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     `);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     // the `obj` field is not yet defined, so 2nd and 3rd interpolations return empty strings
 | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML).toEqual(`<div> ANGULAR -  -  (fr) </div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fixture.componentRef.instance.obj = { | 
					
						
							|  |  |  |       a: {b: 'value 1'}, | 
					
						
							|  |  |  |       getA: () => ({b: 'value 2'}), | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     fixture.detectChanges(); | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |         .toEqual(`<div> ANGULAR - value 1 - value 2 (fr) </div>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support elements', () => { | 
					
						
							|  |  |  |     loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       [computeMsgId( | 
					
						
							|  |  |  |           'Hello {$START_TAG_SPAN}world{$CLOSE_TAG_SPAN} and {$START_TAG_DIV}universe{$CLOSE_TAG_DIV}!', | 
					
						
							|  |  |  |           '')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |           'Bonjour {$START_TAG_SPAN}monde{$CLOSE_TAG_SPAN} et {$START_TAG_DIV}univers{$CLOSE_TAG_DIV}!' | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const fixture = initWithTemplate( | 
					
						
							|  |  |  |         AppComp, `<div i18n>Hello <span>world</span> and <div>universe</div>!</div>`); | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |         .toEqual(`<div>Bonjour <span>monde</span> et <div>univers</div>!</div>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support removing elements', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |     loadTranslations({ | 
					
						
							|  |  |  |       [computeMsgId( | 
					
						
							|  |  |  |           'Hello {$START_BOLD_TEXT}my{$CLOSE_BOLD_TEXT}{$START_TAG_SPAN}world{$CLOSE_TAG_SPAN}', | 
					
						
							|  |  |  |           '')]: 'Bonjour {$START_TAG_SPAN}monde{$CLOSE_TAG_SPAN}' | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     const fixture = | 
					
						
							|  |  |  |         initWithTemplate(AppComp, `<div i18n>Hello <b>my</b><span>world</span></div><div>!</div>`); | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |         .toEqual(`<div>Bonjour <span>monde</span></div><div>!</div>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support moving elements', () => { | 
					
						
							|  |  |  |     loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       [computeMsgId( | 
					
						
							|  |  |  |           'Hello {$START_TAG_SPAN}world{$CLOSE_TAG_SPAN} and {$START_TAG_DIV}universe{$CLOSE_TAG_DIV}!', | 
					
						
							|  |  |  |           '')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |           'Bonjour {$START_TAG_DIV}univers{$CLOSE_TAG_DIV} et {$START_TAG_SPAN}monde{$CLOSE_TAG_SPAN}!' | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const fixture = initWithTemplate( | 
					
						
							|  |  |  |         AppComp, `<div i18n>Hello <span>world</span> and <div>universe</div>!</div>`); | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |         .toEqual(`<div>Bonjour <div>univers</div> et <span>monde</span>!</div>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support template directives', () => { | 
					
						
							|  |  |  |     loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       [computeMsgId( | 
					
						
							|  |  |  |           'Content: {$START_TAG_DIV}before{$START_TAG_SPAN}middle{$CLOSE_TAG_SPAN}after{$CLOSE_TAG_DIV}!', | 
					
						
							|  |  |  |           '')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |           'Contenu: {$START_TAG_DIV}avant{$START_TAG_SPAN}milieu{$CLOSE_TAG_SPAN}après{$CLOSE_TAG_DIV}!' | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const fixture = initWithTemplate( | 
					
						
							|  |  |  |         AppComp, | 
					
						
							|  |  |  |         `<div i18n>Content: <div *ngIf="visible">before<span>middle</span>after</div>!</div>`); | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |         .toEqual(`<div>Contenu: <div>avant<span>milieu</span>après</div><!--bindings={
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |   "ng-reflect-ng-if": "true" | 
					
						
							|  |  |  | }-->!</div>`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     fixture.componentRef.instance.visible = false; | 
					
						
							|  |  |  |     fixture.detectChanges(); | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML).toEqual(`<div>Contenu: <!--bindings={
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |   "ng-reflect-ng-if": "false" | 
					
						
							|  |  |  | }-->!</div>`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support multiple i18n blocks', () => { | 
					
						
							|  |  |  |     loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       [computeMsgId('trad {$INTERPOLATION}')]: 'traduction {$INTERPOLATION}', | 
					
						
							|  |  |  |       [computeMsgId('start {$INTERPOLATION} middle {$INTERPOLATION_1} end')]: | 
					
						
							|  |  |  |           'start {$INTERPOLATION_1} middle {$INTERPOLATION} end', | 
					
						
							|  |  |  |       [computeMsgId( | 
					
						
							|  |  |  |           '{$START_TAG_C}trad{$CLOSE_TAG_C}{$START_TAG_D}{$CLOSE_TAG_D}{$START_TAG_E}{$CLOSE_TAG_E}', | 
					
						
							|  |  |  |           '')]: '{$START_TAG_E}{$CLOSE_TAG_E}{$START_TAG_C}traduction{$CLOSE_TAG_C}' | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  |     const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |       <div> | 
					
						
							|  |  |  |         <a i18n>trad {{name}}</a> | 
					
						
							|  |  |  |         hello | 
					
						
							|  |  |  |         <b i18n i18n-title title="start {{count}} middle {{name}} end"> | 
					
						
							|  |  |  |           <c>trad</c> | 
					
						
							|  |  |  |           <d></d> | 
					
						
							|  |  |  |           <e></e> | 
					
						
							|  |  |  |         </b> | 
					
						
							|  |  |  |       </div>`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |         .toEqual( | 
					
						
							|  |  |  |             `<div><a>traduction Angular</a> hello <b title="start Angular middle 0 end"><e></e><c>traduction</c></b></div>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support multiple sibling i18n blocks', () => { | 
					
						
							|  |  |  |     loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       [computeMsgId('Section 1')]: 'Section un', | 
					
						
							|  |  |  |       [computeMsgId('Section 2')]: 'Section deux', | 
					
						
							|  |  |  |       [computeMsgId('Section 3')]: 'Section trois', | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  |     const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |       <div> | 
					
						
							|  |  |  |         <div i18n>Section 1</div> | 
					
						
							|  |  |  |         <div i18n>Section 2</div> | 
					
						
							|  |  |  |         <div i18n>Section 3</div> | 
					
						
							|  |  |  |       </div>`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |         .toEqual(`<div><div>Section un</div><div>Section deux</div><div>Section trois</div></div>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support multiple sibling i18n blocks inside of a template directive', () => { | 
					
						
							|  |  |  |     loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       [computeMsgId('Section 1')]: 'Section un', | 
					
						
							|  |  |  |       [computeMsgId('Section 2')]: 'Section deux', | 
					
						
							|  |  |  |       [computeMsgId('Section 3')]: 'Section trois', | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  |     const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |       <ul *ngFor="let item of [1,2,3]"> | 
					
						
							|  |  |  |         <li i18n>Section 1</li> | 
					
						
							|  |  |  |         <li i18n>Section 2</li> | 
					
						
							|  |  |  |         <li i18n>Section 3</li> | 
					
						
							|  |  |  |       </ul>`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |         .toEqual( | 
					
						
							|  |  |  |             `<ul><li>Section un</li><li>Section deux</li><li>Section trois</li></ul><ul><li>Section un</li><li>Section deux</li><li>Section trois</li></ul><ul><li>Section un</li><li>Section deux</li><li>Section trois</li></ul><!--bindings={
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |   "ng-reflect-ng-for-of": "1,2,3" | 
					
						
							|  |  |  | }-->`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should properly escape quotes in content', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |     loadTranslations({ | 
					
						
							|  |  |  |       [computeMsgId('\'Single quotes\' and "Double quotes"')]: | 
					
						
							|  |  |  |           '\'Guillemets simples\' et "Guillemets doubles"' | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     const fixture = | 
					
						
							|  |  |  |         initWithTemplate(AppComp, `<div i18n>'Single quotes' and "Double quotes"</div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |         .toEqual('<div>\'Guillemets simples\' et "Guillemets doubles"</div>'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should correctly bind to context in nested template', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |     loadTranslations({[computeMsgId('Item {$INTERPOLATION}')]: 'Article {$INTERPOLATION}'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |           <div *ngFor='let id of items'> | 
					
						
							|  |  |  |             <div i18n>Item {{ id }}</div> | 
					
						
							|  |  |  |           </div> | 
					
						
							|  |  |  |         `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     const element = fixture.nativeElement; | 
					
						
							|  |  |  |     for (let i = 0; i < element.children.length; i++) { | 
					
						
							|  |  |  |       const child = element.children[i]; | 
					
						
							|  |  |  |       expect(child).toHaveText(`Article ${i + 1}`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should ignore i18n attributes on self-closing tags', () => { | 
					
						
							|  |  |  |     const fixture = initWithTemplate(AppComp, '<img src="logo.png" i18n>'); | 
					
						
							|  |  |  |     expect(fixture.nativeElement.innerHTML).toBe(`<img src="logo.png">`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should handle i18n attribute with directives', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |     loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     const fixture = initWithTemplate(AppComp, `<div *ngIf="visible" i18n>Hello {{ name }}</div>`); | 
					
						
							|  |  |  |     expect(fixture.nativeElement.firstChild).toHaveText('Bonjour Angular'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should work correctly with event listeners', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |     loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @Component( | 
					
						
							|  |  |  |         {selector: 'app-comp', template: `<div i18n (click)="onClick()">Hello {{ name }}</div>`}) | 
					
						
							|  |  |  |     class ListenerComp { | 
					
						
							|  |  |  |       name = `Angular`; | 
					
						
							|  |  |  |       clicks = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       onClick() { this.clicks++; } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TestBed.configureTestingModule({declarations: [ListenerComp]}); | 
					
						
							|  |  |  |     const fixture = TestBed.createComponent(ListenerComp); | 
					
						
							|  |  |  |     fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const element = fixture.nativeElement.firstChild; | 
					
						
							|  |  |  |     const instance = fixture.componentInstance; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(element).toHaveText('Bonjour Angular'); | 
					
						
							|  |  |  |     expect(instance.clicks).toBe(0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     element.click(); | 
					
						
							|  |  |  |     expect(instance.clicks).toBe(1); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-25 16:54:27 -07:00
										 |  |  |   it('should support local refs inside i18n block', () => { | 
					
						
							|  |  |  |     loadTranslations({ | 
					
						
							|  |  |  |       [computeMsgId( | 
					
						
							|  |  |  |           '{$START_TAG_NG_CONTAINER} One {$CLOSE_TAG_NG_CONTAINER}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV} Two {$CLOSE_TAG_DIV}' + | 
					
						
							|  |  |  |           '{$START_TAG_SPAN} Three {$CLOSE_TAG_SPAN}')]: | 
					
						
							|  |  |  |           '{$START_TAG_NG_CONTAINER} Une {$CLOSE_TAG_NG_CONTAINER}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV} Deux {$CLOSE_TAG_DIV}' + | 
					
						
							|  |  |  |           '{$START_TAG_SPAN} Trois {$CLOSE_TAG_SPAN}' | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const fixture = initWithTemplate(AppComp, `
 | 
					
						
							|  |  |  |       <div i18n> | 
					
						
							|  |  |  |         <ng-container #localRefA> One </ng-container> | 
					
						
							|  |  |  |         <div #localRefB> Two </div> | 
					
						
							|  |  |  |         <span #localRefC> Three </span> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     `);
 | 
					
						
							|  |  |  |     expect(fixture.nativeElement.textContent).toBe(' Une  Deux  Trois '); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should handle local refs correctly in case an element is removed in translation', () => { | 
					
						
							|  |  |  |     loadTranslations({ | 
					
						
							|  |  |  |       [computeMsgId( | 
					
						
							|  |  |  |           '{$START_TAG_NG_CONTAINER} One {$CLOSE_TAG_NG_CONTAINER}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV} Two {$CLOSE_TAG_DIV}' + | 
					
						
							|  |  |  |           '{$START_TAG_SPAN} Three {$CLOSE_TAG_SPAN}')]: '{$START_TAG_DIV} Deux {$CLOSE_TAG_DIV}' | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const fixture = initWithTemplate(AppComp, `
 | 
					
						
							|  |  |  |       <div i18n> | 
					
						
							|  |  |  |         <ng-container #localRefA> One </ng-container> | 
					
						
							|  |  |  |         <div #localRefB> Two </div> | 
					
						
							|  |  |  |         <span #localRefC> Three </span> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     `);
 | 
					
						
							|  |  |  |     expect(fixture.nativeElement.textContent).toBe(' Deux '); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |   describe('ng-container and ng-template support', () => { | 
					
						
							|  |  |  |     it('should support ng-container', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({[computeMsgId('text')]: 'texte'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = initWithTemplate(AppComp, `<ng-container i18n>text</ng-container>`); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(`texte<!--ng-container-->`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should handle single translation message within ng-template', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = | 
					
						
							|  |  |  |           initWithTemplate(AppComp, `<ng-template i18n tplRef>Hello {{ name }}</ng-template>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const element = fixture.nativeElement; | 
					
						
							|  |  |  |       expect(element).toHaveText('Bonjour Angular'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Note: applying structural directives to <ng-template> is typically user error, but it
 | 
					
						
							|  |  |  |     // is technically allowed, so we need to support it.
 | 
					
						
							|  |  |  |     it('should handle structural directives on ng-template', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = initWithTemplate( | 
					
						
							|  |  |  |           AppComp, `<ng-template *ngIf="name" i18n tplRef>Hello {{ name }}</ng-template>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const element = fixture.nativeElement; | 
					
						
							|  |  |  |       expect(element).toHaveText('Bonjour Angular'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should be able to act as child elements inside i18n block (plain text content)', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{$START_TAG_NG_TEMPLATE} Hello {$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER} Bye {$CLOSE_TAG_NG_CONTAINER}', | 
					
						
							|  |  |  |             '')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |             '{$START_TAG_NG_TEMPLATE} Bonjour {$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER} Au revoir {$CLOSE_TAG_NG_CONTAINER}' | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |         <div i18n> | 
					
						
							|  |  |  |           <ng-template tplRef> | 
					
						
							|  |  |  |             Hello | 
					
						
							|  |  |  |           </ng-template> | 
					
						
							|  |  |  |           <ng-container> | 
					
						
							|  |  |  |             Bye | 
					
						
							|  |  |  |           </ng-container> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |       `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const element = fixture.nativeElement.firstChild; | 
					
						
							|  |  |  |       expect(element.textContent.replace(/\s+/g, ' ').trim()).toBe('Bonjour Au revoir'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     it('should be able to act as child elements inside i18n block (text + tags)', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{$START_TAG_NG_TEMPLATE}{$START_TAG_SPAN}Hello{$CLOSE_TAG_SPAN}{$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER}{$START_TAG_SPAN}Hello{$CLOSE_TAG_SPAN}{$CLOSE_TAG_NG_CONTAINER}', | 
					
						
							|  |  |  |             '')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |             '{$START_TAG_NG_TEMPLATE}{$START_TAG_SPAN}Bonjour{$CLOSE_TAG_SPAN}{$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER}{$START_TAG_SPAN}Bonjour{$CLOSE_TAG_SPAN}{$CLOSE_TAG_NG_CONTAINER}' | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |         <div i18n> | 
					
						
							|  |  |  |           <ng-template tplRef> | 
					
						
							|  |  |  |             <span>Hello</span> | 
					
						
							|  |  |  |           </ng-template> | 
					
						
							|  |  |  |           <ng-container> | 
					
						
							|  |  |  |             <span>Hello</span> | 
					
						
							|  |  |  |           </ng-container> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |       `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const element = fixture.nativeElement; | 
					
						
							|  |  |  |       const spans = element.getElementsByTagName('span'); | 
					
						
							|  |  |  |       for (let i = 0; i < spans.length; i++) { | 
					
						
							|  |  |  |         expect(spans[i]).toHaveText('Bonjour'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should be able to act as child elements inside i18n block (text + pipes)', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{$START_TAG_NG_TEMPLATE}Hello {$INTERPOLATION}{$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER}Bye {$INTERPOLATION}{$CLOSE_TAG_NG_CONTAINER}', | 
					
						
							|  |  |  |             '')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |             '{$START_TAG_NG_TEMPLATE}Hej {$INTERPOLATION}{$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER}Vi ses {$INTERPOLATION}{$CLOSE_TAG_NG_CONTAINER}' | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-07-07 16:35:58 +02:00
										 |  |  |         <div i18n> | 
					
						
							|  |  |  |           <ng-template tplRef>Hello {{name | uppercase}}</ng-template> | 
					
						
							|  |  |  |           <ng-container>Bye {{name | uppercase}}</ng-container> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |       `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const element = fixture.nativeElement.firstChild; | 
					
						
							|  |  |  |       expect(element.textContent.replace(/\s+/g, ' ').trim()).toBe('Hej ANGULARVi ses ANGULAR'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-08-08 22:05:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     it('should be able to handle deep nested levels with templates', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{$START_TAG_SPAN} Hello - 1 {$CLOSE_TAG_SPAN}{$START_TAG_SPAN_1} Hello - 2 {$START_TAG_SPAN_1} Hello - 3 {$START_TAG_SPAN_1} Hello - 4 {$CLOSE_TAG_SPAN}{$CLOSE_TAG_SPAN}{$CLOSE_TAG_SPAN}{$START_TAG_SPAN} Hello - 5 {$CLOSE_TAG_SPAN}', | 
					
						
							|  |  |  |             '')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |             '{$START_TAG_SPAN} Bonjour - 1 {$CLOSE_TAG_SPAN}{$START_TAG_SPAN_1} Bonjour - 2 {$START_TAG_SPAN_1} Bonjour - 3 {$START_TAG_SPAN_1} Bonjour - 4 {$CLOSE_TAG_SPAN}{$CLOSE_TAG_SPAN}{$CLOSE_TAG_SPAN}{$START_TAG_SPAN} Bonjour - 5 {$CLOSE_TAG_SPAN}' | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |         <div i18n> | 
					
						
							|  |  |  |           <span> | 
					
						
							|  |  |  |             Hello - 1 | 
					
						
							|  |  |  |           </span> | 
					
						
							|  |  |  |           <span *ngIf="visible"> | 
					
						
							|  |  |  |             Hello - 2 | 
					
						
							|  |  |  |             <span *ngIf="visible"> | 
					
						
							|  |  |  |               Hello - 3 | 
					
						
							|  |  |  |               <span *ngIf="visible"> | 
					
						
							|  |  |  |                 Hello - 4 | 
					
						
							|  |  |  |               </span> | 
					
						
							|  |  |  |             </span> | 
					
						
							|  |  |  |           </span> | 
					
						
							|  |  |  |           <span> | 
					
						
							|  |  |  |             Hello - 5 | 
					
						
							|  |  |  |           </span> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |       `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const element = fixture.nativeElement; | 
					
						
							|  |  |  |       const spans = element.getElementsByTagName('span'); | 
					
						
							|  |  |  |       for (let i = 0; i < spans.length; i++) { | 
					
						
							|  |  |  |         expect(spans[i].innerHTML).toContain(`Bonjour - ${i + 1}`); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should handle self-closing tags as content', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{$START_TAG_SPAN}My logo{$TAG_IMG}{$CLOSE_TAG_SPAN}')]: | 
					
						
							|  |  |  |             '{$START_TAG_SPAN}Mon logo{$TAG_IMG}{$CLOSE_TAG_SPAN}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const content = `My logo<img src="logo.png" title="Logo">`; | 
					
						
							|  |  |  |       const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |         <ng-container i18n> | 
					
						
							|  |  |  |           <span>${content}</span> | 
					
						
							|  |  |  |         </ng-container> | 
					
						
							|  |  |  |         <ng-template i18n tplRef> | 
					
						
							|  |  |  |           <span>${content}</span> | 
					
						
							|  |  |  |         </ng-template> | 
					
						
							|  |  |  |       `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const element = fixture.nativeElement; | 
					
						
							|  |  |  |       const spans = element.getElementsByTagName('span'); | 
					
						
							|  |  |  |       for (let i = 0; i < spans.length; i++) { | 
					
						
							|  |  |  |         const child = spans[i]; | 
					
						
							|  |  |  |         expect(child).toHaveText('Mon logo'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should correctly find context for an element inside i18n section in <ng-template>', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{$START_LINK}Not logged in{$CLOSE_LINK}')]: | 
					
						
							|  |  |  |             '{$START_LINK}Not logged in{$CLOSE_LINK}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       @Directive({selector: '[myDir]'}) | 
					
						
							|  |  |  |       class Dir { | 
					
						
							|  |  |  |         condition = true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'my-cmp', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-06-07 18:20:35 +02:00
										 |  |  |               <div *ngIf="isLogged; else notLoggedIn"> | 
					
						
							|  |  |  |                 <span>Logged in</span> | 
					
						
							|  |  |  |               </div> | 
					
						
							|  |  |  |               <ng-template #notLoggedIn i18n> | 
					
						
							|  |  |  |                 <a myDir>Not logged in</a> | 
					
						
							|  |  |  |               </ng-template> | 
					
						
							|  |  |  |             `,
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class Cmp { | 
					
						
							|  |  |  |         isLogged = false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({ | 
					
						
							|  |  |  |         declarations: [Cmp, Dir], | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(Cmp); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const a = fixture.debugElement.query(By.css('a')); | 
					
						
							|  |  |  |       const dir = a.injector.get(Dir); | 
					
						
							|  |  |  |       expect(dir.condition).toEqual(true); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('should support ICU expressions', () => { | 
					
						
							|  |  |  |     it('with no root node', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = | 
					
						
							|  |  |  |           initWithTemplate(AppComp, `{count, select, 10 {ten} 20 {twenty} other {other}}`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const element = fixture.nativeElement; | 
					
						
							|  |  |  |       expect(element).toHaveText('autre'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('with no i18n tag', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = initWithTemplate( | 
					
						
							|  |  |  |           AppComp, `<div>{count, select, 10 {ten} 20 {twenty} other {other}}</div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const element = fixture.nativeElement; | 
					
						
							|  |  |  |       expect(element).toHaveText('autre'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('multiple', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{VAR_PLURAL, plural, =0 {no {START_BOLD_TEXT}emails{CLOSE_BOLD_TEXT}!} =1 {one {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} {START_TAG_SPAN}emails{CLOSE_TAG_SPAN}}}', | 
					
						
							|  |  |  |             '')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |             '{VAR_PLURAL, plural, =0 {aucun {START_BOLD_TEXT}email{CLOSE_BOLD_TEXT}!} =1 {un {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} {START_TAG_SPAN}emails{CLOSE_TAG_SPAN}}}', | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId('{VAR_SELECT, select, other {({INTERPOLATION})}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, other {({INTERPOLATION})}}', | 
					
						
							|  |  |  |         [computeMsgId('{$ICU} - {$ICU_1}')]: '{$ICU} - {$ICU_1}', | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  |       const fixture = initWithTemplate(AppComp, `<div i18n>{count, plural,
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |         =0 {no <b>emails</b>!} | 
					
						
							|  |  |  |         =1 {one <i>email</i>} | 
					
						
							|  |  |  |         other {{{count}} <span title="{{name}}">emails</span>} | 
					
						
							|  |  |  |       } - {name, select, | 
					
						
							|  |  |  |         other {({{name}})} | 
					
						
							|  |  |  |       }</div>`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual(`<div>aucun <b>email</b>!<!--ICU 7--> - (Angular)<!--ICU 13--></div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.count = 4; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							|  |  |  |               `<div>4 <span title="Angular">emails</span><!--ICU 7--> - (Angular)<!--ICU 13--></div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.count = 0; | 
					
						
							|  |  |  |       fixture.componentRef.instance.name = 'John'; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual(`<div>aucun <b>email</b>!<!--ICU 7--> - (John)<!--ICU 13--></div>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('with custom interpolation config', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{VAR_SELECT, select, 10 {ten} other {{INTERPOLATION}}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, 10 {dix} other {{INTERPOLATION}}}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const interpolation = ['{%', '%}'] as[string, string]; | 
					
						
							|  |  |  |       TestBed.overrideComponent(AppComp, {set: {interpolation}}); | 
					
						
							|  |  |  |       const fixture = | 
					
						
							|  |  |  |           initWithTemplate(AppComp, `<div i18n>{count, select, 10 {ten} other {{% name %}}}</div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement).toHaveText(`Angular`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('inside HTML elements', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{VAR_PLURAL, plural, =0 {no {START_BOLD_TEXT}emails{CLOSE_BOLD_TEXT}!} =1 {one {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} {START_TAG_SPAN}emails{CLOSE_TAG_SPAN}}}', | 
					
						
							|  |  |  |             '')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |             '{VAR_PLURAL, plural, =0 {aucun {START_BOLD_TEXT}email{CLOSE_BOLD_TEXT}!} =1 {un {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} {START_TAG_SPAN}emails{CLOSE_TAG_SPAN}}}', | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId('{VAR_SELECT, select, other {({INTERPOLATION})}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, other {({INTERPOLATION})}}', | 
					
						
							|  |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{$START_TAG_SPAN_1}{$ICU}{$CLOSE_TAG_SPAN} - ' + | 
					
						
							|  |  |  |             '{$START_TAG_SPAN_1}{$ICU_1}{$CLOSE_TAG_SPAN}')]: | 
					
						
							|  |  |  |             '{$START_TAG_SPAN_1}{$ICU}{$CLOSE_TAG_SPAN} - {$START_TAG_SPAN_1}{$ICU_1}{$CLOSE_TAG_SPAN}', | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  |       const fixture = initWithTemplate(AppComp, `<div i18n><span>{count, plural,
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |         =0 {no <b>emails</b>!} | 
					
						
							|  |  |  |         =1 {one <i>email</i>} | 
					
						
							|  |  |  |         other {{{count}} <span title="{{name}}">emails</span>} | 
					
						
							|  |  |  |       }</span> - <span>{name, select, | 
					
						
							|  |  |  |         other {({{name}})} | 
					
						
							|  |  |  |       }</span></div>`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							|  |  |  |               `<div><span>aucun <b>email</b>!<!--ICU 9--></span> - <span>(Angular)<!--ICU 15--></span></div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.count = 4; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							|  |  |  |               `<div><span>4 <span title="Angular">emails</span><!--ICU 9--></span> - <span>(Angular)<!--ICU 15--></span></div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.count = 0; | 
					
						
							|  |  |  |       fixture.componentRef.instance.name = 'John'; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							|  |  |  |               `<div><span>aucun <b>email</b>!<!--ICU 9--></span> - <span>(John)<!--ICU 15--></span></div>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('inside template directives', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{$START_TAG_SPAN}{$ICU}{$CLOSE_TAG_SPAN}')]: | 
					
						
							|  |  |  |             '{$START_TAG_SPAN}{$ICU}{$CLOSE_TAG_SPAN}', | 
					
						
							|  |  |  |         [computeMsgId('{VAR_SELECT, select, other {({INTERPOLATION})}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, other {({INTERPOLATION})}}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = initWithTemplate(AppComp, `<div i18n><span *ngIf="visible">{name, select,
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |         other {({{name}})} | 
					
						
							|  |  |  |       }</span></div>`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual(`<div><span>(Angular)<!--ICU 4--></span><!--bindings={
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |   "ng-reflect-ng-if": "true" | 
					
						
							|  |  |  | }--></div>`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       fixture.componentRef.instance.visible = false; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(`<div><!--bindings={
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |   "ng-reflect-ng-if": "false" | 
					
						
							|  |  |  | }--></div>`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-08-08 22:05:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     it('inside ng-container', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{VAR_SELECT, select, other {({INTERPOLATION})}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, other {({INTERPOLATION})}}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = initWithTemplate(AppComp, `<ng-container i18n>{name, select,
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |         other {({{name}})} | 
					
						
							|  |  |  |       }</ng-container>`); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(`(Angular)<!--ICU 4--><!--ng-container-->`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('inside <ng-template>', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = initWithTemplate( | 
					
						
							|  |  |  |           AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-08-02 12:42:04 +01:00
										 |  |  |         <ng-template i18n tplRef>` +
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |               `{count, select, 10 {ten} 20 {twenty} other {other}}` + | 
					
						
							|  |  |  |               `</ng-template>
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |       `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const element = fixture.nativeElement; | 
					
						
							|  |  |  |       expect(element).toHaveText('autre'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     it('nested', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{VAR_PLURAL, plural, =0 {zero} other {{INTERPOLATION} {VAR_SELECT, select, cat {cats} dog {dogs} other {animals}}!}}', | 
					
						
							|  |  |  |             '')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |             '{VAR_PLURAL, plural, =0 {zero} other {{INTERPOLATION} {VAR_SELECT, select, cat {chats} dog {chiens} other {animaux}}!}}' | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const fixture = initWithTemplate(AppComp, `<div i18n>{count, plural,
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |         =0 {zero} | 
					
						
							|  |  |  |         other {{{count}} {name, select, | 
					
						
							|  |  |  |                        cat {cats} | 
					
						
							|  |  |  |                        dog {dogs} | 
					
						
							|  |  |  |                        other {animals} | 
					
						
							|  |  |  |                      }!} | 
					
						
							|  |  |  |       }</div>`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(`<div>zero<!--ICU 5--></div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.count = 4; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual(`<div>4 animaux<!--nested ICU 0-->!<!--ICU 5--></div>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('nested with interpolations in "other" blocks', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{VAR_PLURAL, plural, =0 {zero} =2 {{INTERPOLATION} {VAR_SELECT, select, cat {cats} dog {dogs} other {animals}}!} other {other - {INTERPOLATION}}}', | 
					
						
							|  |  |  |             '')]: | 
					
						
							|  |  |  |             '{VAR_PLURAL, plural, =0 {zero} =2 {{INTERPOLATION} {VAR_SELECT, select, cat {chats} dog {chiens} other {animaux}}!} other {autre - {INTERPOLATION}}}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const fixture = initWithTemplate(AppComp, `<div i18n>{count, plural,
 | 
					
						
							| 
									
										
										
										
											2019-07-11 11:59:22 -07:00
										 |  |  |         =0 {zero} | 
					
						
							|  |  |  |         =2 {{{count}} {name, select, | 
					
						
							|  |  |  |                        cat {cats} | 
					
						
							|  |  |  |                        dog {dogs} | 
					
						
							|  |  |  |                        other {animals} | 
					
						
							|  |  |  |                      }!} | 
					
						
							|  |  |  |         other {other - {{count}}} | 
					
						
							|  |  |  |       }</div>`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(`<div>zero<!--ICU 5--></div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.count = 2; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual(`<div>2 animaux<!--nested ICU 0-->!<!--ICU 5--></div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.count = 4; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(`<div>autre - 4<!--ICU 5--></div>`); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |     it('should return the correct plural form for ICU expressions when using a specific locale', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{VAR_PLURAL, plural, =0 {no email} =one {one email} =few {a few emails} =other {lots of emails}}')]: | 
					
						
							|  |  |  |             '{VAR_PLURAL, plural, =0 {no email} =one {one email} =few {a few emails} =other {lots of emails}}' | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       registerLocaleData(localeRo); | 
					
						
							|  |  |  |       TestBed.configureTestingModule({providers: [{provide: LOCALE_ID, useValue: 'ro'}]}); | 
					
						
							|  |  |  |       // We could also use `TestBed.overrideProvider(LOCALE_ID, {useValue: 'ro'});`
 | 
					
						
							|  |  |  |       const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-05-17 16:13:31 +02:00
										 |  |  |           {count, plural, | 
					
						
							|  |  |  |             =0 {no email} | 
					
						
							|  |  |  |             =one {one email} | 
					
						
							|  |  |  |             =few {a few emails} | 
					
						
							|  |  |  |             =other {lots of emails} | 
					
						
							|  |  |  |           }`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->'); | 
					
						
							| 
									
										
										
										
											2019-05-17 16:13:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       // Change detection cycle, no model changes
 | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->'); | 
					
						
							| 
									
										
										
										
											2019-05-17 16:13:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       fixture.componentInstance.count = 3; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 2-->'); | 
					
						
							| 
									
										
										
										
											2019-05-17 16:13:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       fixture.componentInstance.count = 1; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual('one email<!--ICU 2-->'); | 
					
						
							| 
									
										
										
										
											2019-05-17 16:13:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       fixture.componentInstance.count = 10; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 2-->'); | 
					
						
							| 
									
										
										
										
											2019-05-17 16:13:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       fixture.componentInstance.count = 20; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 2-->'); | 
					
						
							| 
									
										
										
										
											2019-05-17 16:13:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       fixture.componentInstance.count = 0; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-06-03 15:05:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     it('projection', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{VAR_PLURAL, plural, =1 {one} other {at least {INTERPOLATION} .}}')]: | 
					
						
							|  |  |  |             '{VAR_PLURAL, plural, =1 {one} other {at least {INTERPOLATION} .}}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       @Component({selector: 'child', template: '<div><ng-content></ng-content></div>'}) | 
					
						
							|  |  |  |       class Child { | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-06-03 15:05:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'parent', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-06-03 15:05:34 +02:00
										 |  |  |       <child i18n>{ | 
					
						
							|  |  |  |         value // i18n(ph = "blah"),
 | 
					
						
							|  |  |  |         plural, | 
					
						
							|  |  |  |          =1 {one} | 
					
						
							|  |  |  |         other {at least {{value}} .} | 
					
						
							|  |  |  |       }</child>`
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class Parent { | 
					
						
							|  |  |  |         value = 3; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [Parent, Child]}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toContain('at least'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('with empty values', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{VAR_SELECT, select, 10 {} 20 {twenty} other {other}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, 10 {} 20 {twenty} other {other}}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = initWithTemplate(AppComp, `{count, select, 10 {} 20 {twenty} other {other}}`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const element = fixture.nativeElement; | 
					
						
							|  |  |  |       expect(element).toHaveText('other'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('inside a container when creating a view via vcr.createEmbeddedView', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{VAR_PLURAL, plural, =1 {ONE} other {OTHER}}')]: | 
					
						
							|  |  |  |             '{VAR_PLURAL, plural, =1 {ONE} other {OTHER}}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       @Directive({ | 
					
						
							|  |  |  |         selector: '[someDir]', | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class Dir { | 
					
						
							|  |  |  |         constructor( | 
					
						
							|  |  |  |             private readonly viewContainerRef: ViewContainerRef, | 
					
						
							|  |  |  |             private readonly templateRef: TemplateRef<any>) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ngOnInit() { this.viewContainerRef.createEmbeddedView(this.templateRef); } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'my-cmp', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-06-11 19:01:49 +02:00
										 |  |  |               <div *someDir> | 
					
						
							|  |  |  |                 <ng-content></ng-content> | 
					
						
							|  |  |  |               </div> | 
					
						
							|  |  |  |             `,
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class Cmp { | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-06-11 19:01:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'my-app', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-06-07 20:46:11 -07:00
										 |  |  |             <my-cmp i18n="test" *ngIf="condition">{ | 
					
						
							| 
									
										
										
										
											2019-06-11 19:01:49 +02:00
										 |  |  |               count, | 
					
						
							|  |  |  |               plural, | 
					
						
							|  |  |  |               =1 {ONE} | 
					
						
							|  |  |  |               other {OTHER} | 
					
						
							|  |  |  |             }</my-cmp> | 
					
						
							|  |  |  |           `,
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class App { | 
					
						
							|  |  |  |         count = 1; | 
					
						
							|  |  |  |         condition = true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({ | 
					
						
							|  |  |  |         declarations: [App, Cmp, Dir], | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(App); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.debugElement.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toContain('<my-cmp><div>ONE<!--ICU 13--></div><!--container--></my-cmp>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.count = 2; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.debugElement.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toContain('<my-cmp><div>OTHER<!--ICU 13--></div><!--container--></my-cmp>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // destroy component
 | 
					
						
							|  |  |  |       fixture.componentInstance.condition = false; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.debugElement.nativeElement.textContent).toBe(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // render it again and also change ICU case
 | 
					
						
							|  |  |  |       fixture.componentInstance.condition = true; | 
					
						
							|  |  |  |       fixture.componentInstance.count = 1; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.debugElement.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toContain('<my-cmp><div>ONE<!--ICU 13--></div><!--container--></my-cmp>'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('with nested ICU expression and inside a container when creating a view via vcr.createEmbeddedView', | 
					
						
							|  |  |  |        () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |          loadTranslations({ | 
					
						
							|  |  |  |            [computeMsgId( | 
					
						
							|  |  |  |                '{VAR_PLURAL, plural, =1 {ONE} other {{INTERPOLATION} ' + | 
					
						
							|  |  |  |                '{VAR_SELECT, select, cat {cats} dog {dogs} other {animals}}!}}')]: | 
					
						
							|  |  |  |                '{VAR_PLURAL, plural, =1 {ONE} other {{INTERPOLATION} ' + | 
					
						
							|  |  |  |                '{VAR_SELECT, select, cat {cats} dog {dogs} other {animals}}!}}' | 
					
						
							|  |  |  |          }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |          let dir: Dir|null = null; | 
					
						
							|  |  |  |          @Directive({ | 
					
						
							|  |  |  |            selector: '[someDir]', | 
					
						
							|  |  |  |          }) | 
					
						
							|  |  |  |          class Dir { | 
					
						
							|  |  |  |            constructor( | 
					
						
							|  |  |  |                private readonly viewContainerRef: ViewContainerRef, | 
					
						
							|  |  |  |                private readonly templateRef: TemplateRef<any>) { | 
					
						
							|  |  |  |              dir = this; | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            attachEmbeddedView() { this.viewContainerRef.createEmbeddedView(this.templateRef); } | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          @Component({ | 
					
						
							|  |  |  |            selector: 'my-cmp', | 
					
						
							|  |  |  |            template: `
 | 
					
						
							| 
									
										
										
										
											2019-06-11 19:01:49 +02:00
										 |  |  |               <div *someDir> | 
					
						
							|  |  |  |                 <ng-content></ng-content> | 
					
						
							|  |  |  |               </div> | 
					
						
							|  |  |  |             `,
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |          }) | 
					
						
							|  |  |  |          class Cmp { | 
					
						
							|  |  |  |          } | 
					
						
							| 
									
										
										
										
											2019-06-11 19:01:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |          @Component({ | 
					
						
							|  |  |  |            selector: 'my-app', | 
					
						
							|  |  |  |            template: `
 | 
					
						
							| 
									
										
										
										
											2019-06-11 19:01:49 +02:00
										 |  |  |             <my-cmp i18n="test">{ | 
					
						
							|  |  |  |               count, | 
					
						
							|  |  |  |               plural, | 
					
						
							|  |  |  |               =1 {ONE} | 
					
						
							|  |  |  |               other {{{count}} {name, select, | 
					
						
							|  |  |  |                 cat {cats} | 
					
						
							|  |  |  |                 dog {dogs} | 
					
						
							|  |  |  |                 other {animals} | 
					
						
							|  |  |  |               }!} | 
					
						
							|  |  |  |             }</my-cmp> | 
					
						
							|  |  |  |           `,
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |          }) | 
					
						
							|  |  |  |          class App { | 
					
						
							|  |  |  |            count = 1; | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          TestBed.configureTestingModule({ | 
					
						
							|  |  |  |            declarations: [App, Cmp, Dir], | 
					
						
							|  |  |  |          }); | 
					
						
							|  |  |  |          const fixture = TestBed.createComponent(App); | 
					
						
							|  |  |  |          fixture.componentRef.instance.count = 2; | 
					
						
							|  |  |  |          fixture.detectChanges(); | 
					
						
							|  |  |  |          expect(fixture.debugElement.nativeElement.innerHTML) | 
					
						
							|  |  |  |              .toBe('<my-cmp><!--container--></my-cmp>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          dir !.attachEmbeddedView(); | 
					
						
							|  |  |  |          fixture.detectChanges(); | 
					
						
							|  |  |  |          expect(fixture.debugElement.nativeElement.innerHTML) | 
					
						
							|  |  |  |              .toBe( | 
					
						
							|  |  |  |                  '<my-cmp><div>2 animals<!--nested ICU 0-->!<!--ICU 15--></div><!--container--></my-cmp>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          fixture.componentRef.instance.count = 1; | 
					
						
							|  |  |  |          fixture.detectChanges(); | 
					
						
							|  |  |  |          expect(fixture.debugElement.nativeElement.innerHTML) | 
					
						
							|  |  |  |              .toBe('<my-cmp><div>ONE<!--ICU 15--></div><!--container--></my-cmp>'); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('with nested containers', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{VAR_SELECT, select, A {A } B {B } other {C }}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, A {A } B {B } other {C }}', | 
					
						
							|  |  |  |         [computeMsgId('{VAR_SELECT, select, A1 {A1 } B1 {B1 } other {C1 }}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, A1 {A1 } B1 {B1 } other {C1 }}', | 
					
						
							|  |  |  |         [computeMsgId(' {$ICU} ')]: ' {$ICU} ', | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'comp', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-06-27 16:10:35 +02:00
										 |  |  |         <ng-container [ngSwitch]="visible"> | 
					
						
							|  |  |  |           <ng-container *ngSwitchCase="isVisible()" i18n> | 
					
						
							|  |  |  |             {type, select, A { A } B { B } other { C }} | 
					
						
							|  |  |  |           </ng-container> | 
					
						
							|  |  |  |           <ng-container *ngSwitchCase="!isVisible()" i18n> | 
					
						
							|  |  |  |             {type, select, A1 { A1 } B1 { B1 } other { C1 }} | 
					
						
							|  |  |  |           </ng-container> | 
					
						
							|  |  |  |         </ng-container> | 
					
						
							|  |  |  |       `,
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class Comp { | 
					
						
							|  |  |  |         type = 'A'; | 
					
						
							|  |  |  |         visible = true; | 
					
						
							|  |  |  |         isVisible() { return true; } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-06-27 16:10:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       TestBed.configureTestingModule({declarations: [Comp]}); | 
					
						
							| 
									
										
										
										
											2019-06-27 16:10:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = TestBed.createComponent(Comp); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2019-06-27 16:10:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       expect(fixture.debugElement.nativeElement.innerHTML).toContain('A'); | 
					
						
							| 
									
										
										
										
											2019-06-27 16:10:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       fixture.componentInstance.visible = false; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2019-06-27 16:10:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       expect(fixture.debugElement.nativeElement.innerHTML).not.toContain('A'); | 
					
						
							|  |  |  |       expect(fixture.debugElement.nativeElement.innerHTML).toContain('C1'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-07-08 17:37:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     it('with named interpolations', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{VAR_SELECT, select, A {A - {PH_A}} ' + | 
					
						
							|  |  |  |             'B {B - {PH_B}} other {other - {PH_WITH_SPACES}}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, A {A (translated) - {PH_A}} ' + | 
					
						
							|  |  |  |                 'B {B (translated) - {PH_B}} other {other (translated) - {PH_WITH_SPACES}}}', | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'comp', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-07-08 17:37:26 -07:00
										 |  |  |           <ng-container i18n>{ | 
					
						
							|  |  |  |             type, | 
					
						
							|  |  |  |             select, | 
					
						
							|  |  |  |               A {A - {{ typeA // i18n(ph="PH_A") }}}
 | 
					
						
							|  |  |  |               B {B - {{ typeB // i18n(ph="PH_B") }}}
 | 
					
						
							|  |  |  |               other {other - {{ typeC // i18n(ph="PH WITH SPACES") }}}
 | 
					
						
							|  |  |  |           }</ng-container> | 
					
						
							|  |  |  |         `,
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class Comp { | 
					
						
							|  |  |  |         type = 'A'; | 
					
						
							|  |  |  |         typeA = 'Type A'; | 
					
						
							|  |  |  |         typeB = 'Type B'; | 
					
						
							|  |  |  |         typeC = 'Type C'; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-07-08 17:37:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       TestBed.configureTestingModule({declarations: [Comp]}); | 
					
						
							| 
									
										
										
										
											2019-07-08 17:37:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = TestBed.createComponent(Comp); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2019-07-08 17:37:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       expect(fixture.debugElement.nativeElement.innerHTML).toContain('A (translated) - Type A'); | 
					
						
							| 
									
										
										
										
											2019-07-08 17:37:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       fixture.componentInstance.type = 'C';  // trigger "other" case
 | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2019-07-08 17:37:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       expect(fixture.debugElement.nativeElement.innerHTML).not.toContain('A (translated) - Type A'); | 
					
						
							|  |  |  |       expect(fixture.debugElement.nativeElement.innerHTML).toContain('other (translated) - Type C'); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-07-22 20:55:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     it('should work inside an ngTemplateOutlet inside an ngFor', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{VAR_SELECT, select, A {A } B {B } other {other - {PH_WITH_SPACES}}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, A {A } B {B } other {other - {PH_WITH_SPACES}}}', | 
					
						
							|  |  |  |         [computeMsgId('{$ICU} ')]: '{$ICU} ' | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'app', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-07-22 20:55:07 -07:00
										 |  |  |           <ng-template #myTemp i18n let-type>{ | 
					
						
							|  |  |  |             type, | 
					
						
							|  |  |  |             select, | 
					
						
							|  |  |  |             A {A } | 
					
						
							|  |  |  |             B {B } | 
					
						
							| 
									
										
										
										
											2019-08-02 12:42:04 +01:00
										 |  |  |             other {other - {{ typeC // i18n(ph="PH WITH SPACES") }}}
 | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2019-07-22 20:55:07 -07:00
										 |  |  |           </ng-template> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           <div *ngFor="let type of types"> | 
					
						
							|  |  |  |             <ng-container *ngTemplateOutlet="myTemp; context: {$implicit: type}"> | 
					
						
							|  |  |  |             </ng-container> | 
					
						
							|  |  |  |           </div> | 
					
						
							|  |  |  |         `
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class AppComponent { | 
					
						
							|  |  |  |         types = ['A', 'B', 'C']; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [AppComponent]}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(AppComponent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fixture.debugElement.nativeElement.innerHTML).toContain('A'); | 
					
						
							|  |  |  |       expect(fixture.debugElement.nativeElement.innerHTML).toContain('B'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-10-15 15:54:14 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should use metadata from container element if a message is a single ICU', () => { | 
					
						
							|  |  |  |       loadTranslations({idA: '{VAR_SELECT, select, 1 {un} other {plus d\'un}}'}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'app', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							|  |  |  |           <div i18n="@@idA">{count, select, 1 {one} other {more than one}}</div> | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class AppComponent { | 
					
						
							|  |  |  |         count = 2; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [AppComponent]}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(AppComponent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.debugElement.nativeElement.innerHTML).toContain('plus d\'un'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-11-25 16:39:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should support ICUs without "other" cases', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         idA: '{VAR_SELECT, select, 1 {un (select)} 2 {deux (select)}}', | 
					
						
							|  |  |  |         idB: '{VAR_PLURAL, plural, =1 {un (plural)} =2 {deux (plural)}}', | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'app', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							|  |  |  |           <div i18n="@@idA">{count, select, 1 {one (select)} 2 {two (select)}}</div> - | 
					
						
							|  |  |  |           <div i18n="@@idB">{count, plural, =1 {one (plural)} =2 {two (plural)}}</div> | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class AppComponent { | 
					
						
							|  |  |  |         count = 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [AppComponent]}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(AppComponent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent).toBe('un (select) - un (plural)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentInstance.count = 3; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       // there is no ICU case for count=3
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent.trim()).toBe('-'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentInstance.count = 4; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       // there is no ICU case for count=4, making sure content is still empty
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent.trim()).toBe('-'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentInstance.count = 2; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       // check switching to an existing case after processing an ICU without matching case
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent.trim()).toBe('deux (select) - deux (plural)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentInstance.count = 1; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       // check that we can go back to the first ICU case
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent).toBe('un (select) - un (plural)'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support nested ICUs without "other" cases', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         idA: '{VAR_SELECT_1, select, A {{VAR_SELECT, select, ' + | 
					
						
							|  |  |  |             '1 {un (select)} 2 {deux (select)}}} other {}}', | 
					
						
							|  |  |  |         idB: '{VAR_SELECT, select, A {{VAR_PLURAL, plural, ' + | 
					
						
							|  |  |  |             '=1 {un (plural)} =2 {deux (plural)}}} other {}}', | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'app', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							|  |  |  |           <div i18n="@@idA">{ | 
					
						
							|  |  |  |             type, select, | 
					
						
							|  |  |  |               A {{count, select, 1 {one (select)} 2 {two (select)}}} | 
					
						
							|  |  |  |               other {} | 
					
						
							|  |  |  |           }</div> - | 
					
						
							|  |  |  |           <div i18n="@@idB">{ | 
					
						
							|  |  |  |             type, select, | 
					
						
							|  |  |  |               A {{count, plural, =1 {one (plural)} =2 {two (plural)}}} | 
					
						
							|  |  |  |               other {} | 
					
						
							|  |  |  |           }</div> | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class AppComponent { | 
					
						
							|  |  |  |         type = 'A'; | 
					
						
							|  |  |  |         count = 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [AppComponent]}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(AppComponent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent).toBe('un (select) - un (plural)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentInstance.count = 3; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       // there is no case for count=3 in nested ICU
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent.trim()).toBe('-'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentInstance.count = 4; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       // there is no case for count=4 in nested ICU, making sure content is still empty
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent.trim()).toBe('-'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentInstance.count = 2; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       // check switching to an existing case after processing nested ICU without matching case
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent.trim()).toBe('deux (select) - deux (plural)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentInstance.count = 1; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       // check that we can go back to the first case in nested ICU
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent).toBe('un (select) - un (plural)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentInstance.type = 'B'; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       // check that nested ICU is removed if root ICU case has changed
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent.trim()).toBe('-'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-12-02 13:58:32 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should support ICUs with pipes', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         idA: '{VAR_SELECT, select, 1 {{INTERPOLATION} article} 2 {deux articles}}', | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'app', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							|  |  |  |           <div i18n="@@idA">{count$ | async, select, 1 {{{count$ | async}} item} 2 {two items}}</div> | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class AppComponent { | 
					
						
							|  |  |  |         count$ = new BehaviorSubject<number>(1); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({ | 
					
						
							|  |  |  |         imports: [CommonModule], | 
					
						
							|  |  |  |         declarations: [AppComponent], | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(AppComponent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent).toBe('1 article'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentInstance.count$.next(3); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       // there is no ICU case for count=3, expecting empty content
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent.trim()).toBe(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentInstance.count$.next(2); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       // checking the second ICU case
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent.trim()).toBe('deux articles'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('should support attributes', () => { | 
					
						
							|  |  |  |     it('text', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({[computeMsgId('text')]: 'texte'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = initWithTemplate(AppComp, `<div i18n i18n-title title='text'></div>`); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(`<div title="texte"></div>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('interpolations', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({[computeMsgId('hello {$INTERPOLATION}')]: 'bonjour {$INTERPOLATION}'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = | 
					
						
							|  |  |  |           initWithTemplate(AppComp, `<div i18n i18n-title title="hello {{name}}"></div>`); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(`<div title="bonjour Angular"></div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.name = 'John'; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(`<div title="bonjour John"></div>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('with pipes', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({[computeMsgId('hello {$INTERPOLATION}')]: 'bonjour {$INTERPOLATION}'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = initWithTemplate( | 
					
						
							|  |  |  |           AppComp, `<div i18n i18n-title title="hello {{name | uppercase}}"></div>`); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(`<div title="bonjour ANGULAR"></div>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('multiple attributes', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({[computeMsgId('hello {$INTERPOLATION}')]: 'bonjour {$INTERPOLATION}'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = initWithTemplate( | 
					
						
							|  |  |  |           AppComp, | 
					
						
							|  |  |  |           `<input i18n i18n-title title="hello {{name}}" i18n-placeholder placeholder="hello {{name}}">`); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual(`<input title="bonjour Angular" placeholder="bonjour Angular">`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.name = 'John'; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual(`<input title="bonjour John" placeholder="bonjour John">`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('on removed elements', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId('text')]: 'texte', | 
					
						
							|  |  |  |         [computeMsgId('{$START_TAG_SPAN}content{$CLOSE_TAG_SPAN}')]: 'contenu', | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  |       const fixture = | 
					
						
							|  |  |  |           initWithTemplate(AppComp, `<div i18n><span i18n-title title="text">content</span></div>`); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(`<div>contenu</div>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('with custom interpolation config', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({[computeMsgId('Hello {$INTERPOLATION}', 'm')]: 'Bonjour {$INTERPOLATION}'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const interpolation = ['{%', '%}'] as[string, string]; | 
					
						
							|  |  |  |       TestBed.overrideComponent(AppComp, {set: {interpolation}}); | 
					
						
							|  |  |  |       const fixture = | 
					
						
							|  |  |  |           initWithTemplate(AppComp, `<div i18n-title="m|d" title="Hello {% name %}"></div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const element = fixture.nativeElement.firstChild; | 
					
						
							|  |  |  |       expect(element.title).toBe('Bonjour Angular'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('in nested template', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({[computeMsgId('Item {$INTERPOLATION}', 'm')]: 'Article {$INTERPOLATION}'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |           <div *ngFor='let item of [1,2,3]'> | 
					
						
							|  |  |  |             <div i18n-title='m|d' title='Item {{ item }}'></div> | 
					
						
							|  |  |  |           </div>`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const element = fixture.nativeElement; | 
					
						
							|  |  |  |       for (let i = 0; i < element.children.length; i++) { | 
					
						
							|  |  |  |         const child = element.children[i]; | 
					
						
							|  |  |  |         expect((child as any).innerHTML).toBe(`<div title="Article ${i + 1}"></div>`); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should add i18n attributes on self-closing tags', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = | 
					
						
							|  |  |  |           initWithTemplate(AppComp, `<img src="logo.png" i18n-title title="Hello {{ name }}">`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const element = fixture.nativeElement.firstChild; | 
					
						
							|  |  |  |       expect(element.title).toBe('Bonjour Angular'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should apply i18n attributes during second template pass', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({[computeMsgId('Set')]: 'Set'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       @Directive({ | 
					
						
							|  |  |  |         selector: '[test]', | 
					
						
							|  |  |  |         inputs: ['test'], | 
					
						
							|  |  |  |         exportAs: 'dir', | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class Dir { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'other', | 
					
						
							|  |  |  |         template: `<div i18n #ref="dir" test="Set" i18n-test="This is also a test"></div>` | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class Other { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'blah', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-06-05 15:38:36 +02:00
										 |  |  |           <other></other> | 
					
						
							|  |  |  |           <other></other> | 
					
						
							|  |  |  |         `
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class Cmp { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({ | 
					
						
							|  |  |  |         declarations: [Dir, Cmp, Other], | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(Cmp); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.debugElement.children[0].children[0].references.ref.test).toBe('Set'); | 
					
						
							|  |  |  |       expect(fixture.debugElement.children[1].children[0].references.ref.test).toBe('Set'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('with complex expressions', () => { | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId('{$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2}')]: | 
					
						
							|  |  |  |             '{$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} (fr)' | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  |       const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-08-24 14:02:30 -07:00
										 |  |  |         <div i18n-title title="{{ name | uppercase }} - {{ obj?.a?.b }} - {{ obj?.getA()?.b }}"></div> | 
					
						
							|  |  |  |       `);
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       // the `obj` field is not yet defined, so 2nd and 3rd interpolations return empty strings
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       expect(fixture.nativeElement.firstChild.title).toEqual(`ANGULAR -  -  (fr)`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.obj = { | 
					
						
							|  |  |  |         a: {b: 'value 1'}, | 
					
						
							|  |  |  |         getA: () => ({b: 'value 2'}), | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.firstChild.title).toEqual(`ANGULAR - value 1 - value 2 (fr)`); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-10-03 16:47:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should create corresponding ng-reflect properties', () => { | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'welcome', | 
					
						
							|  |  |  |         template: '{{ messageText }}', | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class WelcomeComp { | 
					
						
							|  |  |  |         @Input() messageText !: string; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         template: `
 | 
					
						
							|  |  |  |           <welcome | 
					
						
							|  |  |  |             messageText="Hello" | 
					
						
							|  |  |  |             i18n-messageText="Welcome message description"> | 
					
						
							|  |  |  |           </welcome> | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class App { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({ | 
					
						
							|  |  |  |         declarations: [App, WelcomeComp], | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('Hello')]: 'Bonjour', | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(App); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const comp = fixture.debugElement.query(By.css('welcome')); | 
					
						
							|  |  |  |       expect(comp.attributes['messagetext']).toBe('Bonjour'); | 
					
						
							|  |  |  |       expect(comp.attributes['ng-reflect-message-text']).toBe('Bonjour'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-11-05 11:12:27 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should support i18n attributes on <ng-container> elements', () => { | 
					
						
							|  |  |  |       loadTranslations({[computeMsgId('Hello', 'meaning')]: 'Bonjour'}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Directive({selector: '[mydir]'}) | 
					
						
							|  |  |  |       class Dir { | 
					
						
							|  |  |  |         @Input() mydir: string = ''; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'my-cmp', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							|  |  |  |           <ng-container i18n-mydir="meaning|description" mydir="Hello"></ng-container> | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class Cmp { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({ | 
					
						
							|  |  |  |         declarations: [Cmp, Dir], | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(Cmp); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const dir = fixture.debugElement.childNodes[0].injector.get(Dir); | 
					
						
							|  |  |  |       expect(dir.mydir).toEqual('Bonjour'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should work with directives and host bindings', () => { | 
					
						
							|  |  |  |     let directiveInstances: ClsDir[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @Directive({selector: '[test]'}) | 
					
						
							|  |  |  |     class ClsDir { | 
					
						
							|  |  |  |       @HostBinding('className') | 
					
						
							|  |  |  |       klass = 'foo'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       constructor() { directiveInstances.push(this); } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @Component({ | 
					
						
							|  |  |  |       selector: `my-app`, | 
					
						
							|  |  |  |       template: `
 | 
					
						
							| 
									
										
										
										
											2019-12-11 22:04:31 +01:00
										 |  |  |       <div i18n test i18n-title title="start {{exp1}} middle {{exp2}} end" outer> | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |          trad: {exp1, plural, | 
					
						
							|  |  |  |               =0 {no <b title="none">emails</b>!} | 
					
						
							|  |  |  |               =1 {one <i>email</i>} | 
					
						
							|  |  |  |               other {{{exp1}} emails} | 
					
						
							|  |  |  |          } | 
					
						
							| 
									
										
										
										
											2019-12-11 22:04:31 +01:00
										 |  |  |       </div><div test inner></div>`
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     }) | 
					
						
							|  |  |  |     class MyApp { | 
					
						
							|  |  |  |       exp1 = 1; | 
					
						
							|  |  |  |       exp2 = 2; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TestBed.configureTestingModule({declarations: [ClsDir, MyApp]}); | 
					
						
							|  |  |  |     loadTranslations({ | 
					
						
							|  |  |  |       // Note that this translation switches the order of the expressions!
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       [computeMsgId('start {$INTERPOLATION} middle {$INTERPOLATION_1} end')]: | 
					
						
							|  |  |  |           'début {$INTERPOLATION_1} milieu {$INTERPOLATION} fin', | 
					
						
							|  |  |  |       [computeMsgId( | 
					
						
							|  |  |  |           '{VAR_PLURAL, plural, =0 {no {START_BOLD_TEXT}emails{CLOSE_BOLD_TEXT}!} =1 {one {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} emails}}')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |           '{VAR_PLURAL, plural, =0 {aucun {START_BOLD_TEXT}email{CLOSE_BOLD_TEXT}!} =1 {un {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} emails}}', | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       [computeMsgId(' trad: {$ICU} ')]: ' traduction: {$ICU} ' | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  |     const fixture = TestBed.createComponent(MyApp); | 
					
						
							|  |  |  |     fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2019-12-11 22:04:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const outerDiv: HTMLElement = fixture.nativeElement.querySelector('div[outer]'); | 
					
						
							|  |  |  |     const innerDiv: HTMLElement = fixture.nativeElement.querySelector('div[inner]'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Note that ideally we'd just compare the innerHTML here, but different browsers return
 | 
					
						
							|  |  |  |     // the order of attributes differently. E.g. most browsers preserve the declaration order,
 | 
					
						
							|  |  |  |     // but IE does not.
 | 
					
						
							|  |  |  |     expect(outerDiv.getAttribute('title')).toBe('début 2 milieu 1 fin'); | 
					
						
							|  |  |  |     expect(outerDiv.getAttribute('class')).toBe('foo'); | 
					
						
							|  |  |  |     expect(outerDiv.textContent !.trim()).toBe('traduction: un email'); | 
					
						
							|  |  |  |     expect(innerDiv.getAttribute('class')).toBe('foo'); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     directiveInstances.forEach(instance => instance.klass = 'bar'); | 
					
						
							|  |  |  |     fixture.componentRef.instance.exp1 = 2; | 
					
						
							|  |  |  |     fixture.componentRef.instance.exp2 = 3; | 
					
						
							|  |  |  |     fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2019-12-11 22:04:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(outerDiv.getAttribute('title')).toBe('début 3 milieu 2 fin'); | 
					
						
							|  |  |  |     expect(outerDiv.getAttribute('class')).toBe('bar'); | 
					
						
							|  |  |  |     expect(outerDiv.textContent !.trim()).toBe('traduction: 2 emails'); | 
					
						
							|  |  |  |     expect(innerDiv.getAttribute('class')).toBe('bar'); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should handle i18n attribute with directive inputs', () => { | 
					
						
							|  |  |  |     let calledTitle = false; | 
					
						
							|  |  |  |     let calledValue = false; | 
					
						
							|  |  |  |     @Component({selector: 'my-comp', template: ''}) | 
					
						
							|  |  |  |     class MyComp { | 
					
						
							|  |  |  |       t !: string; | 
					
						
							|  |  |  |       @Input() | 
					
						
							|  |  |  |       get title() { return this.t; } | 
					
						
							|  |  |  |       set title(title) { | 
					
						
							|  |  |  |         calledTitle = true; | 
					
						
							|  |  |  |         this.t = title; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Input() | 
					
						
							|  |  |  |       get value() { return this.val; } | 
					
						
							|  |  |  |       set value(value: string) { | 
					
						
							|  |  |  |         calledValue = true; | 
					
						
							|  |  |  |         this.val = value; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       val !: string; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TestBed.configureTestingModule({declarations: [AppComp, MyComp]}); | 
					
						
							|  |  |  |     loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       [computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}', | 
					
						
							|  |  |  |       [computeMsgId('works')]: 'fonctionne', | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  |     const fixture = initWithTemplate( | 
					
						
							|  |  |  |         AppComp, | 
					
						
							|  |  |  |         `<my-comp i18n i18n-title title="works" i18n-value="hi" value="Hello {{name}}"></my-comp>`); | 
					
						
							|  |  |  |     fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const directive = fixture.debugElement.children[0].injector.get(MyComp); | 
					
						
							|  |  |  |     expect(calledValue).toEqual(true); | 
					
						
							|  |  |  |     expect(calledTitle).toEqual(true); | 
					
						
							|  |  |  |     expect(directive.value).toEqual(`Bonjour Angular`); | 
					
						
							|  |  |  |     expect(directive.title).toEqual(`fonctionne`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support adding/moving/removing nodes', () => { | 
					
						
							|  |  |  |     loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       [computeMsgId( | 
					
						
							|  |  |  |           '{$START_TAG_DIV2}{$CLOSE_TAG_DIV2}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV3}{$CLOSE_TAG_DIV3}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV4}{$CLOSE_TAG_DIV4}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV5}{$CLOSE_TAG_DIV5}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV6}{$CLOSE_TAG_DIV6}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV7}{$CLOSE_TAG_DIV7}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV8}{$CLOSE_TAG_DIV8}')]: '{$START_TAG_DIV2}{$CLOSE_TAG_DIV2}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV8}{$CLOSE_TAG_DIV8}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV4}{$CLOSE_TAG_DIV4}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV5}{$CLOSE_TAG_DIV5}Bonjour monde' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV3}{$CLOSE_TAG_DIV3}' + | 
					
						
							|  |  |  |           '{$START_TAG_DIV7}{$CLOSE_TAG_DIV7}' | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  |     const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |       <div i18n> | 
					
						
							|  |  |  |         <div2></div2> | 
					
						
							|  |  |  |         <div3></div3> | 
					
						
							|  |  |  |         <div4></div4> | 
					
						
							|  |  |  |         <div5></div5> | 
					
						
							|  |  |  |         <div6></div6> | 
					
						
							|  |  |  |         <div7></div7> | 
					
						
							|  |  |  |         <div8></div8> | 
					
						
							|  |  |  |       </div>`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |         .toEqual( | 
					
						
							|  |  |  |             `<div><div2></div2><div8></div8><div4></div4><div5></div5>Bonjour monde<div3></div3><div7></div7></div>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('projection', () => { | 
					
						
							|  |  |  |     it('should project the translations', () => { | 
					
						
							|  |  |  |       @Component({selector: 'child', template: '<p><ng-content></ng-content></p>'}) | 
					
						
							|  |  |  |       class Child { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'parent', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |             <div i18n> | 
					
						
							|  |  |  |               <child>I am projected from | 
					
						
							|  |  |  |                 <b i18n-title title="Child of {{name}}">{{name}}<remove-me-1></remove-me-1></b> | 
					
						
							|  |  |  |                 <remove-me-2></remove-me-2> | 
					
						
							|  |  |  |               </child> | 
					
						
							|  |  |  |               <remove-me-3></remove-me-3> | 
					
						
							|  |  |  |             </div>`
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class Parent { | 
					
						
							|  |  |  |         name: string = 'Parent'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [Parent, Child]}); | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId('Child of {$INTERPOLATION}')]: 'Enfant de {$INTERPOLATION}', | 
					
						
							|  |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{$START_TAG_CHILD}I am projected from' + | 
					
						
							|  |  |  |             ' {$START_BOLD_TEXT}{$INTERPOLATION}{$START_TAG_REMOVE_ME_1}{$CLOSE_TAG_REMOVE_ME_1}{$CLOSE_BOLD_TEXT}' + | 
					
						
							|  |  |  |             '{$START_TAG_REMOVE_ME_2}{$CLOSE_TAG_REMOVE_ME_2}' + | 
					
						
							|  |  |  |             '{$CLOSE_TAG_CHILD}' + | 
					
						
							|  |  |  |             '{$START_TAG_REMOVE_ME_3}{$CLOSE_TAG_REMOVE_ME_3}')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |             '{$START_TAG_CHILD}Je suis projeté depuis {$START_BOLD_TEXT}{$INTERPOLATION}{$CLOSE_BOLD_TEXT}{$CLOSE_TAG_CHILD}' | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							|  |  |  |               `<div><child><p>Je suis projeté depuis <b title="Enfant de Parent">Parent</b></p></child></div>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should project a translated i18n block', () => { | 
					
						
							|  |  |  |       @Component({selector: 'child', template: '<p><ng-content></ng-content></p>'}) | 
					
						
							|  |  |  |       class Child { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'parent', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |           <div> | 
					
						
							|  |  |  |             <child> | 
					
						
							|  |  |  |               <any></any> | 
					
						
							|  |  |  |               <b i18n i18n-title title="Child of {{name}}">I am projected from {{name}}</b> | 
					
						
							|  |  |  |               <any></any> | 
					
						
							|  |  |  |             </child> | 
					
						
							|  |  |  |           </div>`
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class Parent { | 
					
						
							|  |  |  |         name: string = 'Parent'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [Parent, Child]}); | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId('Child of {$INTERPOLATION}')]: 'Enfant de {$INTERPOLATION}', | 
					
						
							|  |  |  |         [computeMsgId('I am projected from {$INTERPOLATION}')]: | 
					
						
							|  |  |  |             'Je suis projeté depuis {$INTERPOLATION}' | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							|  |  |  |               `<div><child><p><any></any><b title="Enfant de Parent">Je suis projeté depuis Parent</b><any></any></p></child></div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // it should be able to render a new component with the same template code
 | 
					
						
							|  |  |  |       const fixture2 = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture2.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(fixture2.nativeElement.innerHTML); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture2.componentRef.instance.name = 'Parent 2'; | 
					
						
							|  |  |  |       fixture2.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture2.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							|  |  |  |               `<div><child><p><any></any><b title="Enfant de Parent 2">Je suis projeté depuis Parent 2</b><any></any></p></child></div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // The first fixture should not have changed
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).not.toEqual(fixture2.nativeElement.innerHTML); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should re-project translations when multiple projections', () => { | 
					
						
							|  |  |  |       @Component({selector: 'grand-child', template: '<div><ng-content></ng-content></div>'}) | 
					
						
							|  |  |  |       class GrandChild { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component( | 
					
						
							|  |  |  |           {selector: 'child', template: '<grand-child><ng-content></ng-content></grand-child>'}) | 
					
						
							|  |  |  |       class Child { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({selector: 'parent', template: `<child i18n><b>Hello</b> World!</child>`}) | 
					
						
							|  |  |  |       class Parent { | 
					
						
							|  |  |  |         name: string = 'Parent'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [Parent, Child, GrandChild]}); | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{$START_BOLD_TEXT}Hello{$CLOSE_BOLD_TEXT} World!')]: | 
					
						
							|  |  |  |             '{$START_BOLD_TEXT}Bonjour{$CLOSE_BOLD_TEXT} monde!' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual('<child><grand-child><div><b>Bonjour</b> monde!</div></grand-child></child>'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should be able to remove projected placeholders', () => { | 
					
						
							|  |  |  |       @Component({selector: 'grand-child', template: '<div><ng-content></ng-content></div>'}) | 
					
						
							|  |  |  |       class GrandChild { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component( | 
					
						
							|  |  |  |           {selector: 'child', template: '<grand-child><ng-content></ng-content></grand-child>'}) | 
					
						
							|  |  |  |       class Child { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({selector: 'parent', template: `<child i18n><b>Hello</b> World!</child>`}) | 
					
						
							|  |  |  |       class Parent { | 
					
						
							|  |  |  |         name: string = 'Parent'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [Parent, Child, GrandChild]}); | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations( | 
					
						
							|  |  |  |           {[computeMsgId('{$START_BOLD_TEXT}Hello{$CLOSE_BOLD_TEXT} World!')]: 'Bonjour monde!'}); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual('<child><grand-child><div>Bonjour monde!</div></grand-child></child>'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should project translations with selectors', () => { | 
					
						
							|  |  |  |       @Component({selector: 'child', template: `<ng-content select='span'></ng-content>`}) | 
					
						
							|  |  |  |       class Child { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'parent', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |           <child i18n> | 
					
						
							|  |  |  |             <span title="keepMe"></span> | 
					
						
							|  |  |  |             <span title="deleteMe"></span> | 
					
						
							|  |  |  |           </child> | 
					
						
							|  |  |  |         `
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class Parent { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [Parent, Child]}); | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{$START_TAG_SPAN}{$CLOSE_TAG_SPAN}{$START_TAG_SPAN_1}{$CLOSE_TAG_SPAN}')]: | 
					
						
							|  |  |  |             '{$START_TAG_SPAN}Contenu{$CLOSE_TAG_SPAN}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual('<child><span title="keepMe">Contenu</span></child>'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should project content in i18n blocks', () => { | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'child', | 
					
						
							|  |  |  |         template: `<div i18n>Content projected from <ng-content></ng-content></div>` | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class Child { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({selector: 'parent', template: `<child>{{name}}</child>`}) | 
					
						
							|  |  |  |       class Parent { | 
					
						
							|  |  |  |         name: string = 'Parent'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [Parent, Child]}); | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId('Content projected from {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]: | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |             'Contenu projeté depuis {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}' | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual(`<child><div>Contenu projeté depuis Parent</div></child>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.name = 'Parent component'; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual(`<child><div>Contenu projeté depuis Parent component</div></child>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should project content in i18n blocks with placeholders', () => { | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'child', | 
					
						
							|  |  |  |         template: `<div i18n>Content projected from <ng-content></ng-content></div>` | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class Child { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({selector: 'parent', template: `<child><b>{{name}}</b></child>`}) | 
					
						
							|  |  |  |       class Parent { | 
					
						
							|  |  |  |         name: string = 'Parent'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [Parent, Child]}); | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId('Content projected from {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]: | 
					
						
							|  |  |  |             '{$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT} a projeté le contenu' | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual(`<child><div><b>Parent</b> a projeté le contenu</div></child>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should project translated content in i18n blocks', () => { | 
					
						
							|  |  |  |       @Component( | 
					
						
							|  |  |  |           {selector: 'child', template: `<div i18n>Child content <ng-content></ng-content></div>`}) | 
					
						
							|  |  |  |       class Child { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({selector: 'parent', template: `<child i18n>and projection from {{name}}</child>`}) | 
					
						
							|  |  |  |       class Parent { | 
					
						
							|  |  |  |         name: string = 'Parent'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [Parent, Child]}); | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId('Child content {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]: | 
					
						
							|  |  |  |             'Contenu enfant {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}', | 
					
						
							|  |  |  |         [computeMsgId('and projection from {$INTERPOLATION}')]: | 
					
						
							|  |  |  |             'et projection depuis {$INTERPOLATION}' | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual(`<child><div>Contenu enfant et projection depuis Parent</div></child>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should project bare ICU expressions', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{VAR_PLURAL, plural, =1 {one} other {at least {INTERPOLATION} .}}')]: | 
					
						
							|  |  |  |             '{VAR_PLURAL, plural, =1 {one} other {at least {INTERPOLATION} .}}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       @Component({selector: 'child', template: '<div><ng-content></ng-content></div>'}) | 
					
						
							|  |  |  |       class Child { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'parent', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-05-31 17:11:57 +02:00
										 |  |  |       <child i18n>{ | 
					
						
							|  |  |  |         value // i18n(ph = "blah"),
 | 
					
						
							|  |  |  |         plural, | 
					
						
							|  |  |  |          =1 {one} | 
					
						
							|  |  |  |         other {at least {{value}} .} | 
					
						
							|  |  |  |       }</child>`
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class Parent { | 
					
						
							|  |  |  |         value = 3; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [Parent, Child]}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toContain('at least'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should project ICUs in i18n blocks', () => { | 
					
						
							|  |  |  |       @Component( | 
					
						
							|  |  |  |           {selector: 'child', template: `<div i18n>Child content <ng-content></ng-content></div>`}) | 
					
						
							|  |  |  |       class Child { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'parent', | 
					
						
							|  |  |  |         template: | 
					
						
							|  |  |  |             `<child i18n>and projection from {name, select, angular {Angular} other {{{name}}}}</child>` | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       class Parent { | 
					
						
							|  |  |  |         name: string = 'Parent'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [Parent, Child]}); | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId('{VAR_SELECT, select, angular {Angular} other {{INTERPOLATION}}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, angular {Angular} other {{INTERPOLATION}}}', | 
					
						
							|  |  |  |         [computeMsgId('Child content {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]: | 
					
						
							|  |  |  |             'Contenu enfant {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}', | 
					
						
							|  |  |  |         [computeMsgId('and projection from {$ICU}')]: 'et projection depuis {$ICU}' | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							|  |  |  |               `<child><div>Contenu enfant et projection depuis Parent<!--ICU 15--></div></child>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.componentRef.instance.name = 'angular'; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							|  |  |  |               `<child><div>Contenu enfant et projection depuis Angular<!--ICU 15--></div></child>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it(`shouldn't project deleted projections in i18n blocks`, () => { | 
					
						
							|  |  |  |       @Component( | 
					
						
							|  |  |  |           {selector: 'child', template: `<div i18n>Child content <ng-content></ng-content></div>`}) | 
					
						
							|  |  |  |       class Child { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({selector: 'parent', template: `<child i18n>and projection from {{name}}</child>`}) | 
					
						
							|  |  |  |       class Parent { | 
					
						
							|  |  |  |         name: string = 'Parent'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [Parent, Child]}); | 
					
						
							|  |  |  |       loadTranslations({ | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |         [computeMsgId('Child content {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]: | 
					
						
							|  |  |  |             'Contenu enfant', | 
					
						
							|  |  |  |         [computeMsgId('and projection from {$INTERPOLATION}')]: | 
					
						
							|  |  |  |             'et projection depuis {$INTERPOLATION}' | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(Parent); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(fixture.nativeElement.innerHTML).toEqual(`<child><div>Contenu enfant</div></child>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should display/destroy projected i18n content', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId('{VAR_SELECT, select, A {A} B {B} other {other}}')]: | 
					
						
							|  |  |  |             '{VAR_SELECT, select, A {A} B {B} other {other}}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'app', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-06-07 20:46:11 -07:00
										 |  |  |             <ng-container>(<ng-content></ng-content>)</ng-container> | 
					
						
							|  |  |  |         `
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class MyContentApp { | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-06-07 20:46:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       @Component({ | 
					
						
							|  |  |  |         selector: 'my-app', | 
					
						
							|  |  |  |         template: `
 | 
					
						
							| 
									
										
										
										
											2019-06-07 20:46:11 -07:00
										 |  |  |           <app i18n *ngIf="condition">{type, select, A {A} B {B} other {other}}</app> | 
					
						
							|  |  |  |         `
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |       class MyApp { | 
					
						
							|  |  |  |         type = 'A'; | 
					
						
							|  |  |  |         condition = true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [MyApp, MyContentApp]}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = TestBed.createComponent(MyApp); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent).toContain('(A)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // change `condition` to remove <app>
 | 
					
						
							|  |  |  |       fixture.componentInstance.condition = false; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // should not contain 'A'
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent).toBe(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // display <app> again
 | 
					
						
							|  |  |  |       fixture.componentInstance.type = 'B'; | 
					
						
							|  |  |  |       fixture.componentInstance.condition = true; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // expect that 'B' is now displayed
 | 
					
						
							|  |  |  |       expect(fixture.nativeElement.textContent).toContain('(B)'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('queries', () => { | 
					
						
							|  |  |  |     function toHtml(element: Element): string { | 
					
						
							|  |  |  |       return element.innerHTML.replace(/\sng-reflect-\S*="[^"]*"/g, '') | 
					
						
							|  |  |  |           .replace(/<!--bindings=\{(\W.*\W\s*)?\}-->/g, ''); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('detached nodes should still be part of query', () => { | 
					
						
							|  |  |  |       @Directive({selector: '[text]', inputs: ['text'], exportAs: 'textDir'}) | 
					
						
							|  |  |  |       class TextDirective { | 
					
						
							|  |  |  |         // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |         text !: string; | 
					
						
							|  |  |  |         constructor() {} | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Component({selector: 'div-query', template: '<ng-container #vc></ng-container>'}) | 
					
						
							|  |  |  |       class DivQuery { | 
					
						
							|  |  |  |         // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |         @ContentChild(TemplateRef, {static: true}) template !: TemplateRef<any>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |         @ViewChild('vc', {read: ViewContainerRef, static: true}) | 
					
						
							|  |  |  |         vc !: ViewContainerRef; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |         @ContentChildren(TextDirective, {descendants: true}) | 
					
						
							|  |  |  |         query !: QueryList<TextDirective>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         create() { this.vc.createEmbeddedView(this.template); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         destroy() { this.vc.clear(); } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TestBed.configureTestingModule({declarations: [TextDirective, DivQuery]}); | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |       loadTranslations({ | 
					
						
							|  |  |  |         [computeMsgId( | 
					
						
							|  |  |  |             '{$START_TAG_NG_TEMPLATE}{$START_TAG_DIV_1}' + | 
					
						
							|  |  |  |             '{$START_TAG_DIV}' + | 
					
						
							|  |  |  |             '{$START_TAG_SPAN}Content{$CLOSE_TAG_SPAN}' + | 
					
						
							|  |  |  |             '{$CLOSE_TAG_DIV}' + | 
					
						
							|  |  |  |             '{$CLOSE_TAG_DIV}{$CLOSE_TAG_NG_TEMPLATE}')]: | 
					
						
							|  |  |  |             '{$START_TAG_NG_TEMPLATE}Contenu{$CLOSE_TAG_NG_TEMPLATE}' | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const fixture = initWithTemplate(AppComp, `
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  |           <div-query #q i18n> | 
					
						
							|  |  |  |             <ng-template> | 
					
						
							|  |  |  |               <div> | 
					
						
							|  |  |  |                 <div *ngIf="visible"> | 
					
						
							|  |  |  |                   <span text="1">Content</span> | 
					
						
							|  |  |  |                 </div> | 
					
						
							|  |  |  |               </div> | 
					
						
							|  |  |  |             </ng-template> | 
					
						
							|  |  |  |           </div-query> | 
					
						
							|  |  |  |         `);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |       const q = fixture.debugElement.children[0].references.q; | 
					
						
							|  |  |  |       expect(q.query.length).toEqual(0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Create embedded view
 | 
					
						
							|  |  |  |       q.create(); | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(q.query.length).toEqual(1); | 
					
						
							|  |  |  |       expect(toHtml(fixture.nativeElement)) | 
					
						
							|  |  |  |           .toEqual(`<div-query>Contenu<!--ng-container--></div-query>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Disable ng-if
 | 
					
						
							|  |  |  |       fixture.componentInstance.visible = false; | 
					
						
							|  |  |  |       fixture.detectChanges(); | 
					
						
							|  |  |  |       expect(q.query.length).toEqual(0); | 
					
						
							|  |  |  |       expect(toHtml(fixture.nativeElement)) | 
					
						
							|  |  |  |           .toEqual(`<div-query>Contenu<!--ng-container--></div-query>`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-16 11:55:50 -08:00
										 |  |  |   it('should reflect lifecycle hook changes in text interpolations in i18n block', () => { | 
					
						
							|  |  |  |     @Directive({selector: 'input'}) | 
					
						
							|  |  |  |     class InputsDir { | 
					
						
							|  |  |  |       constructor(private elementRef: ElementRef) {} | 
					
						
							|  |  |  |       ngOnInit() { this.elementRef.nativeElement.value = 'value set in Directive.ngOnInit'; } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @Component({ | 
					
						
							|  |  |  |       template: `
 | 
					
						
							|  |  |  |         <input #myinput> | 
					
						
							|  |  |  |         <div i18n>{{myinput.value}}</div> | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     class App { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TestBed.configureTestingModule({declarations: [App, InputsDir]}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const fixture = TestBed.createComponent(App); | 
					
						
							|  |  |  |     fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(fixture.nativeElement.textContent).toContain('value set in Directive.ngOnInit'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should reflect lifecycle hook changes in text interpolations in i18n attributes', () => { | 
					
						
							|  |  |  |     @Directive({selector: 'input'}) | 
					
						
							|  |  |  |     class InputsDir { | 
					
						
							|  |  |  |       constructor(private elementRef: ElementRef) {} | 
					
						
							|  |  |  |       ngOnInit() { this.elementRef.nativeElement.value = 'value set in Directive.ngOnInit'; } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @Component({ | 
					
						
							|  |  |  |       template: `
 | 
					
						
							|  |  |  |         <input #myinput> | 
					
						
							|  |  |  |         <div i18n-title title="{{myinput.value}}"></div> | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     class App { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TestBed.configureTestingModule({declarations: [App, InputsDir]}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const fixture = TestBed.createComponent(App); | 
					
						
							|  |  |  |     fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(fixture.nativeElement.querySelector('div').title) | 
					
						
							|  |  |  |         .toContain('value set in Directive.ngOnInit'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |   it('should not alloc expando slots when there is no new variable to create', () => { | 
					
						
							| 
									
										
										
										
											2019-10-02 18:17:56 +01:00
										 |  |  |     loadTranslations({ | 
					
						
							|  |  |  |       [computeMsgId('{$START_TAG_DIV} Some content {$CLOSE_TAG_DIV}')]: | 
					
						
							|  |  |  |           '{$START_TAG_DIV} Some content {$CLOSE_TAG_DIV}', | 
					
						
							|  |  |  |       [computeMsgId( | 
					
						
							|  |  |  |           '{$START_TAG_SPAN_1}{$ICU}{$CLOSE_TAG_SPAN} - {$START_TAG_SPAN_1}{$ICU_1}{$CLOSE_TAG_SPAN}')]: | 
					
						
							|  |  |  |           '{$START_TAG_SPAN_1}{$ICU}{$CLOSE_TAG_SPAN} - {$START_TAG_SPAN_1}{$ICU_1}{$CLOSE_TAG_SPAN}', | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     @Component({ | 
					
						
							|  |  |  |       template: `
 | 
					
						
							| 
									
										
										
										
											2019-07-08 14:59:10 +02:00
										 |  |  |       <div dialog i18n> | 
					
						
							|  |  |  |           <div *ngIf="data"> | 
					
						
							|  |  |  |               Some content | 
					
						
							|  |  |  |           </div> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |       <button [close]="true">Button label</button> | 
					
						
							|  |  |  |   `
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     }) | 
					
						
							|  |  |  |     class ContentElementDialog { | 
					
						
							|  |  |  |       data = false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-08 14:59:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     TestBed.configureTestingModule({declarations: [DialogDir, CloseBtn, ContentElementDialog]}); | 
					
						
							| 
									
										
										
										
											2019-07-08 14:59:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     const fixture = TestBed.createComponent(ContentElementDialog); | 
					
						
							|  |  |  |     fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2019-12-11 22:04:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Remove the reflect attribute, because the attribute order in innerHTML
 | 
					
						
							|  |  |  |     // isn't guaranteed in different browsers so it could throw off our assertions.
 | 
					
						
							|  |  |  |     const button = fixture.nativeElement.querySelector('button'); | 
					
						
							|  |  |  |     button.removeAttribute('ng-reflect-dialog-result'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |     expect(fixture.nativeElement.innerHTML).toEqual(`<div dialog=""><!--bindings={
 | 
					
						
							| 
									
										
										
										
											2019-07-08 14:59:10 +02:00
										 |  |  |   "ng-reflect-ng-if": "false" | 
					
						
							| 
									
										
										
										
											2019-12-11 22:04:31 +01:00
										 |  |  | }--></div><button title="Close dialog">Button label</button>`);
 | 
					
						
							| 
									
										
										
										
											2019-09-13 12:46:05 +01:00
										 |  |  |   }); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | function initWithTemplate(compType: Type<any>, template: string) { | 
					
						
							|  |  |  |   TestBed.overrideComponent(compType, {set: {template}}); | 
					
						
							|  |  |  |   const fixture = TestBed.createComponent(compType); | 
					
						
							|  |  |  |   fixture.detectChanges(); | 
					
						
							|  |  |  |   return fixture; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @Component({selector: 'app-comp', template: ``}) | 
					
						
							|  |  |  | class AppComp { | 
					
						
							|  |  |  |   name = `Angular`; | 
					
						
							|  |  |  |   visible = true; | 
					
						
							|  |  |  |   count = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-09 17:21:31 -07:00
										 |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'app-comp-with-whitespaces', | 
					
						
							|  |  |  |   template: ``, | 
					
						
							|  |  |  |   preserveWhitespaces: true, | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class AppCompWithWhitespaces { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:33:34 +02:00
										 |  |  | @Directive({ | 
					
						
							|  |  |  |   selector: '[tplRef]', | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class DirectiveWithTplRef { | 
					
						
							|  |  |  |   constructor(public vcRef: ViewContainerRef, public tplRef: TemplateRef<{}>) {} | 
					
						
							|  |  |  |   ngOnInit() { this.vcRef.createEmbeddedView(this.tplRef, {}); } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-07 16:35:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | @Pipe({name: 'uppercase'}) | 
					
						
							|  |  |  | class UppercasePipe implements PipeTransform { | 
					
						
							|  |  |  |   transform(value: string) { return value.toUpperCase(); } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-08 14:59:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | @Directive({selector: `[dialog]`}) | 
					
						
							|  |  |  | export class DialogDir { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @Directive({selector: `button[close]`, host: {'[title]': 'name'}}) | 
					
						
							|  |  |  | export class CloseBtn { | 
					
						
							|  |  |  |   @Input('close') dialogResult: any; | 
					
						
							|  |  |  |   name: string = 'Close dialog'; | 
					
						
							|  |  |  | } |