@@ -4,16 +4,38 @@ import { TestBed } from "@angular/core/testing";
44import { provideTranslateService , TranslateService , Translation } from "@ngx-translate/core" ;
55import {
66 provideTranslateHttpLoader ,
7+ provideTranslateMultiHttpLoader ,
78 TranslateHttpLoader ,
89 TranslateHttpLoaderConfig ,
10+ TranslateMultiHttpLoaderConfig ,
911} from "../public-api" ;
1012import { MarkerInterceptor } from "../test-helper/marker-interceptor" ;
1113
1214describe ( "TranslateHttpLoader (HttpClient)" , ( ) => {
1315 let translate : TranslateService ;
1416 let http : HttpTestingController ;
1517
16- const prepare = ( config : Partial < TranslateHttpLoaderConfig > = { } ) => {
18+ const prepareMulti = ( config : Partial < TranslateMultiHttpLoaderConfig > = { } ) => {
19+ TestBed . configureTestingModule ( {
20+ providers : [
21+ MarkerInterceptor ,
22+ {
23+ provide : HTTP_INTERCEPTORS ,
24+ useExisting : MarkerInterceptor ,
25+ multi : true ,
26+ } ,
27+ provideHttpClient ( withInterceptorsFromDi ( ) ) ,
28+ provideHttpClientTesting ( ) ,
29+ provideTranslateService ( ) ,
30+ provideTranslateMultiHttpLoader ( config ) ,
31+ ] ,
32+ } ) ;
33+
34+ translate = TestBed . inject ( TranslateService ) ;
35+ http = TestBed . inject ( HttpTestingController ) ;
36+ } ;
37+
38+ const prepareSingle = ( config : Partial < TranslateHttpLoaderConfig > = { } ) => {
1739 TestBed . configureTestingModule ( {
1840 providers : [
1941 MarkerInterceptor ,
@@ -38,29 +60,44 @@ describe("TranslateHttpLoader (HttpClient)", () => {
3860 } ) ;
3961
4062 it ( "should be able to provide TranslateHttpLoader" , ( ) => {
41- prepare ( ) ;
63+ prepareSingle ( ) ;
4264 expect ( TranslateHttpLoader ) . toBeDefined ( ) ;
4365 expect ( translate . currentLoader ) . toBeDefined ( ) ;
4466 expect ( translate . currentLoader instanceof TranslateHttpLoader ) . toBeTruthy ( ) ;
4567 } ) ;
4668
4769 describe ( "Config" , ( ) => {
4870 it ( "uses prefix" , ( ) => {
49- prepare ( { prefix : "XXXX/" } ) ;
71+ prepareSingle ( { prefix : "XXXX/" } ) ;
72+ translate . use ( "en" ) ;
73+ http . expectOne ( "XXXX/en.json" ) . flush ( { } ) ;
74+ expect ( true ) . toBeTruthy ( ) ; // http.expectOne() is not detected by jasmine...
75+ } ) ;
76+
77+ it ( "uses multipleHttpLoader prefix" , ( ) => {
78+ prepareMulti ( { resources : [ "XXXX/" , "YYYY/" ] } ) ;
5079 translate . use ( "en" ) ;
5180 http . expectOne ( "XXXX/en.json" ) . flush ( { } ) ;
81+ http . expectOne ( "YYYY/en.json" ) . flush ( { } ) ;
5282 expect ( true ) . toBeTruthy ( ) ; // http.expectOne() is not detected by jasmine...
5383 } ) ;
5484
5585 it ( "uses suffix" , ( ) => {
56- prepare ( { suffix : ".XXXX" } ) ;
86+ prepareSingle ( { suffix : ".XXXX" } ) ;
87+ translate . use ( "en" ) ;
88+ http . expectOne ( "/assets/i18n/en.XXXX" ) . flush ( { } ) ;
89+ expect ( true ) . toBeTruthy ( ) ; // http.expectOne() is not detected by jasmine...
90+ } ) ;
91+
92+ it ( "uses multipleHttpLoader suffix" , ( ) => {
93+ prepareMulti ( { resources : [ { prefix : "/assets/i18n/" , suffix : ".XXXX" } ] } ) ;
5794 translate . use ( "en" ) ;
5895 http . expectOne ( "/assets/i18n/en.XXXX" ) . flush ( { } ) ;
5996 expect ( true ) . toBeTruthy ( ) ; // http.expectOne() is not detected by jasmine...
6097 } ) ;
6198
6299 it ( "uses cache buster" , ( ) => {
63- prepare ( { enforceLoading : true } ) ;
100+ prepareSingle ( { enforceLoading : true } ) ;
64101 translate . use ( "en" ) ;
65102 http . expectOne ( ( req ) =>
66103 req . url . startsWith ( "/assets/i18n/en.json?enforceLoading=" ) ,
@@ -70,7 +107,29 @@ describe("TranslateHttpLoader (HttpClient)", () => {
70107 } ) ;
71108
72109 it ( "should be able to get translations" , ( ) => {
73- prepare ( ) ;
110+ prepareSingle ( ) ;
111+
112+ translate . use ( "en" ) ;
113+
114+ // this will request the translation from the backend because we use a static files loader for TranslateService
115+ translate . get ( "TEST" ) . subscribe ( ( res : Translation ) => {
116+ expect ( res as string ) . toEqual ( "This is a test" ) ;
117+ } ) ;
118+
119+ // mock response after the xhr request, otherwise it will be undefined
120+ http . expectOne ( "/assets/i18n/en.json" ) . flush ( {
121+ TEST : "This is a test" ,
122+ TEST2 : "This is another test" ,
123+ } ) ;
124+
125+ // this will request the translation from downloaded translations without making a request to the backend
126+ translate . get ( "TEST2" ) . subscribe ( ( res : Translation ) => {
127+ expect ( res as string ) . toEqual ( "This is another test" ) ;
128+ } ) ;
129+ } ) ;
130+
131+ it ( "should be able to get translations from multipleHttpLoader" , ( ) => {
132+ prepareMulti ( ) ;
74133
75134 translate . use ( "en" ) ;
76135
@@ -92,7 +151,18 @@ describe("TranslateHttpLoader (HttpClient)", () => {
92151 } ) ;
93152
94153 it ( "should trigger MarkerInterceptor when loading translations" , ( ) => {
95- prepare ( ) ;
154+ prepareSingle ( ) ;
155+
156+ translate . use ( "en" ) . subscribe ( ) ;
157+
158+ const req = http . expectOne ( "/assets/i18n/en.json" ) ;
159+ req . flush ( { HELLO : "Hello" } ) ;
160+
161+ expect ( req . request . headers . get ( "X-Test-Header" ) ) . toBe ( "marker" ) ;
162+ } ) ;
163+
164+ it ( "should trigger MarkerInterceptor when loading translations with multipleHttpLoader" , ( ) => {
165+ prepareMulti ( ) ;
96166
97167 translate . use ( "en" ) . subscribe ( ) ;
98168
@@ -103,7 +173,28 @@ describe("TranslateHttpLoader (HttpClient)", () => {
103173 } ) ;
104174
105175 it ( "should be able to reload a lang" , ( ) => {
106- prepare ( ) ;
176+ prepareSingle ( ) ;
177+
178+ translate . use ( "en" ) ;
179+
180+ // this will request the translation from the backend because we use a static files loader for TranslateService
181+ translate . get ( "TEST" ) . subscribe ( ( res : Translation ) => {
182+ expect ( res as string ) . toEqual ( "This is a test" ) ;
183+
184+ // reset the lang as if it was never initiated
185+ translate . reloadLang ( "en" ) . subscribe ( ( ) => {
186+ expect ( translate . instant ( "TEST" ) as string ) . toEqual ( "This is a test 2" ) ;
187+ } ) ;
188+
189+ http . expectOne ( "/assets/i18n/en.json" ) . flush ( { TEST : "This is a test 2" } ) ;
190+ } ) ;
191+
192+ // mock response after the xhr request, otherwise it will be undefined
193+ http . expectOne ( "/assets/i18n/en.json" ) . flush ( { TEST : "This is a test" } ) ;
194+ } ) ;
195+
196+ it ( "should be able to reload a lang with multipleHttpLoader" , ( ) => {
197+ prepareMulti ( ) ;
107198
108199 translate . use ( "en" ) ;
109200
@@ -124,7 +215,37 @@ describe("TranslateHttpLoader (HttpClient)", () => {
124215 } ) ;
125216
126217 it ( "should be able to reset a lang" , ( done : DoneFn ) => {
127- prepare ( ) ;
218+ prepareSingle ( ) ;
219+
220+ translate . use ( "en" ) ;
221+ spyOn ( http , "expectOne" ) . and . callThrough ( ) ;
222+
223+ // this will request the translation from the backend because we use a static files loader for TranslateService
224+ translate . get ( "TEST" ) . subscribe ( ( res : Translation ) => {
225+ expect ( res as string ) . toEqual ( "This is a test" ) ;
226+ expect ( http . expectOne ) . toHaveBeenCalledTimes ( 1 ) ;
227+
228+ // reset the lang as if it was never initiated
229+ translate . resetLang ( "en" ) ;
230+
231+ expect ( translate . instant ( "TEST" ) as string ) . toEqual ( "TEST" ) ;
232+
233+ // use set timeout because no request is really made and we need to trigger zone to resolve the observable
234+ setTimeout ( ( ) => {
235+ translate . get ( "TEST" ) . subscribe ( ( res2 : Translation ) => {
236+ expect ( res2 as string ) . toEqual ( "TEST" ) ; // because the loader is "pristine" as if it was never called
237+ expect ( http . expectOne ) . toHaveBeenCalledTimes ( 1 ) ;
238+ done ( ) ;
239+ } ) ;
240+ } , 10 ) ;
241+ } ) ;
242+
243+ // mock response after the xhr request, otherwise it will be undefined
244+ http . expectOne ( "/assets/i18n/en.json" ) . flush ( { TEST : "This is a test" } ) ;
245+ } ) ;
246+
247+ it ( "should be able to reset a lang from MultiHttpLoader" , ( done : DoneFn ) => {
248+ prepareMulti ( ) ;
128249
129250 translate . use ( "en" ) ;
130251 spyOn ( http , "expectOne" ) . and . callThrough ( ) ;
@@ -152,4 +273,74 @@ describe("TranslateHttpLoader (HttpClient)", () => {
152273 // mock response after the xhr request, otherwise it will be undefined
153274 http . expectOne ( "/assets/i18n/en.json" ) . flush ( { TEST : "This is a test" } ) ;
154275 } ) ;
276+
277+ it ( "should merge translations from multiple resources" , ( ) => {
278+ prepareMulti ( {
279+ resources : [ "/assets/i18n/" , { prefix : "/custom/" , suffix : ".lang.json" } ] ,
280+ } ) ;
281+ translate . use ( "en" ) . subscribe ( ) ;
282+ http . expectOne ( "/assets/i18n/en.json" ) . flush ( { TEST : "A" , ONLY1 : "X" } ) ;
283+ http . expectOne ( "/custom/en.lang.json" ) . flush ( { TEST : "B" , ONLY2 : "Y" } ) ;
284+ // TEST should be overwritten by the second resource
285+ expect ( translate . instant ( "TEST" ) ) . toBe ( "B" ) ;
286+ expect ( translate . instant ( "ONLY1" ) ) . toBe ( "X" ) ;
287+ expect ( translate . instant ( "ONLY2" ) ) . toBe ( "Y" ) ;
288+ } ) ;
289+
290+ it ( "should handle error in one resource and still merge others" , ( ) => {
291+ prepareMulti ( {
292+ resources : [ "/assets/i18n/" , { prefix : "/custom/" , suffix : ".lang.json" } ] ,
293+ } ) ;
294+ translate . use ( "en" ) . subscribe ( ) ;
295+ http . expectOne ( "/assets/i18n/en.json" ) . flush ( { TEST : "A" } ) ;
296+ http . expectOne ( "/custom/en.lang.json" ) . flush ( null , {
297+ status : 500 ,
298+ statusText : "Server Error" ,
299+ } ) ;
300+ expect ( translate . instant ( "TEST" ) ) . toBe ( "A" ) ;
301+ } ) ;
302+
303+ it ( "should log error if showLog is true" , ( ) => {
304+ prepareMulti ( {
305+ resources : [
306+ "/assets/i18n/" ,
307+ { prefix : "/custom/" , suffix : ".lang.json" , showLog : true } ,
308+ ] ,
309+ showLog : true ,
310+ } ) ;
311+ spyOn ( console , "error" ) ;
312+ translate . use ( "en" ) . subscribe ( ) ;
313+ http . expectOne ( "/assets/i18n/en.json" ) . flush ( { TEST : "A" } ) ;
314+ http . expectOne ( "/custom/en.lang.json" ) . flush ( null , {
315+ status : 500 ,
316+ statusText : "Server Error" ,
317+ } ) ;
318+ expect ( console . error ) . toHaveBeenCalled ( ) ;
319+ } ) ;
320+
321+ it ( "should fallback to empty object if all resources fail" , ( ) => {
322+ prepareMulti ( {
323+ resources : [ "/assets/i18n/" , { prefix : "/custom/" , suffix : ".lang.json" } ] ,
324+ } ) ;
325+ translate . use ( "en" ) . subscribe ( ) ;
326+ http . expectOne ( "/assets/i18n/en.json" ) . flush ( null , {
327+ status : 500 ,
328+ statusText : "Server Error" ,
329+ } ) ;
330+ http . expectOne ( "/custom/en.lang.json" ) . flush ( null , {
331+ status : 500 ,
332+ statusText : "Server Error" ,
333+ } ) ;
334+ expect ( translate . instant ( "ANY" ) ) . toBe ( "ANY" ) ;
335+ } ) ;
336+
337+ it ( "should support resource as string and object with suffix" , ( ) => {
338+ prepareMulti ( {
339+ resources : [ "/assets/i18n/" , { prefix : "/custom/" , suffix : ".lang.json" } ] ,
340+ } ) ;
341+ translate . use ( "en" ) . subscribe ( ) ;
342+ http . expectOne ( "/assets/i18n/en.json" ) . flush ( { TEST : "A" } ) ;
343+ http . expectOne ( "/custom/en.lang.json" ) . flush ( { TEST : "B" } ) ;
344+ expect ( translate . instant ( "TEST" ) ) . toBe ( "B" ) ;
345+ } ) ;
155346} ) ;
0 commit comments