Skip to content
This repository has been archived by the owner on Nov 8, 2021. It is now read-only.

Multiple HTTP requests #68

Open
SoapyMan opened this issue Sep 20, 2019 · 6 comments
Open

Multiple HTTP requests #68

SoapyMan opened this issue Sep 20, 2019 · 6 comments

Comments

@SoapyMan
Copy link

SoapyMan commented Sep 20, 2019

Current behavior

Currently TranslateHttpLoader produces HTTP request every time getTranslation is called.

Expected behavior

TranslateHttpLoader should store state of language file loading and only one HTTP request is made.

How do you think that we should fix this?

This is how I implemented this (proof of concept, it performs only ONE request, everything works and tokens are translated):

	private errorState = false;
	private waiter = new Subject<Object>();
	private requestedLang: string;

    getTranslation(lang: string): Observable<Object>
	{
		if(this.errorState)
			return of({});

		if(this.requestedLang != null && this.requestedLang == lang)
			return this.waiter.asObservable();

		let languagPath = `assets/locale/${lang}.json`;

		this.requestedLang = lang;

		this.http.get(languagPath).pipe(
				catchError(error => {
					console.warn("can't load language file", languagPath, error);
					this.errorState = true;
					return of({});
				})
			).subscribe(result => {
				//console.log("translation", lang,"loaded!");
				this.waiter.next(result);
			});

		return this.waiter.asObservable();
	}

Minimal reproduction of the problem with instructions

Even standard ngx-translate template calls getTranslation at least two times.
My app got approximately 140 (app with multiple pages and modules) and lots of annoying alerts were displayed in case when translations were not found. If success, other requests fetched (304), but fetch still has delay.

Environment


ngx-translate version: 11.0.1
Angular version: 7.1.4

Browser:
- [x] Chrome (desktop) version XX

 
For Tooling issues:
- Node version: 10.15
- Platform:  Windows

@emeryowa
Copy link

I'm experiencing the same issue.
The json file with i18n translations is requested multiple times. It seems to be requested in an infinite loop
It only occurs with non default language files (= languages that have not been set with setDefaultLang())

See https://cl.ly/f5b0f57313a8

@SoapyMan
Copy link
Author

SoapyMan commented Oct 1, 2019

@emeryowa this is indeed not well behaviour. In fact now i'm not using http-loader due to this issue. This TranslateHttpLoader implementation itself is too trivial to be added as package to your project IMO. Instead, it's better to implement your own TranslateLoader with the getTranslation function i've posted in the issue.

@emeryowa
Copy link

@SoapyMan I have implemented a custom loader, identical to the function you posted. I am getting the same error though = the call to the translations file is requested multiple times. Do you have any tips?

@bjesuiter
Copy link

bjesuiter commented Dec 9, 2019

@emeryowa @SoapyMan

I've encountered the same error. Fortunately, the error message with your loader @SoapyMan is much better than the one in the ngx-translate loader.

My Error shows:

     my-translate-loader.ts:31 can't load language file assets/i18n/en.json TypeError: Cannot read property 'length' of undefined
    at HttpHeaders.push../node_modules/@angular/common/fesm5/http.js.HttpHeaders.applyUpdate (http.js:244)
    at http.js:215
    at Array.forEach (<anonymous>)
    at HttpHeaders.push../node_modules/@angular/common/fesm5/http.js.HttpHeaders.init (http.js:215)
    at HttpHeaders.push../node_modules/@angular/common/fesm5/http.js.HttpHeaders.forEach (http.js:280)
    at Observable._subscribe (http.js:1596)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable._trySubscribe (Observable.js:43)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe (Observable.js:29)
    at subscribeToResult (subscribeToResult.js:13)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._innerSub (mergeMap.js:74)

@larsvliet
Copy link

larsvliet commented Apr 8, 2020

I created the following loader which does simple caching:

import {HttpClient} from "@angular/common/http";
import {TranslateLoader} from "@ngx-translate/core";
import {Observable} from "rxjs";
import {shareReplay} from "rxjs/operators";

export class CachedHttpTranslationLoader implements TranslateLoader {
  
    cache$: Observable<Object> = null;
    cachedLang: string = null;
    
    constructor(private http: HttpClient, public prefix: string = "/assets/i18n/", public suffix: string = ".json") {}
  
    /**
     * Gets the translations from the server
     */
    public getTranslation(lang: string): Observable<Object> {
      if (!this.cache$ || this.cachedLang !== lang) {
        this.cache$ = this.http.get(`${this.prefix}${lang}${this.suffix}`).pipe(shareReplay(1));
        this.cachedLang = lang;
      }
      return this.cache$;
    }
  }

@mwmw7
Copy link

mwmw7 commented Sep 6, 2021

@larsvliet thank you
It works very well

 TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useClass: CachedHttpTranslationLoader,
        deps: [HttpClient]
      },
      defaultLanguage: 'ko' 
    }),

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants