angularinternationalizationtransloco

Transloco merge local with serverside translation objects


I am looking for a robust way to prefetch a translation file from a server, and merge with the local translation file during app initialization.

The docs state that you can set the translation language using an APP_INITIALIZER provider https://ngneat.github.io/transloco/docs/recipes/prefetch

This may work if you only have a static json asset file (e.g. src/assets/i18n/en.json), but I can't make this work combining with a json translation fetched from a server.

Here is my attempt at using the app initializer :

// app.module.ts 
...
    {
      provide: APP_INITIALIZER,
      multi: true,
      useFactory: preloadServer,
      deps: [TranslocoService, HttpClient]
    }
...
export function preloadUser(transloco: TranslocoService, _httpClient: HttpClient) {
  return () => {
    combineLatest([
      _httpClient.get(`http://my.server.com/en.json`), // fetches a remote translation
      transloco.selectTranslation('en') // fetches the local static asset file
    ]).pipe(
      take(1),
      map(([server, client]) => (
        Object.assign(client, server) // Merges the 2 objects
      )),
      tap(merged => transloco.setTranslation(merged, 'en')) // Updates the 'en' translation with the merged object
    ).toPromise();
  }
}

Weird thing is that this randomly works. If I reload the app 10 times, half of the times I'll see the server translations and half the client translations.

Update

After @naren-murali 's answer, I realized that I can re-write the app initializer function to utilize the transloco API which provides a translation merge option, so I am adding my updated approach

export function preloadTranslation(transloco: TranslocoService, httpClient: HttpClient) {
  return () => {
    return concat(
      transloco.selectTranslation('en'), // This fetches the local translation
      httpClient.get(`http://my.server.com/en.json`) // This fetches the server translation
    ).pipe(
      // Merge the server keys into the local object using the transloco API option "{ merge: true }"
      tap(serverTranslation => transloco.setTranslation(serverTranslation, 'en', { merge: true }))
    ).toPromise();
  }
}

Solution

  • Could you try returning the combineLatest maybe that is what's missing!

    export function preloadUser(transloco: TranslocoService, _httpClient: HttpClient) {
      return () => {
        return combineLatest([ //                        <-- changed here!
          _httpClient.get(`http://my.server.com/en.json`), // fetches a remote translation
          transloco.selectTranslation('en') // fetches the local static asset file
        ]).pipe(
          take(1),
          map(([server, client]) => (
            Object.assign(client, server) // Merges the 2 objects
          )),
          tap(merged => transloco.setTranslation(merged, 'en')) // Updates the 'en' translation with the merged object
        ).toPromise();
      }
    }