[
I try to migrate from @storybook/addon-knobs
to @storybook/addon-controls
and I’ve got an issue.
I have a knob that I use to update i18n locale.
It also switch from rtl to ltr.
It works flawlessly:
import { select } from '@storybook/addon-knobs'
import Vue from "vue";
// import vue plugins
import VueI18n from "vue-i18n";
// import language file
const message = require("./translations.json");
// i18n and store
Vue.use(VueI18n);
import store from "../src/store";
addDecorator(() => ({
template: "<story/>",
i18n: new VueI18n({
defaultLocale: 'en',
locale: 'en',
locales: [ 'en', 'ar' ],
messages: {
en: message.en,
ar: message.ar,
},
}),
// add a props to toggle language
props: {
storybookLocale: {
type: String,
default: select('I18n locale', ['en', 'ar'], 'en'),
},
},
watch: {
// add a watcher to toggle language
storybookLocale: {
handler() {
this.$i18n.locale = this.storybookLocale;
let dir = this.storybookLocale === 'ar' ? 'rtl' : 'ltr';
document.querySelector('html').setAttribute('dir', dir);
},
immediate: true,
},
},
}));
Now, when I try to use @storybook/addon-controls
, I fail to understand how to do it.
I’ve read Storybook documentation and was able to remove my knob to add a new select in the toolbar.
export const globalTypes = {
storybookLocale: {
name: 'storybookLocale',
description: 'Internationalization locale',
defaultValue: 'en',
toolbar: {
icon: 'globe',
items: [
{ value: 'en', right: 'πΊπΈ', title: 'English' },
{ value: 'ar', right: 'π¦πͺ', title: 'Arabic' },
],
},
},
};
Here is an exemple of a story:
import SectionTitle from '../src/components/onboarding/section-title.vue'
export default {
title: 'Onboarding/Components/Title',
component: SectionTitle,
};
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { SectionTitle },
template: '<SectionTitle v-bind="$props" />',
});
export const Title:any = Template.bind({});
Title.args = {
stepNumber: 1,
}
I don’t know how to watch for this global change to update my i18n and the language direction.
In the doc, the global is consumed within a story, but I want it to be global.
Any help would be appreciated.
,
I’m more familiar with React, but I think something along these lines should work.
Solution
- Listen to
context.globals
passed as the second parameter to the decorator. - Replace
addDecorator
with the exporteddecorators
array. - Update
this.storybookLocale
to
context.globals.storybookLocale
.
Notes
- Docs explain how to use a decorator for globals here.
- I found this related article, but ultimately didn’t gain much from it given that you already had the basic set up. They do go through some additional steps, but I’m not sure they’re necessary in your case.
.storybook/preview.js
import Vue from "vue";
import VueI18n from "vue-i18n";
import store from "../src/store";
import message from "./translations.json";
Vue.use(VueI18n);
export const globalTypes = {
storybookLocale: {
name: 'storybookLocale',
description: 'Internationalization locale',
defaultValue: 'en',
toolbar: {
icon: 'globe',
items: [
{ value: 'en', right: 'πΊπΈ', title: 'English' },
{ value: 'ar', right: 'π¦πͺ', title: 'Arabic' },
],
},
},
};
export const decorators = [
(story, context) => ({
template: "<story/>",
i18n: new VueI18n({
defaultLocale: 'en',
locale: 'en',
locales: [ 'en', 'ar' ],
messages: {
en: message.en,
ar: message.ar,
},
}),
props: {
storybookLocale: {
type: String,
default: 'en',
},
},
watch: {
storybookLocale: {
handler() {
this.$i18n.locale = context.globals.storybookLocale;
let dir = storybookLocale === 'ar' ? 'rtl' : 'ltr';
document.querySelector('html').setAttribute('dir', dir);
},
immediate: true,
},
},
})
];
]