import { fakeAsync , TestBed , tick } from "@angular/core/testing" ; import { Observable , of , timer , zip , defer } from "rxjs" ; import { mapTo , take , toArray , first } from 'rxjs/operators' ; import { LangChangeEvent , TranslateLoader , TranslateModule , TranslateService , TranslationChangeEvent } from '@rxweb/ngx-translate-extension' ; import { RxTranslateModule } from "@rxweb/translate" ; let translations = { "TEST" : "This is a test" } ; class FakeLoader implements TranslateLoader { getTranslation ( lang ) { return of ( translations ) ; } } describe ( 'TranslateService' , ( ) => { let translate ; beforeEach ( ( ) => { TestBed . configureTestingModule ( { imports : [ TranslateModule . forRoot ( { loader : { provide : TranslateLoader , useClass : FakeLoader } } ) , RxTranslateModule . forRoot ( { isTest : true , forNgxTranslate : true , cacheLanguageWiseObject : true , } ) ] } ) ; translate = TestBed . get ( TranslateService ) ; } ) ; afterEach ( ( ) => { translate = undefined ; translations = { "TEST" : "This is a test" } ; } ) ; it ( 'is defined' , ( ) => { expect ( TranslateService ) . toBeDefined ( ) ; expect ( translate ) . toBeDefined ( ) ; expect ( translate instanceof TranslateService ) . toBeTruthy ( ) ; } ) ; it ( 'should be able to get translations' , ( ) => { translations = { "TEST" : "This is a test" , "TEST2" : "This is another test" } ; translate . use ( 'en' ) ; translate . get ( 'TEST' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'This is a test' ) ; } ) ; translate . get ( 'TEST2' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'This is another test' ) ; } ) ; } ) ; it ( 'should be able to get an array translations' , ( ) => { translations = { "TEST" : "This is a test" , "TEST2" : "This is another test2" } ; translate . use ( 'en' ) ; translate . get ( [ 'TEST' , 'TEST2' ] ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( translations ) ; } ) ; } ) ; it ( "should fallback to the default language" , ( ) => { translations = { } ; translate . use ( 'fr' ) ; translate . get ( 'TEST' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'TEST' ) ; translate . setDefaultLang ( 'nl' ) ; translate . setTranslation ( 'nl' , { "TEST" : "Dit is een test" } ) ; translate . get ( 'TEST' ) . subscribe ( ( res2 ) => { expect ( res2 ) . toEqual ( 'Dit is een test' ) ; expect ( translate . getDefaultLang ( ) ) . toEqual ( 'nl' ) ; } ) ; } ) ; } ) ; it ( "should use the default language by default" , ( ) => { translate . setDefaultLang ( 'nl' ) ; translate . setTranslation ( 'nl' , { "TEST" : "Dit is een test" } ) ; translate . get ( 'TEST' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'Dit is een test' ) ; } ) ; } ) ; it ( "should return the key when it doesn't find a translation" , ( ) => { translate . use ( 'en' ) ; translate . get ( 'TEST2' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'TEST2' ) ; } ) ; } ) ; it ( "should return the key when you haven't defined any translation" , ( ) => { translate . get ( 'TEST' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'TEST' ) ; } ) ; } ) ; it ( 'should return an empty value' , ( ) => { translate . setDefaultLang ( 'en' ) ; translate . setTranslation ( 'en' , { "TEST" : "" } ) ; translate . get ( 'TEST' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( '' ) ; } ) ; } ) ; it ( 'should be able to get translations with params' , ( ) => { translations = { "TEST" : "This is a test {{param}}" } ; translate . use ( 'en' ) ; translate . get ( 'TEST' , { param : 'with param' } ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'This is a test with param' ) ; } ) ; } ) ; it ( 'should be able to get translations with nested params' , ( ) => { translations = { "TEST" : "This is a test {{param.value}}" } ; translate . use ( 'en' ) ; translate . get ( 'TEST' , { param : { value : 'with param' } } ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'This is a test with param' ) ; } ) ; } ) ; it ( 'should throw if you forget the key' , ( ) => { translate . use ( 'en' ) ; expect ( ( ) => { translate . get ( undefined ) ; } ) . toThrowError ( 'Parameter "key" required' ) ; expect ( ( ) => { translate . get ( '' ) ; } ) . toThrowError ( 'Parameter "key" required' ) ; expect ( ( ) => { translate . get ( null ) ; } ) . toThrowError ( 'Parameter "key" required' ) ; expect ( ( ) => { translate . instant ( undefined ) ; } ) . toThrowError ( 'Parameter "key" required' ) ; } ) ; it ( 'should be able to get translations with nested keys' , ( ) => { translations = { "TEST" : { "TEST" : "This is a test" } , "TEST2" : { "TEST2" : { "TEST2" : "This is another test" } } } ; translate . use ( 'en' ) ; translate . get ( 'TEST.TEST' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'This is a test' ) ; } ) ; translate . get ( 'TEST2.TEST2.TEST2' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'This is another test' ) ; } ) ; } ) ; it ( "should merge translations if option shouldMerge is true" , ( done ) => { translations = { } ; translate . setTranslation ( 'en' , { "TEST" : { "sub1" : "value1" } } , true ) ; translate . setTranslation ( 'en' , { "TEST" : { "sub2" : "value2" } } , true ) ; translate . use ( 'en' ) ; translate . get ( 'TEST' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( { "sub1" : "value1" , "sub2" : "value2" } ) ; expect ( translations ) . toEqual ( { } ) ; done ( ) ; } ) ; } ) ; it ( "should merge non-valid JSON translations if option shouldMerge is true" , ( ) => { translations = { } ; translate . setTranslation ( 'en' , { "TEST" : { "sub1" : ( ) => "value1" } } , true ) ; translate . setTranslation ( 'en' , { "TEST" : { "sub2" : ( ) => "value2" } } , true ) ; translate . use ( 'en' ) ; translate . get ( 'TEST.sub1' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'value1' ) ; } ) ; translate . get ( 'TEST.sub2' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'value2' ) ; } ) ; } ) ; it ( "shouldn't call the current loader if you set the translation yourself" , ( done ) => { translations = { } ; translate . setTranslation ( 'en' , { "TEST" : "This is a test" } ) ; translate . use ( 'en' ) ; translate . get ( 'TEST' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'This is a test' ) ; expect ( translations ) . toEqual ( { } ) ; done ( ) ; } ) ; } ) ; it ( 'should be able to get a stream array' , ( done ) => { let tr = { "TEST" : "This is a test" , "TEST2" : "This is a test2" } ; translate . setTranslation ( 'en' , tr ) ; translate . use ( 'en' ) ; translate . getStreamOnTranslationChange ( [ 'TEST' , 'TEST2' ] ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( tr ) ; done ( ) ; } ) ; } ) ; it ( 'should initially return the same value for getStreamOnTranslationChange and non-streaming get' , ( done ) => { translations = { "TEST" : "This is a test" } ; translate . use ( 'en' ) ; zip ( translate . getStreamOnTranslationChange ( 'TEST' ) , translate . get ( 'TEST' ) ) . subscribe ( ( value ) => { const [ streamed , nonStreamed ] = value ; expect ( streamed ) . toEqual ( 'This is a test' ) ; expect ( streamed ) . toEqual ( nonStreamed ) ; done ( ) ; } ) ; } ) ; it ( 'should be able to stream a translation on translation change' , ( done ) => { translations = { "TEST" : "This is a test" } ; translate . use ( 'en' ) ; translate . getStreamOnTranslationChange ( 'TEST' ) . pipe ( take ( 3 ) , toArray ( ) ) . subscribe ( ( res ) => { const expected = [ 'This is a test' , 'I changed the test value!' , 'I changed it again!' ] ; expect ( res ) . toEqual ( expected ) ; done ( ) ; } ) ; translate . setTranslation ( 'en' , { "TEST" : "I changed the test value!" } ) ; translate . setTranslation ( 'en' , { "TEST" : "I changed it again!" } ) ; } ) ; it ( 'should interpolate the same param into each streamed value when get strean on translation change' , ( done ) => { translations = { "TEST" : "This is a test {{param}}" } ; translate . use ( 'en' ) ; translate . getStreamOnTranslationChange ( 'TEST' , { param : 'with param' } ) . subscribe ( ( res ) => { const expected = 'This is a test with param' ; expect ( res ) . toEqual ( expected ) ; done ( ) ; } ) ; } ) ; it ( 'should be able to stream a translation for the current language' , ( done ) => { translations = { "TEST" : "This is a test" } ; translate . use ( 'en' ) ; translate . stream ( 'TEST' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'This is a test' ) ; done ( ) ; } ) ; } ) ; it ( 'should be able to stream a translation of an array for the current language' , ( done ) => { let tr = { "TEST" : "This is a test" , "TEST2" : "This is a test2" } ; translate . setTranslation ( 'en' , tr ) ; translate . use ( 'en' ) ; translate . stream ( [ 'TEST' , 'TEST2' ] ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( tr ) ; done ( ) ; } ) ; } ) ; it ( 'should initially return the same value for streaming and non-streaming get' , ( done ) => { translations = { "TEST" : "This is a test" } ; translate . use ( 'en' ) ; zip ( translate . stream ( 'TEST' ) , translate . get ( 'TEST' ) ) . subscribe ( ( value ) => { const [ streamed , nonStreamed ] = value ; expect ( streamed ) . toEqual ( 'This is a test' ) ; expect ( streamed ) . toEqual ( nonStreamed ) ; done ( ) ; } ) ; } ) ; it ( 'should update streaming translations on language change' , ( done ) => { translations = { "TEST" : "This is a test" } ; translate . use ( 'en' ) ; translate . stream ( 'TEST' ) . pipe ( take ( 3 ) , toArray ( ) ) . subscribe ( ( res ) => { const expected = [ 'This is a test' , 'Dit is een test' , 'This is a test' ] ; expect ( res ) . toEqual ( expected ) ; done ( ) ; } ) ; translate . setTranslation ( 'nl' , { "TEST" : "Dit is een test" } ) ; translate . use ( 'nl' ) ; translate . use ( 'en' ) ; } ) ; it ( 'should update lazy streaming translations on translation change' , ( done ) => { translations = { "TEST" : "This is a test" } ; translate . use ( 'en' ) ; const translation$ = translate . getStreamOnTranslationChange ( 'TEST' ) ; translate . setTranslation ( 'en' , { "TEST" : "This is a test2" } ) ; translation$ . pipe ( first ( ) ) . subscribe ( ( res ) => { const expected = "This is a test2" ; expect ( res ) . toEqual ( expected ) ; done ( ) ; } ) ; } ) ; it ( 'should update lazy streaming translations on language change' , ( done ) => { translations = { "TEST" : "This is a test" } ; translate . use ( 'en' ) ; const translation$ = translate . stream ( 'TEST' ) ; translate . setTranslation ( 'nl' , { "TEST" : "Dit is een test" } ) ; translate . use ( 'nl' ) ; translation$ . pipe ( first ( ) ) . subscribe ( ( res ) => { const expected = 'Dit is een test' ; expect ( res ) . toEqual ( expected ) ; done ( ) ; } ) ; } ) ; it ( 'should update streaming translations of an array on language change' , ( done ) => { const en = { "TEST" : "This is a test" , "TEST2" : "This is a test2" } ; const nl = { "TEST" : "Dit is een test" , "TEST2" : "Dit is een test2" } ; translate . setTranslation ( 'en' , en ) ; translate . use ( 'en' ) ; translate . stream ( [ 'TEST' , 'TEST2' ] ) . pipe ( take ( 3 ) , toArray ( ) ) . subscribe ( ( res ) => { const expected = [ en , nl , en ] ; expect ( res ) . toEqual ( expected ) ; done ( ) ; } ) ; translate . setTranslation ( 'nl' , nl ) ; translate . use ( 'nl' ) ; translate . use ( 'en' ) ; } ) ; it ( 'should interpolate the same param into each streamed value' , ( done ) => { translations = { "TEST" : "This is a test {{param}}" } ; translate . use ( 'en' ) ; translate . stream ( 'TEST' , { param : 'with param' } ) . pipe ( take ( 3 ) , toArray ( ) ) . subscribe ( ( res ) => { const expected = [ 'This is a test with param' , 'Dit is een test with param' , 'This is a test with param' ] ; expect ( res ) . toEqual ( expected ) ; done ( ) ; } ) ; translate . setTranslation ( 'nl' , { "TEST" : "Dit is een test {{param}}" } ) ; translate . use ( 'nl' ) ; translate . use ( 'en' ) ; } ) ; it ( 'should be able to get instant translations' , ( ) => { translate . setTranslation ( 'en' , { "TEST" : "This is a test" } ) ; translate . use ( 'en' ) ; expect ( translate . instant ( 'TEST' ) ) . toEqual ( 'This is a test' ) ; } ) ; it ( 'should be able to get instant translations of an array' , ( ) => { let tr = { "TEST" : "This is a test" , "TEST2" : "This is a test2" } ; translate . setTranslation ( 'en' , tr ) ; translate . use ( 'en' ) ; expect ( translate . instant ( [ 'TEST' , 'TEST2' ] ) ) . toEqual ( tr ) ; } ) ; it ( 'should return the key if instant translations are not available' , ( ) => { translate . setTranslation ( 'en' , { "TEST" : "This is a test" } ) ; translate . use ( 'en' ) ; expect ( translate . instant ( 'TEST2' ) ) . toEqual ( 'TEST2' ) ; } ) ; it ( 'should trigger an event when the translation value changes' , ( ) => { translate . setTranslation ( 'en' , { } ) ; translate . onTranslationChange . subscribe ( ( event ) => { expect ( event . translations ) . toBeDefined ( ) ; expect ( event . translations [ "TEST" ] ) . toEqual ( "This is a test" ) ; expect ( event . lang ) . toBe ( 'en' ) ; } ) ; translate . set ( "TEST" , "This is a test" , 'en' ) ; } ) ; it ( 'should trigger an event when the lang changes' , ( ) => { let tr = { "TEST" : "This is a test" } ; translate . setTranslation ( 'en' , tr ) ; translate . onLangChange . subscribe ( ( event ) => { expect ( event . lang ) . toBe ( 'en' ) ; expect ( event . translations ) . toEqual ( tr ) ; } ) ; translate . use ( 'en' ) ; } ) ; it ( 'should be able to reset a lang' , ( done ) => { translate . use ( 'en' ) ; translate . get ( 'TEST' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( translations [ 'TEST' ] ) ; translate . resetLang ( 'en' ) ; expect ( translate . instant ( 'TEST' ) ) . toEqual ( 'TEST' ) ; translate . get ( 'TEST' ) . subscribe ( ( res2 ) => { expect ( res2 ) . toEqual ( 'TEST' ) ; done ( ) ; } ) ; } ) ; } ) ; it ( 'should be able to reload a lang' , ( ) => { translations = { } ; translate . use ( 'en' ) ; translate . get ( 'TEST' ) . subscribe ( ( res ) => { expect ( res ) . toEqual ( 'TEST' ) ; translations = { "TEST" : "This is a test 2" } ; translate . reloadLang ( 'en' ) . subscribe ( ( res2 ) => { expect ( translate . instant ( 'TEST' ) ) . toEqual ( translations [ 'TEST' ] ) ; } ) ; } ) ; } ) ; it ( 'should be able to add new langs' , ( ) => { translate . addLangs ( [ 'pl' , 'es' ] ) ; expect ( translate . getLangs ( ) ) . toEqual ( [ 'pl' , 'es' ] ) ; translate . addLangs ( [ 'fr' ] ) ; translate . addLangs ( [ 'pl' , 'fr' ] ) ; expect ( translate . getLangs ( ) ) . toEqual ( [ 'pl' , 'es' , 'fr' ] ) ; translate . use ( 'en' ) . subscribe ( ( res ) => { expect ( translate . getLangs ( ) ) . toEqual ( [ 'pl' , 'es' , 'fr' , 'en' ] ) ; translate . addLangs ( [ 'de' ] ) ; expect ( translate . getLangs ( ) ) . toEqual ( [ 'pl' , 'es' , 'fr' , 'en' , 'de' ] ) ; } ) ; } ) ; it ( 'should be able to get the browserLang' , ( ) => { let browserLang = translate . getBrowserLang ( ) ; expect ( browserLang ) . toBeDefined ( ) ; expect ( typeof browserLang === 'string' ) . toBeTruthy ( ) ; } ) ; it ( 'should be able to get the browserCultureLang' , ( ) => { let browserCultureLand = translate . getBrowserCultureLang ( ) ; expect ( browserCultureLand ) . toBeDefined ( ) ; expect ( typeof browserCultureLand === 'string' ) . toBeTruthy ( ) ; } ) ; it ( 'should not make duplicate getTranslation calls' , fakeAsync ( ( ) => { let getTranslationCalls = 0 ; spyOn ( translate . currentLoader , 'getTranslation' ) . and . callFake ( ( ) => { getTranslationCalls += 1 ; return timer ( 1000 ) . pipe ( mapTo ( of ( translations ) ) ) ; } ) ; translate . use ( 'en' ) ; translate . use ( 'en' ) ; tick ( 1001 ) ; expect ( getTranslationCalls ) . toEqual ( 1 ) ; } ) ) ; it ( 'should subscribe to the loader just once' , ( ) => { let subscriptions = 0 ; spyOn ( translate . currentLoader , 'getTranslation' ) . and . callFake ( ( ) => { return defer ( ( ) => { subscriptions ++ ; return of ( translations ) ; } ) ; } ) ; translate . use ( 'en' ) ; translate . use ( 'en' ) ; translate . use ( 'en' ) . subscribe ( ) ; translate . use ( 'en' ) . subscribe ( ) ; expect ( subscriptions ) . toEqual ( 1 ) ; } ) ; it ( 'should compile translations only once, even when subscribing to translations while translations are loading' , fakeAsync ( ( ) => { spyOn ( translate . currentLoader , 'getTranslation' ) . and . callFake ( ( ) => { return timer ( 1000 ) . pipe ( mapTo ( of ( translations ) ) ) ; } ) ; let translateCompilerCallCount = 0 ; spyOn ( translate . compiler , 'compile' ) . and . callFake ( ( value ) => { ++ translateCompilerCallCount ; return value ; } ) ; spyOn ( translate . compiler , 'compileTranslations' ) . and . callFake ( ( value ) => { ++ translateCompilerCallCount ; return value ; } ) ; translate . setDefaultLang ( 'en-US' ) ; translate . get ( 'TEST1' ) . subscribe ( ) ; translate . get ( 'TEST2' ) . subscribe ( ) ; translate . get ( 'TEST3' ) . subscribe ( ) ; translate . get ( 'TEST4' ) . subscribe ( ) ; tick ( 1001 ) ; expect ( translateCompilerCallCount ) . toBe ( 1 ) ; } ) ) ; } ) ;