Posez votre question et obtenez un résumé du document en referencant cette page et le Provider AI de votre choix
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
i18next VS @intlayer/i18next | Même API, Bundle Différent
@intlayer/i18next, @intlayer/react-i18next et @intlayer/next-i18next sont des adaptateurs de compatibilité. Ils exposent l'API i18next que votre code utilise déjà (useTranslation, t(), <Trans>, i18n.changeLanguage(), getFixedT, serverSideTranslations...) et la distribuent à partir de dictionnaires compilés par Intlayer. Les composants ne changent pas. Le runtime sous-jacent, lui, change.
Cet article mesure ce remplacement sur la même application Next.js, construite une fois avec next-i18next et une fois avec @intlayer/next-i18next. Les chiffres proviennent de Benchmark Bloom. Pour comparer i18next et Intlayer en tant que bibliothèques distinctes, consultez i18next vs Intlayer. Celui-ci se concentre sur ce que l'adaptateur transforme lorsque vous conservez votre code tel quel.
tl;dr : Sur la même application Next.js, remplacernext-i18nextpar@intlayer/next-i18nextfait passer le JavaScript par page de 218.5 Ko à 150.7 Ko gzip (configuration naïve) et surpasse la configurationnext-i18nextentièrement optimisée (163.4 Ko) de 12.7 Ko. Le composant moyen passe de 78.5 Ko à 9.7 Ko, la fuite de chaînes vers d'autres pages passe de ~90% à 0%, l'hydratation de 15.6 ms à 11.3 ms, et le runtime de 19.7 Ko à 9.4 Ko. Aucun composant n'a été modifié, un seul fichier de provider l'a été. Les pluginsi18next(backends, détecteurs de langue) sont acceptés mais ne font rien : il n'y a plus rien à charger ni à détecter au runtime.
Ce qu'est @intlayer/i18next
i18next est un runtime. i18n.init({ resources }) ou un plugin backend charge locales/{lng}/{ns}.json dans une instance globale ; useTranslation("about") y abonne le composant ; t("title") recherche la clé au moment du rendu. Les namespaces, le lazy loading, les listes de namespaces par page et la sécurité de typage sont entièrement à votre charge en matière de configuration et de maintenance.
Les adaptateurs conservent l'API et remplacent l'instance :
- Alias d'importation.
createNextI18nPlugin()depuis@intlayer/next-i18next/plugin(ouwithI18next) enveloppewithIntlayeret ajoute des alias Webpack / Turbopack pour quenext-i18next,react-i18nexteti18nextrenvoient vers leurs équivalents@intlayer/*. Sur Vite,reactI18nextVitePlugin()depuis@intlayer/react-i18next/pluginfait de même. Aucun import n'a besoin d'être renommé. - JSON comme source de vérité. Le plugin
syncJSONlit vos fichiers existantslocales/{lng}/{ns}.jsonavecformat: "i18next"(ainsi{{name}}, l'imbrication$t(), les suffixes_one/_otheret de contexte sont correctement analysés) et réécrit les traductions lorsque le CLI ou le CMS les met à jour. - Liaison sur le site d'appel. La passe d'optimisation d'Intlayer réécrit
useTranslation("about")en un appel qui reçoit directement le dictionnaireabout, dans la locale active. Le composant cesse d'interroger le store global.
Copier le code dans le presse-papiers
Copier le code dans le presse-papiers
Cette réécriture est précisément ce qui fait basculer les colonnes de taille des composants et de fuite de page ci-dessous.
Ce que les adaptateurs conservent, ignorent et ne remplacent pas
Ouvrir le tableau dans une fenêtre modale pour voir tout le contenu clairement
API i18next | Avec @intlayer/* |
|---|---|
useTranslation("ns"), useTranslation("ns", { keyPrefix }) | ✅ Conservé. Lié au dictionnaire ns au moment du build ; clés typées selon votre contenu |
t("key", { name }), {{interpolation}}, imbrication $t(key) | ✅ Conservé |
Pluriels key_one / key_other, contexte key_male, returnObjects | ✅ Conservé. Pluriels évalués avec Intl.PluralRules |
<Trans> avec components, balises numérotées <1>...</1>, values | ✅ Conservé |
withTranslation, Translation, I18nContext | ✅ Conservé |
i18n.changeLanguage(), i18n.language, i18n.dir(), on("languageChanged") | ✅ Conservé. changeLanguage pilote la locale d'Intlayer |
getFixedT(lng, ns, keyPrefix), i18n.exists(), hasLoadedNamespace() | ✅ Conservé |
i18n.use(Backend).use(LanguageDetector).init({...}) | ⚠️ use() appelle le init du plugin et s'arrête là ; les backends et détecteurs n'ont rien à charger ni à détecter |
init({ resources }), addResourceBundle() | ⚠️ resources est ignoré avec un avertissement en dev ; supprimez les imports JSON pour obtenir les gains de bundle |
I18nextProvider i18n={i18n} | ⚠️ Rend un IntlayerProvider ; la prop i18n est ignorée. Sur App Router, transmettez la locale (voir ci-dessous) |
serverSideTranslations(locale, ["common"]) (next-i18next) | ⚠️ Renvoie la structure attendue et ne charge rien. Inoffensif à garder, sûr à supprimer |
appWithTranslation(App) (next-i18next) | ✅ Conservé |
next-i18next.config.js | ⚠️ Non lu. Les locales proviennent de intlayer.config.ts |
useTranslation() sans namespace spécifié | ✅ Fonctionne avec le dictionnaire global translation du fichier complet (splitKeys: false) |
Le benchmark
Ce qui a été mesuré
La suite Benchmark Bloom construit la même application avec chaque configuration : 10 pages (accueil, à propos, blog, carrières, contact, FAQ, tarifs, produits, paramètres, équipe), 10 locales (en, fr, es, de, it, pt, zh, ja, ko, ru), des composants identiques et un contenu identique. Les pages sont mesurées en en et fr.
next-i18next a été testé avec quatre stratégies de chargement, depuis le JSON de chaque locale importé dans resources (static) jusqu'à un namespace par route, chargé paresseusement via un backend (scoped-dynamic). L'adaptateur a été construit sur les mêmes composants que la configuration naïve, avec uniquement next.config.ts, intlayer.config.ts et le fichier de provider modifiés. Il ne propose aucune variante "scopée" manuelle : le compilateur scope le contenu par composant.
Pour chaque build, la suite enregistre :
- Taille de la lib : taille gzip d'un composant vide qui n'importe que la bibliothèque i18n.
- JS par page : moyenne du JavaScript gzip téléchargé par page sur toutes les pages et locales.
- % de fuite de locale : part des chaînes traduites dans le JS téléchargé qui appartiennent à une locale que l'utilisateur ne consulte pas.
- % de fuite de page : part des chaînes traduites dans le JS téléchargé qui appartiennent à une page sur laquelle l'utilisateur ne se trouve pas.
- Moyenne composant : taille moyenne gzip de chaque composant compilé isolément.
- Réactivité E2E : temps réel mesuré entre le choix d'une nouvelle locale et la mise à jour de
html[lang]dans le DOM (Playwright, 5 itérations). - Hydratation : durée de la phase d'hydratation de React.
Les chiffres ci-dessous proviennent de l'exécution du 12/09/2026 avecnext-i18next16.3.0 (react-i18next17.0.13,i18next26.4.2) et@intlayer/next-i18next9.5.1. L'application de test est volontairement compacte (quelques dizaines de chaînes par locale), les pourcentages de fuite décrivent donc une tendance : ils croissent avec votre contenu tandis que le coût du runtime reste fixe.
Résultats sur Next.js
Ouvrir le tableau dans une fenêtre modale pour voir tout le contenu clairement
| Configuration | Stratégie | Taille lib (gz) | JS page moy (gz) | Fuite locale | Fuite page | Composant moy (gz) | Réactivité E2E | Hydratation |
|---|---|---|---|---|---|---|---|---|
| base (sans i18n) | - | 0.0 Ko | 141.0 Ko | 0.0% | 0.0% | 0.9 Ko | 13.4 ms | 11.8 ms |
next-i18next | static | 19.7 Ko | 218.5 Ko | 0.0% | 89.8% | 78.5 Ko | 16.4 ms | 15.6 ms |
next-i18next | dynamic | 19.7 Ko | 169.5 Ko | 50.0% | 89.8% | 26.1 Ko | 15.4 ms | 27.7 ms |
next-i18next | scoped-static | 19.7 Ko | 220.1 Ko | 0.0% | 89.8% | 78.9 Ko | 16.4 ms | 14.7 ms |
next-i18next | scoped-dynamic | 19.7 Ko | 163.4 Ko | 0.0% | 0.0% | 27.1 Ko | 15.9 ms | 15.1 ms |
@intlayer/next-i18next | static | 9.4 Ko | 150.7 Ko | 0.0% | 0.0% | 9.7 Ko | 10.7 ms | 11.3 ms |
@intlayer/next-i18next | dynamic | 9.4 Ko | 150.7 Ko | 0.0% | 0.0% | 9.7 Ko | 11.9 ms | 10.6 ms |
next-intlayer (natif) | static | 5.5 Ko | 141.3 Ko | 0.0% | 0.0% | 8.5 Ko | 15.5 ms | 16.9 ms |
next-intlayer (natif) | dynamic | 5.5 Ko | 141.3 Ko | 0.0% | 0.0% | 6.9 Ko | 15.3 ms | 15.9 ms |
Comment l'interpréter
- 68 Ko de moins par page par rapport à la configuration naïve.
resources: { en, fr, ... }expédie chaque locale et chaque namespace sur chaque page : 218.5 Ko. Le build avec adaptateur pour les mêmes composants tombe à 150.7 Ko. Il surpasse également la meilleure configuration denext-i18next(163.4 Ko, un namespace par route, chargé à la demande) de 12.7 Ko, car le runtimei18nextpèse à lui seul 19.7 Ko contre 9.4 Ko. - La fuite passe à 0% sans toucher au moindre composant. Chaque configuration de
next-i18nextsauf la version entièrement découpée expédie ~90% de chaînes d'autres pages. La lignedynamicest plus pénalisante qu'il n'y paraît : elle n'élimine pas la fuite de page et introduit 50% de fuite de locale, car le backend par locale rapatrie toujours l'intégralité du namespacetranslation. L'adaptateur atteint 0% / 0% directement sur le code d'origine. - Composants : 8x plus légers. Un composant utilisant
useTranslation()compilé isolément pèse en moyenne 78.5 Ko avecresourcesinliné et 26-27 Ko avec un backend, cartreste lié au store global. Avec l'adaptateur, il n'affiche plus que 9.7 Ko. - Hydratation et basculement plus rapides. L'hydratation passe de 15.6 ms à 11.3 ms (et de 27.7 ms dans la configuration
dynamic, où l'appel backend se situe sur le chemin critique). Le basculement de locale passe de 15-16 ms à 11-12 ms. - L'adaptateur n'est pas le runtime natif.
next-intlayeratteint 141.3 Ko, soit +0.3 Ko par rapport à l'application de base. L'adaptateur supporte la surface d'API dei18next(dialecte d'interpolation, résolution des pluriels et contextes, analyse des balises<Trans>) en surcouche du cœur d'Intlayer : 9.4 Ko et +9.4 Ko par page par rapport au natif. Il constitue une passerelle, non une fin en soi.
L'adaptateurreact-i18nextsur Vite / TanStack Start n'a pas été inclus dans ce cycle de test. La référence pourreact-i18nextsur TanStack Start se trouve dans i18next vs Intlayer : 127-184 Ko par page et 123-185 ms de temps de basculement de locale quand le backend est différé.
Pourquoi ces écarts de métriques
Rien n'a changé dans le dossier components/ : les gains proviennent donc exclusivement de la cible à laquelle useTranslation est relié.
Avec i18next, la liaison s'établit avec l'instance globale. Tout ce qui y a été chargé (toutes les locales en static, l'ensemble du namespace de la locale active en dynamic) est accessible depuis chaque composant appelant useTranslation(). Le bundler ne peut pas découper plus finement que ce que l'instance retient, et le runtime ne peut pas anticiper les clés demandées au rendu.
Copier le code dans le presse-papiers
Avec @intlayer/next-i18next, la liaison s'opère directement avec le dictionnaire. syncJSON convertit chaque fichier de namespace en dictionnaire ; la passe d'optimisation transmet au composant le dictionnaire correspondant sous forme d'un import que le bundler peut tracer et séparer par page et par locale.
Copier le code dans le presse-papiers
Le fichier i18n/i18n.ts et son import de resources deviennent du code mort. C'est là que résident les 68 Ko d'économie.
Migration en trois étapes
Installation
bashCopier le codeCopier le code dans le presse-papiers
La commande détecte
i18next/react-i18next/next-i18next, installeintlayer, le package de framework (next-intlayeroureact-intlayer), l'adaptateur@intlayer/*correspondant ainsi que@intlayer/sync-json-plugin, et pré-remplitintlayer.config.ts. Laissez les packages d'origine installés : ils servent de peer dependencies et fournissent les définitions de types.Pointer Intlayer vers vos fichiers de locales
intlayer.config.tsCopier le codeCopier le code dans le presse-papiers
Si vous disposez d'un unique fichier
translation.jsonpar locale (le namespace par défaut d'i18next), définissezsplitKeys: falseafin que le fichier complet reste un seul dictionnaire et qu'un appel simple àuseTranslation()continue de fonctionner.Ajouter le plugin
next.config.tsCopier le codeCopier le code dans le presse-papiers
Sur l'App Router, les composants clients obtiennent leur locale via le segment
[locale]. L'I18nextProviderde l'adaptateur ne prenant aucune locale en paramètre, remplacez-le une seule fois dans votre fichier de provider :components/AppProviders.tsxCopier le codeCopier le code dans le presse-papiers
Tous les composants enfants continuent d'appeler
useTranslation()sans modification.vite.config.tsCopier le codeCopier le code dans le presse-papiers
reactI18nextVitePlugin()enveloppevite-intlayeret crée les alias pourreact-i18nexteti18next. Pour un projet sans React,i18nextVitePlugin()depuis@intlayer/i18next/plugincrée l'alias pouri18nextseul.
Ce que vous pouvez supprimer par la suite
Ouvrir le tableau dans une fenêtre modale pour voir tout le contenu clairement
| Fichier / modèle | Raison |
|---|---|
resources: { en, fr, ... } et les imports JSON | Ignorés par l'adaptateur. C'est ici que se trouvaient les 68 Ko |
i18next-http-backend, i18next-resources-to-backend | Plus rien à récupérer au runtime |
i18next-browser-languagedetector | La détection de locale dépend du routage d'Intlayer (préfixe URL, cookie, en-tête) |
serverSideTranslations() dans getStaticProps | Renvoie une structure vide ; inoffensif, mais inutile |
next-i18next.config.js | Non lu. Les locales sont déclarées dans intlayer.config.ts |
Listes ns: [...] par page | Le compilateur sélectionne les namespaces par composant |
Ce que vous gagnez au-delà des octets
- Clés typées.
useTranslation("about")est typé d'après le dictionnaire compiléabout;t("does.not.exist")déclenche une erreur TypeScript au lieu de renvoyer la chaîne de clé. npx intlayer testbloque la CI en cas de clé manquante dans n'importe quelle langue.npx intlayer filltraduit automatiquement les clés manquantes avec votre propre clé d'API (OpenAI, Anthropic, Mistral, Gemini...) et les réécrit danslocales/{lng}/{ns}.json.- Éditeur visuel et CMS opèrent sur le même JSON, permettant aux équipes éditoriales de modifier le contenu via une interface pendant que les fichiers se mettent à jour.
- Transition progressive vers
.content.ts. Chaque composant peut basculer indépendamment deuseTranslation("about")àuseIntlayer("about")avec un fichier de contenu dédié. Fichiers JSON et.content.tscoexistent naturellement.
Limites à connaître avant de démarrer
- Backends et détecteurs sont inertes.
i18n.use(HttpBackend)exécute leinitdu plugin et rien de plus. Si votre application dépendait de traductions rapatriées depuis un CMS au moment de la requête, ce flux n'existe plus ; utilisez le CMS d'Intlayer ou les commandesintlayer pull/push. resourcesest ignoré, non fusionné. Contrairement à certains adaptateurs,@intlayer/i18nextn'utilise pasresourcesinliné comme solution de repli. Chaque clé doit exister dans les dictionnaires synchronisés, ce que valideintlayer test.- L'App Router nécessite la retouche du provider. Un seul fichier, présenté ci-dessus. Le Pages Router avec
appWithTranslationne nécessite aucun ajustement. next-i18next.config.jsn'est pas lu.localePath,fallbackLng,reloadOnPrerenderet équivalents n'ont pas d'effet direct ; les locales et le repli sont gérés dansintlayer.config.ts.- L'adaptateur a un coût résiduel. 9.4 Ko de runtime et +9.4 Ko par page par rapport à
next-intlayer. Lorsque tous vos composants seront passés àuseIntlayer, retirez-le.
Quand choisir quelle solution ?
- Restez sur
i18nextsi votre application nécessite impérativement des backends au runtime (traductions servies par un CMS à la volée), l'écosystème spécifique de plugins, ou une cible hors React non couverte par les adaptateurs. - Optez pour
@intlayer/*si vous utilisezreact-i18next/next-i18nextet souhaitez récupérer 68 Ko, obtenir des composants 8x plus légers, 0% de fuite, des clés typées et des contrôles en CI sans devoir tout réécrire. C'est le point d'entrée idéal pour une codebasei18nextexistante. - Passez au natif (
next-intlayer/react-intlayer) pour les nouveaux projets ou une fois l'adaptateur assimilé. C'est la formule la plus légère (5.5 Ko, +0.3 Ko par page) qui débloque les Server Components synchrones et les fichiers de contenu.content.tspar composant.
Comparatifs associés
- i18next vs Intlayer (comparatif des bibliothèques, même benchmark)
- next-intl vs @intlayer/next-intl (même série d'adaptateurs)
- Lingui vs @intlayer/lingui (même série d'adaptateurs)
- vue-i18n vs @intlayer/vue-i18n (même série d'adaptateurs)
- Guides de migration : i18next, react-i18next, next-i18next
- Références des adaptateurs : i18next, react-i18next, next-i18next
Conclusion
i18next constitue le runtime le plus lourd de ce benchmark, et les adaptateurs en retirent la majeure partie sans vous obliger à quitter son API. Sur la même application Next.js, cela représente 68 Ko de moins par page par rapport à la configuration naïve, 12.7 Ko de moins que la version la plus optimisée à la main, des composants 8x plus légers, 0% de fuite et 4 ms d'hydratation, le tout en échange d'un fichier de configuration, d'une ligne de plugin et d'un ajustement de provider. Les backends et détecteurs deviennent sans effet, resources est ignoré plutôt que fusionné, et le runtime natif next-intlayer conserve 9 Ko d'avance supplémentaire en légèreté.
L'ensemble des données brutes, des applications de test et des scripts est disponible dans le dépôt Benchmark Bloom. Vous pouvez le reproduire vous-même.
Consultez le document Pourquoi Intlayer ? pour en savoir plus.
Commentaires
Aucun commentaire pour le moment. Soyez le premier à partager vos pensées.
