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

    Intlayer avec Storybook

    Table des matières

    Pourquoi Intlayer plutôt que des alternatives ?

    Par rapport aux solutions principales telles que storybook-react-i18next ou i18next, Intlayer est une solution dotée d'optimisations intégrées telles que :

    Intlayer est optimisé pour fonctionner parfaitement avec Storybook en proposant des décorateurs d'histoires multilingues, un changement de paramètres régionaux et toutes les fonctionnalités nécessaires à la mise à l'échelle de l'internationalisation (i18n) dans votre système de conception.

    Au lieu de charger de lourds fichiers JSON dans vos pages, ne chargez que le contenu strictement nécessaire. Intlayer vous aide à réduire la taille de votre bundle et de vos pages jusqu'à 50 %.

    Déclarer le contenu directement au plus près de vos composants facilite la maintenance des applications de grande envergure. Vous pouvez dupliquer ou supprimer le dossier d'une fonctionnalité sans le fardeau mental de devoir passer en revue toute votre base de code de contenu. De plus, Intlayer est entièrement typé pour garantir l'exactitude de vos traductions.

    La colocalisation du contenu réduit le contexte nécessaire aux grands modèles de langage (LLM). Intlayer est également livré avec une suite d'outils, tels qu'une CLI pour vérifier les traductions manquantes, un LSP, un MCP et des agent skills, afin de rendre l'expérience développeur (DX) encore plus fluide pour les agents IA.

    Automatisez les traductions dans votre pipeline CI/CD en utilisant le LLM de votre choix au coût de votre propre fournisseur d'IA. Intlayer propose également un compilateur pour automatiser l'extraction de contenu, ainsi qu'une plateforme web pour vous aider à traduire en arrière-plan.

    Associer de gros fichiers JSON à vos composants peut ralentir les performances et impacter la réactivité. Intlayer optimise le chargement du contenu directement au moment du build.

    Bien plus qu'une simple solution i18n, Intlayer propose un éditeur visuel auto-hébergé et un CMS complet pour gérer votre contenu multilingue en temps réel. Cela rend la collaboration avec les traducteurs, concepteurs-rédacteurs et autres membres de l'équipe extrêmement simple. Le contenu peut être stocké localement et/ou à distance.


    Pourquoi utiliser Intlayer avec Storybook ?

    Storybook est l'outil standard de l'industrie pour développer et documenter des composants UI de manière isolée. Combiner Storybook avec Intlayer vous permet de :

    • Prévisualiser chaque langue directement dans le canvas Storybook à l'aide d'un sélecteur dans la barre d'outils.
    • Détecter les traductions manquantes avant qu'elles n'atteignent la production.
    • Documenter des composants multilingues avec un contenu réel et de type sécurisé plutôt qu'avec des chaînes de caractères codées en dur.

    Configuration étape par étape

    1. Installer les dépendances

      bash
      npm install intlayer react-intlayernpm install vite-intlayer --save-dev
      Paquet Rôle
      intlayer Cœur - configuration, compilation de contenu, CLI
      react-intlayer Liaisons React - IntlayerProvider, hook useIntlayer
      vite-intlayer Plugin Vite - surveille et compile les fichiers de contenu

    2. Créer une configuration Intlayer

      Créez intlayer.config.ts à la racine de votre projet (ou à l'intérieur de votre paquet design-system) :

      intlayer.config.ts
      import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [      Locales.ENGLISH,      Locales.FRENCH,      Locales.SPANISH,      // ajoutez d'autres langues si nécessaire    ],    defaultLocale: Locales.ENGLISH,  },  content: {    contentDir: ["./src"], // où se trouvent vos fichiers *.content.ts  },};export default config;
      Pour la liste complète des options, voir la référence de configuration.

    3. Ajouter le plugin Vite à Storybook

      Le hook viteFinal de Storybook vous permet d'étendre la configuration interne de Vite. Importez et ajoutez le plugin intlayer() ici :

      .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",    // …autres 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;

      Le plugin intlayer() surveille vos fichiers *.content.ts et reconstruit automatiquement les dictionnaires lors des changements pendant le développement Storybook.


    4. Ajouter le décorateur `IntlayerProvider` et une barre d'outils de langue

    5. Le fichier preview de Storybook est l'endroit idéal pour envelopper chaque story avec l' IntlayerProvider et exposer un sélecteur de langue dans la barre d'outils :

      .storybook/preview.tsx
      import type { Preview, StoryContext } from "@storybook/react";import { IntlayerProvider } from "react-intlayer";const preview: Preview = {  // Envelopper chaque story dans l'IntlayerProvider  decorators: [    (Story, context: StoryContext) => {      const locale = context.globals.locale ?? "en";      return (        <IntlayerProvider locale={locale}>          <Story />        </IntlayerProvider>      );    },  ],  // Exposer un sélecteur de langue dans la barre d'outils Storybook  globalTypes: {    locale: {      description: "Langue active",      defaultValue: "en",      toolbar: {        title: "Langue",        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;
      Les valeurs de locale doivent correspondre aux langues déclarées dans votre intlayer.config.ts.

      </Step>

      </Steps>

      Déclaration de contenu

      Créez un fichier *.content.ts à côté de chaque composant. Intlayer le détecte automatiquement pendant la compilation.

      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;
      Pour plus de formats de déclaration de contenu et de fonctionnalités, consultez la documentation de déclaration de contenu.

      Utilisation de useIntlayer dans un composant

      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}    >      Copier    </button>  );};

      useIntlayer renvoie le dictionnaire compilé pour la langue actuelle fournie par le IntlayerProvider le plus proche. Changer de langue dans la barre d'outils Storybook rafraîchit automatiquement la story avec les traductions mises à jour.


      Écrire des stories pour des composants internationalisés

      Avec le décorateur IntlayerProvider en place, vos stories fonctionnent exactement comme avant. La barre d'outils de langue contrôle la langue active pour tout le 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 par défaut - changez la langue dans la barre d'outils pour prévisualiser les traductions. */export const Default: Story = {  args: {    content: "npm install intlayer react-intlayer",  },};/** Affiche le bouton à l'intérieur d'un bloc de code, un cas d'utilisation courant. */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",  },};
      Chaque story hérite de la globale locale de la barre d'outils, vous pouvez donc vérifier chaque langue sans changer le code de la story.

      Tester les traductions dans les stories

      Utilisez les fonctions play de Storybook pour affirmer que le texte traduit correctement est affiché pour une langue donnée :

      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");    // Vérifier que le bouton a un nom accessible non vide    await expect(button).toHaveAccessibleName();    // Vérifier que le bouton n'est pas désactivé    await expect(button).not.toBeDisabled();    // Vérifier l'accessibilité au clavier    await expect(button).toHaveAttribute("tabindex", "0");  },};

      Ressources supplémentaires