Issue
I'm trying to implement Transloco in my Angular application that consists of a library and multiple SPA projects. I would like to have one global configuration class in the library project common
and extend that with a production mode variable that the library does not have access to.
Currently, I have the following working configuration architecture:
transloco-common-config.module.ts (in common
library):
@NgModule()
export class TranslocoCommonConfig implements TranslocoConfig {
public defaultLang = 'en';
public availableLangs: string[] = [];
public reRenderOnLangChange = true;
constructor(private localeService: LocaleService) {
this.availableLangs = this.localeService.getAvailableLanguages();
}
}
Which I can successfully use in an SPA project-specific module like this:
@NgModule({
exports: [TranslocoModule],
providers: [
{ provide: TRANSLOCO_CONFIG, useClass: TranslocoCommonConfig },
{ provide: TRANSLOCO_LOADER, useClass: TranslocoHttpLoader },
],
})
export class TranslocoRootModule {
}
The available languages are correctly loaded through LocaleService
and Transloco works in the SPA project as expected.
To extend this configuration in the SPA project, my intuition is to use the forRoot() pattern. I modified the common configuration module into this:
class TranslocoCommonConfigOptions {
productionMode = true;
}
@NgModule()
export class TranslocoCommonConfig implements TranslocoConfig {
public defaultLang = 'en';
public availableLangs: string[] = [];
public reRenderOnLangChange = true;
constructor(private localeService: LocaleService) {
this.availableLangs = this.localeService.getAvailableLanguages();
}
static forRoot(options: TranslocoCommonConfigOptions): ModuleWithProviders<TranslocoCommonConfig> {
return {
ngModule: TranslocoCommonConfig,
providers: [
{
provide: TranslocoCommonConfigOptions,
useValue: options,
},
],
};
}
}
To my understanding, this should be correct. However, I'm struggling to use this correctly in the SPA project. If I modify the TranslocoRootModule
class to provide TRANSLOCO_CONFIG
like this:
{ provide: TRANSLOCO_CONFIG, useClass: TranslocoCommonConfig.forRoot({ productionMode: true }) }
I get the following error:
TS2322: Type '{ provide: InjectionToken<TranslocoConfig>; useClass: ModuleWithProviders<TranslocoCommonConfig>; }' is not assignable to type 'Provider'. Types of property 'useClass' are incompatible. Type 'ModuleWithProviders<TranslocoCommonConfig>' is missing the following properties from type 'Type<any>': apply, call, bind, prototype, and 5 more.
How should I implement this with preferably minimal boilerplate code (I have five SPA projects and would like to have as little duplicate code as possible)?
Solution
I was able to solve this by creating two library modules for Transloco configuration.
TranslocoCommonConfigModule
is responsible for the actual configuration:
export class TranslocoCommonConfigOptions {
productionMode: boolean;
loader: Type<TranslocoLoader>;
}
/**
* Global configuration for the Transloco library. Accepts a `TranslocoCommonConfigOptions`
* configuration object to dynamically set `TranslocoConfig.prodMode`.
*/
@NgModule()
export class TranslocoCommonConfigModule implements TranslocoConfig {
// Static and global configuration:
defaultLang = 'en';
reRenderOnLangChange = true;
// Dynamic configuration:
availableLangs: string[] = [];
prodMode = true;
constructor(private localeService: LocaleService, config: TranslocoCommonConfigOptions) {
this.availableLangs = this.localeService.getAvailableLanguages();
this.prodMode = config.productionMode;
}
}
While TranslocoCommonModule
is resposible for injecting the required service and configuration object via the forRoot
method:
/**
* Common module for importing Transloco configuration in frontends with minimal boilerplate.
*
* Uses the `forRoot()` paradigm to inject `environment.production` dynamically from a frontend along with
* a frontend-specific translation loader. The rest of `TranslocoConfig` options are global and provided by
* `TranslocoCommonConfigModule`.
*/
@NgModule()
export class TranslocoCommonModule {
static forRoot(options: TranslocoCommonConfigOptions): ModuleWithProviders<TranslocoCommonModule> {
return {
ngModule: TranslocoCommonModule,
providers: [
{
provide: TRANSLOCO_CONFIG,
useFactory: (localeService: LocaleService) =>
new TranslocoCommonConfigModule(localeService, options),
deps: [LocaleService],
},
{
provide: TRANSLOCO_LOADER,
useClass: options.loader,
},
],
};
}
}
After implementing a frontend-specific translation file loader, the configuration can be imported in a module like so:
@NgModule({
imports: [
TranslocoCommonModule.forRoot({
productionMode: environment.production,
loader: TranslocoHttpLoader,
}),
],
})
Answered By - basse
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.