Creation:2026-03-20Last update:2026-05-31

    Intlayer com Storybook

    Índice

    Por que Intlayer em vez de alternativas?

    Comparado com soluções principais como storybook-react-i18next ou i18next, Intlayer é uma solução que vem com otimizações integradas como:

    O Intlayer é otimizado para funcionar perfeitamente com o Storybook, oferecendo decoradores de histórias multilíngues, alteração de local e todos os recursos necessários para dimensionar a internacionalização (i18n) em seu sistema de design.

    Em vez de carregar arquivos JSON enormes em suas páginas, carregue apenas o conteúdo necessário. O Intlayer ajuda a reduzir o tamanho do bundle e das páginas em até 50%.

    Definir o escopo do conteúdo do seu aplicativo facilita a manutenção de aplicativos de grande escala. Você pode duplicar ou excluir uma única pasta de recursos sem o fardo mental de revisar toda a base de código de seu conteúdo. Além disso, o Intlayer é totalmente tipado (fully typed) para garantir a precisão do seu conteúdo.

    A co-localização de conteúdo reduz o contexto necessário pelos Large Language Models (LLMs). O Intlayer também vem com um conjunto de ferramentas, como uma CLI para testar traduções ausentes,LSP, MCP, e habilidades do agente, para tornar a experiência do desenvolvedor (DX) ainda mais tranquila para os agentes de IA.

    Use a automação para traduzir seu pipeline de CI/CD usando o LLM de sua escolha às custas de seu provedor de IA. O Intlayer também oferece um compilador para automatizar a extração de conteúdo, bem como uma plataforma web para ajudar a traduzir em segundo plano.

    Conectar arquivos JSON enormes a componentes pode levar a problemas de desempenho e reatividade. O Intlayer otimiza o carregamento do seu conteúdo no momento da construção.

    Mais do que apenas uma solução i18n, o Intlayer fornece um [editor visual] auto-hospedado(/pt/doc/concept/editor) e um CMS completo para ajudá-lo a gerenciar seu conteúdo multilíngue em tempo real, facilitando a colaboração com tradutores, redatores e outros membros da equipe. O conteúdo pode ser armazenado local e/ou remotamente.


    Porquê usar o Intlayer com o Storybook?

    O Storybook é a ferramenta padrão da indústria para desenvolver e documentar componentes de UI isoladamente. Combiná-lo com o Intlayer permite-lhe:

    • Visualizar cada local diretamente dentro do canvas do Storybook usando um seletor na barra de ferramentas.
    • Detetar traduções em falta antes de chegarem à produção.
    • Documentar componentes multilíngues com conteúdo real e seguro em termos de tipos, em vez de strings codificadas rigidamente.

    Configuração Passo a Passo

    1. Instalar Dependências

      bash
      npm install intlayer react-intlayernpm install vite-intlayer --save-dev
      Pacote Função
      intlayer Core - configuração, compilação de conteúdo, CLI
      react-intlayer Bindings React - IntlayerProvider, hook useIntlayer
      vite-intlayer Plugin Vite - monitoriza e compila ficheiros de declaração de conteúdo

    2. Criar uma Configuração do Intlayer

      Crie intlayer.config.ts na raiz do seu projeto (ou dentro do seu pacote de design system):

      intlayer.config.ts
      import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [      Locales.ENGLISH,      Locales.FRENCH,      Locales.SPANISH,      // adicione mais locais conforme necessário    ],    defaultLocale: Locales.ENGLISH,  },  content: {    contentDir: ["./src"], // onde os seus ficheiros *.content.ts residem  },};export default config;
      Para a lista completa de opções, consulte a referência de configuração.

    3. Adicionar o Plugin Vite ao Storybook

      O hook viteFinal do Storybook permite-lhe estender a configuração interna do Vite. Importe e adicione o plugin intlayer() aqui:

      .storybook/main.ts
      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",    // …outros addons  ],  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;

      O plugin intlayer() monitoriza os seus ficheiros *.content.ts e reconstrói os dicionários automaticamente sempre que houver alterações durante o desenvolvimento no Storybook.


    4. Adicionar o Decorador `IntlayerProvider` e uma Barra de Ferramentas de Local

    5. O ficheiro preview do Storybook é o local ideal para envolver cada story com o IntlayerProvider e expor um seletor de local na barra de ferramentas:

      .storybook/preview.tsx
      import type { Preview, StoryContext } from "@storybook/react";import { IntlayerProvider } from "react-intlayer";const preview: Preview = {  // Envolver cada story dentro do IntlayerProvider  decorators: [    (Story, context: StoryContext) => {      const locale = context.globals.locale ?? "en";      return (        <IntlayerProvider locale={locale}>          <Story />        </IntlayerProvider>      );    },  ],  // Expor um seletor de local na barra de ferramentas do Storybook  globalTypes: {    locale: {      description: "Local ativo",      defaultValue: "en",      toolbar: {        title: "Local",        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;
      Os valores de locale devem coincidir com os locais declarados no seu intlayer.config.ts.

      </Step>

      </Steps>

      Declarar Conteúdo

      Crie um ficheiro *.content.ts ao lado de cada componente. O Intlayer deteta-o automaticamente durante a compilação.

      src/components/CopyButton/CopyButton.content.ts
      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;
      Para mais formatos e funcionalidades de declaração de conteúdo, consulte a documentação de declaração de conteúdo.

      Usar useIntlayer num Componente

      src/components/CopyButton/index.tsx
      "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}    >      Copiar    </button>  );};

      O useIntlayer retorna o dicionário compilado para o local atual fornecido pelo IntlayerProvider mais próximo. Alterar o local na barra de ferramentas do Storybook volta a renderizar automaticamente a story com as traduzioni atualizadas.


      Escrever Stories para Componentes Internacionalizados

      Com o decorador IntlayerProvider configurado, as suas stories funcionam exatamente como antes. A barra de ferramentas de local controla o local ativo para todo o canvas:

      src/components/CopyButton/CopyButton.stories.tsx
      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>;/** Story padrão - altere o local na barra de ferramentas para visualizar as traduções. */export const Default: Story = {  args: {    content: "npm install intlayer react-intlayer",  },};/** Renderiza o botão dentro de um bloco de código, um caso de uso comum no mundo real. */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",  },};
      Cada story herda a variável global locale da barra de ferramentas, para que possa verificar cada local sem alterar qualquer código da story.

      Testar Traduções em Stories

      Use as funções play do Storybook para garantir que o texto traduzido corretamente é renderizado para um determinado local:

      src/components/CopyButton/CopyButton.stories.tsx
      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");    // Verificar se o botão tem um nome acessível não vazio    await expect(button).toHaveAccessibleName();    // Verificar se o botão não está desativado    await expect(button).not.toBeDisabled();    // Verificar a acessibilidade do teclado    await expect(button).toHaveAttribute("tabindex", "0");  },};

      Recursos Adicionais