이 페이지와 원하는 AI 어시스턴트를 사용하여 문서를 요약합니다
버전 기록
- "Solid useIntlayer API 사용법을 직접 속성 액세스로 업데이트"v8.9.02026. 5. 4.
- "Init doc"v8.4.52026. 3. 20.
이 페이지의 콘텐츠는 AI를 사용하여 번역되었습니다.
영어 원본 내용의 최신 버전을 보기If you have an idea for improving this documentation, please feel free to contribute by submitting a pull request on GitHub.
GitHub link to the documentationCopy doc Markdown to clipboard
Storybook과 함께하는 Intlayer
목차
대안보다 Intlayer를 선택해야 하는 이유는 무엇입니까?
'storybook-react-i18next' 또는 'i18next'와 같은 주요 솔루션과 비교할 때 Intlayer는 다음과 같은 통합 최적화가 제공되는 솔루션입니다.
Intlayer는 다국어 스토리 데코레이터, 로케일 전환 및 디자인 시스템 전반에 걸쳐 국제화(i18n)를 확장하는 데 필요한 모든 기능을 제공하여 Storybook과 완벽하게 작동하도록 최적화되었습니다.
대용량 JSON 파일을 페이지에 로드하는 대신 필요한 콘텐츠만 로드하세요. Intlayer는 번들 및 페이지 크기를 최대 50% 줄이는 데 도움이 됩니다.
애플리케이션 콘텐츠의 범위를 지정하면 대규모 애플리케이션의 유지 관리가 용이해집니다. 전체 콘텐츠 코드베이스를 검토해야 하는 정신적 부담 없이 단일 기능 폴더를 복제하거나 삭제할 수 있습니다. 또한 Intlayer는 완전히 유형되어 콘텐츠의 정확성을 보장합니다.
콘텐츠를 같은 위치에 배치하면 LLM(대형 언어 모델)에 필요한 컨텍스트가 줄어듭니다. Intlayer에는 누락된 번역을 테스트하기 위한 CLI, LSP, MCP 및 agent)와 같은 도구 모음도 함께 제공됩니다. 기술, AI 에이전트를 위한 개발자 경험(DX)을 더욱 원활하게 만듭니다.
AI 공급자의 비용으로 선택한 LLM을 사용하여 CI/CD 파이프라인을 번역하려면 자동화를 사용하세요. Intlayer는 또한 콘텐츠 추출을 자동화하는 컴파일러와 백그라운드에서 번역을 돕는 웹 플랫폼을 제공합니다.
대규모 JSON 파일을 구성 요소에 연결하면 성능 및 반응성 문제가 발생할 수 있습니다. Intlayer는 빌드 시 콘텐츠 로딩을 최적화합니다.
왜 Storybook에서 Intlayer를 사용해야 하나요?
Storybook은 UI 컴포넌트를 독립적으로 개발하고 문서화하기 위한 업계 표준 도구입니다. Intlayer와 결합하면 다음과 같은 이점이 있습니다:
- 모든 로케일 미리보기: 도구 모음 스위처를 사용하여 Storybook 캔버스 내부에서 직접 확인할 수 있습니다.
- 누락된 번역 감지: 프로덕션에 도달하기 전에 번역 누락을 확인할 수 있습니다.
- 다국어 컴포넌트 문서화: 하드코딩된 문자열 대신 실제 형식이 안전한(type-safe) 콘텐츠를 사용하여 문서화할 수 있습니다.
단계별 설정
1단계: 종속성 설치
코드를 클립보드에 복사
npm install intlayer react-intlayernpm install vite-intlayer --save-dev테이블을 모달로 열어 모든 데이터를 명확하게 확인
| 패키지 | 역할 |
|---|---|
intlayer | 코어 - 구성, 콘텐츠 컴파일, CLI |
react-intlayer | React 바인딩 - IntlayerProvider, useIntlayer 훅 |
vite-intlayer | Vite 플러그인 - 콘텐츠 선언 파일을 감시하고 컴파일 |
2단계: Intlayer 구성 생성
프로젝트 루트(또는 디자인 시스템 패키지 내부)에 intlayer.config.ts를 생성합니다:
코드를 클립보드에 복사
import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = { internationalization: { locales: [ Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH, // 필요한 로케일을 추가하세요 ], defaultLocale: Locales.ENGLISH, }, content: { contentDir: ["./src"], // *.content.ts 파일이 있는 위치 },};export default config;전체 옵션 목록은 구성 참조를 확인하세요.
3단계: Storybook에 Vite 플러그인 추가
Storybook의 viteFinal 훅을 사용하면 내부 Vite 구성을 확장할 수 있습니다. 여기에 intlayer() 플러그인을 가져와서 추가합니다:
코드를 클립보드에 복사
import type { StorybookConfig } from "@storybook/react-vite";import { defineConfig, mergeConfig } from "vite";import { intlayer } from "vite-intlayer";const config: StorybookConfig = { stories: ["../src/**/*.stories.@(js|jsx|ts|tsx)"], addons: [ "@storybook/addon-essentials", // …기타 애드온 ], framework: { name: "@storybook/react-vite", options: {}, }, async viteFinal(baseConfig, { configType }) { const env = { command: configType === "DEVELOPMENT" ? "serve" : "build", mode: configType === "DEVELOPMENT" ? "development" : "production", } as const; const viteConfig = defineConfig(() => ({ plugins: [intlayer()], })); return mergeConfig(baseConfig, viteConfig(env)); },};export default config;intlayer() 플러그인은 *.content.ts 파일을 감시하고 Storybook 개발 중에 변경 사항이 생길 때마다 자동으로 사전을 다시 빌드합니다.
4단계: IntlayerProvider 데코레이터 및 로케일 도구 모음 추가
Storybook의 preview 파일은 모든 스토리를 IntlayerProvider로 감싸고 도구 모음에 로케일 스위처를 노출하기에 적합한 장소입니다:
코드를 클립보드에 복사
import type { Preview, StoryContext } from "@storybook/react";import { IntlayerProvider } from "react-intlayer";const preview: Preview = { // 모든 스토리를 IntlayerProvider 내부에 래핑 decorators: [ (Story, context: StoryContext) => { const locale = context.globals.locale ?? "en"; return ( <IntlayerProvider locale={locale}> <Story /> </IntlayerProvider> ); }, ], // Storybook 도구 모음에 로케일 스위처 노출 globalTypes: { locale: { description: "활성 로케일", defaultValue: "en", toolbar: { title: "로케일", icon: "globe", items: [ { value: "en", title: "English" }, { value: "fr", title: "Français" }, { value: "es", title: "Español" }, ], dynamicTitle: true, }, }, }, parameters: { controls: { matchers: { color: /(background|color)$/i, date: /Date$/i, }, }, },};export default preview;locale값은intlayer.config.ts에 선언된 로케일과 일치해야 합니다.
콘텐츠 선언
각 컴포넌트 옆에 *.content.ts 파일을 생성합니다. Intlayer는 컴파일 중에 이를 자동으로 감지합니다.
코드를 클립보드에 복사
import { type Dictionary, t } from "intlayer";
const copyButtonContent = {
key: "copy-button",
content: {
label: t({
en: "Copy content",
fr: "Copier le contenu",
es: "Copiar contenido",
}),
},
} satisfies Dictionary;
export default copyButtonContent;더 많은 콘텐츠 선언 형식과 기능은 콘텐츠 선언 문서를 참조하세요.
컴포넌트에서 useIntlayer 사용하기
코드를 클립보드에 복사
"use client";import { type FC } from "react";import { useIntlayer } from "react-intlayer";type CopyButtonProps = { content: string;};export const CopyButton: FC<CopyButtonProps> = ({ content }) => { const { label } = useIntlayer("copy-button"); return ( <button onClick={() => navigator.clipboard.writeText(content)} aria-label={label.value} title={label.value} > 복사 </button> );};useIntlayer는 가장 가까운 IntlayerProvider에서 제공하는 현재 로케일에 대한 컴파일된 사전을 반환합니다. Storybook 도구 모음에서 로케일을 전환하면 업데이트된 번역으로 스토리가 자동으로 다시 렌더링됩니다.
국제화된 컴포넌트를 위한 스토리 작성
IntlayerProvider 데코레이터가 설정되면 스토리는 이전과 동일하게 작동합니다. 로케일 도구 모음은 전체 캔버스의 활성 로케일을 제어합니다:
코드를 클립보드에 복사
import type { Meta, StoryObj } from "@storybook/react";import { CopyButton } from ".";const meta: Meta<typeof CopyButton> = { title: "Components/CopyButton", component: CopyButton, tags: ["autodocs"], argTypes: { content: { control: "text" }, },};export default meta;type Story = StoryObj<typeof CopyButton>;/** 기본 스토리 - 번역을 미리 보려면 도구 모음에서 로케일을 전환하세요. */export const Default: Story = { args: { content: "npm install intlayer react-intlayer", },};/** 일반적인 실제 사용 사례인 코드 블록 내부에 버튼을 렌더링합니다. */export const InsideCodeBlock: Story = { render: (args) => ( <div style={{ position: "relative", display: "inline-block" }}> <pre style={{ background: "#1e1e1e", color: "#fff", padding: "1rem" }}> <code>{args.content}</code> </pre> <CopyButton content={args.content} style={{ position: "absolute", top: 8, right: 8 }} /> </div> ), args: { content: "npx intlayer init", },};각 스토리는 도구 모음에서 locale 전역 변수를 상속하므로 스토리 코드를 변경하지 않고도 모든 로케일을 확인할 수 있습니다.
스토리에서 번역 테스트하기
Storybook의 play 기능을 사용하여 특정 로케일에 대해 올바른 번역 텍스트가 렌더링되었는지 확인하세요:
코드를 클립보드에 복사
import type { Meta, StoryObj } from "@storybook/react";import { expect, within } from "@storybook/test";import { CopyButton } from ".";const meta: Meta<typeof CopyButton> = { title: "Components/CopyButton", component: CopyButton, tags: ["autodocs"],};export default meta;type Story = StoryObj<typeof CopyButton>;export const AccessibleLabel: Story = { args: { content: "Hello World" }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); const button = canvas.getByRole("button"); // 버튼에 비어 있지 않은 접근 가능한 이름이 있는지 확인 await expect(button).toHaveAccessibleName(); // 버튼이 비활성화되지 않았는지 확인 await expect(button).not.toBeDisabled(); // 키보드 접근성 확인 await expect(button).toHaveAttribute("tabindex", "0"); },};