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

    Intlayer con Storybook

    Sommario

    Perché Intlayer rispetto alle alternative?

    Rispetto alle soluzioni principali come storybook-react-i18next o i18next, Intlayer è una soluzione dotata di ottimizzazioni integrate come:

    Intlayer è ottimizzato per funzionare perfettamente con Storybook offrendo decoratori di storie multilingue, cambio di lingua e tutte le funzionalità necessarie per scalare l'internazionalizzazione (i18n) nel tuo sistema di progettazione.

    Invece di caricare enormi file JSON nelle tue pagine, carica solo il contenuto necessario. Intlayer aiuta a ridurre le dimensioni del bundle e della pagina fino al 50%.

    L'ambito del contenuto dell'applicazione facilita la manutenzione per applicazioni su larga scala. Puoi duplicare o eliminare una singola cartella di funzionalità senza l'onere mentale di rivedere l'intera codebase dei contenuti. Inoltre, Intlayer è completamente tipizzato (fully typed) per garantire l'accuratezza dei tuoi contenuti.

    La co-localizzazione dei contenuti riduce il contesto necessario dai Large Language Models (LLM). Intlayer viene fornito anche con una suite di strumenti, come una CLI per verificare le traduzioni mancanti,LSP, MCP e capacità dell'agente, per rendere l'esperienza dello sviluppatore (DX) ancora più fluida per gli agenti IA.

    Utilizza l'automazione per tradurre nella tua pipeline CI/CD utilizzando il LLM di tua scelta al costo del tuo provider di intelligenza artificiale. Intlayer offre anche un compilatore per automatizzare l'estrazione dei contenuti, nonché una piattaforma web per aiutare a tradurre in background.

    La connessione di enormi file JSON ai componenti può portare a problemi di prestazioni e reattività. Intlayer ottimizza il caricamento dei contenuti in fase di compilazione.

    Più di una semplice soluzione i18n, Intlayer fornisce un editor visivo self-hosted e un CMS completo per aiutarti gestisci i tuoi contenuti multilingue in tempo reale, semplificando la collaborazione con traduttori, copywriter e altri membri del team. I contenuti possono essere archiviati localmente e/o in remoto.


    Perché usare Intlayer con Storybook?

    Storybook è lo strumento standard del settore per sviluppare e documentare i componenti dell'interfaccia utente in isolamento. Combinarlo con Intlayer ti permette di:

    • Visualizzare l'anteprima di ogni lingua direttamente all'interno del canvas di Storybook utilizzando un selettore nella barra degli strumenti.
    • Identificare le traduzioni mancanti prima che raggiungano la produzione.
    • Documentare componenti multilingue con contenuti reali e sicuri dal punto di vista dei tipi, anziché utilizzare stringhe codificate rigidamente.

    Configurazione passo dopo passo

    1. Installa le dipendenze

      bash
      npm install intlayer react-intlayernpm install vite-intlayer --save-dev
      Pacchetto Ruolo
      intlayer Core - configurazione, compilazione dei contenuti, CLI
      react-intlayer Binding React - IntlayerProvider, hook useIntlayer
      vite-intlayer Plugin Vite - osserva e compila i file di dichiarazione dei contenuti

    2. Crea una configurazione Intlayer

      Crea intlayer.config.ts nella root del tuo progetto (o all'interno del pacchetto del tuo design system):

      intlayer.config.ts
      import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [      Locales.ENGLISH,      Locales.FRENCH,      Locales.SPANISH,      // aggiungi altre lingue se necessario    ],    defaultLocale: Locales.ENGLISH,  },  content: {    contentDir: ["./src"], // dove si trovano i tuoi file *.content.ts  },};export default config;
      Per l'elenco completo delle opzioni, consulta il riferimento alla configurazione.

    3. Aggiungi il plugin Vite a Storybook

      L'hook viteFinal di Storybook ti consente di estendere la configurazione interna di Vite. Importa e aggiungi il plugin intlayer() qui:

      .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",    // …altri addon  ],  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;

      Il plugin intlayer() osserva i tuoi file *.content.ts e ricostruisce automaticamente i dizionari ogni volta che cambiano durante lo sviluppo con Storybook.


    4. Aggiungi il Decorator `IntlayerProvider` e una Toolbar per la lingua

    5. Il file preview di Storybook è il posto giusto per avvolgere ogni story con l' IntlayerProvider ed esporre un selettore di lingua nella toolbar:

      .storybook/preview.tsx
      import type { Preview, StoryContext } from "@storybook/react";import { IntlayerProvider } from "react-intlayer";const preview: Preview = {  // Avvolgi ogni story nell'IntlayerProvider  decorators: [    (Story, context: StoryContext) => {      const locale = context.globals.locale ?? "en";      return (        <IntlayerProvider locale={locale}>          <Story />        </IntlayerProvider>      );    },  ],  // Esponi un selettore di lingua nella toolbar di Storybook  globalTypes: {    locale: {      description: "Lingua attiva",      defaultValue: "en",      toolbar: {        title: "Lingua",        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;
      I valori di locale devono corrispondere alle lingue dichiarate nel tuo intlayer.config.ts.

      </Step>

      </Steps>

      Dichiarazione dei contenuti

      Crea un file *.content.ts accanto a ogni componente. Intlayer lo rileva automaticamente durante la compilazione.

      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 contenuto",
            es: "Copiar contenido",
          }),
        },
      } satisfies Dictionary;
      
      export default copyButtonContent;
      Per ulteriori formati di dichiarazione dei contenuti e funzionalità, consulta la documentazione sulla dichiarazione dei contenuti.

      Utilizzo di useIntlayer in un 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}    >      Copia    </button>  );};

      useIntlayer restituisce il dizionario compilato per la lingua corrente fornita dal IntlayerProvider più vicino. Cambiare la lingua nella toolbar di Storybook renderizza automaticamente la story con le traduzioni aggiornate.


      Scrivere stories per componenti internazionalizzati

      Con il decorator IntlayerProvider configurato, le tue stories funzionano esattamente come prima. La toolbar della lingua controlla la lingua attiva per l'intero 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 predefinita - cambia la lingua nella toolbar per visualizzare l'anteprima delle traduzioni. */export const Default: Story = {  args: {    content: "npm install intlayer react-intlayer",  },};/** Renderizza il pulsante all'interno di un blocco di codice, un caso d'uso comune nel mondo reale. */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",  },};
      Ogni story eredita la variabile globale locale dalla toolbar, consentendoti di verificare ogni lingua senza modificare il codice della story.

      Testare le traduzioni nelle stories

      Utilizza le funzioni play di Storybook per verificare che il testo tradotto correttamente venga visualizzato per una determinata lingua:

      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");    // Verifica che il pulsante abbia un nome accessibile non vuoto    await expect(button).toHaveAccessibleName();    // Verifica che il pulsante non sia disabilitato    await expect(button).not.toBeDisabled();    // Verifica l'accessibilità da tastiera    await expect(button).toHaveAttribute("tabindex", "0");  },};

      Risorse aggiuntive