Posez votre question et obtenez un résumé du document en referencant cette page et le Provider AI de votre choix
Historique des versions
- "Version initiale"v9.5.1026/09/2026
Le contenu de cette page a été traduit à l'aide d'une IA.
Voir la dernière version du contenu original en anglaisSi vous avez une idée d’amélioration pour améliorer cette documentation, n’hésitez pas à contribuer en submitant une pull request sur GitHub.
Lien GitHub de la documentationCopier le Markdown du doc dans le presse-papiers
Comment internationaliser votre application TanStack Start avec Lingui en 2026
Table des Matières
Qu'est-ce que Lingui ?
Lingui est une bibliothèque d'i18n conçue autour des macros et de l'extraction de messages. Vous écrivez le texte source directement dans vos composants ( t`Hello` , <Trans>Hello</Trans>), lingui extract rassemble chaque message dans des catalogues (fichiers PO par défaut), les traducteurs les remplissent, et le plugin Vite les compile en JavaScript compact. Les messages utilisent ICU MessageFormat, donc les pluriels et les sélections sont pris en charge.
TanStack Start n'intègre pas de couche d'i18n par défaut, ce guide configure donc Lingui de zéro :
- Macros compilées par Babel via
@rolldown/plugin-babel(requis avec@vitejs/plugin-reactv6 et Vite 8). - Routage par locale avec un segment optionnel
{-$locale}(/about,/fr/about). - Un catalogue par locale, chargé à la demande, et une instance
I18npar rendu afin que les requêtes SSR concurrentes ne partagent jamais de locale. - SEO multilingue complet :
<title>et description traduits, URL canonique,hreflangavecx-default, locales Open Graph, JSON-LD, sitemap,robots.txt, pré-rendu et pages 404 localisées.
Vous recherchez une autre stack ? Consultez le guide TanStack Start + use-intl, le guide TanStack Start + Paraglide ou le guide TanStack Start + Intlayer.
Vous utilisez Next.js ? Consultez le guide Next.js + Lingui. Vous comparez les bibliothèques ? Lisez Lingui vs Intlayer.
Ce que dit le benchmark sur Lingui avec TanStack Start
Le benchmark i18n exécute la même application TanStack Start de 10 pages et 10 locales avec chaque bibliothèque majeure et mesure ce que le navigateur télécharge réellement.
Chargement JSON dynamique
Charge les traductions à la volée
JSON scopé (espaces de noms)
Espaces de noms de traduction par page
Benchmark de Performance I18n
Quelle est cette métrique ?
La taille totale compressée en gzip du bundle de la bibliothèque d’internationalisation. Elle n’inclut que le fournisseur et la logique de récupération de contenu après tree-shaking et minification.
Pourquoi est-ce important ?
Une taille de bibliothèque plus petite réduit la charge utile JavaScript initiale, ce qui accélère le téléchargement et le temps d’exécution sur le client.
Voir comme
Chiffres clés pour @lingui/core@6.6.0, mesurés le 2026-09-26 (gzip) :
Ouvrir le tableau dans une fenêtre modale pour voir tout le contenu clairement
| Configuration | Taille de la bibliothèque | JS par page | Fuite d'autres locales | Fuite d'autres pages |
|---|---|---|---|---|
| Sans i18n (application de base) | - | 111.0 KB | 0% | 0% |
| Lingui (configuration de ce guide) | 56.7 KB | 115.2 KB | 9.3% | 0% |
@intlayer/lingui (compat) | 9.8 KB | 136.7 KB | 9.9% | 0% |
react-intlayer (Intlayer natif) | 4.5 KB | 126.8 KB | 0% | 0% |
Ce qu'il faut retenir :
- Chargez un catalogue par locale, à la demande. Cela maintient les pages proches de la taille de l'application de base.
- Le runtime reste lourd (~57 KB gzip). L'adaptateur de compatibilité
@intlayer/lingui(étape 16) conserve vos macros et le réduit à ~10 KB.
Voir les données complètes : Rapport de benchmark TanStack Start, et le dépôt du benchmark.
Comparaison des fonctionnalités sur TanStack Start
Comment Lingui se compare aux autres bibliothèques couramment utilisées sur TanStack Start :
Ouvrir le tableau dans une fenêtre modale pour voir tout le contenu clairement
| Fonctionnalité | react-intlayer (Intlayer) | use-intl | Paraglide JS | Lingui |
|---|---|---|---|---|
| Traductions proches des composants | ✅ Colocalisées | ❌ JSON centralisé | ❌ Un fichier JSON par locale | ⚠️ Texte source dans les composants |
| Intégration TypeScript | ✅ Types auto-générés | ✅ Via AppConfig | ✅ Fonctions de message typées | ⚠️ Macros uniquement |
| Détection des traductions manquantes | ✅ Erreurs de type et avertissements de build | ⚠️ Fallback au runtime | ⚠️ Repli sur la locale de base | ⚠️ Repli sur le texte source |
| Contenu riche (JSX, Markdown) | ✅ Support direct | ⚠️ Balises via t.rich | ⚠️ Chaînes de caractères | ✅ JSX dans <Trans> |
| Routage localisé | ✅ Intégré | ❌ {-$locale} manuel | ✅ urlPatterns + réécriture routeur | ❌ {-$locale} manuel |
| Changement de locale sans rechargement | ✅ Oui | ✅ Oui | ❌ Rechargement complet de la page | ✅ Oui |
| Pluralisation | ✅ Basée sur l'énumération | ✅ ICU | ✅ Variantes | ✅ ICU |
| ICU MessageFormat | ✅ Via format: "icu" | ✅ Natif | ⚠️ Via un plugin inlang | ✅ Natif |
| Formats de contenu | ✅ .ts, .json, .md, .yaml... | ⚠️ .json | ⚠️ JSON inlang | ✅ PO, JSON, CSV |
| Traduction par IA | ✅ Votre propre fournisseur et clé | ❌ Non | ❌ Non | ❌ Non |
| Éditeur visuel / CMS | ✅ Éditeur local + CMS optionnel | ❌ Plateformes externes | ⚠️ Applications de l'écosystème inlang | ❌ Plateformes externes |
| Aides SEO (hreflang, sitemap) | ✅ Intégré | ❌ Manuel | ⚠️ URLs localisées, reste manuel | ❌ Manuel |
| Taille du runtime (gzip, benchmark) | 4.5 KB | 75.9 KB | 1.8 KB | 56.7 KB |
| Fuite, meilleure config (locale / page) | 0% / 0% | 0% / 0% | 49.7% / 0% | 8.6% / 0% |
| Traductions manquantes en CI | ✅ npx intlayer test | ⚠️ Non intégré | ⚠️ Non intégré | ✅ lingui compile --strict |
Les chiffres de taille de runtime et de fuite proviennent du benchmark TanStack Start. La fuite est mesurée sur la meilleure configuration de chaque bibliothèque.
Autres guides TanStack Start : use-intl, Paraglide JS, et Intlayer.
Bonnes pratiques à suivre
- Définissez
langetdirsur<html>à partir de la locale de la route, afin qu'ils soient corrects dans le HTML du serveur. - Conservez une URL par locale avec un préfixe, afin que chaque version linguistique soit indexable.
- Créez une instance
I18npar locale, ne modifiez jamais une instance globale pendant le SSR : deux requêtes concurrentes écraseraient mutuellement leur locale. - Chargez uniquement le catalogue actif, n'importez jamais l'ensemble des catalogues dans le code client.
- Choisissez un style de macro (
useLingui+tdans les composants,msgpour les descripteurs différés) et tenez-vous-y. Mélangert,i18n._,i18n.tet<Trans>rend le code plus difficile à lire pour les humains et les assistants IA. - Exécutez
lingui extractdans la CI pour qu'aucun nouveau message ne soit déployé sans traduction. - Traduisez vos métadonnées, et déclarez
canonical,hreflangetx-defaultsur chaque page. - Générez un sitemap multilingue et un robots.txt, et pré-rendez chaque locale.
- Utilisez de vrais liens pour le sélecteur de langue, afin que les robots d'indexation découvrent chaque langue.
Consultez notre guide sur l'internationalisation et le SEO et le guide hreflang.
Guide étape par étape pour configurer Lingui dans une application TanStack Start
Voici la structure de projet que nous allons créer :
Copier le code dans le presse-papiers
Installer les dépendances
bashCopier le codeCopier le code dans le presse-papiers
- @lingui/core / @lingui/react : runtime,
I18nProvideret les macros (@lingui/core/macro,@lingui/react/macro). - @lingui/cli :
lingui extractpour collecter les messages dans les catalogues. - @lingui/vite-plugin : compile les catalogues
.poà l'import,lingui compilen'est donc pas nécessaire. - @lingui/babel-plugin-lingui-macro + @rolldown/plugin-babel : transforment les macros au moment du build.
- @lingui/core / @lingui/react : runtime,
Centraliser votre configuration de locale
La locale par défaut reste sans préfixe (
/about), les autres locales sont préfixées (/fr/about).src/i18n/config.tsCopier le codeCopier le code dans le presse-papiers
Configurer Lingui
La configuration Lingui réutilise la même liste de locales, afin que les catalogues, le routeur et le sitemap soient toujours synchronisés.
lingui.config.tsCopier le codeCopier le code dans le presse-papiers
Ajoutez les scripts d'extraction :
package.jsonCopier le codeCopier le code dans le presse-papiers
i18n:checkéchoue en CI lorsqu'un composant contient un message qui n'a pas été extrait et commité.Configurer Vite
Avec
@vitejs/plugin-reactv6, Babel n'est plus intégré.@rolldown/plugin-babelexécute le plugin de macro Lingui, etlinguiTransformerBabelPresettraite uniquement les fichiers qui importent une macro, ce qui garantit des builds rapides.vite.config.tsCopier le codeCopier le code dans le presse-papiers
Charger les catalogues par locale
Le template literal dans
import()permet à Vite de générer un chunk par catalogue, et le plugin Lingui y compile le fichier.po. Un visiteur français ne télécharge que le catalogue français.Les messages compilés sont de simples données, ils peuvent donc être retournés par un loader de route, sérialisés dans le HTML et réutilisés lors de l'hydratation.
src/i18n/lingui.tsCopier le codeCopier le code dans le presse-papiers
Pour que TypeScript accepte l'import
.po, déclarez le module une fois :src/i18n/po.d.tsCopier le codeCopier le code dans le presse-papiers
Créer le document racine
La route racine lit le paramètre de locale optionnel pour définir
langetdirsur la balise<html>rendue côté serveur.src/routes/__root.tsxCopier le codeCopier le code dans le presse-papiers
Créer la route de layout de locale
Le dossier
{-$locale}crée un segment de chemin optionnel :/aboutet/fr/aboutcorrespondent tous deux à/{-$locale}/about. Le layout rejette les préfixes inconnus, charge le catalogue de la locale actuelle et fournit une instanceI18ndédiée.src/routes/{-$locale}/route.tsxCopier le codeCopier le code dans le presse-papiers
Utiliser les traductions dans vos pages
Écrivez le texte source dans le composant. Les macros le transforment en identifiants de message au moment du build, et
lingui extractles récupère.<Trans>pour le contenu JSX, y compris les éléments imbriqués ;useLingui().tpour les chaînes de caractères (attributs, props) ;<Plural>pour les pluriels ICU.
src/routes/{-$locale}/about.tsxCopier le codeCopier le code dans le presse-papiers
L'
import()dynamique d'un catalogue est mis en cache par le système de modules, donc appelerloadI18ndans plusieurs loaders ne télécharge pas le catalogue deux fois.Extraire et traduire vos messages
Exécutez l'extraction. Lingui écrit chaque message dans le catalogue de chaque locale :
bashCopier le codeCopier le code dans le presse-papiers
Traduisez ensuite le
msgstrde chaque entrée :src/locales/fr/messages.poCopier le codeCopier le code dans le presse-papiers
src/locales/es/messages.poCopier le codeCopier le code dans le presse-papiers
Par défaut, les identifiants de message sont des hachages du texte source : modifier le texte anglais crée un nouveau message. Utilisez des identifiants explicites (
<Trans id="about.title">About us</Trans>) pour les textes qui changent souvent.Créer un composant de lien localisé
FacultatifChaque route réside sous
{-$locale}, les liens doivent donc transmettre le paramètre de locale actuelle.src/components/LocalizedLink.tsxCopier le codeCopier le code dans le presse-papiers
Changer la langue de votre contenu
FacultatifAffichez le sélecteur sous forme de liens, afin que les moteurs de recherche découvrent chaque version linguistique.
to="."conserve la page actuelle et remplace le paramètre de locale. Le loader du layout de locale récupère ensuite le nouveau catalogue.src/components/LocaleSwitcher.tsxCopier le codeCopier le code dans le presse-papiers
Internationaliser vos métadonnées
FacultatifChaque version linguistique peut se positionner de manière autonome, à condition que chaque page expose un
<title>et une description traduits, une balise canonique auto-référencée, unhreflangpar locale plusx-default, les locales Open Graph, et JSON-LD avecinLanguage. Les métadonnées sont traduites dans le loader (étape 8), et cet utilitaire construit le reste :src/i18n/seo.tsCopier le codeCopier le code dans le presse-papiers
Internationaliser votre sitemap et robots.txt
FacultatifLe sitemap liste chaque URL de chaque locale, chaque entrée déclarant toutes ses alternatives avec
xhtml:link.robots.txtbloque les routes privées dans chaque langue et pointe vers le sitemap. Supprimezpublic/robots.txtsi le starter en a créé un.src/routes/sitemap[.]xml.tsCopier le codeCopier le code dans le presse-papiers
src/routes/robots[.]txt.tsCopier le codeCopier le code dans le presse-papiers
Pré-rendre chaque locale
FacultatifListez chaque chemin localisé afin que TanStack Start pré-rende toutes les versions linguistiques au moment du build :
vite.config.tsCopier le codeCopier le code dans le presse-papiers
Rediriger les nouveaux visiteurs et gérer les pages 404
FacultatifUn middleware de requête redirige un visiteur arrivant sur
/vers sa langue préférée (le cookie en priorité, puisAccept-Language). Les liens profonds ne sont jamais redirigés, garantissant ainsi que les moteurs de recherche et les URLs partagées obtiennent toujours la page demandée.src/i18n/negotiateLocale.tsCopier le codeCopier le code dans le presse-papiers
src/start.tsCopier le codeCopier le code dans le presse-papiers
Pour les pages 404, une route fourre-tout rend le
notFoundComponentlocalisé du layout. Marquez-la avecnoindex: React 19 hisse la balise<meta>dans<head>.src/components/NotFound.tsxCopier le codeCopier le code dans le presse-papiers
src/routes/{-$locale}/$.tsxCopier le codeCopier le code dans le presse-papiers
Conserver vos macros, réduire le runtime avec Intlayer
FacultatifL'adaptateur de compatibilité
@intlayer/linguiconserve votre code source intact : les macros se compilent exactement comme avant, et les appelsi18n._(),useLingui()et<Trans>résultants sont pris en charge par les dictionnaires Intlayer compilés. Dans le benchmark, le runtime passe de ~56.7 KB à ~9.8 KB gzip.bashCopier le codeCopier le code dans le presse-papiers
Ajoutez le plugin après la transformation des macros, afin qu'il crée un alias de
@lingui/coreet@lingui/reactvers l'adaptateur :vite.config.tsCopier le codeCopier le code dans le presse-papiers
Les catalogues sont synchronisés avec le plugin sync JSON (catalogues JSON) ou le plugin sync PO (catalogues PO). Retrouvez la configuration complète dans le guide de compatibilité Lingui, ainsi qu'une comparaison côte à côte dans Lingui vs @intlayer/lingui.
Automatiser vos traductions avec Intlayer
FacultatifLingui extrait les messages, mais remplir des dizaines de catalogues à la main représente la majeure partie du temps passé. Intlayer est gratuit et open source, et ses outils fonctionnent en harmonie avec Lingui :
- Traduire avec l'IA en utilisant votre propre clé API et fournisseur. Voir auto-remplissage et la CLI.
- Conserver vos fichiers PO comme source de vérité avec le plugin sync PO.
- Tester les traductions manquantes en CI. Voir tester vos traductions.
- Auditer votre site déployé pour détecter les
hreflangmanquants, les URLs canoniques incorrectes et les fuites de locale avec la commande scan.
Foire Aux Questions
Oui. Lingui ne propose pas d'intégration dédiée à TanStack Start, mais son plugin Vite et son plugin de macros Babel fonctionnent directement. Les deux points essentiels à respecter consistent à exécuter les macros via @rolldown/plugin-babel (Vite 8 et @vitejs/plugin-react v6 n'incluant plus Babel), et à créer une instance I18n par locale plutôt que d'activer une instance globale pendant le SSR.
Côté serveur, un processus traite de nombreuses requêtes simultanément. Appeler i18n.activate("fr") sur un objet partagé changerait la langue d'une requête en cours de rendu en anglais en parallèle. setupI18n crée une instance isolée par locale, ce qui est totalement sûr.
Non. @lingui/vite-plugin compile les catalogues .po dès qu'ils sont importés. Vous n'avez besoin d'exécuter lingui extract que pour collecter de nouveaux messages.
Déclarez-les avec la macro msg, et traduisez-les dans le loader de route avec i18n._(msg`...`). Le loader retourne de simples chaînes de caractères, ce qui permet à head() de rester synchrone et aux valeurs d'être sérialisées pour l'hydratation. L'étape 8 et l'étape 12 présentent la configuration complète.
Le benchmark mesure ~56.7 KB gzip pour le runtime. Avec un catalogue par locale chargé à la demande, les pages pèsent ~115 KB contre 111 KB sans i18n. Importer statiquement chaque catalogue fait monter la taille à ~152 KB.
Oui. L'adaptateur @intlayer/lingui conserve les macros et remplace le runtime. Vous pouvez ensuite migrer vos composants vers useIntlayer progressivement. Consultez les adaptateurs de compatibilité.
Commentaires
Aucun commentaire pour le moment. Soyez le premier à partager vos pensées.
