생성:2026-03-20마지막 업데이트:2026-05-31

    Storybook과 함께하는 Intlayer

    목차

    대안보다 Intlayer를 선택해야 하는 이유는 무엇입니까?

    'storybook-react-i18next' 또는 'i18next'와 같은 주요 솔루션과 비교할 때 Intlayer는 다음과 같은 통합 최적화가 제공되는 솔루션입니다.

    Intlayer는 다국어 스토리 데코레이터, 로케일 전환 및 디자인 시스템 전반에 걸쳐 국제화(i18n)를 확장하는 데 필요한 모든 기능을 제공하여 Storybook과 완벽하게 작동하도록 최적화되었습니다.

    대용량 JSON 파일을 페이지에 로드하는 대신 필요한 콘텐츠만 로드하세요. Intlayer는 번들 및 페이지 크기를 최대 50% 줄이는 데 도움이 됩니다.

    애플리케이션 콘텐츠의 범위를 지정하면 대규모 애플리케이션의 유지 관리가 용이해집니다. 전체 콘텐츠 코드베이스를 검토해야 하는 정신적 부담 없이 단일 기능 폴더를 복제하거나 삭제할 수 있습니다. 또한 Intlayer는 완전히 유형되어 콘텐츠의 정확성을 보장합니다.

    콘텐츠를 같은 위치에 배치하면 LLM(대형 언어 모델)에 필요한 컨텍스트가 줄어듭니다. Intlayer에는 누락된 번역을 테스트하기 위한 CLI, LSP, MCPagent)와 같은 도구 모음도 함께 제공됩니다. 기술, AI 에이전트를 위한 개발자 경험(DX)을 더욱 원활하게 만듭니다.

    AI 공급자의 비용으로 선택한 LLM을 사용하여 CI/CD 파이프라인을 번역하려면 자동화를 사용하세요. Intlayer는 또한 콘텐츠 추출을 자동화하는 컴파일러백그라운드에서 번역을 돕는 웹 플랫폼을 제공합니다.

    대규모 JSON 파일을 구성 요소에 연결하면 성능 및 반응성 문제가 발생할 수 있습니다. Intlayer는 빌드 시 콘텐츠 로딩을 최적화합니다.

    Intlayer는 단순한 i18n 솔루션 그 이상으로 관리에 도움이 되는 자체 호스팅 비주얼 편집기전체 CMS를 제공합니다. 다국어 콘텐츠를 실시간으로 제공하여 번역가, 카피라이터, 기타 팀원과 원활하게 협업할 수 있습니다. 콘텐츠는 로컬 및/또는 원격으로 저장될 수 있습니다.


    왜 Storybook에서 Intlayer를 사용해야 하나요?

    Storybook은 UI 컴포넌트를 독립적으로 개발하고 문서화하기 위한 업계 표준 도구입니다. Intlayer와 결합하면 다음과 같은 이점이 있습니다:

    • 모든 로케일 미리보기: 도구 모음 스위처를 사용하여 Storybook 캔버스 내부에서 직접 확인할 수 있습니다.
    • 누락된 번역 감지: 프로덕션에 도달하기 전에 번역 누락을 확인할 수 있습니다.
    • 다국어 컴포넌트 문서화: 하드코딩된 문자열 대신 실제 형식이 안전한(type-safe) 콘텐츠를 사용하여 문서화할 수 있습니다.

    단계별 설정


    콘텐츠 선언

    각 컴포넌트 옆에 *.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");
      },
    };

    추가 리소스