Ionic3 / Ngx-translate - TranslateHttpLoader with external URL

Viewed 6297

I'm loading the translation files from the server using TranslateHttpLoader in my app.module.ts like this:

export function createTranslateLoader(http: Http) {
   return new TranslateHttpLoader(http, AppConfig.API_URL+'/static/i18n/', '.json');
}

@NgModule({
  ...

  imports: [

    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: (createTranslateLoader),
        deps: [Http]
      }
    }), 

  ],
  ...
})

Everything works fine, but i'm wondering if there is a way to catch event when the loader fails to retrieve the language file for whatever reason (server issues, net con etc.) and possibly load a local json file with some default translation strings?

I want to catch this event if the app on the first load fails to grab the language file , and fallback to minimal local json file to just display translated mainetnance page/error page or something.

3 Answers

UPDATE for Angular >= 4.3

As new Angular versions use HttpClient instead of Http, an updated and much shorter version of mike_t's CustomTranslateLoader would be:

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { TranslateLoader } from '@ngx-translate/core';
import { Observable } from 'rxjs/Observable';
import { catchError } from 'rxjs/operators';
import { AppConfig } from './config';


@Injectable()
export class CustomTranslateLoader implements TranslateLoader  {
    contentHeader = new HttpHeaders({
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*',
    });

    constructor(private httpClient: HttpClient) {}
    getTranslation(lang: string): Observable<any> {
        const apiAddress = AppConfig.API_URL + `/static/i18n/${lang}.json`;
        return this.httpClient.get(apiAddress, { headers: this.contentHeader })
          .pipe(
            catchError(_ => this.httpClient.get(`/assets/i18n/en.json`))
          );
    }
}


UPDATE for Angular 12+

  1. Create a new custom translate loader
// loader/customTranslate.loader.ts
import { TranslateLoader } from '@ngx-translate/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';

const LOCAL_URL = 'http://your.url.blanik.me/api';

export class CustomTranslateLoader implements TranslateLoader {
  constructor(private httpClient: HttpClient) {}

  getTranslation(lang: string): Observable<any> {
    const url = `${LOCAL_URL}/assets/i18n/${lang}.json`;

    return this.httpClient.get(url).pipe(catchError((_) => this.httpClient.get(`/assets/i18n/en.json`)));
  }
}
  1. Update angular app module
// app.module.ts
// {...}
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { HttpClient } from '@angular/common/http';
import { CustomTranslateLoader } from './loader/customTranslate.loader';

@NgModule({
  declarations: [AppComponent, OtherComponent],
  imports: [
    BrowserModule,
    // ...
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useClass: CustomTranslateLoader,
        deps: [HttpClient],
      },
    }),
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}
  1. Add language switch to your component
<select class="form-control" #langauge (change)="translateSite(langauge.value)">
  <option *ngFor="let localization of translateService.getLangs()" [value]="localization"
          [selected]="localization === translateService.currentLang">
    {{ localization }}
  </option>
</select>
import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent{
  title = 'your-app-name';

  constructor(public translateService: TranslateService) {
    translateService.addLangs(['en', 'fr', 'pl']);
    translateService.setDefaultLang('en');
  }

  translateSite(langauge: string) {
    this.translateService.use(langauge);
  }
}

Please remember to set proper CORS on your server and/or (recommended) keep your translation file under the same domain.

Do not add custom CORS headers in httpClient. Otherwise, the browser will prevent reading the file.

Cheers!

Related