A library for best-practice i18n addons in Storybook:
- Easy-to-use locale configuration
- Simple drop-down menu
- URL-linkable state for sharing
- 2.x is for Storybook
>=7.0.0
- 3.x is for Storybook
>=8.0.0
- 3.1.x is for Storybook
>=8.2.0
As an addon author, you can use this library by adding it as a dependency and adding the following to your src/manager.ts
and src/preview.ts
files:
src/manager.ts
export * from 'storybook-i18n/manager';
src/preview.ts
import type { Renderer, ProjectAnnotations } from '@storybook/types';
import i18n from 'storybook-i18n/preview';
import { withYourI18nDecorator } from './withYourDecorator';
// @ts-ignore
const i18nDecorators = i18n?.decorators || [];
const preview: ProjectAnnotations<Renderer> = {
...i18n,
decorators: [...i18nDecorators, withYourI18nDecorator],
}
export default preview;
Due to an issue with Storybook (pending resolution), you will need that @ts-ignore
above the decorators line.
The currently selected locale is available in the locale
global, so you can access it in a decorator using the following snippet:
import { MyProvider } from 'your-i18n-library';
import { useGlobals } from '@storybook/manager-api';
const myDecorator = (story, context) => {
const [{locale}] = useGlobals();
return <MyProvider locale={locale}>;
}
End users configure the locales
and locale
globals in .storybook/preview.ts
.
As of Storybook 8.2, you should use initialGlobals
instead of globals
.
locales
is an object where the keys are the "ids" of the locale/language and the values are the plain text name of that locale you want to use. This is what will appear in the dropdown in the toolbar.
const preview: Preview = {
initialGlobals: {
locale: "en",
locales: {
en: "English",
fr: "Français",
ja: "日本語",
},
},
};
Users can also use full locale strings.
const preview: Preview = {
initialGlobals: {
locale: "en_US",
locales: {
en_US: "English (US)",
en_GB: "English (GB)",
fr_FR: "Français",
ja_JP: "日本語",
},
},
};
The locales
object can also have values as an object with keys of title
, icon
, and/or right
.
This is useful if you want to include an emoji flag or some other string to the left and/or right side.
For example:
const preview: Preview = {
initialGlobals: {
locale: 'en',
locales: {
en: {icon: '🇺🇸', title: 'English', right: 'US'},
fr: {icon: '🇫🇷', title: 'Français', right: 'FR'},
ja: {icon: '🇯🇵', title: '日本語', right: 'JP'},
},
},
};
Or something like this:
const preview: Preview = {
initialGlobals: {
locale: 'en_US',
locales: {
en_US: {title: 'English', right: 'US'},
en_GB: {title: 'English', right: 'GB'},
fr_FR: {title: 'Français', right: 'FR'},
ja_JP: {title: '日本語', right: 'JP'},
},
},
};
When the locale has been changed, an event is emitted on the addons-channel
.
You can subscribe to this event in your preview.ts
, to configure global environment settings yourself, related to your i18n-config.
The event is emitted with the selected locale as a parameter
.
Your implementation could look like this:
import { addons } from '@storybook/preview-api'
addons.getChannel().on('LOCALE_CHANGED', (newLocale) => {
changeMyI18nConfig(newLocale)
});
Addons should instruct them to use whichever format your i18n implementation expects.