Closed androdel closed 5 years ago
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:
installed @ngx-tranlsate/core
added assets/i18n/en.json
In your angular.json
(example with two different i18n directories)
{ "glob": "**", "input": "./src/assets/i18n", "output": "./i18n" },
{ "glob": "**", "input": "./projects/ui/src/assets/i18n", "output": "./i18n/ui" }
Add a loader
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:
<presenter-empty-screen
[title]="title | translate"
[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:
<presenter-empty-screen
[title]="title | translate"
[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! :)
I want to create a story where I can change the Ngx default language, in an Angular app usually, this is done through Ngx TranslateService
, any ideas on how to use this service in a story?
Son of a gun!! I just released https://github.com/storybookjs/storybook/releases/tag/v6.3.0-alpha.7 containing PR #14226 that references this issue. Upgrade today to the @next
NPM tag to try it out!
npx sb upgrade --prerelease
I've worked my way through of the examples above and have managed to get it 'working' intermittently. However, this does require that the default language is set it the contructor of the i18n module and when the story is refreshed (F5) it reverts back to en-GB.
Has anyone actually got this working were by you can select the local from the toolbar in Storybook and set the local using TranslateService? I am new to SB but cannot see a way to hook into the changes in the globalTypes for me then to be able to set the locale on the fly?
NB: Using Angular 13
@Stusaw did you find an answer to this? I'm also struggling with the same issues. The solutions I found all seem to apply to React, not Angular.
@Stusaw did you find an answer to this? I'm also struggling with the same issues. The solutions I found all seem to apply to React, not Angular.
Unfortunately not via the SB UI. I did however build a 'translate' button component and included that as part of my story (Eg. in the main navigation toolbar). As I was building a composite 'full-page' story this worked for me.
@Stusaw that could be a workaround, but not very practical with a lot of components to test in my library. I got the language button to display in StoryBook with adding to preview.js locales: { en: "English", fr: "Français", es: "Espanol" },
But I can't figure out to grab the new value and set the TranslateService accordingly. Clicking on another language has no effect.
I was able to use ngx-translate just by creating a specific module for the storybook and adding the translation configuration. My storybook.module.ts:
import { TranslateModule, TranslateService, TranslateLoader } from "@ngx-translate/core"
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { LOCALE_ID, NgModule } from '@angular/core';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { CommonModule, registerLocaleData } from "@angular/common";
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, "../assets/i18n/", ".json")
}
import localePt from '@angular/common/locales/pt';
registerLocaleData(localePt);
@NgModule({
declarations: [],
imports: [
HttpClientModule,
CommonModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
},
}),
],
exports: [TranslateModule],
providers: [
{ provide: LOCALE_ID, useValue: 'pt'}
]
})
export class StorybookModule {
constructor(translate: TranslateService) {
translate.setDefaultLang("pt");
translate.use("pt")
}
}
My component.story.ts
export default {
title: 'Shape-U/Components/Lista',
component: ListaBaseComponent,
decorators: [
moduleMetadata({
imports: [StorybookModule],
})
]
} as Meta;
@Stusaw did you find an answer to this? I'm also struggling with the same issues. The solutions I found all seem to apply to React, not Angular.
@Stusaw, @leekFreak I figure out the solution and it's surprisingly simple!
So I guess you set the default language in the module's constructor like in the previous answers. This is the place where you can add listener for Storybook's globals updates. The whole module declaration can look like this. The last few lines of the constructor is where the magic happens.
import { TranslateModule, TranslateService, TranslateLoader } from "@ngx-translate/core"
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { LOCALE_ID, NgModule } from '@angular/core';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { CommonModule, registerLocaleData } from "@angular/common";
import { addons } from "@storybook/addons";
import { GLOBALS_UPDATED } from "@storybook/core-events";
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, "../assets/i18n/", ".json")
}
import localePl from '@angular/common/locales/pt';
registerLocaleData(localePl);
@NgModule({
declarations: [],
imports: [
HttpClientModule,
CommonModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
},
}),
],
exports: [TranslateModule],
providers: [
{ provide: LOCALE_ID, useValue: 'pl'},
TranslateService
]
})
export class StorybookTranslateModule {
constructor(translate: TranslateService) {
translate.setDefaultLang("pl");
translate.use("pl");
let channel = addons.getChannel();
channel.addListener(GLOBALS_UPDATED, (args) => {
translate.use(args.globals.locale)
});
}
}
This way you can use the local picker in the Toolbar and it will update the TranslateService's current language. The picker is specified in the preview file.
...
globalTypes: {
locale: {
description: 'Internationalization locale',
defaultValue: 'en',
toolbar: {
icon: 'globe',
items: [
{ value: 'en', right: '🇬🇧', title: 'English' },
{ value: 'pl', right: '🇵🇱', title: 'Polski' },
],
dynamicTitle: true,
},
},
},
...
what to do for standalone components?
Hi,
How do I integrate ngx-translate so I can use it with Storybook for Angular?
Kind regards, androdel