0

This is a question about using the angular-l10n translation module, but since it's a more typescript specific question i post it here.

To dynamically configure the module (and for example set the default language), i have to use the following method:

load(): Function {
  this.localeConfig.language = 'en';
  return () => this.l10nLoader.load();
}

localeConfig and l10nLoader are both injected.

return () => this.l10nLoader.load(); has to be executed at the end to actually show the page after configuration.

What i would like to do is to load the language from an api and then set the configuration.

I do this in a service which returns an Observable and then subscribe to it inside of the load() function.

load(): Function {
  this.languageService.getDefaultLanguage().subscribe(
    lang => {
      this.localeConfig.language = lang;
      return ???
    }
  );
}

The problem is: I don't know how to return this.l10nLoader.load(); at the end of the subscription. If i return it at the end of the function it is done before the subscription ends.

How do i return something of type Function after the subscription is finished?

3
  • Why don't you call this.l10nLoader.load() in there rather than returning the same wrapped in an arrow function? Any value in returning it? Commented Mar 8, 2018 at 15:55
  • Anything wrong in just doing : load(): Function { this.localeConfig.language = 'en'; this.l10nLoader.load(); } without the return statement? I'm trying to understand the requirement for a higher order function here. Commented Mar 8, 2018 at 16:00
  • @sabithpocker I guess the easiest way to explain is if i link to the documentation: robisim74.github.io/angular-l10n/spec/configuration . It's under "Dynamic settings" the 2nd part "use the advanced initialization". Commented Mar 8, 2018 at 16:06

3 Answers 3

1

You cannot do this with return, because the load() function is asynchronous. What I suggest to do, is change load() return value to Observable<Function> and create new Observable inside it.

Here is the code snippet:

load(): Observable<Function> {
   return new Observable(observer => {
       this.languageService.getDefaultLanguage().subscribe(
          lang => {
             this.localeConfig.language = lang;
             observer.next(this.l10nLoader.load);
             observer.complete();
          }
       );
   });
}

After that you can call this function in the following way:

load().subscribe(fn => fn());
Sign up to request clarification or add additional context in comments.

3 Comments

This seems correct but this.l10nLoader.load() is still executed before the configuration is set... which is weird, as i don't see how this could happen. I changed observer.next(() => this.l10nLoader.load()); otherwise it would return Promise<void> and not Function. Could this have anything to do with it?
Actually i see what the problem is. load().subscribe(fn => fn()); runs async and i have to wait for everything to complete. Otherwise the page is loaded before the configuration is done.
If you need to load and set locales first before everything else loads, you should look into resolvers. Look into my answer here: stackoverflow.com/questions/47170450/…
0

In Vanilla JS, you use callbacks for that.

For instance, you could do this :

load(cb: Function): Function {
  this.languageService.getDefaultLanguage().subscribe(lang => {
    this.localeConfig.language = lang;
    cb(lang);
  });
}

Now, you can call your function like this :

this.myL10nService.load(lang => {
  console.log('selected language is ' + lang);
});

6 Comments

Strikes me as pointless to not utilize rxjs when it's already being used. Why go back to plain callbacks instead of using the subscription?
Because you should know the basics of Javascript, while you're not supposed to know rxjs when you start. Also, native code will always be faster than libraries or frameworks, and you will reduce your bundle size by not importing a useless library. But that's my point of view, if it isn't shared I don't mind !
But rxjs is already there. It's being used literally right there to get the default language.
Didn't see, but still doesn't change the point about performance and knowledge !
Performance as an argument here is frankly ridiculous. And to an extent, so is »knowledge«. Why use any framework if it's better to do it with vanilla Javascript for knowledge reasons? But let's not discuss this here.
|
0

I found a working Solution.
Using .toPromise() instead of .subscribe() and then returning l10nLoader.load(); as the result of the Promise solved my problem.

language-configuration.service:

@Injectable()
export class LocalizationConfig {
  constructor(
      public l10nLoader: L10nLoader,
      @Inject(TRANSLATION_CONFIG) private translationConfig: TranslationConfig,
      @Inject(LOCALE_CONFIG) private localeConfig: LocaleConfig,
      private language: LanguageService
  ) { }

  load(): Promise<void> {
    return this.language.getUserLanguages().toPromise()
    .then(
      res => {
        this.localeConfig.language = res.language;
        return this.l10nLoader.load(); // this is important!!
      })
    .catch(  
      err => {
        // set default language or desired strategy
        return this.l10nLoader.load();   
      }
    );
  }
}

export function initLocalization(localizationConfig: LocalizationConfig): Function {
  return () => localizationConfig.load();
}

app.module:

providers: [
  ...
  {
    provide: APP_INITIALIZER,
    useFactory: initLocalization,
    deps: [LocalizationConfig],
    multi: true,
  },
  ...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.