Inline Loaders
When working on a feature module or a library (which is common in a monorepo environment), we may want to have the translation files inside the module folder and ship them together with it.
To enable this feature, Transloco supports scope
with inline loaders. We can pass the scope name and an inline loader that leverages Webpack import function to lazy load the local translation files.
Let's say we have the following Angular CLI project:
- Standalone
- NgModule
📦projects
┗ 📂feature
┃ ┣ 📂src
┃ ┃ ┣ 📂lib
┃ ┃ ┃ ┣ 📂i18n
┃ ┃ ┃ ┃ ┣ 📜en.json
┃ ┃ ┃ ┃ ┗ 📜es.json
┃ ┃ ┃ ┣ 📜feature.component.ts
┃ ┃ ┃ ┣ 📜feature.routes.ts
┃ ┃ ┃ ┗ 📜feature.service.ts
┃ ┃ ┣ 📜public-api.ts
📦src
┣ 📂app
┃ ┣ 📜app.routes.ts
┃ ┣ 📜app.component.css
┃ ┣ 📜app.component.html
┃ ┣ 📜app.component.ts
┃ ┣ 📜app.config.ts
┃ ┗ 📜transloco.loader.ts
┣ 📂assets
┃ ┣ 📂i18n
┃ ┃ ┣ 📜en.json
┃ ┃ ┗ 📜es.json
Inside the feature
route/component, we can define a scope provider and pass an inline loader:
export const loader = ['en', 'es'].reduce((acc, lang) => {
acc[lang] = () => import(`../i18n/${lang}.json`);
return acc;
}, {});
export const FEATURE_ROUTES: Route = {
path: 'feature',
loadComponent: () => import('./feature.component').then(FeatureComponent => FeatureComponent),
providers: [
provideTranslocoScope({
scope: 'scopeName',
loader
})
]
};
📦projects
┗ 📂feature-module
┃ ┣ 📂src
┃ ┃ ┣ 📂lib
┃ ┃ ┃ ┣ 📂i18n
┃ ┃ ┃ ┃ ┣ 📜en.json
┃ ┃ ┃ ┃ ┗ 📜es.json
┃ ┃ ┃ ┣ 📜feature-module.component.ts
┃ ┃ ┃ ┣ 📜feature-module.module.ts
┃ ┃ ┃ ┗ 📜feature-module.service.ts
┃ ┃ ┣ 📜public-api.ts
📦src
┣ 📂app
┃ ┣ 📜app-routing.module.ts
┃ ┣ 📜app.component.css
┃ ┣ 📜app.component.html
┃ ┣ 📜app.component.ts
┃ ┣ 📜app.module.ts
┃ ┣ 📜transloco-root.module.ts
┃ ┗ 📜transloco.loader.ts
┣ 📂assets
┃ ┣ 📂i18n
┃ ┃ ┣ 📜en.json
┃ ┃ ┗ 📜es.json
Inside the feature
module, we can define a scope provider and pass an inline loader:
export const loader = ['en', 'es'].reduce((acc, lang) => {
acc[lang] = () => import(`../i18n/${lang}.json`);
return acc;
}, {});
@NgModule({
imports: [TranslocoModule],
providers: [
provideTranslocoScope({
scope: 'scopeName',
loader
})
],
declarations: [YourComponent],
exports: [YourComponent]
})
export class FeatureModule {}
Note that when using an inline loader, the scope
key is used as the alias
.
Now we can translate our content using the scope
we define:
@Component({
selector: 'app-feature',
template: `
<ng-container *transloco="let t">
<p>{{ t('scopeName.title') }}</p>
</ng-container>`,
imports: [TranslocoDirective]
})
export default class FeatureComponent {}
@Component({
selector: 'app-feature',
template: `
<ng-container *transloco="let t">
<p>{{ t('scopeName.title') }}</p>
</ng-container>`
})
export class FeatureComponent {}
And lazy-loaded both the feature
module and its translation files in our application:
@NgModule({
declarations: [AppComponent],
imports: [
TranslocoRootModule,
RouterModule.forRoot([
{
path: 'route-name',
loadChildren: () =>
import('path/to/feature/module').then( m => m.FeatureModule)
}
])
],
bootstrap: [AppComponent]
})
export class AppModule {}
You can find a complete working example that uses nx here.
Note that following the Angular DI rules, it can be done either in a feature module that we lazy-loaded or at the component providers level.