Aller au contenu

Ajouter des fonctionnalités i18n

Dans cette recette, vous apprendrez à utiliser les collections de contenus et le routage dynamique pour construire votre propre solution d'internationalisation (i18n) et servir votre contenu dans différentes langues.

:::tipDans la version 4.0, Astro a ajouté une prise en charge intégrée pour le routage i18n permettant de configurer les langues par défaut et prises en charge, mais a aussi inclut des fonctions d'aide précieuses pour vous aider à servir un public international. Si vous souhaitez l'utiliser à la place, consultez notre guide d'internationalisation pour en savoir plus sur ces fonctionnalités.:::Cet exemple sert chaque langue dans son propre sous-chemin, par exemple example.com/en/blog pour l'anglais et example.com/fr/blog pour le français.

Si vous préférez que la langue par défaut ne soit pas visible dans l'URL contrairement aux autres langues, vous trouverez des instructions pour masquer la langue par défaut ci-dessous.

Consultez la section ressources pour trouver des liens externes liés à de sujets tels que le style de droite-à-gauche (RTL) et le choix des balises de langue.

Méthode

Créer des pages pour chaque langue

  1. Créez un répertoire pour chaque langue que vous souhaitez prendre en charge. Par exemple, en/ et fr/ si vous prenez en charge l'anglais et le français :

    • Répertoiresrc/
      • Répertoirepages/
        • Répertoireen/
          • about.astro
          • index.astro
        • Répertoirefr/
          • about.astro
          • index.astro
        • index.astro
  2. Configurez src/pages/index.astro pour rediriger vers votre langue par défaut.

      ---
      // src/pages/index.astro
      ---
      <meta http-equiv="refresh" content="0;url=/en/" />

    Cette approche utilise un meta refresh et fonctionnera quelle que soit la manière dont vous déployez votre site. Certains hôtes statiques vous permettent également de configurer les redirections du serveur à l'aide d'un fichier de configuration personnalisé. Consultez la documentation de votre plateforme de déploiement pour plus de détails.

Utiliser des collections pour le contenu traduit

  1. Créez un dossier dans src/content/ pour chaque type de contenu que vous voulez inclure et ajoutez des sous-répertoires pour chaque langue prise en charge. Par exemple, pour prendre en charge les articles de blog en anglais et en français :

    • Répertoiresrc/
      • Répertoirecontent/
        • Répertoireblog/
          • Répertoireen/ Articles de blog en anglais
            • post-1.md
            • post-2.md
          • Répertoirefr/ Articles de blog en français
            • post-1.md
            • post-2.md
  2. Créez un fichier src/content.config.ts et exporter une collection pour chaque type de contenu.

    //src/content.config.ts
    import { defineCollection } from 'astro:content';
    import { z } from 'astro/zod';
    
    const blogCollection = defineCollection({
      schema: z.object({
        title: z.string(),
        author: z.string(),
        date: z.date()
      })
    });
    
    export const collections = {
      'blog': blogCollection
    };

    En savoir plus sur les Collections de contenus.

  3. Utilisez les routes dynammiques pour récupérer et générer le contenu en fonction d'un paramètre lang et d'un paramètre slug.

    En mode de rendu statique, utilisez getStaticPaths pour faire correspondre chaque entrée de contenu à une page :

          //src/pages/[lang]/blog/[...slug].astro
          ---
          import { getCollection, render } from 'astro:content';
    
          export async function getStaticPaths() {
            const pages = await getCollection('blog');
    
            const paths = pages.map(page => {
              const [lang, ...slug] = page.id.split('/');
              return { params: { lang, slug: slug.join('/') || undefined }, props: page };
            });
    
            return paths;
          }
    
          const { lang, slug } = Astro.params;
          const page = Astro.props;
          const formattedDate = page.data.date.toLocaleString(lang);
          const { Content } = await render(page);
          ---
          <h1>{page.data.title}</h1>
          <p>par {page.data.author} • {formattedDate}</p>
          <Content/>

    En savoir plus sur les routes dynamiques.

    :::tip[Mise en forme de la date]L'exemple ci-dessus utilise la méthode intégrée de mise en forme de la date toLocaleString() pour créer une chaîne lisible par un humain à partir de la date de la page d'accueil.Cela permet de s'assurer que la date et l'heure sont formatées pour correspondre à la langue de l'utilisateur.:::

Traduire les chaînes de l'UI

Créez des dictionnaires de vocabulaire pour traduire les appellations des éléments de l'interface utilisateur de votre site. Cela permet à vos visiteurs de découvrir votre site dans leur langue.

  1. Créez un fichier src/i18n/ui.ts pour stocker vos chaînes de traduction :

    // src/i18n/ui.ts
    export const languages = {
      en: 'English',
      fr: 'Français',
    };
    
    export const defaultLang = 'en';
    
    export const ui = {
      en: {
        'nav.home': 'Home',
        'nav.about': 'About',
        'nav.twitter': 'Twitter',
      },
      fr: {
        'nav.home': 'Accueil',
        'nav.about': 'À propos',
      },
    } as const;
  2. Créez deux fonctions d'aide : une pour détecter la langue de la page basée sur l'URL courante, et une pour obtenir les chaînes de traduction pour les différentes parties de l'interface utilisateur dans src/i18n/utils.ts :

    // src/i18n/utils.ts
    import { ui, defaultLang } from './ui';
    
    export function getLangFromUrl(url: URL) {
      const [, lang] = url.pathname.split('/');
      if (lang in ui) return lang as keyof typeof ui;
      return defaultLang;
    }
    
    export function useTranslations(lang: keyof typeof ui) {
      return function t(key: keyof typeof ui[typeof defaultLang]) {
        return ui[lang][key] || ui[defaultLang][key];
      }
    }

    :::note[Avez-vous remarqué ?]À l'étape 1, la chaîne nav.twitter n'a pas été traduite en français. Il se peut que vous ne souhaitiez pas que tous les mots soient traduits, comme les noms propres ou les expressions courantes de la profession. L'aide useTranslations renvoie la valeur de la langue par défaut si une clé n'est pas traduite. Dans cet exemple, les utilisateurs français verront également « Twitter » dans la barre de navigation.:::

  3. Importez les aides là où elles sont nécessaires et utilisez-les pour choisir la chaîne de l'interface utilisateur qui correspond à la langue actuelle. Par exemple, un composant de navigation peut ressembler à ce qui suit :

    ---
    // src/components/Nav.astro
    import { getLangFromUrl, useTranslations } from '../i18n/utils';
    
    const lang = getLangFromUrl(Astro.url);
    const t = useTranslations(lang);
    ---
    <ul>
        <li>
            <a href={`/${lang}/home/`}>
              {t('nav.home')}
            </a>
        </li>
        <li>
            <a href={`/${lang}/about/`}>
              {t('nav.about')}
            </a>
        </li>
        <li>
            <a href="https://twitter.com/astrodotbuild">
              {t('nav.twitter')}
            </a>
        </li>
    </ul>
  4. Chaque page doit avoir un attribut lang sur l'élément <html> qui correspond à la langue de la page. Dans cet exemple, une mise en page réutilisable extrait la langue de la route actuelle :

    ---
    // src/layouts/Base.astro
    
    import { getLangFromUrl } from '../i18n/utils';
    
    const lang = getLangFromUrl(Astro.url);
    ---
    <html lang={lang}>
        <head>
            <meta charset="utf-8" />
            <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
            <meta name="viewport" content="width=device-width" />
            <title>Astro</title>
        </head>
        <body>
            <slot />
        </body>
    </html>

    Vous pouvez ensuite utiliser cette mise en page de base pour garantir que les pages utilisent automatiquement l'attribut lang correct.

    ---
    // src/pages/en/about.astro
    import Base from '../../layouts/Base.astro';
    ---
    <Base>
        <h1>À propos de moi</h1>
        ...
    </Base>

Permettre aux utilisateurs de passer d'une langue à l'autre

Créez des liens vers les différentes langues que vous prenez en charge afin que les utilisateurs puissent choisir la langue dans laquelle ils souhaitent lire votre site.

  1. Créez un composant pour afficher un lien pour chaque langue :

    ---
    // src/components/LanguagePicker.astro
    import { languages } from '../i18n/ui';
    ---
    <ul>
      {Object.entries(languages).map(([lang, label]) => (
        <li>
          <a href={`/${lang}/`}>{label}</a>
        </li>
      ))}
    </ul>
  2. Ajoutez <LanguagePicker /> à votre site pour qu'il apparaisse sur chaque page. L'exemple ci-dessous l'ajoute au pied de page du site dans une mise en page de base :

    ---
    // src/layouts/Base.astro
    import LanguagePicker from '../components/LanguagePicker.astro';
    import { getLangFromUrl } from '../i18n/utils';
    
    const lang = getLangFromUrl(Astro.url);
    ---
    <html lang={lang}>
        <head>
            <meta charset="utf-8" />
            <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
            <meta name="viewport" content="width=device-width" />
            <title>Astro</title>
        </head>
        <body>
            <slot />
            <footer>
              <LanguagePicker />
            </footer>
        </body>
    </html>

Masquer la langue par défaut dans l'URL

  1. Créez un répertoire pour chaque langue à l'exception de la langue par défaut. Par exemple, stockez vos pages dans la langue par défaut directement dans pages/, et vos pages traduites dans fr/ :

    • Répertoiresrc/
      • Répertoirepages/
        • about.astro
        • index.astro
        • Répertoirefr/
          • about.astro
          • index.astro
  2. Ajoutez une autre ligne au fichier src/i18n/ui.ts pour activer our désactiver la fonctionnalité :

    // src/i18n/ui.ts
    export const showDefaultLang = false;
  3. Ajoutez une fonction d'aide à src/i18n/utils.ts, pour traduire les chemins en fonction de la langue courante :

    // src/i18n/utils.ts
    import { ui, defaultLang, showDefaultLang } from './ui';
    
    export function useTranslatedPath(lang: keyof typeof ui) {
      return function translatePath(path: string, l: string = lang) {
        return !showDefaultLang && l === defaultLang ? path : `/${l}${path}`
      }
    }
  4. Importez l'aide là où c'est nécessaire. Par exemple, un composant nav peut ressembler à ceci :

    ---
    // src/components/Nav.astro
    import { getLangFromUrl, useTranslations, useTranslatedPath } from '../i18n/utils';
    
    const lang = getLangFromUrl(Astro.url);
    const t = useTranslations(lang);
    const translatePath = useTranslatedPath(lang);
    ---
    <ul>
        <li>
            <a href={translatePath('/home/')}>
              {t('nav.home')}
            </a>
        </li>
        <li>
            <a href={translatePath('/about/')}>
              {t('nav.about')}
            </a>
        </li>
        <li>
            <a href="https://twitter.com/astrodotbuild">
              {t('nav.twitter')}
            </a>
        </li>
    </ul>
  5. La fonction d'aide peut également être utilisée pour traduire des chemins d'accès dans une langue spécifique. Par exemple, lorsque les utilisateurs passent d'une langue à l'autre :

    ---
    // src/components/LanguagePicker.astro
    import { languages } from '../i18n/ui';
    import { getLangFromUrl, useTranslatedPath } from '../i18n/utils';
    
    const lang = getLangFromUrl(Astro.url);
    const translatePath = useTranslatedPath(lang);
    ---
    <ul>
      {Object.entries(languages).map(([lang, label]) => (
        <li>
          <a href={translatePath('/', lang)}>{label}</a>
        </li>
      ))}
    </ul>

Traduire les routes

Traduisez les routes de vos pages pour chaque langue.

  1. Ajouter les associations de routes dans src/i18n/ui.ts :

    // src/i18n/ui.ts
    export const routes = {
      de: {
        'services': 'leistungen',
      },
      fr: {
        'services': 'prestations-de-service',
      },
    }
  2. Mettre à jour la fonction d'aide useTranslatedPath dans src/i18n/utils.ts pour ajouter la logique de traduction du routeur.

    // src/i18n/utils.ts
    import { ui, defaultLang, showDefaultLang, routes } from './ui';
    
    export function useTranslatedPath(lang: keyof typeof ui) {
      return function translatePath(path: string, l: string = lang) {
        const pathName = path.replaceAll('/', '')
        const hasTranslation = defaultLang !== l && routes[l] !== undefined && routes[l][pathName] !== undefined
        const translatedPath = hasTranslation ? '/' + routes[l][pathName] : path
    
        return !showDefaultLang && l === defaultLang ? translatedPath : `/${l}${translatedPath}`
      }
    }
  3. Créer une fonction d'aide pour obtenir la route, si elle existe en fonction de l'URL actuelle, dans src/i18n/utils.ts :

    // src/i18n/utils.ts
    import { ui, defaultLang, showDefaultLang, routes } from './ui';
    
    export function getRouteFromUrl(url: URL): string | undefined {
      const pathname = new URL(url).pathname;
      const parts = pathname?.split('/');
      const path = parts.pop() || parts.pop();
    
      if (path === undefined) {
        return undefined;
      }
      
      const currentLang = getLangFromUrl(url);
    
      if (defaultLang === currentLang) {
        const route = Object.values(routes)[0];
        return route[path] !== undefined ? route[path] : undefined;
      }
      
      const getKeyByValue = (obj: Record<string, string>, value: string): string | undefined  => {
          return Object.keys(obj).find((key) => obj[key] === value);
      }
    
      const reversedKey = getKeyByValue(routes[currentLang], path);
    
      if (reversedKey !== undefined) {
        return reversedKey;
      }
    
      return undefined;
    }
  4. La fonction d'aide peut être utilisée pour obtenir une route traduite. Par exemple, si aucune route traduite n'est définie, l'utilisateur sera redirigé vers la page d'accueil :

    ---
    // src/components/LanguagePicker.astro
    import { languages } from '../i18n/ui';
    import { getRouteFromUrl, useTranslatedPath } from '../i18n/utils';
    
    const route = getRouteFromUrl(Astro.url);
    ---
    <ul>
      {Object.entries(languages).map(([lang, label]) => {
        const translatePath = useTranslatedPath(lang);
        return (
          <li>
            <a href={translatePath(`/${route ? route : ''}`)}>{label}</a>
          </li>
        )
      })}
    </ul>

Ressources

Bibliothèques communautaires

Retrouvez des utilitaires i18n créés par la communauté que vous pouvez ajouter à votre projet Astro dans notre répertoire d'intégrations.

Contribuer Communauté Parrainer