Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to know when the translation bundles are loaded #455

Open
jiayihu opened this issue Mar 3, 2017 · 11 comments
Open

How to know when the translation bundles are loaded #455

jiayihu opened this issue Mar 3, 2017 · 11 comments

Comments

@jiayihu
Copy link

jiayihu commented Mar 3, 2017

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

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

Current behavior
I have the necessity to know then the translation bundle is loaded and only then do some extra work.
In my case I need to load other modules translations (not lazy-loaded) and I noticed that when a bundle is loaded it completely overrides existing translations instead of merging like setTranslation does with shouldMerge. (Probably related to this line of code, I'll make a PR if necessary.)
Therefore I need a way to know when the AppModule bundle is loaded with the specified loader. For the time being I resolved subscribing translate.use() and setting a custom AsyncSubject, but I'm not sure it's the correct Observable to subscribe to.
Another way would be maybe creating a custom loader with an AsyncSubject, but wouldn't be very different from the former solution I suppose.

  • ngx-translate version: 6.0.0

  • Angular version: 2.4.x

@fulls1z3
Copy link

fulls1z3 commented Mar 7, 2017

I agree with @jiayihu, determining if the translations are loaded or not could be very useful.

In my case, I'm developing a TranslateLoader for an utility, getting translations using ngx-translate. If there was an injection token (such as TRANSLATIONS_LOADED), I could rather leverate the use of it rather than subscribing to translate.use().

@Arikael
Copy link

Arikael commented Apr 5, 2018

I needed the same functionality.
Why not just check translateService.store.translations if it's empty or not.

@enoh-barbu
Copy link

enoh-barbu commented Oct 17, 2018

no updates on this yet? pretty sad!

@animbalk
Copy link

animbalk commented Feb 1, 2019

I think this is a must fix to use ngx-translate. Client code need to know if things are loaded or not.

@Juliete
Copy link

Juliete commented Feb 5, 2019

I check it in this way.

  ngOnInit() {
    if (this.translateService.store.translations[this.translateService.currentLang]) {
      this.inicializar();
    } else {
      this.suscripcionLangChange = this.translateService.onLangChange.subscribe(() => {
        this.inicializar();
      });
    }
  }

@BeSpunky
Copy link

Just use one of the following observables:

  • onDefaultLangChange
  • onLangChange
  • onTranslationChange

You would probably want to pipe it with a take(1) operator to avoid triggering your code multiple times (and also release memory by having the observable complete after one emission):

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

export class SomeComponentOrService
{
    constructor(private translate: TranslateService)
    {
        this.translate.onDefaultLangChange.pipe(take(1)).subscribe(_ => doWhatYouWant());
    }
}

@mattiLeBlanc
Copy link

mattiLeBlanc commented Apr 27, 2020

I am having trouble detecting when my translations have been loaded.
I am using the instant function but I have to check when the loader is finished.
Subscribing to onLangChange only works once when the page is first loaded, but if I am in another page that languageChange will not emit any more value so that doesnt work either.

I noticed that

constructor(
  private translate: TranslateService,) {
    console.log('-->',JSON.stringify(translate.store.translations[translate.currentLang]));
   console.log(this.translate.instant('ORGANISATION.TABLE'));

is logging as

--> {"HEADINGS":{"ORGANISATION":"Organisation","ORGANISATIONS":"Organisations AU"},"BUTTONS":{"CREATE_ORG":"Create Org"},"FOO":"HELLO","TABLE":{"ORGANISATION":"Organisation"}}
list.component.ts:74 ORGANISATION.TABLE

which means the translation was already available, but still the instant function is not returning the translation.

Why is this?

@BeSpunky
Copy link

BeSpunky commented Apr 27, 2020

Seems like you're translation id is reversed. It should match your data hierarchy.
Try this.translate.instant('TABLE.ORGANISATION').

@mattiLeBlanc
Copy link

Yeah, that was a stupid mistake in my console.log. I did use the correct hierarchy in the actual code.
I am just creating a wrapper service that will check if the store exists, if not it will return an observable based on language changed. If the store does exist it will also return an Observable.
So then I can just subscribe to this combined Observable to execute the instant function.

Shame there is no generic translationsLoaded observable you can subscribe to.

@mattiLeBlanc
Copy link

mattiLeBlanc commented Apr 27, 2020

So I did this:

import { Injectable, OnDestroy } from '@angular/core';
import { Observable, of } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class I18NService  {

  constructor(
    private translate: TranslateService
  ) {}

  translationsLoaded(): Observable<boolean> {

    if (this.translate.store.translations[this.translate.currentLang]) {
      return of(true);
    } else {
      return this.translate.onLangChange
        .pipe(
          map(res => !!res)
        );
    }
  }
}

and then in my controller I can do

    this.i18NService.translationsLoaded().subscribe(res => {
      // just update some labels that will go into the headers of a dynamic table 
      this.columns.map(col => {
        if (col.label) {
          col.label = this.translate.instant(col.label);
        }
        return col;
      })
    });

@BeSpunky
Copy link

BeSpunky commented Apr 27, 2020

A simple solution would be to expose a promise in your service and extract its resolve() function:

class YourLangService
{
    public isReady: Promise<string>;

    private resolveIsReady: (locale: string) => void;

    constructor(...)
    {
        this.isReady = new Promise<string>(resolve => this.resolveIsReady = resolve);
    }
}

Then subscribe to onLangChange() or find any other convenient place to resolve the promise.

Now you could simply inject your service and query the promise:

class SomeComponent
{
    constructor(private lang: YourLangService)
    {
        this.lang.isReady.then(...);
    }
}

You could replace the promise with a BehaviorSubject, but I find the promise easier to work with than an observable in this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants