Providing runtime translations
@flyze/lib-core-angular 1.0.0-alpha.34· latestHow to feed a transloco scope from your own backend, so scoped translation configs resolve against
translations that were not in the bundle.
Mechanics: features/runtime-scoped-translations.
1. Implement the data service
Section titled “1. Implement the data service”import { AbstractFyzTranslateConfigDataService, FyzScopedTranslocoConfig} from '@flyze/lib-core-angular';
@Injectable({ providedIn: 'root' })export class MyTranslateConfigDataService implements AbstractFyzTranslateConfigDataService { constructor(private http: HttpClient) {}
loadConfig(scope: string): Observable<FyzScopedTranslocoConfig> { return this.http.get<FyzScopedTranslocoConfig>(`/api/translations/${scope}`); }
saveConfig(config: FyzScopedTranslocoConfig): Observable<FyzScopedTranslocoConfig> { return this.http.put<FyzScopedTranslocoConfig>(`/api/translations/${config.scope}`, config); }}The payload is keyed by translation key, with every language of that key together:
{ "scope": "orders", "translations": { "GREETING": [ { "language": "de", "text": "Hallo {{name}}" }, { "language": "en", "text": "Hello {{name}}" } ] }}If you never save, still implement saveConfig — the abstract class requires it. Returning
throwError(() => new Error('read only')) is honest; the test app throws synchronously
(custom-transloco-config-data.service.ts).
2. Provide it under the token
Section titled “2. Provide it under the token”@NgModule({ providers: [ { provide: FYZ_TRANSLATE_CONFIG_DATA_SERVICE, useClass: MyTranslateConfigDataService } ]})export class AppModule {}Provide it in the root injector. The lookup happens once, in the constructor of a root-provided
service, so a provider registered inside a lazy route’s injector is never found — and the failure is
silent: you get the built-in no-op provider that returns an empty config, with a console.info
note.
3. Load a scope
Section titled “3. Load a scope”constructor(private configService: FyzTranslateTranslocoConfigService) {}
ngOnInit() { this.configService .loadConfig('orders') .pipe(takeUntil(this.destroy$)) .subscribe();}loadConfig applies the result to transloco by default; the subscription is what triggers the
request. Pass false as the second argument to fetch without applying.
Do this before anything renders the scope — a scoped config for a key that is not loaded yet
renders the bare key and does not retry. If the scope is needed by the first view, resolve it
during bootstrap (APP_INITIALIZER) or in a route resolver.
Applying a config you already have
Section titled “Applying a config you already have”this.configService.applyConfigLocal({ scope: 'orders', translations: { GREETING: [{ language: 'de', text: 'Hallo' }] }});Synchronous, no request. Use it for translations that arrived over a websocket or came from a local edit.
Replacing versus merging
Section titled “Replacing versus merging”Applying a config is additive. Keys the new config omits keep their old values, even for a scope
you already loaded — removeConfigLocal does not actually remove anything (see the limitation in
features/runtime-scoped-translations).
To genuinely clear a scope, go through transloco directly:
constructor(private transloco: TranslocoService) {}
clearScope(scope: string) { for (const lang of this.transloco.getAvailableLangs() as string[]) { this.transloco.setTranslation({}, `${scope}/${lang}`, { merge: false }); }}Verify
Section titled “Verify”The /transloco-test route of the test app runs the whole flow against a fake data service: it
loads the playground2 scope, then applies a second config three seconds later so you can watch
already rendered text change.