Core: Using TranslateService in a provider is not working

Created on 9 Mar 2017  Â·  24Comments  Â·  Source: ngx-translate/core

I'm submitting a ... (check one with "x")

[x] bug report => check the FAQ and search github for a similar issue or PR before submitting
[ ] support request => check the FAQ and search github for a similar issue before submitting
[ ] feature request

Current behavior
Does not find the TranslateService...

Reproduction of the problem

Add a provider, import TranslateService and add it to the constructor... says "The name "TranslateService" cannot be found."

What is the expected behavior?

Please tell us about your environment:

cordova CLI: 6.5.0
Ionic Framework Version: 2.1.0-201703061537
Ionic CLI Version: 2.2.1
Ionic App Lib Version: 2.2.0
Ionic App Scripts Version: 1.1.3
ios-deploy version: Not installed
ios-sim version: Not installed
OS: Windows 10
Node Version: v6.10.0
Xcode version: Not installed

Most helpful comment

Calling getTranslation before get resolves the issue.

All 24 comments

Hello,

can you add more context please, like some code?

Make sure to import TranslateModule in the module where you define the provider.

The provider is located in src/provider/http-service.ts

This is the code simplified:

import { TranslateService } from '@ngx-translate/core'; 

@Injectable()
export class HttpService {
  constructor(public translate: TranslateService) {
  }
}

Visual Studio underlines TranslateService in the constructor and says that it could not find the name...

This is my app.module.ts:

import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { Http } from '@angular/http';
import { MyApp } from './app.component';
import { LoginPage } from '../pages/login-page/login-page';
import { Page1 } from '../pages/page1/page1';
import { Page2 } from '../pages/page2/page2';

import { HttpService } from '../providers/http-service';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';


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

@NgModule({
  declarations: [
    MyApp,
    LoginPage,
    Page1,
    Page2
  ],
  imports: [
      IonicModule.forRoot(MyApp),
      TranslateModule.forRoot({
          loader: {
              provide: TranslateLoader,
              useFactory: (createTranslateLoader),
              deps: [Http]
          }
      })
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    LoginPage,
    Page1,
    Page2
  ],
  providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}, HttpService]
})
export class AppModule {}

Seems like a Visual Studio issue rather then a ngx-translate issue. Can you compile the project? Have you tried turning it off and on again?

Thanks was Visual Studio... still got a problem.

Can you get the translation data. save it and then use it later? Because this way I just get the name of the values and not the values itself :/

private translationLet: any;

this.translate.get(['LOGIN','LOADING','DOWNLOADED','NOCONNECTION']).subscribe((translation: [string]) => {
        this.translationLet = translation;
    });

Make sure to use service.use ('nl'); somewhere at the start of you application. Then you will get the correct values.

Doing it in the app.component.ts, also added a fallback which works fine in the rest of the app

When I add this.translation.use('en') before this.translation.get() an error occurs... it does not seem to find the translation json :/

import { TranslateService } from '@ngx-translate/core'; 

@Injectable()
export class HttpService {
  private translationLet: any;
  constructor(public translate: TranslateService) {
     this.translate.use('en'); //getting error when using, without it texts are just LOGIN, LOADING etc.
     this.translate.get(['LOGIN','LOADING','DOWNLOADED','NOCONNECTION']).subscribe((translation: [string]) => {
        this.translationLet = translation;
    });
  }
}

Open developer tools and look in the network tab. Can you see it request the en.json file successfully? If not, make sure the json files are being copied over to the dist folder where the application is being served.

Yes it does... it works well on all Pages but not in the service :/

One thing that might be the reason why you think it's not working is because the result is not an array but an object with key-value pairs.

Try the following things, what does this output?

this.translate.get('LOGIN').subscribe(result => {
    console.log(result);
});

this.translate.get(['LOGIN','LOADING']).subscribe(result => {
    console.log(JSON.stringify(result));
});

console.log(this.translate.instant('LOGIN'));

First one:
LOGIN
Second one:
{"LOGIN":"LOGIN", "LOADING":"LOADING"}
Third one:
LOGIN

Same code run in a component for example page1.ts instead of the provider http-service.ts works fine :/

That's really weird. I have no clue why that's not working. If you're able to setup a basic ionic application with ngx-translate which shows this behaviour and publish it to GitHub, we can have a closer look. I don't see any reason why this shouldn't work.

OK did that and there it worked... now I went back to my main project changed nothing and it works. Very odd....

I got exactly same issue, how did you solve it ?

I solved it by removing node_modules and npm install everything again, was using cnpm, and it was broken. Should use npm.

I Have the same issue.

Calling getTranslation before get resolves the issue.

@samanmohamadi Where do you call it?

@AlexanderKozhevin Sorry, I don't remember it. Recently I moved the whole project to React.

@AlexanderKozhevin

This works for me, I have called getTranslation before calling get method:

  translated: Array<{display: string, target: any}> = [];

    var tmp = this.translate.getTranslation('fa');

    var keys= ['AppTitle','Home.Register','AboutUs.Title'];
    this.translate.get(keys).subscribe(
      value => {
        var values = _.values(value);
        for(var key in keys){
          this.translated.push({display:values[key],target:keys[key]});
        }
      });

Note that I'm using lodash plugin to work with arrays

Calling getTranslation(lang) in the provider before usingthis.translate.get(key)does indeed work.
However, if you want to use the browser's language instead of a fixed string, you would need to have it available in a static context. Unfortunately, this is currently not a feature of ngx-translate (see open ticket here https://github.com/ngx-translate/core/pull/822)

What I did to work around this for now was to copy the non-static function from the ngx-translate source code of how to get the browser's language, and make the following two static functions and a static field in UtilProvider.ts

UtilsProvider.ts

     /** 
     * Language
     */

    public static defaultLang: string = "de";

    //The language to use throughout the app
    public static getLang() {
        let browserLang = UtilsProvider.getBrowserLang();
        if (browserLang) {
            return browserLang;
        } else {
            return UtilsProvider.defaultLang;
        }
    }

    //Helper to get the language of the browser in a static context.
    public static getBrowserLang() {
        if (typeof window === 'undefined' || typeof window.navigator === 'undefined') {
            return undefined;
        }
        var browserLang = window.navigator.languages ? window.navigator.languages[0] : null;
        browserLang = browserLang || window.navigator.language || (<any>window.navigator).browserLanguage || (<any>window.navigator).userLanguage;
        if (browserLang.indexOf('-') !== -1) {
            browserLang = browserLang.split('-')[0];
        }
        if (browserLang.indexOf('_') !== -1) {
            browserLang = browserLang.split('_')[0];
        }
        return browserLang;
    }

Then in the provider that needs to do a translation based on browser's actual language:
OtherProvider.ts

private initTranslate() {

        //Since this is loaded before app.initTranslate() is executed,
        //we have to call getTranslation here using a statically available value for the language
        let lang = UtilsProvider.getLang();
        this.translate.getTranslation(lang);

        this.translate.get("MONTH_NAMES")
            .subscribe(values => {
                this.translatedMonthNames = values;
            });
    }

for me what worked eventually was wrapping the use(lang) call inside a try catch block, as it does change the language even if it throws an exception, and you get the get method inside the finally block.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rbaumi picture rbaumi  Â·  4Comments

briancullinan picture briancullinan  Â·  3Comments

ryanki1 picture ryanki1  Â·  4Comments

guysan picture guysan  Â·  4Comments

crebuh picture crebuh  Â·  3Comments