Auteur:
    Création:2025-08-06Dernière mise à jour:2026-08-06

    Traduire votre site SolidStart avec Intlayer | Internationalisation (i18n)

    www.youtube.com

    Table des matières

    Ce guide couvre une application SolidStart rendue côté serveur : la détection de la locale se fait lors de la requête, les pages sont rendues sur le serveur dans la bonne langue, et les signaux <html lang>, hreflang et sitemap dont les moteurs de recherche ont besoin sont émis côté serveur.

    Pourquoi Intlayer plutôt que des alternatives ?

    Par rapport aux principales solutions comme @solid-primitives/i18n ou i18next, Intlayer est une solution qui intègre des optimisations comme :

    Intlayer est optimisé pour fonctionner parfaitement avec Solid en offrant un ciblage du contenu au niveau des composants, des traductions réactives, et toutes les fonctionnalités nécessaires pour faire évoluer l'internationalisation (i18n).

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

    Cibler le contenu de votre application facilite la maintenance pour les applications à grande échelle. Vous pouvez dupliquer ou supprimer un dossier de fonctionnalité individuel sans la charge mentale de vérifier l'ensemble de votre base de code de contenu. De plus, Intlayer est entièrement typé pour garantir l'exactitude de votre contenu.

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

    Utilisez l'automatisation pour traduire dans votre pipeline CI/CD en utilisant le LLM de votre choix au coût de votre 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.

    Connecter de volumineux fichiers JSON à des composants peut entraîner des problèmes de performance et de réactivité. Intlayer optimise le chargement de votre contenu au moment du build.

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


    Guide étape par étape pour configurer Intlayer dans une application SolidStart

    1. Installer les dépendances

      Installez les paquets nécessaires en utilisant npm :

      bash
      npx intlayer init --interactive
      Le drapeau --interactive est optionnel. Utilisez intlayer-cli init si vous êtes un agent IA.
      Cette commande détectera votre environnement et installera les paquets requis. Par exemple :
      bash
      npm install intlayer solid-intlayer vite-intlayer
      • intlayer

        Le paquet principal qui fournit des outils d'internationalisation pour la gestion de la configuration, la traduction, la déclaration de contenu, la transpilation et les commandes CLI.

      • solid-intlayer

        Le paquet qui intègre Intlayer avec l'application Solid. Il fournit des fournisseurs de contexte et des hooks pour l'internationalisation Solid.

      • vite-intlayer

        Inclut le plugin Vite pour intégrer Intlayer avec le bundler Vite, ainsi que le gestionnaire de routage de locale qui détecte la locale préférée de l'utilisateur, gère les cookies et s'occupe de la redirection d'URL.

      vite-intlayer est ici une préoccupation côté serveur, et pas seulement au moment du build : il fournit le gestionnaire de requête exécuté par le serveur Nitro de SolidStart. Le conserver dans dependencies est l'option sécurisée par défaut — vous ne pouvez le déplacer dans devDependencies que si vous déployez le répertoire .output construit, dans lequel Nitro intègre le gestionnaire.
    2. Configuration de votre projet

      Créez un fichier de configuration pour configurer les langues de votre application :

      intlayer.config.ts
      import { type IntlayerConfig, Locales } from "intlayer";
      
      const config: IntlayerConfig = {
        internationalization: {
          locales: [
            Locales.ENGLISH,
            Locales.FRENCH,
            Locales.SPANISH,
            // Vos autres locales
          ],
          defaultLocale: Locales.ENGLISH,
        },
        routing: {
          mode: "prefix-no-default",
        },
      };
      
      export default config;

      Avec prefix-no-default, la locale par défaut est servie depuis des URL sans préfixe :

      plaintext
      /            /about          → Anglais  (locale par défaut)/fr          /fr/about       → Français/es          /es/about       → Espagnol
      Grâce à ce fichier de configuration, vous pouvez configurer les URL localisées, la redirection middleware, les noms de cookies, l'emplacement et l'extension de vos déclarations de contenu, désactiver les logs Intlayer dans la console, et plus encore. Pour une liste complète des paramètres disponibles, reportez-vous à la documentation de configuration.
    3. Intégrer Intlayer dans votre configuration Vite

      Ajoutez le plugin Intlayer à votre configuration :

      vite.config.ts
      import { solidStart } from "@solidjs/start/config";
      import { nitro } from "nitro/vite";
      import { defineConfig } from "vite";
      import { intlayer } from "vite-intlayer";
      
      export default defineConfig({
        plugins: [solidStart(), nitro(), intlayer()],
      });
      Le plugin Vite intlayer() construit vos fichiers de déclaration de contenu, les surveille en mode développement et définit les variables d'environnement Intlayer dans l'application. Il fournit également des alias qui optimisent les performances.

      Le routage de locale est inclus avec le plugin

      SolidStart fonctionne sur Nitro, et intlayer() enregistre son gestionnaire de routage de locale directement dans le pipeline serveur de Nitro (via l'option routing.enableProxy, à true par défaut). Rien d'autre à câbler : sur un serveur construit, chaque requête est inspectée avant d'atteindre le routeur, et

      • la locale est lue depuis le préfixe de l'URL, puis le cookie INTLAYER_LOCALE, puis l'en-tête Accept-Language ;
      • une URL non préfixée est redirigée vers sa contrepartie localisée lorsque la locale résolue n'est pas celle par défaut (//fr) ;
      • une URL préfixée de manière redundante est redirigée vers sa forme canonique (/en/about/about) ;
      • le cookie de locale est réécrit sur la réponse.
    4. Déclarer votre contenu

      Créez et gérez vos déclarations de contenu pour stocker les traductions :

      src/contents/home.content.ts
      import { type Dictionary, t } from "intlayer";
      
      const homeContent = {
        key: "home-page",
        content: {
          title: t({
            en: "Hello world!",
            fr: "Bonjour le monde !",
            es: "¡Hola mundo!",
          }),
          metaTitle: "SolidStart + Intlayer",
          metaDescription: t({
            en: "A SolidStart application internationalized with Intlayer.",
            fr: "Une application SolidStart internationalisée avec Intlayer.",
            es: "Una aplicación SolidStart internacionalizada con Intlayer.",
          }),
          documentation: t({
            en: "Visit start.solidjs.com to learn how to build SolidStart apps.",
            fr: "Visitez start.solidjs.com pour apprendre à créer des applications SolidStart.",
            es: "Visita start.solidjs.com para aprender a crear aplicaciones SolidStart.",
          }),
        },
      } satisfies Dictionary;
      
      export default homeContent;
      ⚠️ Piège spécifique à SolidStart : chaque fichier .ts / .tsx sous src/routes devient une route, et un fichier .content.ts a un export par défaut, donc il serait considéré comme une page. Conservez les déclarations de contenu de vos pages en dehors du répertoire des routes (src/contents/ fonctionne très bien). Le contenu des composants peut rester colocalisé, car src/components n'est pas scanné par le routeur basé sur le système de fichiers.

      Vos déclarations de contenu peuvent être définies n'importe où dans votre application dès lors qu'elles sont incluses dans le répertoire contentDir (par défaut, ./src), et correspondent à l'extension de fichier de déclaration de contenu (par défaut, .content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml}).

      Pour plus de détails, reportez-vous à la documentation de déclaration de contenu.

    5. Ajouter le routage localisé

      L'objectif de cette étape est de donner à chaque langue sa propre URL, ce que les moteurs de recherche indexent.

      Déplacez vos pages sous un segment dynamique optionnel. Dans le routeur basé sur le système de fichiers de SolidStart, [[locale]] se compile selon le motif de chemin :locale? :

      plaintext
      src/routes/  [[locale]].tsx          ← layout qui valide le segment  [[locale]]/    index.tsx             → /        et /fr        et /es    about.tsx             → /about   et /fr/about  et /es/about  [...404].tsx            → catch-all pour tout le reste

      Le seul rôle du fichier de layout est de restreindre le segment à une locale configurée :

      src/routes/[[locale]].tsx
      import type { RouteSectionProps } from "@solidjs/router";import { locales } from "intlayer";export const route = {  matchFilters: {    locale: locales,  },};export default function LocaleLayout(props: RouteSectionProps) {  return <>{props.children}</>;}

      @solidjs/router développe :locale? en deux motifs — un avec le segment et un sans — et les tente par ordre de spécificité décroissante. matchFilters est ce qui fait la différence entre une configuration fonctionnelle et une configuration confuse :

      URL Sans matchFilters Avec matchFilters
      /fr/about Page à propos en français Page à propos en français
      /about Page à propos (le segment statique gagne) Page à propos
      /unknown Page d'accueil, silencieusement, avec locale=unknown Pas de correspondance → passe au 404 global
      Préférez [locale] (obligatoire) à [[locale]] si vous utilisez le mode de routage 'prefix-all', et supprimez complètement le segment pour 'no-prefix' ou 'search-params'.
    6. Fournir la locale à votre application

      L'URL est la source unique de vérité pour la locale : le middleware a déjà redirigé la requête vers son chemin localisé, donc lire le chemin dans le layout racine maintient le rendu serveur et l'hydratation client en accord, et permet à chaque navigation côté client de mettre à jour la locale gratuitement.

      src/app.tsx
      import { MetaProvider } from "@solidjs/meta";import { Router, useLocation } from "@solidjs/router";import { FileRoutes } from "@solidjs/start/router";import { defaultLocale, getHTMLTextDir, getLocaleFromPath } from "intlayer";import { IntlayerProvider } from "solid-intlayer";import { createEffect, type ParentProps, Suspense } from "solid-js";import { isServer } from "solid-js/web";import { Nav } from "~/components/Nav";import "./app.css";const RootLayout = (props: ParentProps) => {  const location = useLocation();  const locale = () => getLocaleFromPath(location.pathname) ?? defaultLocale;  // Le serveur rend <html> dans entry-server.tsx ; les navigations côté client  // entre les locales doivent mettre à jour les attributs elles-mêmes.  createEffect(() => {    if (isServer) return;    document.documentElement.lang = locale();    document.documentElement.dir = getHTMLTextDir(locale());  });  return (    <MetaProvider>      <IntlayerProvider locale={locale()}>        <Nav />        <Suspense>{props.children}</Suspense>      </IntlayerProvider>    </MetaProvider>  );};export default function App() {  return (    <Router root={RootLayout}>      <FileRoutes />    </Router>  );}
      IntlayerProvider réagit à sa prop locale, donc passer l'appel d'accesseur locale() dans le JSX est suffisant — Solid le compile en un getter, et l'ensemble de l'arbre se ré-affiche dans la nouvelle langue lorsque l'URL change.
    7. Définir les attributs HTML lang et dir sur le serveur

      L'élément <html> est rendu par entry-server.tsx, en dehors du Router. Lisez plutôt la locale depuis l'URL de la requête :

      src/entry-server.tsx
      // @refresh reloadimport { createHandler, StartServer } from "@solidjs/start/server";import { defaultLocale, getHTMLTextDir, getLocaleFromPath } from "intlayer";import { getRequestEvent } from "solid-js/web";export default createHandler(() => (  <StartServer    document={({ assets, children, scripts }) => {      const url = getRequestEvent()?.request.url ?? "/";      const locale = getLocaleFromPath(url) ?? defaultLocale;      return (        <html dir={getHTMLTextDir(locale)} lang={locale}>          <head>            <meta charset="utf-8" />            <meta              name="viewport"              content="width=device-width, initial-scale=1"            />            <link rel="icon" href="/favicon.ico" />            {assets}          </head>          <body>            <div id="app">{children}</div>            {scripts}          </body>        </html>      );    }}  />));

      Les robots d'indexation reçoivent désormais la bonne langue dès le premier octet :

      html
      <html dir="ltr" lang="fr"></html>
    8. Utiliser Intlayer dans vos pages

      Accédez à vos dictionnaires de contenu dans l'ensemble de votre application :

      src/routes/[[locale]]/index.tsx
      import { Meta, Title } from "@solidjs/meta";import { useIntlayer } from "solid-intlayer";import Counter from "~/components/Counter";export default function Home() {  const content = useIntlayer("home-page");  return (    <main>      <Title>{content.metaTitle.value}</Title>      <Meta content={content.metaDescription.value} name="description" />      <h1>{content.title}</h1>      <Counter />      <p>{content.documentation}</p>    </main>  );}
      Dans Solid, useIntlayer renvoie du contenu réactif (ex. content). Vous pouvez accéder directement à ses propriétés.

      Si vous souhaitez utiliser votre contenu dans un attribut string, tel que alt, title, href, aria-label, etc., vous pouvez utiliser la valeur de la fonction, comme :

      html
      <img src="{content.image.src.value}" alt="{content.image.value}" /><img src="{content.image.src.toString()}" alt="{content.image.toString()}" /><img src="{String(content.image.src)}" alt="{String(content.image)}" />
      Pour en savoir plus sur le hook useIntlayer, reportez-vous à la documentation.

      Les nœuds de contenu ne se limitent pas à de simples traductions. Un compteur pluralisé, par exemple :

      src/components/Counter.content.ts
      import { type Dictionary, plural, t } from "intlayer";const counterContent = {  key: "counter",  content: {    clicks: plural({      one: t({        en: "{{count}} click",        fr: "{{count}} clic",        es: "{{count}} clic",      }),      other: t({        en: "{{count}} clicks",        fr: "{{count}} clics",        es: "{{count}} clics",      }),    }),  },} satisfies Dictionary;export default counterContent;
      src/components/Counter.tsx
      import { useIntlayer } from "solid-intlayer";import { createSignal } from "solid-js";export default function Counter() {  const [count, setCount] = createSignal(0);  const content = useIntlayer("counter");  return (    <button onClick={() => setCount(count() + 1)} type="button">      {content.clicks(count())}    </button>  );}

      plural() sélectionne la catégorie via Intl.PluralRules pour la locale active, ainsi les langues ayant plus de deux formes pluriel fonctionnent sans aucun code supplémentaire.

    9. Créez un composant Link personnalisé qui préfixe automatiquement les URL internes avec la langue actuelle :

      src/components/LocalizedLink.tsx
      import { A, type AnchorProps } from "@solidjs/router";import { getLocalizedUrl } from "intlayer";import { useLocale } from "solid-intlayer";import type { ParentComponent } from "solid-js";export const LocalizedLink: ParentComponent<AnchorProps> = (props) => {  const { locale } = useLocale();  const isExternal = () => /^[a-z][a-z0-9+.-]*:/i.test(props.href);  const localizedHref = () =>    isExternal() ? props.href : getLocalizedUrl(props.href, locale());  return <A {...props} href={localizedHref()} />;};
      src/components/Nav.tsx
      import { useIntlayer } from "solid-intlayer";import type { Component } from "solid-js";import { LocaleSwitcher } from "./LocaleSwitcher";import { LocalizedLink } from "./LocalizedLink";export const Nav: Component = () => {  const content = useIntlayer("nav");  return (    <nav>      <LocalizedLink href="/">{content.home}</LocalizedLink>      <LocalizedLink href="/about">{content.about}</LocalizedLink>      <LocaleSwitcher />    </nav>  );};

      Écrire href="/about" une seule fois produit désormais /about, /fr/about ou /es/about selon la locale active — aucun préfixage manuel n'est nécessaire dans vos pages.

    10. Créer un composant de changement de locale

      Rendez le sélecteur sous forme de vrais ancres plutôt qu'un <select> : chaque langue de la page actuelle devient un lien explorable pouvant être ouvert dans un nouvel onglet, ce qu'un contrôle uniquement basé sur JavaScript ne peut pas offrir.

      getPathWithoutLocale supprime le segment de locale du chemin actuel, et getLocalizedUrl le reconstruit pour la locale cible, afin que les liens suivent votre mode de routage sans rien coder en dur. La navigation est ce qui modifie la locale rendue — la route [[locale]] la déduit de l'URL — tandis que setLocale persiste le choix dans le cookie INTLAYER_LOCALE afin qu'une visite ultérieure sur une URL sans locale soit résolue dans la même langue.

      src/components/LocaleSwitcher.tsx
      import { A, useLocation } from "@solidjs/router";
      import {
        getHTMLTextDir,
        getLocaleName,
        getLocalizedUrl,
        getPathWithoutLocale,
      } from "intlayer";
      import { useIntlayer, useLocale } from "solid-intlayer";
      import { type Component, For } from "solid-js";
      
      export const LocaleSwitcher: Component = () => {
        const content = useIntlayer("locale-switcher");
        const location = useLocation();
        const { locale, setLocale, availableLocales } = useLocale();
      
        // Chemin canonique (sans locale) de la page actuellement affichée
        const pathWithoutLocale = () => getPathWithoutLocale(location.pathname);
      
        return (
          <div>
            <button
              aria-label={content.label.value}
              popoverTarget="localePopover"
              type="button"
            >
              {getLocaleName(locale())}
            </button>
            <div id="localePopover" popover="auto">
              <For each={availableLocales}>
                {(localeItem) => (
                  <A
                    dir={getHTMLTextDir(localeItem)}
                    // Correspondance exacte uniquement, afin que le lien de la locale par défaut ne soit pas marqué
                    // actif sur chaque page
                    end
                    href={getLocalizedUrl(pathWithoutLocale(), localeItem)}
                    hreflang={localeItem}
                    lang={localeItem}
                    onClick={() => setLocale(localeItem)}
                    // S'assure que le bouton "retour" du navigateur revienne à la page précédente
                    replace
                  >
                    {/* Langue dans sa propre locale - ex. Français */}
                    {getLocaleName(localeItem)}
                  </A>
                )}
              </For>
            </div>
          </div>
        );
      };

      Dans Solid, locale provenant de useLocale est un accesseur de signal. Utilisez locale() (avec parenthèses) pour lire sa valeur actuelle de manière réactive.

      getLocaleName(localeItem) rend chaque langue dans sa propre langue — English / Français / Español. Passez un second argument pour traduire les noms dans la langue actuellement affichée à la place : getLocaleName(localeItem, locale()) donne English / French / Spanish en anglais, anglais / français / espagnol en français.

      <A> définit déjà aria-current="page" sur le lien correspondant à l'URL actuelle, il n'y a donc rien à ajouter pour cela. replace est lu depuis l'attribut rendu par le routeur : il remplace l'entrée d'historique au lieu d'en ajouter une, ainsi le bouton "retour" du navigateur revient à la page visitée avant le changement plutôt qu'à la même page dans la langue précédente.

      dir et hreflang sur chaque lien permettent de conserver les noms de langues de droite à gauche correctement orientés et d'indiquer aux technologies d'assistance et aux robots d'indexation la langue vers laquelle pointe chaque lien.

      Pour en savoir plus sur le hook useLocale, reportez-vous à la documentation.

    11. Émettre les liens canoniques et hreflang

      Facultatif

      Les annotations hreflang indiquent aux moteurs de recherche que /about, /fr/about et /es/about représentent la même page dans des langues différentes. getMultilingualUrls les déduit du chemin canonique (sans locale), en suivant votre mode de routage, afin que rien ne soit codé en dur :

      src/components/AlternateLinks.tsx
      import {  defaultLocale,  getMultilingualUrls,  getPathWithoutLocale,} from "intlayer";import { type Component, For } from "solid-js";export type AlternateLinksProps = {  /** URL absolue de la page en cours de rendu. */  url: string;};export const AlternateLinks: Component<AlternateLinksProps> = (props) => {  const multilingualUrls = () => {    const { origin, pathname } = new URL(props.url);    return Object.entries(      getMultilingualUrls(`${origin}${getPathWithoutLocale(pathname)}`)    );  };  const canonicalUrl = () =>    new URL(props.url).origin + new URL(props.url).pathname;  return (    <>      <link href={canonicalUrl()} rel="canonical" />      <For each={multilingualUrls()}>        {([locale, localizedUrl]) => (          <link href={localizedUrl} hreflang={locale} rel="alternate" />        )}      </For>      <link        href={          multilingualUrls().find(([locale]) => locale === defaultLocale)?.[1]        }        hreflang="x-default"        rel="alternate"      />    </>  );};

      Rendez-le dans l'en-tête du document, où l'URL de la requête est disponible :

      src/entry-server.tsx
      import { AlternateLinks } from "~/components/AlternateLinks";// … à l'intérieur de <head>, à côté des autres balises meta :<AlternateLinks url={url} />;

      GET /fr/about sert alors :

      html
      <link href="https://example.com/fr/about" rel="canonical" /><link href="https://example.com/about" hreflang="en" rel="alternate" /><link href="https://example.com/fr/about" hreflang="fr" rel="alternate" /><link href="https://example.com/es/about" hreflang="es" rel="alternate" /><link href="https://example.com/about" hreflang="x-default" rel="alternate" />
      Note sur @solidjs/meta : au moment d'écrire ces lignes, <Title> et <Meta> de @solidjs/meta sont appliqués sur le client après l'hydratation mais ne sont pas émis dans le <head> rendu côté serveur dans SolidStart v2. En attendant que cela soit corrigé en amont, rendez les balises que les robots doivent voir sans JavaScript — canonical, hreflang, et si nécessaire title / description — directement dans entry-server.tsx, comme montré ci-dessus.
    12. Gérer les pages non trouvées

      Facultatif

      Une route splat à la racine de src/routes intercepte tous les chemins que le segment de locale n'a pas fait correspondre — y compris les préfixes de locale invalides rejetés par matchFilters. Parce que la locale provient toujours de l'URL à travers le layout racine, la page 404 est affichée dans la langue du visiteur :

      src/routes/[...404].tsx
      import { Title } from "@solidjs/meta";import { HttpStatusCode } from "@solidjs/start";import { useIntlayer } from "solid-intlayer";import { LocalizedLink } from "~/components/LocalizedLink";export default function NotFound() {  const content = useIntlayer("not-found-page");  return (    <main>      <Title>{content.metaTitle.value}</Title>      <HttpStatusCode code={404} />      <h1>{content.title}</h1>      <LocalizedLink href="/">{content.backHome}</LocalizedLink>    </main>  );}
      Requête Résultat
      /xx 404xx n'est pas une locale configurée
      /nonexistent 404 dans la locale par défaut
      /fr/nonexistent 404 en français (Page introuvable)
    13. Générer un sitemap multilingue

      Facultatif

      Le générateurs de sitemap d'Intlayer étend chaque chemin en une entrée par locale et câble les alternatives xhtml:link entre elles, de sorte que la route n'a qu'à lister les chemins canoniques sans locale.

      Contrairement aux générateurs de base qui n'émettent que des URL plates, Intlayer câble des liens bidirectionnels entre chaque variante localisée de chaque page, ce qui aide les moteurs de recherche à relier les URL localisées et à servir la bonne au bon public.

      SolidStart transforme un fichier exportant une méthode HTTP en route d'API, et supprime l'extension .ts du chemin — ainsi src/routes/sitemap.xml.ts est servi sur /sitemap.xml :

      src/routes/sitemap.xml.ts
      import type { APIEvent } from "@solidjs/start/server";
      import { generateSitemap } from "intlayer";
      
      const SITE_URL = process.env.SITE_URL ?? "http://localhost:3000";
      
      export const GET = (_event: APIEvent) => {
        const sitemap = generateSitemap(
          [
            { path: "/", changefreq: "daily", priority: 1.0 },
            { path: "/about", changefreq: "monthly", priority: 0.8 },
          ],
          { siteUrl: SITE_URL }
        );
      
        return new Response(sitemap, {
          headers: { "Content-Type": "application/xml" },
        });
      };
      sortie de GET /sitemap.xml
      <?xml version="1.0" encoding="UTF-8"?><urlset  xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"  xmlns:xhtml="http://www.w3.org/1999/xhtml">  <url>    <loc>https://example.com/about</loc>    <changefreq>monthly</changefreq>    <priority>0.8</priority>    <xhtml:link rel="alternate" hreflang="en" href="https://example.com/about"/>    <xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/about"/>    <xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/about"/>    <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/about"/>  </url></urlset>
      Les routes d'API ne prennent pas en charge les paramètres optionnels, conservez donc ce fichier à la racine de src/routes, en dehors du segment [[locale]]. Le sitemap contient déjà chaque locale.

      Vous pouvez construire un robots.txt de la même manière avec getMultilingualUrls, de sorte que les entrées Disallow couvraient chaque orthographe localisée d'un chemin sensible :

      src/routes/robots.txt.ts
      import { getMultilingualUrls } from "intlayer";
      
      const SITE_URL = process.env.SITE_URL ?? "http://localhost:3000";
      
      const disallowedPaths = ["/admin", "/private"].flatMap((path) =>
        Object.values(getMultilingualUrls(path))
      );
      
      export const GET = () =>
        new Response(
          [
            "User-agent: *",
            "Allow: /",
            ...disallowedPaths.map((path) => `Disallow: ${path}`),
            "",
            `Sitemap: ${SITE_URL}/sitemap.xml`,
          ].join("\n"),
          { headers: { "Content-Type": "text/plain" } }
        );
    14. Récupérer la locale dans vos fonctions serveur

      Facultatif

      Vous souhaiterez peut-être accéder à la locale actuelle depuis une fonction serveur ou une route d'API.

      Dans une configuration basée sur des préfixes comme celle-ci, l'URL fait foi : getLocaleFromPath lit le préfixe depuis l'URL de la requête. getLocale est la solution de repli pour les requêtes qui ne portent pas de préfixe de locale — elle inspecte le cookie INTLAYER_LOCALE, puis l'en-tête x-intlayer-locale, puis négocie Accept-Language.

      src/routes/[[locale]]/index.tsx
      import { createAsync } from "@solidjs/router";import { getCookie, getIntlayer, getLocale, getLocaleFromPath } from "intlayer";import { getRequestEvent } from "solid-js/web";const loadLocalizedData = async () => {  "use server";  const request = getRequestEvent()?.request;  const locale =    getLocaleFromPath(request?.url) ??    (await getLocale({      // Récupérer le cookie depuis la requête (par défaut : 'INTLAYER_LOCALE')      getCookie: (name) =>        getCookie(name, request?.headers.get("cookie") ?? ""),      // Récupérer l'en-tête depuis la requête (par défaut : 'x-intlayer-locale'),      // avec repli sur la négociation Accept-Language      getHeader: (name) => request?.headers.get(name) ?? undefined,    }));  // Récupérer du contenu en dehors d'un composant en utilisant getIntlayer()  const content = getIntlayer("home-page", locale);  return { locale, title: String(content.title) };};export default function Page() {  const data = createAsync(() => loadLocalizedData());  return <p>{data()?.title}</p>;}
      Ne vous fiez pas uniquement à getLocale ici : le cookie de locale n'est écrit qu'une fois qu'un visiteur change activement de langue, donc une première visite sur /fr/... serait résolue avec la locale par défaut.
    15. Extraire le contenu de vos composants

      Facultatif

      Si vous avez une base de code existante, transformer des milliers de fichiers peut prendre du temps.

      Pour faciliter ce processus, Intlayer propose un compilateur / extracteur pour transformer vos composants et en extraire le contenu.

      Pour le configurer, vous pouvez ajouter une section compiler dans votre fichier intlayer.config.ts :

      intlayer.config.ts
      import { type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        // ... Reste de votre configuration
        compiler: {
          /**
           * Indique si le compilateur doit être activé.
           */
          enabled: true,
      
          /**
           * Définit le chemin des fichiers de sortie
           */
          output: ({ fileName, extension }) => `./${fileName}${extension}`,
      
          /**
           * Indique si les composants doivent être enregistrés après avoir été transformés.
           *
           * - Si `true`, le compilateur réécrira le fichier du composant sur le disque. La transformation sera donc permanente et le compilateur ignorera la transformation lors du processus suivant. De cette façon, le compilateur peut transformer l'application, puis être retiré.
           *
           * - Si `false`, le compilateur injectera l'appel de fonction `useIntlayer()` dans le code dans le résultat du build uniquement, et gardera la base de code intacte. La transformation sera effectuée uniquement en mémoire.
           */
          saveComponents: false,
      
          /**
           * Préfixe de clé de dictionnaire
           */
          dictionaryKeyPrefix: "",
        },
      };
      
      export default config;

      Exécutez l'extracteur pour transformer vos composants et extraire le contenu

      bash
      npx intlayer extract
      Déplacez ensuite les fichiers de contenu générés de vos pages hors de src/routes, pour la raison expliquée à l'étape 5.
    16. Configurer TypeScript

      Intlayer utilise l'augmentation de module pour bénéficier des avantages de TypeScript et rendre votre base de code plus solide.

      Assurez-vous que votre configuration TypeScript inclut les types générés automatiquement :

      tsconfig.json
      {  compilerOptions: {    // ... vos configurations existantes  },  include: [    "src",    "*.ts",    ".intlayer/**/*.ts", // Inclure les types générés automatiquement  ],}

      Les clés de dictionnaire et les chemins de contenu sont désormais vérifiés au moment de la compilation :

      tsx
      useIntlayer("home-page"); // ✅useIntlayer("hom-page"); // ❌ Argument of type '"hom-page"' is not assignable to parameter of type 'keyof __DictionaryRegistry'

    Vérification de votre configuration

    Construisez et démarrez le serveur, puis vérifiez que ces requêtes se comportent comme prévu :

    bash
    npm run buildnode .output/server/index.mjs
    Requête Réponse attendue
    GET / 200 — Anglais
    GET / avec Accept-Language: fr 302/fr
    GET / avec cookie INTLAYER_LOCALE=es 302/es
    GET /fr 200 — Français, <html lang="fr">
    GET /fr/about 200 — Page à propos en français
    GET /en/about 302/about (redirection canonique)
    GET /xx 404
    GET /fr/nonexistent 404 en français
    GET /sitemap.xml 200 — Sitemap XML multilingue

    Les lignes qui rendent une page se comportent à l'identique sous vite dev. Les trois lignes de redirection s'appliquent uniquement à un serveur construit, sauf si vous enregistrez vous-même le gestionnaire comme middleware — voir l'étape 3.

    Exécutez le serveur dev sur Node (vite dev) plutôt que sur Bun (bun --bun vite dev) : le SSR de SolidStart échoue actuellement sous le runtime Bun avec Expected a Response object, but received 'NodeResponse'. Ceci n'a aucun lien avec Intlayer — cela se reproduit sur le modèle de base — et n'affecte que le serveur dev, pas vite build.

    Configuration Git

    Il est recommandé d'ignorer les fichiers générés par Intlayer. Cela vous permet d'éviter de les commiter dans votre dépôt Git.

    Pour ce faire, vous pouvez ajouter les instructions suivantes à votre fichier .gitignore :

    .gitignore
    # Ignorer les fichiers générés par Intlayer.intlayer

    Extension VS Code

    Pour améliorer votre expérience de développement avec Intlayer, vous pouvez installer l'extension VS Code officielle Intlayer.

    Installer depuis le VS Code Marketplace

    Cette extension fournit :

    • L'autocomplétion pour les clés de traduction.
    • La détection d'erreurs en temps réel pour les traductions manquantes.
    • Aperçus en ligne du contenu traduit.
    • Actions rapides pour créer et mettre à jour facilement les traductions.

    Pour aller plus loin

    Pour aller plus loin, vous pouvez implémenter l'éditeur visuel ou externaliser votre contenu à l'aide du CMS.


    Références de documentation