ngx-translate / core

The internationalization (i18n) library for Angular
MIT License
4.51k stars 575 forks source link

Translations are not working after adding http interceptor in ionic/angular #1239

Closed rajeshwarpatlolla closed 4 years ago

rajeshwarpatlolla commented 4 years ago

Current behavior

The translations are working fine in local machine. But when i generate the apk using ionic and install it in device it's not working. It is throwing an error.

Expected behavior

It should also work fine without any error in mobile app as well

How do you think that we should fix this?

I am not very sure about the way to fix it.

Minimal reproduction of the problem with instructions

I added the code below. Please correct me if something is missing

// THIS IS THE CODE I AM USING FOR HTTP INTERCEPTOR

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpRequest, HttpResponse, HttpHandler, HttpErrorResponse, HTTP_INTERCEPTORS, HttpHeaders } from '@angular/common/http';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { Storage } from '@ionic/storage';

import consts from './consts';

@Injectable()
export class ApiHttpInterceptor implements HttpInterceptor {
  constructor(private router: Router, public http: HttpClient, public storage: Storage) { }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const token = this.storage.get('token');
    const refreshToken = this.storage.get('refresh-token');

    request = request.clone({
      setHeaders: {
        Authorization: 'Bearer ' + token,
        // 'Content-Type': 'application/json',
        // Accept: 'application/json',
      },
      url: request.url.indexOf('http') >= 0 ? request.url : consts.API_URL + request.url,
    });

    return next.handle(request).pipe(
      map((event: HttpEvent<any>) => {
        return event;
      }),
      catchError((error: HttpErrorResponse) => {
        console.log('HttpErrorResponse', error);
        if (error.status === 401) {
          this.storage.clear();
          this.router.navigate(['/login']);
        }
        return throwError(error);
      }),
    );
  }
}

// THIS IS THE CODE I AM USING FOR TRANSLATIONS LOADER

export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

// THIS IS THE CODE I AM USING IN MY app.module.ts

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    BrowserModule,
    IonicModule.forRoot(),
    AppRoutingModule,
    HttpClientModule,
    TranslateModule.forRoot({
      defaultLanguage: 'en',
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      }
    }),
    IonicStorageModule.forRoot({ name: 'da-merchant', driverOrder: ['indexeddb', 'sqlite', 'websql'] }),
    ComponentsModule
  ],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
    Events,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: ApiHttpInterceptor,
      multi: true,
    },
  ],
  bootstrap: [AppComponent]
})

Environment

    "@angular/common": "~9.1.6",
    "@angular/core": "~9.1.6",
    "@angular/forms": "~9.1.6",
    "@angular/platform-browser": "~9.1.6",
    "@angular/platform-browser-dynamic": "~9.1.6",
    "@angular/router": "~9.1.6",
    "@capacitor/android": "^2.4.0",
    "@capacitor/core": "2.4.0",
    "@capacitor/ios": "^2.4.0",
    "@ionic-native/core": "^5.0.7",
    "@ionic-native/splash-screen": "^5.0.0",
    "@ionic-native/status-bar": "^5.0.0",
    "@ionic/angular": "^5.0.0",
    "@ionic/storage": "^2.3.0",
    "@mdi/font": "^5.5.55",
    "@ngx-translate/core": "^13.0.0",
    "@ngx-translate/http-loader": "^6.0.0",
    "rxjs": "~6.5.1",
    "tslib": "^1.10.0",
    "zone.js": "~0.10.2"

Yes

Browser:

For Tooling issues:

Others: The issue here is only when i run the ionic app in device after installing the apk. As i mentioned, in local env it's working fine.

Screenshot 2020-08-17 at 3 24 57 PM
rajeshwarpatlolla commented 4 years ago

I found the solution.

export function HttpLoaderFactory(http: HttpClient) {
  const path = window.location.origin + '/assets/i18n/';
  return new TranslateHttpLoader(http, path, '.json');
}

The issue was with the path/url. In local env it hits https://localhost:8100/ but in real device it is hitting https://localhost/ only. There is no port number.

I am answering it myself as it might help someone who has similar issue.

For more details on the code, please check this stack overflow link for the answer

freed00m commented 3 years ago

I am still seeing problems, I am using bare Angular 11 AOT with Ivy + a simple interceptor makes the translation not work. They are being GETed successfully but no translation is used.

import {
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
} from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Observable } from 'rxjs'
import { tap } from 'rxjs/operators'

@Injectable()
export class ServerErrorInterceptor implements HttpInterceptor {
  intercept(
    request: HttpRequest<any>,
    next: HttpHandler,
  ): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(tap(console.log))
  }
}

Even using the HttpLoaderFactory suggested ain't working

export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, 'assets/i18n/', '.json')
}

EDIT: disregard, It works but I have sporadic issues most likely related to something else. 50:50 chance the translation file is loaded but no translations happen

neikxd commented 3 years ago

Here is my solution:

https://github.com/ngx-translate/core/issues/1050#issuecomment-952389069

freed00m commented 3 years ago

@neikxd An idea for you, if you use fetch Api instead of the angular http client to get the i18n json files, then it would not get intercepted.

Would save you the if !request.url.includes('/assets/i18n/') statement check on every other requests

jhunger commented 1 year ago

Just in case someone stumbles on this issue this is how I implemented a TranslateLoader using the fetch api.

@Injectable()
export class TranslationLoaderService implements TranslateLoader {
    getTranslation(lang: string): Observable<any> {
      return from(fetch("./assets/i18n/${lang}.json").then(resp => resp.json()));
    }
}

@NgModule({
  declarations: [
    HomeComponent
  ],
  imports: [
    CommonModule,
    TranslateModule.forChild({
      loader: {
            provide: TranslateLoader,
            useClass: (TranslationLoaderService)
        },
        defaultLanguage: "en",
        useDefaultLang: true
    })
  ],
  providers: [
    TranslateStore
  ]
})
export class HomeModule {

}