Hi,
How do I integrate ngx-translate so I can use it with Storybook for Angular?
Kind regards,
androdel
What have you tried so far? A colleague implemented it in our mono-repo but as far as I can see we needed to do some extra stuff in our story
import { FakeMissingTranslationHandler, MissingTranslationHandler, TranslateLoader } from '@ngx-translate/core';
import { storiesOf } from '@storybook/angular';
import { of } from 'rxjs';
import { I18nModule } from '../i18n.module';
import { I18nDemoComponent } from './i18n-demo.component';
// symbols used in decorators need to be exported
export const staticTranslateLoader: TranslateLoader = {
getTranslation(lang: string) {
return of(require('./i18n/en.json'));
}
};
storiesOf('Foundation', module)
.add(
'I18n',
() => ({
component: I18nDemoComponent,
moduleMetadata: {
imports: [
I18nModule.forRoot({
loader: {
provide: TranslateLoader,
useValue: staticTranslateLoader
},
missingTranslationHandler: {
provide: MissingTranslationHandler,
useClass: FakeMissingTranslationHandler
}
})
]
}
})
);
Note: I18nModule is something we added. Replace this code with TranslationModule from ngx-translate. Maybe it works right away 馃檪
If this does not solve your issue, we configured it like that:
@ngx-tranlsate/core assets/i18n/en.jsonangular.json (example with two different i18n directories) { "glob": "**", "input": "./src/assets/i18n", "output": "./i18n" },
{ "glob": "**", "input": "./projects/ui/src/assets/i18n", "output": "./i18n/ui" }
export function createStandardLoader(httpClient: HttpClient) {
const paths = ['./i18n/ui', './i18n'];
return new MergingMultiHttpLoader(httpClient, paths.map(prefix => ({
prefix: prefix + '/', suffix: '.json'
})));
}
Hello I seem to be facing the same issue as well..
I tried the method above but it didn't work
I did a fresh Angular installation and integrated ngx-translate into the actual angular app + into storybook
https://github.com/kroeder/storybook-ngx-translate
I also added a library project but haven't tried integrating ngx-translate there yet.
Please let me know if this is of any help
A couple of notes:
I18nModule but it uses forRoot() for ngx-translate so this should only be imported once per appapp.module.ts or any other root-module of your libs etc.storiesOf('Button', module).add('with text', () => ({
template: `
<button>{{ 'basic.submit' | translate }}</button>
`,
moduleMetadata: {
imports: [I18nModule]
}
}));
Ofcourse, putting the code in a module would be the answer (stupid me).
Anyway, this raises another issue and that is that he cannot find my en.json file, but it is present.


PS: I'm working in an Angular 6 app
@androdel is it in src/assets or projects/your-project/src/assets ?
If you need a custom assets folder then try using https://storybook.js.org/docs/configurations/serving-static-files/#2-via-a-directory
@kroeder it's in src/assets
I now also started with a clean build and it works! Could the issue be Angular 6 related?
I don't think so. They might have added something to the default angular.json when bootstrapping a new angular app. Can you try to upgrading to 7 using ng update @angular/cli @angular/core in a branch?
@kroeder
For some reason, i18nModule doesn't work out of the box. I had to use
translate.setDefaultLang('en');
translate.use('en');
everywhere inside the constructor of the Components for which I was creating the story.
Do you have any idea why that would be the case ?
@deepaksslibra https://github.com/kroeder/storybook-ngx-translate/blob/master/src/app/i18n/i18n.module.ts#L26 I did it in the constructor of my I18nModule
This does not work for you?
Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!
Hi everyone,
I managed to make it work combining some of your solutions. The key is what @kroeder was suggesting of creating a "fake" I18 module and import it in the moduleMetadata. Moreover, the staticTranslateLoader can be used to handle translations within the component. Here I paste the working config that should be added to you component stories.

Thanks to everyone and I hope you have a nice day :-)
Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!
Hey there, it's me again! I am going close this issue to help our maintainers focus on the current development roadmap instead. If the issue mentioned is still a concern, please open a new ticket and mention this old one. Cheers and thanks for using Storybook!
Thank you so much for the solution! Though, diving deeper I stumbled upon a problem. I started to use this feature with the 'StoriesOf' function, but eventually, I had to pass to an arrow function approach to build the story. The reason is, basically, for combine Knobs with the translate pipe and it works fine! Unfortunately, with the template on the arrow functions inputs works properly whilst actions don't! I leave an example below, thank you!
export const primary = () => ({
title: "UiEmptyScreen",
moduleMetadata: {
imports: [I18nModule],
declarations: [UiEmptyScreenComponent],
providers: [TranslateService]
},
component: UiEmptyScreenComponent,
template:
[subtitle]="subtitle | translate"
[icon]="icon | translate"
[buttonTitle]="buttonTitle | translate"
(clickedButton)="clickedButton"
, props: { title: text("title", "dashboard.claim.empty_screen.TITLE"), subtitle: text("subtitle", "dashboard.claim.empty_screen.SUBTITLE"), icon: text("icon", "dashboard.claim.empty_screen.ICON"), buttonTitle: text( "buttonTitle", "dashboard.claim.empty_screen.BUTTON_TITLE" ), clickedButton: action("clickedButton event") } });
Component.ts:
`import { Component, Input, Output, EventEmitter } from "@angular/core";
@Component({
selector: "presenter-empty-screen",
templateUrl: "./ui-empty-screen.component.html",
styleUrls: ["./ui-empty-screen.component.scss"]
})
export class UiEmptyScreenComponent {
@Input() title: string;
@Input() subtitle: string;
@Input() icon: string;
@Input() buttonTitle: string;
@Output() clickedButton = new EventEmitter();
constructor() {}
onClick(): void {
this.clickedButton.emit();
}
}
`
I've solved it! I attach the code below. Anyway, I would like to be capable of switch language translate with a knob, is it possible?
Thanks!
export const englishComponent = () => ({
moduleMetadata: {
imports: [I18nModule],
declarations: [UiEmptyScreenComponent],
providers: [TranslateService]
},
component: UiEmptyScreenComponent,
template:
[subtitle]="subtitle | translate"
[icon]="icon | translate"
[buttonTitle]="buttonTitle | translate"
(clickedButton)="clickedButton()"
, props: { title: text("title", "dashboard.claim.empty_screen.TITLE"), subtitle: text("subtitle", "dashboard.claim.empty_screen.SUBTITLE"), icon: text("icon", "dashboard.claim.empty_screen.ICON"), buttonTitle: text( "buttonTitle", "dashboard.claim.empty_screen.BUTTON_TITLE" ), clickedButton: () => TranslateService.use("es") } });
I've written a small article about this subject, in case anyone is looking for help: https://medium.com/@dSebastien/using-ngx-translate-in-storybook-stories-3f4228f80e02
@dsebastien i have a nx monorepo angular + storybook setup, i tried what you described in your blog but i still get error because it cannot resolve that pipe translate on the templates. any clues?
```
// THE STORYBOOK NGX TRANSLATE CONFIG MODULE
import { TranslateModule, TranslateService, TranslateLoader } from "@ngx-translate/core"
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { NgModule } from '@angular/core';
import { HttpClient, HttpClientModule } from '@angular/common/http';
export function HttpLoaderFactory(httpClient: HttpClient) {
return new TranslateHttpLoader(httpClient, './assets/i18n/', '.json');
}
@NgModule({
imports: [
HttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient],
},
})
],
providers: [TranslateService]
})
export class SBTranslateModule {
constructor(translateService: TranslateService) {
console.log("Configuring the translation service: ", translateService);
console.log("Translations: ", translateService.translations);
translateService.setDefaultLang("en-US");
translateService.use("en-US");
}
}
// THE STORYBOOK STORY
...
export default {
title: 'HeaderComponent',
decorators:[
moduleMetadata({
declarations:[HeaderComponent],
imports: [SBTranslateModule],
providers: [{ provide: APP_BASE_HREF, useValue: '/' }],
}),
]
};
const label = 'title';
const defaultValue = {
title: 'back',
routerLink: '/',
};
const groupId = 'GROUP-ID1';
export const Default = () => ({
props: {
title: text('text', 'Header!'),
back: object(label, defaultValue, groupId),
},
component: HeaderComponent,
});
I think I know why. You still need to import the TranslateModule, not only for .forRoot. You can do it like this for example:
@NgModule({
imports: [
HttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient],
},
}),
TranslateModule,
],
providers: [TranslateService]
})
export class SBTranslateModule {
constructor(translateService: TranslateService) {
console.log("Configuring the translation service: ", translateService);
console.log("Translations: ", translateService.translations);
translateService.setDefaultLang("en-US");
translateService.use("en-US");
}
}
In my case I didn't need it because I have a CoreModule which takes care of it. I'll adapt the blog post to mention it! :)
Most helpful comment
Hi everyone,
I managed to make it work combining some of your solutions. The key is what @kroeder was suggesting of creating a "fake" I18 module and import it in the moduleMetadata. Moreover, the staticTranslateLoader can be used to handle translations within the component. Here I paste the working config that should be added to you component stories.

Thanks to everyone and I hope you have a nice day :-)