Ngx translate is broken when used with ionic lazy loading

ngx translate is broken when used with ionic 3 layzy loading and is not being fixed at all.
What next??

Update: The issue has been solved (I think it should be considered as a WORKAROUND). Please see reedrichards’ solution below. If you follow the official Ionic Doc in this case , you will not be able to make it work

Here is the repo for showing the issue.

I’ve opened a issue on the official ngx translate github page as well.

1 Like

Like I told your there Ngx-translate and Ionic 3? I think it’s still working pretty fine

Could you display a bit of code so we could try to figure out what doesn’t work for you?

Hi Reedrichards,
First of all, thank you very much for helping.
I have a simple app. On the homepage, user can click to change languages. Everything works fine before lazy loading.
After using lazy loading, language files are not loaded when clicking to switch language. Just an empty object:

{lang: "es", translations: {}}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';

import {HttpClientModule, HttpClient} from '@angular/common/http';
import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';

import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';

import { MyApp } from './app.component';

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

@NgModule({
  declarations: [
    MyApp
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    IonicModule.forRoot(MyApp),
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: (createTranslateLoader),
        deps: [HttpClient]
      }
    })
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})

export class AppModule {}

app.component.ts

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { TranslateService, LangChangeEvent} from '@ngx-translate/core';

@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage:any = 'HomePage';

  constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen, translate: TranslateService) {
    translate.setDefaultLang('en');
    translate.onLangChange.subscribe((event: LangChangeEvent) => {
      console.log("lang changed detected", event);
      translate.setDefaultLang(event.lang);
  });
    platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      statusBar.styleDefault();
      splashScreen.hide();
    });
  }
}

home.module.ts

import { TranslateModule} from '@ngx-translate/core'; //For lazy loading
import { HomePage } from './home';

@NgModule({
  declarations: [
    HomePage,
  ],
  imports: [
    IonicPageModule.forChild(HomePage),
    TranslateModule.forChild() //For lazy loading
  ],
  exports: [
    HomePage
  ]
})
export class HomePageModule {}

home.component.ts

import { Component } from '@angular/core';
import { IonicPage, NavController, ModalController } from 'ionic-angular';
import { LangChangeEvent, TranslateService } from '@ngx-translate/core';
import { PopoverController } from 'ionic-angular';

@IonicPage()
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
      
  constructor(public popoverCtrl: PopoverController, public navCtrl: NavController, public modalCtrl: ModalController, public translateService: TranslateService) {
      
  }


  translateToSpanish() {
      this.translateService.use("es");
  }

  goToPage(page) {
    this.navCtrl.push(page);
  }
}

home.html

      <ion-col col-sm-3 col-md-1>
        <div>
          <div>
            <p><b>{{ 'languageLinkText' | translate }}</b></p>
          </div>
          <ul style="list-style-type:none; padding-left: 0pt;">
            <li style="margin-bottom:5px;"><a style="text-decoration: none;" href="#" (click)="translateToEnglish()">{{ 'englishLinkText' | translate }}</a></li>
            <li style="margin-bottom:5px;"><a style="text-decoration: none;" href="#" (click)="translateToDutch()">{{ 'dutchLinkText' | translate }}</a></li>
            <li style="margin-bottom:5px;"><a style="text-decoration: none;" href="#" (click)="translateToSpanish()">{{ 'spanishLinkText' | translate }}</a></li>
            <li style="margin-bottom:5px;"><a style="text-decoration: none;" href="#" (click)="translateToCNS()">{{ 'chsLinkText' | translate }}</a></li>
              <li style="margin-bottom:5px;"><a style="text-decoration: none;" href="#" (click)="translateToCNT()">{{ 'chtLinkText' | translate }}</a></li>
              <li style="margin-bottom:5px;"><a style="text-decoration: none;" href="#" (click)="translateToRussian()">{{ 'russianLinkText' | translate }}</a></li>
          </ul>
        </div>
      </ion-col>

Which @ngx-translate/core and @ngx-translate/http-loader versions are you using?

I use @ngx-translate/core 8.0.0 and @ngx-translate/http-loader 2.0.0

Is the following piece of codes really needed?

translate.onLangChange.subscribe((event: LangChangeEvent) => {
  console.log("lang changed detected", event);
  translate.setDefaultLang(event.lang); // <----- Why resetting the default on language change?
 });

Btw. is onLangChange triggered when you user another languages?

Otherwise your code looks good to me, only difference with my app is that I don’t have parenthesis around the loader but that can’t be the problem

 useFactory: (createTranslateLoader)

I’ve got

useFactory: createTranslateLoader

Is your app open source? could I clone it to give a try?

I use these versions:
"@ngx-translate/core": “^8.0.0”,
"@ngx-translate/http-loader": “^2.0.0”,

this is only for debugging purpose. onLangChange does get triggered
console.log(“lang changed detected”, event);

output an empty translation{}.

just to try, could you then remove this “debug piece of code” and could you also set a “default use” in app.component.ts?

in app.component.ts:

translate.setDefaultLang('en');
translate.use('en');

really not sure gonna help, but who knows

also like I said, if you agree, I could clone your repository to try…

I found something interesting:

Only the page that is changing the language needs to have the second loader in it:
(TranslateModule.forChild({…}). All other pages just need TranslateModule.forChild()

I think that your problem is the following: in the pages where the user could change the language, you need to define again your loader

To do so, in home.module.ts add

export function createTranslateLoader(http: HttpClient) {
   return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
...
TranslateModule.forChild({
    loader: {
      provide: TranslateLoader,
      useFactory: createTranslateLoader,
      deps: [HttpClient]
    }
  }

or, as @ccdex_chris said in his post, you could also import your loader from your app.module.ts, like

import {createTranslateLoader} from "../../app/app.module";
....
TranslateModule.forChild({
    loader: {
      provide: TranslateLoader,
      useFactory: createTranslateLoader,
      deps: [HttpClient]
    }
  }
5 Likes

Hi reedrichards,
Tried that. Also didn’t work.
I will create a new repo for you. Not sure if I can make it today, otherwise, tomorrow.
thanks again. So happy that I chose ionic cuz~ we’ve got awesome people like you in the community. I am still a noob in mobile development using ionic/angular. Any help is much appreciated.

I have the exact issue as describe in that thread but the second loader solution didn’t work in my case.

Freak I was hoping I would have find something interesting, crap

I’m quite busy begin of next weeks, but as of tuesday night I will have time to check your repo if you didn’t find a solution till then :wink:

And no worries, we are all noobs

1 Like

Hi reedrichards,
Sorry for my late reply.
I just created the repo.

git clone
npm install
ionic serve

When clicking to switch to Dutch lang, Open chrome debug console you will see that an empty translation object is loaded.

@lolaswift1 thx for the repo. The solution is the one mentioned above, respectively adding a loader to forChild in every pages where you want the user to be able to change the language

here your correct home.module.ts:

import {HttpClient} from '@angular/common/http';
import {NgModule} from '@angular/core';
import {IonicPageModule} from 'ionic-angular';

import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {createTranslateLoader} from '../../app/app.module';

import {HomePage} from './home';

@NgModule({
    declarations: [
        HomePage,
    ],
    imports: [
        IonicPageModule.forChild(HomePage),
        TranslateModule.forChild({
            loader: {
                provide: TranslateLoader,
                useFactory: createTranslateLoader,
                deps: [HttpClient]
            }
        })
    ],
})
export class TestPageModule {
}

I didn’t committed this in your repo, if you want me to do so, let me know

P.S.: Screenshot, it works

5 Likes

Thanks reedrichards for your lightening fast reply.
I tried your solution and it’s working.
Does it mean I have to do the same to all my other pages if I have many?
Is this a workaround or a solution?
btw, I tried the solution in my original project and it messed up the translation completely. Only the Keys show, not the translation. I still need to find out why that was.

You need to do it in every pages where the users is able to change the language. That being said, I didn’t try, but if you’ve got like a central page/component/observable/provider which take care of switching the language, you might need to do this tricks only there. But like I said, only a wild guess, it would need to be tested.

Don’t know if it’s a solution or workaround. Since ngx-translate is quite stable, I would need solution, but you would have probably to go thru the list of issue of this project to confirm it or not.

If it doesn’t work in your original project, you should probably try to go piece after piece, because this demo proof that it’s possible

Good luck!

so glad it’s working on this small simple project.
I will debug my original project.
Just can’t thank you enough for your help.

No worries, my pleasure, was interesting to test :wink:

reedrichards wrote: “You need to do it in every pages where the users is able to change the language. That being said, I didn’t try, but if you’ve got like a central page/component/observable/provider which take care of switching the language, you might need to do this tricks only there. But like I said, only a wild guess, it would need to be tested.”

I’ve confirmed that this is correct. Pages that set or change the default language require this additional code. e.g.

import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { SettingsPage } from './settings';

// Required to change translation language.
import { HttpClient } from '@angular/common/http';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { createTranslateLoader } from '../../app/app.module';

@NgModule({
    declarations: [
        SettingsPage,
    ],
    imports: [
        IonicPageModule.forChild(SettingsPage),
        // Required to change translation language.
        TranslateModule.forChild({
            loader: {
                provide: TranslateLoader,
                useFactory: createTranslateLoader,
                deps: [HttpClient]
            }
        })
    ],
})
export class SettingsPageModule { }

Pages that translate text need this code only e,g,

import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { AboutPage } from './about';
import { TranslateModule } from '@ngx-translate/core'; // Required for translation.

@NgModule({
  declarations: [
    AboutPage,
  ],
  imports: [
      IonicPageModule.forChild(AboutPage),
      TranslateModule.forChild() // Required for translation.
  ],
})
export class AboutPageModule {}