/**
 * @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
 */
// 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';
import {registerLocaleData} from '@angular/common';
import localeRo from '@angular/common/locales/ro';
import {Component, ContentChild, ContentChildren, Directive, HostBinding, Input, LOCALE_ID, QueryList, TemplateRef, Type, ViewChild, ViewContainerRef, Pipe, PipeTransform} from '@angular/core';
import {setDelayProjection} from '@angular/core/src/render3/instructions/projection';
import {TestBed} from '@angular/core/testing';
import {loadTranslations, clearTranslations} from '@angular/localize';
import {By} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {onlyInIvy} from '@angular/private/testing';
import {computeMsgId} from '@angular/compiler';
onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({declarations: [AppComp, DirectiveWithTplRef, UppercasePipe]});
  });
  afterEach(() => {
    setDelayProjection(false);
    clearTranslations();
  });
  it('should translate text', () => {
    loadTranslations({[computeMsgId('text')]: 'texte'});
    const fixture = initWithTemplate(AppComp, `
text
`);
    expect(fixture.nativeElement.innerHTML).toEqual(`texte
`);
  });
  it('should support interpolations', () => {
    loadTranslations({[computeMsgId('Hello {$INTERPOLATION}!')]: 'Bonjour {$INTERPOLATION}!'});
    const fixture = initWithTemplate(AppComp, `Hello {{name}}!
`);
    expect(fixture.nativeElement.innerHTML).toEqual(`Bonjour Angular!
`);
    fixture.componentRef.instance.name = `John`;
    fixture.detectChanges();
    expect(fixture.nativeElement.innerHTML).toEqual(`Bonjour John!
`);
  });
  it('should support named interpolations', () => {
    loadTranslations({
      [computeMsgId(' Hello {$USER_NAME}! Emails: {$AMOUNT_OF_EMAILS_RECEIVED} ')]:
          ' Bonjour {$USER_NAME}! Emails: {$AMOUNT_OF_EMAILS_RECEIVED} '
    });
    const fixture = initWithTemplate(AppComp, `
      
        Hello {{ name // i18n(ph="user_name") }}!
        Emails: {{ count // i18n(ph="amount of emails received") }}
      
    `);
    expect(fixture.nativeElement.innerHTML).toEqual(` Bonjour Angular! Emails: 0 
`);
    fixture.componentRef.instance.name = `John`;
    fixture.componentRef.instance.count = 5;
    fixture.detectChanges();
    expect(fixture.nativeElement.innerHTML).toEqual(` Bonjour John! Emails: 5 
`);
  });
  it('should support interpolations with custom interpolation config', () => {
    loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
    const interpolation = ['{%', '%}'] as[string, string];
    TestBed.overrideComponent(AppComp, {set: {interpolation}});
    const fixture = initWithTemplate(AppComp, `Hello {% name %}
`);
    expect(fixture.nativeElement.innerHTML).toBe('Bonjour Angular
');
  });
  it('should support &ngsp; in translatable sections', () => {
    // note: the `` unicode symbol represents the `&ngsp;` in translations
    loadTranslations({[computeMsgId('text ||')]: 'texte ||'});
    const fixture = initWithTemplate(AppCompWithWhitespaces, `text |&ngsp;|
`);
    expect(fixture.nativeElement.innerHTML).toEqual(`texte | |
`);
  });
  it('should support interpolations with complex expressions', () => {
    loadTranslations({
      [computeMsgId(' {$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} ')]:
          ' {$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} (fr) '
    });
    const fixture = initWithTemplate(AppComp, `
      
        {{ name | uppercase }} -
        {{ obj?.a?.b }} -
        {{ obj?.getA()?.b }}
      
    `);
    // the `obj` field is not yet defined, so 2nd and 3rd interpolations return empty strings
    expect(fixture.nativeElement.innerHTML).toEqual(` ANGULAR -  -  (fr) 
`);
    fixture.componentRef.instance.obj = {
      a: {b: 'value 1'},
      getA: () => ({b: 'value 2'}),
    };
    fixture.detectChanges();
    expect(fixture.nativeElement.innerHTML)
        .toEqual(` ANGULAR - value 1 - value 2 (fr) 
`);
  });
  it('should support elements', () => {
    loadTranslations({
      [computeMsgId(
          'Hello {$START_TAG_SPAN}world{$CLOSE_TAG_SPAN} and {$START_TAG_DIV}universe{$CLOSE_TAG_DIV}!',
          '')]:
          'Bonjour {$START_TAG_SPAN}monde{$CLOSE_TAG_SPAN} et {$START_TAG_DIV}univers{$CLOSE_TAG_DIV}!'
    });
    const fixture = initWithTemplate(
        AppComp, `Hello 
world  and 
universe
!
Bonjour 
monde  et 
univers
!
Hello my world 
!
`);
    expect(fixture.nativeElement.innerHTML)
        .toEqual(`Bonjour monde 
!
`);
  });
  it('should support moving elements', () => {
    loadTranslations({
      [computeMsgId(
          'Hello {$START_TAG_SPAN}world{$CLOSE_TAG_SPAN} and {$START_TAG_DIV}universe{$CLOSE_TAG_DIV}!',
          '')]:
          'Bonjour {$START_TAG_DIV}univers{$CLOSE_TAG_DIV} et {$START_TAG_SPAN}monde{$CLOSE_TAG_SPAN}!'
    });
    const fixture = initWithTemplate(
        AppComp, `Hello 
world  and 
universe
!
Bonjour 
univers
 et 
monde !
Content: 
beforemiddle after
!
Contenu: 
avantmilieu après
!
Contenu: !
`);
  });
  it('should support multiple i18n blocks', () => {
    loadTranslations({
      [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}'
    });
    const fixture = initWithTemplate(AppComp, `
      `);
    expect(fixture.nativeElement.innerHTML)
        .toEqual(
            ``);
  });
  it('should support multiple sibling i18n blocks', () => {
    loadTranslations({
      [computeMsgId('Section 1')]: 'Section un',
      [computeMsgId('Section 2')]: 'Section deux',
      [computeMsgId('Section 3')]: 'Section trois',
    });
    const fixture = initWithTemplate(AppComp, `
      
        Section 1
        Section 2
        Section 3
       `);
    expect(fixture.nativeElement.innerHTML)
        .toEqual(`Section un
Section deux
Section trois
        Section 1 
        Section 2 
        Section 3 
       `);
    expect(fixture.nativeElement.innerHTML)
        .toEqual(
            `Section un Section deux Section trois Section un Section deux Section trois Section un Section deux Section trois 'Single quotes' and "Double quotes"
`);
    expect(fixture.nativeElement.innerHTML)
        .toEqual('\'Guillemets simples\' et "Guillemets doubles"
');
  });
  it('should correctly bind to context in nested template', () => {
    loadTranslations({[computeMsgId('Item {$INTERPOLATION}')]: 'Article {$INTERPOLATION}'});
    const fixture = initWithTemplate(AppComp, `
          
        `);
    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, 'Hello {{ name }}
`);
    expect(fixture.nativeElement.firstChild).toHaveText('Bonjour Angular');
  });
  it('should work correctly with event listeners', () => {
    loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
    @Component(
        {selector: 'app-comp', template: `Hello {{ name }}
`})
    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);
  });
  describe('ng-container and ng-template support', () => {
    it('should support ng-container', () => {
      loadTranslations({[computeMsgId('text')]: 'texte'});
      const fixture = initWithTemplate(AppComp, `text `);
      expect(fixture.nativeElement.innerHTML).toEqual(`texte`);
    });
    it('should handle single translation message within ng-template', () => {
      loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
      const fixture =
          initWithTemplate(AppComp, `Hello {{ name }} `);
      const element = fixture.nativeElement;
      expect(element).toHaveText('Bonjour Angular');
    });
    // Note: applying structural directives to  is typically user error, but it
    // is technically allowed, so we need to support it.
    it('should handle structural directives on ng-template', () => {
      loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
      const fixture = initWithTemplate(
          AppComp, `Hello {{ name }} `);
      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({
        [computeMsgId(
            '{$START_TAG_NG_TEMPLATE} Hello {$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER} Bye {$CLOSE_TAG_NG_CONTAINER}',
            '')]:
            '{$START_TAG_NG_TEMPLATE} Bonjour {$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER} Au revoir {$CLOSE_TAG_NG_CONTAINER}'
      });
      const fixture = initWithTemplate(AppComp, `
        
          
            Hello
           
          
            Bye
           
        
      `);
      const element = fixture.nativeElement.firstChild;
      expect(element.textContent.replace(/\s+/g, ' ').trim()).toBe('Bonjour Au revoir');
    });
    it('should be able to act as child elements inside i18n block (text + tags)', () => {
      loadTranslations({
        [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}',
            '')]:
            '{$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, `
        
          
            Hello 
           
          
            Hello 
           
        
      `);
      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({
        [computeMsgId(
            '{$START_TAG_NG_TEMPLATE}Hello {$INTERPOLATION}{$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER}Bye {$INTERPOLATION}{$CLOSE_TAG_NG_CONTAINER}',
            '')]:
            '{$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, `
        
          Hello {{name | uppercase}} 
          Bye {{name | uppercase}} 
        
      `);
      const element = fixture.nativeElement.firstChild;
      expect(element.textContent.replace(/\s+/g, ' ').trim()).toBe('Hej ANGULARVi ses ANGULAR');
    });
    it('should be able to handle deep nested levels with templates', () => {
      loadTranslations({
        [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}',
            '')]:
            '{$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, `
        
          
            Hello - 1
           
          
            Hello - 2
            
              Hello - 3
              
                Hello - 4
               
             
           
          
            Hello - 5
           
        
      `);
      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', () => {
      loadTranslations({
        [computeMsgId('{$START_TAG_SPAN}My logo{$TAG_IMG}{$CLOSE_TAG_SPAN}')]:
            '{$START_TAG_SPAN}Mon logo{$TAG_IMG}{$CLOSE_TAG_SPAN}'
      });
      const content = `My logo
          ${content} 
         
        
          ${content} 
         
      `);
      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 ', () => {
      loadTranslations({
        [computeMsgId('{$START_LINK}Not logged in{$CLOSE_LINK}')]:
            '{$START_LINK}Not logged in{$CLOSE_LINK}'
      });
      @Directive({selector: '[myDir]'})
      class Dir {
        condition = true;
      }
      @Component({
        selector: 'my-cmp',
        template: `
              
                Logged in 
              
              
                Not logged in 
               
            `,
      })
      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', () => {
      loadTranslations({
        [computeMsgId('{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}')]:
            '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'
      });
      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', () => {
      loadTranslations({
        [computeMsgId('{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}')]:
            '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'
      });
      const fixture = initWithTemplate(
          AppComp, `{count, select, 10 {ten} 20 {twenty} other {other}}
`);
      const element = fixture.nativeElement;
      expect(element).toHaveText('autre');
    });
    it('multiple', () => {
      loadTranslations({
        [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}}}',
            '')]:
            '{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}}}',
        [computeMsgId('{VAR_SELECT, select, other {({INTERPOLATION})}}')]:
            '{VAR_SELECT, select, other {({INTERPOLATION})}}',
        [computeMsgId('{$ICU} - {$ICU_1}')]: '{$ICU} - {$ICU_1}',
      });
      const fixture = initWithTemplate(AppComp, `{count, plural,
        =0 {no emails !}
        =1 {one email }
        other {{{count}} emails }
      } - {name, select,
        other {({{name}})}
      }
`);
      expect(fixture.nativeElement.innerHTML)
          .toEqual(`aucun email ! - (Angular)
`);
      fixture.componentRef.instance.count = 4;
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML)
          .toEqual(
              `4 emails  - (Angular)
`);
      fixture.componentRef.instance.count = 0;
      fixture.componentRef.instance.name = 'John';
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML)
          .toEqual(`aucun email ! - (John)
`);
    });
    it('with custom interpolation config', () => {
      loadTranslations({
        [computeMsgId('{VAR_SELECT, select, 10 {ten} other {{INTERPOLATION}}}')]:
            '{VAR_SELECT, select, 10 {dix} other {{INTERPOLATION}}}'
      });
      const interpolation = ['{%', '%}'] as[string, string];
      TestBed.overrideComponent(AppComp, {set: {interpolation}});
      const fixture =
          initWithTemplate(AppComp, `{count, select, 10 {ten} other {{% name %}}}
`);
      expect(fixture.nativeElement).toHaveText(`Angular`);
    });
    it('inside HTML elements', () => {
      loadTranslations({
        [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}}}',
            '')]:
            '{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}}}',
        [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}',
      });
      const fixture = initWithTemplate(AppComp, `{count, plural,
        =0 {no emails !}
        =1 {one email }
        other {{{count}} emails }
      }  - {name, select,
        other {({{name}})}
      } 
`);
      expect(fixture.nativeElement.innerHTML)
          .toEqual(
              `aucun email !  - (Angular) 
`);
      fixture.componentRef.instance.count = 4;
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML)
          .toEqual(
              `4 emails   - (Angular) 
`);
      fixture.componentRef.instance.count = 0;
      fixture.componentRef.instance.name = 'John';
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML)
          .toEqual(
              `aucun email !  - (John) 
`);
    });
    it('inside template directives', () => {
      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})}}'
      });
      const fixture = initWithTemplate(AppComp, `{name, select,
        other {({{name}})}
      } 
`);
      expect(fixture.nativeElement.innerHTML)
          .toEqual(`(Angular) 
`);
      fixture.componentRef.instance.visible = false;
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML).toEqual(`
`);
    });
    it('inside ng-container', () => {
      loadTranslations({
        [computeMsgId('{VAR_SELECT, select, other {({INTERPOLATION})}}')]:
            '{VAR_SELECT, select, other {({INTERPOLATION})}}'
      });
      const fixture = initWithTemplate(AppComp, `{name, select,
        other {({{name}})}
      } `);
      expect(fixture.nativeElement.innerHTML).toEqual(`(Angular)`);
    });
    it('inside ', () => {
      loadTranslations({
        [computeMsgId('{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}')]:
            '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'
      });
      const fixture = initWithTemplate(
          AppComp, `
        ` +
              `{count, select, 10 {ten} 20 {twenty} other {other}}` +
              ` 
      `);
      const element = fixture.nativeElement;
      expect(element).toHaveText('autre');
    });
    it('nested', () => {
      loadTranslations({
        [computeMsgId(
            '{VAR_PLURAL, plural, =0 {zero} other {{INTERPOLATION} {VAR_SELECT, select, cat {cats} dog {dogs} other {animals}}!}}',
            '')]:
            '{VAR_PLURAL, plural, =0 {zero} other {{INTERPOLATION} {VAR_SELECT, select, cat {chats} dog {chiens} other {animaux}}!}}'
      });
      const fixture = initWithTemplate(AppComp, `{count, plural,
        =0 {zero}
        other {{{count}} {name, select,
                       cat {cats}
                       dog {dogs}
                       other {animals}
                     }!}
      }
`);
      expect(fixture.nativeElement.innerHTML).toEqual(`zero
`);
      fixture.componentRef.instance.count = 4;
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML)
          .toEqual(`4 animaux!
`);
    });
    it('nested with interpolations in "other" blocks', () => {
      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}}}'
      });
      const fixture = initWithTemplate(AppComp, `{count, plural,
        =0 {zero}
        =2 {{{count}} {name, select,
                       cat {cats}
                       dog {dogs}
                       other {animals}
                     }!}
        other {other - {{count}}}
      }
`);
      expect(fixture.nativeElement.innerHTML).toEqual(`zero
`);
      fixture.componentRef.instance.count = 2;
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML)
          .toEqual(`2 animaux!
`);
      fixture.componentRef.instance.count = 4;
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML).toEqual(`autre - 4
`);
    });
    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, `
          {count, plural,
            =0 {no email}
            =one {one email}
            =few {a few emails}
            =other {lots of emails}
          }`);
      expect(fixture.nativeElement.innerHTML).toEqual('no email');
      // Change detection cycle, no model changes
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML).toEqual('no email');
      fixture.componentInstance.count = 3;
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML).toEqual('a few emails');
      fixture.componentInstance.count = 1;
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML).toEqual('one email');
      fixture.componentInstance.count = 10;
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML).toEqual('a few emails');
      fixture.componentInstance.count = 20;
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML).toEqual('lots of emails');
      fixture.componentInstance.count = 0;
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML).toEqual('no email');
    });
    it('projection', () => {
      loadTranslations({
        [computeMsgId('{VAR_PLURAL, plural, =1 {one} other {at least {INTERPOLATION} .}}')]:
            '{VAR_PLURAL, plural, =1 {one} other {at least {INTERPOLATION} .}}'
      });
      @Component({selector: 'child', template: '
'})
      class Child {
      }
      @Component({
        selector: 'parent',
        template: `
      {
        value // i18n(ph = "blah"),
        plural,
         =1 {one}
        other {at least {{value}} .}
      } `
      })
      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', () => {
      loadTranslations({
        [computeMsgId('{VAR_SELECT, select, 10 {} 20 {twenty} other {other}}')]:
            '{VAR_SELECT, select, 10 {} 20 {twenty} other {other}}'
      });
      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', () => {
      loadTranslations({
        [computeMsgId('{VAR_PLURAL, plural, =1 {ONE} other {OTHER}}')]:
            '{VAR_PLURAL, plural, =1 {ONE} other {OTHER}}'
      });
      @Directive({
        selector: '[someDir]',
      })
      class Dir {
        constructor(
            private readonly viewContainerRef: ViewContainerRef,
            private readonly templateRef: TemplateRef) {}
        ngOnInit() { this.viewContainerRef.createEmbeddedView(this.templateRef); }
      }
      @Component({
        selector: 'my-cmp',
        template: `
              
                
            `,
      })
      class Cmp {
      }
      @Component({
        selector: 'my-app',
        template: `
            {
              count,
              plural,
              =1 {ONE}
              other {OTHER}
            } 
          `,
      })
      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('ONE
OTHER
ONE
) {
             dir = this;
           }
           attachEmbeddedView() { this.viewContainerRef.createEmbeddedView(this.templateRef); }
         }
         @Component({
           selector: 'my-cmp',
           template: `
              
                
            `,
         })
         class Cmp {
         }
         @Component({
           selector: 'my-app',
           template: `
            {
              count,
              plural,
              =1 {ONE}
              other {{{count}} {name, select,
                cat {cats}
                dog {dogs}
                other {animals}
              }!}
            } 
          `,
         })
         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('2 animals!
ONE
          
            {type, select, A { A } B { B } other { C }}
           
          
            {type, select, A1 { A1 } B1 { B1 } other { C1 }}
           
         
      `,
      })
      class Comp {
        type = 'A';
        visible = true;
        isVisible() { return true; }
      }
      TestBed.configureTestingModule({declarations: [Comp]});
      const fixture = TestBed.createComponent(Comp);
      fixture.detectChanges();
      expect(fixture.debugElement.nativeElement.innerHTML).toContain('A');
      fixture.componentInstance.visible = false;
      fixture.detectChanges();
      expect(fixture.debugElement.nativeElement.innerHTML).not.toContain('A');
      expect(fixture.debugElement.nativeElement.innerHTML).toContain('C1');
    });
    it('with named interpolations', () => {
      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}}}',
      });
      @Component({
        selector: 'comp',
        template: `
          {
            type,
            select,
              A {A - {{ typeA // i18n(ph="PH_A") }}}
              B {B - {{ typeB // i18n(ph="PH_B") }}}
              other {other - {{ typeC // i18n(ph="PH WITH SPACES") }}}
          } 
        `,
      })
      class Comp {
        type = 'A';
        typeA = 'Type A';
        typeB = 'Type B';
        typeC = 'Type C';
      }
      TestBed.configureTestingModule({declarations: [Comp]});
      const fixture = TestBed.createComponent(Comp);
      fixture.detectChanges();
      expect(fixture.debugElement.nativeElement.innerHTML).toContain('A (translated) - Type A');
      fixture.componentInstance.type = 'C';  // trigger "other" case
      fixture.detectChanges();
      expect(fixture.debugElement.nativeElement.innerHTML).not.toContain('A (translated) - Type A');
      expect(fixture.debugElement.nativeElement.innerHTML).toContain('other (translated) - Type C');
    });
    it('should work inside an ngTemplateOutlet inside an ngFor', () => {
      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} '
      });
      @Component({
        selector: 'app',
        template: `
          {
            type,
            select,
            A {A }
            B {B }
            other {other - {{ typeC // i18n(ph="PH WITH SPACES") }}}
          }
           
          
            
             
          
        `
      })
      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');
    });
  });
  describe('should support attributes', () => {
    it('text', () => {
      loadTranslations({[computeMsgId('text')]: 'texte'});
      const fixture = initWithTemplate(AppComp, `
`);
      expect(fixture.nativeElement.innerHTML).toEqual(`
`);
    });
    it('interpolations', () => {
      loadTranslations({[computeMsgId('hello {$INTERPOLATION}')]: 'bonjour {$INTERPOLATION}'});
      const fixture =
          initWithTemplate(AppComp, `
`);
      expect(fixture.nativeElement.innerHTML).toEqual(`
`);
      fixture.componentRef.instance.name = 'John';
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML).toEqual(`
`);
    });
    it('with pipes', () => {
      loadTranslations({[computeMsgId('hello {$INTERPOLATION}')]: 'bonjour {$INTERPOLATION}'});
      const fixture = initWithTemplate(
          AppComp, `
`);
      expect(fixture.nativeElement.innerHTML).toEqual(`
`);
    });
    it('multiple attributes', () => {
      loadTranslations({[computeMsgId('hello {$INTERPOLATION}')]: 'bonjour {$INTERPOLATION}'});
      const fixture = initWithTemplate(
          AppComp,
          `content 
`);
      expect(fixture.nativeElement.innerHTML).toEqual(`contenu
`);
    });
    it('with custom interpolation config', () => {
      loadTranslations({[computeMsgId('Hello {$INTERPOLATION}', 'm')]: 'Bonjour {$INTERPOLATION}'});
      const interpolation = ['{%', '%}'] as[string, string];
      TestBed.overrideComponent(AppComp, {set: {interpolation}});
      const fixture =
          initWithTemplate(AppComp, `
`);
      const element = fixture.nativeElement.firstChild;
      expect(element.title).toBe('Bonjour Angular');
    });
    it('in nested template', () => {
      loadTranslations({[computeMsgId('Item {$INTERPOLATION}', 'm')]: 'Article {$INTERPOLATION}'});
      const fixture = initWithTemplate(AppComp, `
          `);
      const element = fixture.nativeElement;
      for (let i = 0; i < element.children.length; i++) {
        const child = element.children[i];
        expect((child as any).innerHTML).toBe(`
`);
      }
    });
    it('should add i18n attributes on self-closing tags', () => {
      loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
      const fixture =
          initWithTemplate(AppComp, `
`
      })
      class Other {
      }
      @Component({
        selector: 'blah',
        template: `
          
      `);
      // the `obj` field is not yet defined, so 2nd and 3rd interpolations return empty strings
      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)`);
    });
    it('should create corresponding ng-reflect properties', () => {
      @Component({
        selector: 'welcome',
        template: '{{ messageText }}',
      })
      class WelcomeComp {
        @Input() messageText !: string;
      }
      @Component({
        template: `
          
           
        `
      })
      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');
    });
  });
  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: `
      
         trad: {exp1, plural,
              =0 {no emails !}
              =1 {one email }
              other {{{exp1}} emails}
         }
      
`
    })
    class MyApp {
      exp1 = 1;
      exp2 = 2;
    }
    TestBed.configureTestingModule({declarations: [ClsDir, MyApp]});
    loadTranslations({
      // Note that this translation switches the order of the expressions!
      [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}}')]:
          '{VAR_PLURAL, plural, =0 {aucun {START_BOLD_TEXT}email{CLOSE_BOLD_TEXT}!} =1 {un {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} emails}}',
      [computeMsgId(' trad: {$ICU} ')]: ' traduction: {$ICU} '
    });
    const fixture = TestBed.createComponent(MyApp);
    fixture.detectChanges();
    expect(fixture.nativeElement.innerHTML)
        .toEqual(
            ` traduction: un email  ` +
            `
`);
    directiveInstances.forEach(instance => instance.klass = 'bar');
    fixture.componentRef.instance.exp1 = 2;
    fixture.componentRef.instance.exp2 = 3;
    fixture.detectChanges();
    expect(fixture.nativeElement.innerHTML)
        .toEqual(
            ` traduction: 2 emails ` +
            `
`);
  });
  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({
      [computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}',
      [computeMsgId('works')]: 'fonctionne',
    });
    const fixture = initWithTemplate(
        AppComp,
        `
'})
      class Child {
      }
      @Component({
        selector: 'parent',
        template: `
            
              I am projected from
                {{name}} 
                 
              
`
      })
      class Parent {
        name: string = 'Parent';
      }
      TestBed.configureTestingModule({declarations: [Parent, Child]});
      loadTranslations({
        [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}')]:
            '{$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(
              `Je suis projeté depuis Parent 
'})
      class Child {
      }
      @Component({
        selector: 'parent',
        template: `
          
            
              I am projected from {{name}} 
               
           `
      })
      class Parent {
        name: string = 'Parent';
      }
      TestBed.configureTestingModule({declarations: [Parent, Child]});
      loadTranslations({
        [computeMsgId('Child of {$INTERPOLATION}')]: 'Enfant de {$INTERPOLATION}',
        [computeMsgId('I am projected from {$INTERPOLATION}')]:
            'Je suis projeté depuis {$INTERPOLATION}'
      });
      const fixture = TestBed.createComponent(Parent);
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML)
          .toEqual(
              `Je suis projeté depuis Parent 
Je suis projeté depuis Parent 2 
'})
      class GrandChild {
      }
      @Component(
          {selector: 'child', template: 'Hello  World!Bonjour  monde!
'})
      class GrandChild {
      }
      @Component(
          {selector: 'child', template: 'Hello  World!Bonjour monde!
             
        `
      })
      class Parent {
      }
      TestBed.configureTestingModule({declarations: [Parent, Child]});
      loadTranslations({
        [computeMsgId('{$START_TAG_SPAN}{$CLOSE_TAG_SPAN}{$START_TAG_SPAN_1}{$CLOSE_TAG_SPAN}')]:
            '{$START_TAG_SPAN}Contenu{$CLOSE_TAG_SPAN}'
      });
      const fixture = TestBed.createComponent(Parent);
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML)
          .toEqual('Contenu Content projected from 
`
      })
      class Child {
      }
      @Component({selector: 'parent', template: `{{name}} `})
      class Parent {
        name: string = 'Parent';
      }
      TestBed.configureTestingModule({declarations: [Parent, Child]});
      loadTranslations({
        [computeMsgId('Content projected from {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]:
            'Contenu projeté depuis {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}'
      });
      const fixture = TestBed.createComponent(Parent);
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML)
          .toEqual(`Contenu projeté depuis Parent
Contenu projeté depuis Parent component
Content projected from 
`
      })
      class Child {
      }
      @Component({selector: 'parent', template: `{{name}} Parent  a projeté le contenu
Child content 
`})
      class Child {
      }
      @Component({selector: 'parent', template: `and projection from {{name}} `})
      class Parent {
        name: string = 'Parent';
      }
      TestBed.configureTestingModule({declarations: [Parent, Child]});
      loadTranslations({
        [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}'
      });
      const fixture = TestBed.createComponent(Parent);
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML)
          .toEqual(`Contenu enfant et projection depuis Parent
'})
      class Child {
      }
      @Component({
        selector: 'parent',
        template: `
      {
        value // i18n(ph = "blah"),
        plural,
         =1 {one}
        other {at least {{value}} .}
      } `
      })
      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: `Child content 
`})
      class Child {
      }
      @Component({
        selector: 'parent',
        template:
            `and projection from {name, select, angular {Angular} other {{{name}}}} `
      })
      class Parent {
        name: string = 'Parent';
      }
      TestBed.configureTestingModule({declarations: [Parent, Child]});
      loadTranslations({
        [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}'
      });
      const fixture = TestBed.createComponent(Parent);
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML)
          .toEqual(
              `Contenu enfant et projection depuis Parent
Contenu enfant et projection depuis Angular
Child content 
`})
      class Child {
      }
      @Component({selector: 'parent', template: `and projection from {{name}} `})
      class Parent {
        name: string = 'Parent';
      }
      TestBed.configureTestingModule({declarations: [Parent, Child]});
      loadTranslations({
        [computeMsgId('Child content {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]:
            'Contenu enfant',
        [computeMsgId('and projection from {$INTERPOLATION}')]:
            'et projection depuis {$INTERPOLATION}'
      });
      const fixture = TestBed.createComponent(Parent);
      fixture.detectChanges();
      expect(fixture.nativeElement.innerHTML).toEqual(`Contenu enfant
( 
        `
      })
      class MyContentApp {
      }
      @Component({
        selector: 'my-app',
        template: `
          {type, select, A {A} B {B} other {other}} 
        `
      })
      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 
      fixture.componentInstance.condition = false;
      fixture.detectChanges();
      // should not contain 'A'
      expect(fixture.nativeElement.textContent).toBe('');
      // display  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(//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: ';
        // TODO(issue/24571): remove '!'.
        @ViewChild('vc', {read: ViewContainerRef, static: true})
        vc !: ViewContainerRef;
        // TODO(issue/24571): remove '!'.
        @ContentChildren(TextDirective, {descendants: true})
        query !: QueryList;
        create() { this.vc.createEmbeddedView(this.template); }
        destroy() { this.vc.clear(); }
      }
      TestBed.configureTestingModule({declarations: [TextDirective, DivQuery]});
      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}'
      });
      const fixture = initWithTemplate(AppComp, `
          
            
              
             
           
        `);
      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(`Contenu `);
      // Disable ng-if
      fixture.componentInstance.visible = false;
      fixture.detectChanges();
      expect(q.query.length).toEqual(0);
      expect(toHtml(fixture.nativeElement))
          .toEqual(`Contenu `);
    });
  });
  it('should not alloc expando slots when there is no new variable to create', () => {
    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}',
    });
    @Component({
      template: `
      
      Button label 
  `
    })
    class ContentElementDialog {
      data = false;
    }
    TestBed.configureTestingModule({declarations: [DialogDir, CloseBtn, ContentElementDialog]});
    const fixture = TestBed.createComponent(ContentElementDialog);
    fixture.detectChanges();
    expect(fixture.nativeElement.innerHTML).toEqual(`
Button label `);
  });
});
function initWithTemplate(compType: Type, 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;
}
@Component({
  selector: 'app-comp-with-whitespaces',
  template: ``,
  preserveWhitespaces: true,
})
class AppCompWithWhitespaces {
}
@Directive({
  selector: '[tplRef]',
})
class DirectiveWithTplRef {
  constructor(public vcRef: ViewContainerRef, public tplRef: TemplateRef<{}>) {}
  ngOnInit() { this.vcRef.createEmbeddedView(this.tplRef, {}); }
}
@Pipe({name: 'uppercase'})
class UppercasePipe implements PipeTransform {
  transform(value: string) { return value.toUpperCase(); }
}
@Directive({selector: `[dialog]`})
export class DialogDir {
}
@Directive({selector: `button[close]`, host: {'[title]': 'name'}})
export class CloseBtn {
  @Input('close') dialogResult: any;
  name: string = 'Close dialog';
}