👉 Next.js 14 + Storybook8도 동일하게 작업
👉 storybook-i18n addon만 3버전으로 설치
레포지토리 준비
v13.5.6
v4.1.1
v7.6.17
^3.10.0
[next-intl] next-intl 공식문서에서 Storybook과 함께 사용할 수 있음 확인
[Storybook Addon] storybook-i18n 설치
Storybook i18n Addon | Storybook: Frontend workshop for UI development
현재 Storybook7을 사용하고 있기때문에 storybook-i18n 2버전대 설치
yarn add [email protected]
스토리북의 Global Decorators
를 사용하여 next-intl 적용하기
.storybook > preview.ts
preview.ts
는 각 stories 파일들에 대하여 전역적인 설정을 할 수 있는 영역
Next.js 의 가장 root에 위치한 layout.tsx 과 비슷한 역할
모든 생성 stories 파일이 preview.ts의 영향력 안에 있음
storybook의 preview.ts에서 한 설정의 적용 영역
preview 영역에 locale 툴바 적용하기 ( .storybook > preview.ts )
Toolbars & globals • Storybook docs
툴바 메뉴 설정하기
globalTypes를 사용해서 툴바 내부에 여러가지 기능 버튼을 적용할 수 있음
const preview: Preview = {
globalTypes: {
locale: {
description: '국제화 locale',
defaultValue: 'ko',
toolbar: {
icon: 'globe',
items: [
{ value: 'ko', right: '🇰🇷', title: '한국어' },
{ value: 'en', right: '🇺🇸', title: 'English' },
{ value: 'ja', right: '🇯🇵', title: '日本語' },
],
},
},
},
}
preview 화면에 locale 버튼이 툴바에 추가된 모습
생성된 모든 stories 파일에서 next-intl을 사용할 수 있도록 NextIntlClientProvider
를 적용
stories 파일은 프로젝트의 기존 설정이 적용되는 것이 아닌 storybook 별도의 환경에서 작동
preview.ts에서 NextIntlClientProvider
설정을 전역적으로 해줘야함
Storybook의 Decorator 설정을 이용
[Storybook][MUI] 스토리북 실무에서 사용하기
Story 상위에 추가적인 마크업을 생성하여 래핑하는 기능
각 스토리에서 개별로 decorator를 적용할 수도 있고, preview.ts 에서 작성하면 전역적으로 적용됨 (Global Decorator)
export const Primary: Story = {
**decorators: [**
(Story) => (
<div className="i_am_decorator">
<Story />
</div>
),
**],**
args: {
primary: true,
label: 'Button',
},
}
기존 스토리 컴포넌트 바로 위에 추가로 생성된 decorator 마크업
preview.ts에서 decorators 설정을 적용 (Global Decorators)
decorators는 배열을 받기때문에 decorator가 많아질 경우, 별도 파일로 빼서 관리할 수도 있음
decorators에서는 globalTypes에 정의된 locale의 value를 가져와서 활용할 수 있음
import { NextIntlClientProvider } from 'next-intl'
import * as KoMsg from '../messages/ko.json'
import * as EnMsg from '../messages/en.json'
import * as JaMsg from '../messages/ja.json'
const preview: Preview = {
**globalTypes: {**
**locale**: {
description: '국제화 locale',
defaultValue: 'ko',
toolbar: {
icon: 'globe',
items: [
{ value: 'ko', right: '🇰🇷', title: '한국어' },
{ value: 'en', right: '🇺🇸', title: 'English' },
{ value: 'ja', right: '🇯🇵', title: '日本語' },
],
},
**},**
},
decorators: [
(Story, **context**) => {
const **selectedLocale** = context.globals.locale
// NextIntlClientProvider에 필요한 messages를
// 변경되는 globalTypes locale 값에 맞게 언어 json을 바꿔줌
const convertLocaleMsg = () => {
switch (selectedLocale) {
case 'ko':
return KoMsg
case 'en':
return EnMsg
case 'ja':
return JaMsg
}
}
return (
<NextIntlClientProvider locale={selectedLocale} messages={convertLocaleMsg()}>
<Story />
</NextIntlClientProvider>
)
},
],
}
적용한 전역 설정을 받을 Button.stories.tsx 를 생성
components > Buttons.tsx
stories > Button.stories.tsx
생성한 Button.tsx 컴포넌트를 stories파일에 import함
Button.stories.tsx
stories 파일에서 함수를 export 시키면 preview화면에 등록됨
다른 화면에서 하듯이 useTranslations 훅을 이용하여 언어 적용
Button 컴포넌트의 텍스트로 들어가는 props → label
import { Button } from './Button' // 일반 Button.tsx 컴포넌트
import { useTranslations } from 'next-intl'
...
Button.stories.tsx에 대한 여러가지 설정
...
// 1개의 story export
// Button.stories.tsx 는 여러개의 story를 export하는 파일
export const StoryWithLocale = {
render: () => {
const t = useTranslations('About')
return <Button label={t('title')} primary={true} />
},
}
Preview 화면에 등록된 StoryWithLocale 함수
툴바 Locale 메뉴 변경값에따라 바뀌는 Story 화면