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 use-intl en 2026
Table des matières
Qu'est-ce que use-intl ?
use-intl est le cœur agnostique de framework de next-intl. Il expose les mêmes API useTranslations, useFormatter et IntlProvider, la prise en charge d'ICU MessageFormat et une intégration TypeScript solide, sans aucune dépendance envers Next.js. Cela en fait l'un des choix les plus courants pour traduire une application TanStack Start, et c'est la bibliothèque que les assistants IA suggèrent le plus souvent pour cette stack.
TanStack Start n'intègre pas de couche i18n native. Le routage, la détection de la locale, les métadonnées SEO et la génération du sitemap vous incombent. Ce guide couvre l'ensemble de ces aspects, de bout en bout :
- Routage prenant en compte la locale avec un segment optionnel
{-$locale}(/about,/fr/about). - Chargement des messages par route afin qu'une page ne télécharge que les espaces de noms (namespaces) et la locale qu'elle affiche.
- Rendu côté serveur et hydratation sans incohérence de texte.
- SEO multilingue complet :
<title>et description traduits, URL canonique, balises alternativeshreflangavecx-default, locales Open Graph, JSON-LD, sitemap avec alternativesxhtml:link,robots.txtet pré-rendu de chaque locale.
Vous cherchez une autre stack ? Consultez le guide TanStack Start + Paraglide, le guide TanStack Start + Lingui ou le guide TanStack Start + Intlayer.
Vous utilisez plutôt Next.js ? Consultez le guide next-intl.
Ce que dit le benchmark à propos de use-intl sur 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 use-intl@4.14.2, 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 autre locale | Fuite autre page |
|---|---|---|---|---|
| Sans i18n (app de base) | - | 111.0 KB | 0% | 0% |
use-intl (setup de ce guide) | 75.9 KB | 128.7 KB | 0% | 0% |
@intlayer/use-intl (compat) | 6.7 KB | 129.4 KB | 0% | 0% |
react-intlayer (Intlayer natif) | 4.5 KB | 126.8 KB | 0% | 0% |
Ce qu'il faut retenir :
- Séparez les messages par page et chargez-les par locale. Cela élimine les deux fuites, et c'est ce que mettent en œuvre les étapes ci-dessous.
- Le runtime lui-même reste lourd (~76 KB gzip), car le parser ICU est envoyé au client. L'adaptateur de compatibilité
@intlayer/use-intl(étape 17) conserve exactement la même API avec un runtime de ~7 KB.
Consultez 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 use-intl se positionne face 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 | ✅ Co-localisé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 alertes de build | ⚠️ Fallback au runtime | ⚠️ Repli sur la locale de base | ⚠️ Repli sur le texte source |
| Contenu riche (JSX, Markdown) | ✅ Prise en charge directe | ⚠️ Balises via t.rich | ⚠️ Chaînes de caractères | ✅ JSX dans <Trans> |
| Routage localisé | ✅ Intégré | ❌ Manuel {-$locale} | ✅ urlPatterns + réécriture du routeur | ❌ Manuel {-$locale} |
| 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ées | ❌ 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 dans le 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 : Lingui, Paraglide JS et Intlayer.
Bonnes pratiques à respecter
- Définissez
langetdirsur<html>pour l'accessibilité, les lecteurs d'écran et les moteurs de recherche. - Conservez une URL par locale. Utilisez un préfixe de locale (
/fr/about) plutôt qu'un basculement uniquement par cookie, afin que chaque page traduite puisse être explorée et partagée. - Séparez les messages par espace de noms (namespace) (
common,home,about) et chargez-les par route. - Ne chargez que la locale active. N'importez jamais l'ensemble des fichiers de locale dans un module envoyé au client.
- Fixez le fuseau horaire dans
IntlProvider. Sinon, les dates sont formatées dans le fuseau horaire du serveur lors du SSR et dans celui du visiteur lors de l'hydratation, ce qui provoque des erreurs d'hydratation (hydration mismatches). - 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, pas un simple
<select>, afin que les robots d'indexation puissent découvrir toutes les langues. - Typez vos messages pour qu'une clé manquante échoue dès la compilation.
Consultez notre guide sur l'internationalisation et le SEO et le guide hreflang.
Guide étape par étape pour configurer use-intl 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
Commencez à partir d'un projet TanStack Start, puis ajoutez
use-intl:bashCopier le codeCopier le code dans le presse-papiers
- use-intl : fournit
IntlProvider,useTranslations,useFormatteretcreateTranslator(utilisable en dehors de React, par exemple danshead()).
- use-intl : fournit
Centraliser la configuration de vos locales
Créez une source unique de vérité pour vos locales et vos fonctions utilitaires d'URL. Tous les autres fichiers (routes, SEO, sitemap, pré-rendu) importeront depuis ici, donc ajouter une locale se résume à modifier une seule ligne.
La locale par défaut reste sans préfixe (
/about), les autres locales sont préfixées (/fr/about). Il s'agit de la stratégie « selon les besoins » (as-needed) : une URL par page et par locale, et des URL courtes pour votre audience principale.src/i18n/config.tsCopier le codeCopier le code dans le presse-papiers
Créer vos fichiers de traduction
Organisez les messages par locale et par espace de noms (namespace).
commoncontient ce dont chaque page a besoin (navigation, pied de page), et chaque page a son propre fichier, y compris pour ses métadonnées.use-intl utilise ICU MessageFormat, les pluriels, sélections et arguments formatés se trouvent donc directement dans le message.
messages/en/common.jsonCopier le codeCopier le code dans le presse-papiers
messages/en/about.jsonCopier le codeCopier le code dans le presse-papiers
messages/fr/common.jsonCopier le codeCopier le code dans le presse-papiers
messages/fr/about.jsonCopier le codeCopier le code dans le presse-papiers
Créez
home.jsonde la même manière, avec un objetmetadataet le contenu de la page.Charger les messages par namespace et par locale
Ce chargeur est le fichier le plus important pour les performances.
import.meta.globindique à Vite d'émettre un chunk par fichier JSON. Une route qui demande["about"]en français téléchargemessages/fr/about.jsonet rien d'autre, ce qui permet au benchmark d'atteindre 0% de fuite de locale et 0% de fuite de page.src/i18n/messages.tsCopier le codeCopier le code dans le presse-papiers
Typer vos messages
L'augmentation de module vous offre l'autocomplétion sur
useTranslations("about")ett("counter.label"), ainsi qu'une erreur de compilation pour toute faute de frappe ou clé supprimée.src/i18n/use-intl.d.tsCopier le codeCopier le code dans le presse-papiers
Assurez-vous que
resolveJsonModuleest activé dans votre fichiertsconfig.json.Créer le document racine
La route racine affiche
<html>. Elle lit le paramètre de locale optionnel pour définirlangetdir, garantissant ainsi que les attributs sont corrects dans le HTML rendu côté serveur, avant même que le JavaScript ne s'exécute.src/routes/__root.tsxCopier le codeCopier le code dans le presse-papiers
Créer la route de layout pour la locale
Le dossier
{-$locale}crée un segment d'URL optionnel :/aboutet/fr/aboutcorrespondent tous deux à/{-$locale}/about. Ce layout :- Rejette les préfixes non pris en charge (
/xx/about→ 404). - Charge le namespace
commonpour la locale actuelle uniquement. - Fournit les messages via
IntlProvider.
Le résultat du loader est sérialisé dans le HTML et réutilisé lors de l'hydratation, ce qui évite au client de télécharger
common.jsonune seconde fois.staleTime: Infinityle conserve en cache lors des navigations côté client.src/routes/{-$locale}/route.tsxCopier le codeCopier le code dans le presse-papiers
IntlProviderne fusionne pas les messages d'un provider parent. L'étape suivante ajoute un petit composant qui s'en charge, afin que chaque page puisse ajouter son propre namespace par-dessuscommon.- Rejette les préfixes non pris en charge (
Délimiter la portée des messages de la page
Chaque page charge son propre namespace dans son loader, puis enveloppe son contenu avec
ScopedMessages, qui fusionne le namespace de la page avec les messages parents.src/components/ScopedMessages.tsxCopier le codeCopier le code dans le presse-papiers
Utiliser les traductions dans vos pages
Le loader de la page récupère le namespace
aboutpour la locale actuelle,head()génère des métadonnées traduites et complètes pour le SEO à partir de celui-ci (voir étape 13), et le composant affiche le contenu.src/routes/{-$locale}/about.tsxCopier le codeCopier le code dans le presse-papiers
Utiliser les traductions et formateurs dans les composants
Tout composant situé sous les providers peut appeler
useTranslationsetuseFormatter. Les pluriels sont résolus par ICU, et les nombres sont formatés selon la locale active.src/components/Counter.tsxCopier le codeCopier le code dans le presse-papiers
Créer un composant Link localisé
FacultatifChaque route vit sous
{-$locale}, un lien doit donc transmettre le paramètre de locale actuel. Ce wrapper conserve le typage detode TanStack Router et injecte automatiquement la locale pour vous.src/components/LocalizedLink.tsxCopier le codeCopier le code dans le presse-papiers
src/components/Header.tsxCopier le codeCopier le code dans le presse-papiers
Changer la langue de votre contenu
FacultatifAffichez le sélecteur sous forme de liens, et non d'un élément
<select>. Les liens peuvent être explorés par les moteurs de recherche pour découvrir toutes les versions linguistiques, et ils fonctionnent sans JavaScript.to="."conserve la page actuelle et remplace uniquement le paramètre de locale. Le cookie mémorise le choix explicite pour le middleware de redirection de l'étape 16.src/components/LocaleSwitcher.tsxCopier le codeCopier le code dans le presse-papiers
Internationaliser vos métadonnées
FacultatifC'est ici que l'i18n porte ses fruits : chaque version linguistique peut se positionner de manière indépendante. Chaque page doit exposer :
- un
<title>et unedescriptiontraduits ; - une URL canonique pointant vers elle-même (et non vers la locale par défaut) ;
- une alternative
hreflangpar locale, plusx-defaultpour les langues non prises en charge ; - les balises Open Graph
og:locale,og:locale:alternateetog:url, utilisées par les aperçus sociaux ; - un bloc JSON-LD avec
inLanguage, qui aide les moteurs de recherche et assistants IA à attribuer la langue de la page.
Un helper unique génère l'ensemble de ces éléments pour garder vos pages concises :
src/i18n/seo.tsCopier le codeCopier le code dans le presse-papiers
Utilisez-le dans le
head()de chaque page, comme illustré à l'étape 9. Pour la page d'accueil, passezpath: "/".- un
Internationaliser votre sitemap
FacultatifUn sitemap multilingue liste chaque URL de chaque locale, et chaque entrée déclare toutes ses alternatives avec
xhtml:link. Google utilise ces annotations exactement comme les baliseshreflangde la page, ce qui en fait un filet de sécurité fiable lorsqu'une page est rarement explorée.Les routes serveur de TanStack Start vous permettent de le servir directement depuis une route de fichier :
src/routes/sitemap[.]xml.tsCopier le codeCopier le code dans le presse-papiers
Internationaliser votre robots.txt
FacultatifLes routes privées existent dans toutes les langues, les règles
Disallowdoivent donc couvrir chaque préfixe. Supprimezpublic/robots.txtsi le starter en a créé un, puis servez-le depuis une route :src/routes/robots[.]txt.tsCopier le codeCopier le code dans le presse-papiers
Rediriger les nouveaux visiteurs vers leur langue
FacultatifUn middleware de requête redirige un visiteur arrivant sur
/vers sa langue préférée, en se basant d'abord sur le cookie de locale, puis sur l'en-têteAccept-Language. Seule l'URL/est redirigée : les liens profonds ne sont jamais modifiés, de sorte que les URL partagées et les robots d'indexation reçoivent toujours exactement 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
Un visiteur qui choisit explicitement l'anglais dans le sélecteur reçoit
locale=endans le cookie, de sorte qu'il n'est plus jamais redirigé. Sur un déploiement entièrement statique (étape 18),/est servi comme un fichier et ce middleware ne s'exécute pas, ce qui convient parfaitement : la page reste accessible et le sélecteur fait le reste.Conserver l'API use-intl et réduire le runtime avec Intlayer
FacultatifLe benchmark montre que la partie la plus lourde d'une configuration use-intl est le runtime lui-même (~76 KB gzip). L'adaptateur de compatibilité
@intlayer/use-intlexpose la même API (useTranslations,useFormatter,IntlProvider,createTranslator, pluriels ICU,t.rich), mais la sert à partir de dictionnaires Intlayer compilés : ~6.7 KB au lieu de ~75.9 KB, 0% de fuite de locale et 0% de fuite de page, sans aucune modification de vos composants.bashCopier le codeCopier le code dans le presse-papiers
Le plugin Vite crée un alias de
use-intlvers l'adaptateur, afin que les imports existants continuent de fonctionner :vite.config.tsCopier le codeCopier le code dans le presse-papiers
Vos fichiers JSON restent la source de vérité grâce au plugin sync JSON :
intlayer.config.tsCopier le codeCopier le code dans le presse-papiers
L'adaptateur constitue également une voie de migration fluide : une fois en place, vous pouvez migrer vos composants un par un vers l'API native
useIntlayer. Consultez le guide Intlayer pour TanStack Start.Pré-rendre chaque locale
FacultatifLe HTML statique est la page la plus rapide à servir et la plus facile à indexer. Listez chaque chemin localisé afin que TanStack Start pré-rende toutes les versions linguistiques au moment du build, ainsi que le sitemap et les fichiers robots :
vite.config.tsCopier le codeCopier le code dans le presse-papiers
Comme le sélecteur de locale affiche de vrais liens,
crawlLinks: truedécouvre également les pages que vous auriez oublié de lister.Gérer les pages 404 localisées
FacultatifLe layout de l'étape 7 déclenche déjà
notFound()pour les préfixes de locale inconnus. Ajoutez une route catch-all pour que les chemins inconnus au sein d'une locale affichent également la 404 localisée, et marquez-la avecnoindex: React 19 hisse automatiquement 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
Accéder à la locale dans les fonctions serveur
FacultatifLes fonctions serveur ne reçoivent pas les paramètres de route. Lisez le cookie de locale, et rabattez-vous sur l'en-tête
Accept-Language, pour envoyer un e-mail localisé ou enregistrer une préférence linguistique :src/server/getServerLocale.tsCopier le codeCopier le code dans le presse-papiers
Pour traduire à l'intérieur de la fonction serveur, combinez-la avec
loadMessagesetcreateTranslatordeuse-intl.Automatiser vos traductions avec Intlayer
Facultatifuse-intl affiche les traductions, mais ne vous aide pas à les produire. Intlayer est gratuit et open source, et comble ce manque même si vous conservez use-intl :
- Testez les traductions manquantes dans la CI ou les tests unitaires. Voir tester vos traductions.
- Traduisez avec l'IA en utilisant votre propre clé d'API et fournisseur :
npx intlayer filltraduit les clés manquantes avec le contexte de votre application. Voir remplissage automatique et la CLI. - Conservez vos fichiers JSON comme source de vérité avec le plugin sync JSON.
- Éditez le contenu visuellement avec l'éditeur visuel et le CMS, pour permettre aux non-développeurs de mettre à jour les traductions.
- Donnez du contexte à votre agent IA avec le serveur MCP et les skills d'agent.
- Analysez votre site déployé pour détecter les balises
hreflangmanquantes, les mauvaises balises canoniques et les fuites de locale avec la commande scan.
Pour découvrir toutes les fonctionnalités, consultez l'intérêt d'Intlayer.
Foire aux questions
Oui, si vous souhaitez l'API de next-intl en dehors de Next.js. Il vous apporte les messages ICU, les formateurs et un bon support TypeScript, tout en évitant les contraintes spécifiques à Next.js telles que setRequestLocale. Le compromis réside dans le poids : le benchmark mesure ~76 KB gzip pour le runtime, et une configuration naïve envoie chaque locale et chaque page au navigateur. Chargez les namespaces par route et par locale, comme expliqué dans ce guide, pour éviter les fuites.
use-intl est le cœur de next-intl. next-intl ajoute par-dessus des intégrations pour Next.js : un middleware, des helpers de navigation, getTranslations pour les Server Components et la configuration de requête. Sur TanStack Start, vous utilisez use-intl directement et implémentez le routage avec TanStack Router, comme montré ci-dessus.
Utilisez un préfixe dans l'URL. Chaque version linguistique dispose ainsi de sa propre URL que les moteurs de recherche peuvent indexer et que les utilisateurs peuvent partager. Un cookie reste utile pour mémoriser un choix explicite, ce que fait le middleware de redirection de l'étape 16.
Le serveur et le navigateur formatent les dates dans des fuseaux horaires différents. Passez un timeZone explicite à IntlProvider (ou le fuseau horaire du visiteur stocké dans un cookie), afin que les deux côtés produisent le même texte.
Tout d'abord, séparez les messages par namespace et chargez-les par route et par locale avec import.meta.glob, ce qui élimine les fuites de locale et de page. Ensuite, si la taille du runtime est importante pour vous, passez à l'adaptateur @intlayer/use-intl : même API, ~6.7 KB au lieu de ~75.9 KB dans le benchmark.
Appelez createTranslator dans la fonction head() de la route avec les messages retournés par le loader de route, puis renvoyez title, description, ainsi que les liens canoniques et hreflang. L'étape 13 fournit un helper réutilisable.
Commentaires
Aucun commentaire pour le moment. Soyez le premier à partager vos pensées.
