ngx-translate .instant returns key instead of value

80.3k Views Asked by At

I am trying to make a method which would accept string key and return translated string value by using translate.instant(parameter). The problem is that it returns key(parameter). Usually this is returned if it doesn't find translation. I think the problem is that method gets called before loader loads translations.

My app.module.ts imports:

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

createTranslateLoader function:

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

In my app.component:

constructor(public translate: TranslateService){
   translate.setDefaultLang('en');
   translate.use('en');
}

When I translate in html using pipes it works ok.

6

There are 6 best solutions below

5
On BEST ANSWER

You are using the TranslateHttpLoader which makes an HTTP request when it's asked for translations - translate.use('en'). If you call the instant(messageKey) method before the HTTP call returns, ngx-translate will return the key, since it has no translations yet. So you should use the get(messageKey) method to get the translation - it's asynchronous and returns an Observable:

this.translateService.get('hello.world').subscribe((translated: string) => {
    console.log(res);
    //=> 'Hello world'

    // You can call instant() here
    const translation = this.translateService.instant('something.else');
    //=> 'Something else'
});

You can use the instant method only when you are sure that the translations have been already loaded (as in the code example) or you can write your custom synchronous translation loader and use instant anywhere.

4
On

You can also make a dummy call, and await for the response. After the response, every instant call will work because its sure than the translations are loaded.

async ngOnInit() {
  await this.translate.get('dummyTranslation').toPromise().then();
  this.translate.instant("realTranslation");
1
On

Just a reminder: Remember to clear the localStorage. It was my mistake.

4
On

You can use TranslateService only when translation file is loaded. If you want to use safely TranslateService.instant you can write an angular resolver or a guard. Resolver and guard wait to exec your component code until the observable return a value.

This is the code:

-------------------------GUARD------------------------------------



@Injectable()
export class TranslationLoaderGuard {

    constructor(private translate: TranslateService, private languageService: SetLanguageService) {
    }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
        this.languageService.inizializeLanguage()

        return new Observable((observer) => {
            this.translate.get("last.dummy").subscribe({
                next: () => {
                    observer.next(true);
                },
                error: error => {
                    observer.next(false);
                    observer.error(error);
                },
                complete: () => {
                    observer.complete();
                },
            })
        })
    }

    canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
        this.languageService.inizializeLanguage()

        return new Observable((observer) => {
            this.translate.get("last.dummy").subscribe({
                next: () => {
                    observer.next(true);
                },
                error: error => {
                    observer.next(false);
                    observer.error(error);
                },
                complete: () => {
                    observer.complete();
                },
            })
        })
    }

}

---------------------ROUTING MODULE------------------

let routing = RouterModule.forChild([
    {path: "dashboard", component: DashboardComponent, canActivate: [TranslationLoaderGuard],,
     children: [
        ........//here you can omit Guard
        },
}

-----Files i18n-----

In last line of each i18n translation file add the following line 
as is (do not translate this) ----> "last.dummy"="dummy translation"

SetLanguageService is a service that you can create to store the language used, for example in session storage (for example lang is 'it', 'en').

I hope this can help

0
On

You can also do :

await firstValueFrom(this.translate.get('key')).then(t => this.text = t);

or :

await firstValueFrom(this.translate.get('_'));
this.text = this.translate.instant('key');
1
On

Just wrap your $translate.instant with the onReady like so:

$translate.onReady(function () { //Code here })