Auteur:
    Création:2026-04-20Dernière mise à jour:2026-09-27

    Bibliothèques i18n Solid - Rapport de Benchmark 2026

    Cette page est un rapport de benchmark pour les solutions i18n sur Solid.

    Table des Matières

    Benchmark Interactif

    Métrique

    Chargement JSON dynamique

    Charge les traductions à la volée

    JSON scopé (espaces de noms)

    Espaces de noms de traduction par page

    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

    Référence des résultats :

    Introduction

    Les solutions d'internationalisation figurent parmi les dépendances les plus lourdes d'une application Solid. Le risque principal est d'embarquer du contenu inutile : les traductions d'autres pages et d'autres locales dans le bundle d'une seule route.

    À mesure que votre application grandit, ce problème peut rapidement faire exploser la quantité de JavaScript envoyée au client et ralentir la navigation.

    En pratique, pour les implémentations les moins optimisées, une page internationalisée peut finir par être plusieurs fois plus lourde que la version sans i18n.

    L'autre impact concerne l'expérience développeur (DX) : la façon dont vous déclarez le contenu, les types, l'organisation des namespaces, le chargement dynamique et la réactivité lors du changement de langue.

    Pour comprendre d'où viennent ces bibliothèques, lisez l'histoire de l'i18n en JavaScript.

    TL;DR

    • Intlayer : Choix recommandé pour les applications Solid professionnelles nécessitant des fonctionnalités avancées et une optimisation poussée (v9.5.10).
    • @solid-primitives/i18n : Excellente alternative légère pour les projets simples, bien qu'il manque de fonctionnalités avancées comme le lazy loading.
    • solid-i18next : Option standard mais lourde (~3.5× Intlayer) avec les mêmes inconvénients que React i18next.
    • Tolgee : Plateforme de traduction riche en fonctionnalités, mais assez lourde (~12.7 Ko, soit environ 3.0× Intlayer), sans primitives Solid dédiées (repose sur @tolgee/web), avec d'importantes fuites de traduction entre les pages en configuration statique (90 % de fuite de page).
    • Paraglide : Approche innovante mais DX complexe et problèmes de tree-shaking dans certaines configurations.

    Testez votre application

    Pour repérer rapidement les problèmes de fuite i18n, vous pouvez essayer le scanner SEO i18n gratuit.

    Le problème

    Deux leviers sont essentiels pour limiter le coût d'une application multilingue :

    • Découper le contenu par page / namespace afin de ne pas charger des dictionnaires entiers quand on n'en a pas besoin
    • Charger la bonne locale dynamiquement, uniquement quand nécessaire

    Comprendre les limitations techniques de ces approches :

    Chargement dynamique

    Sans chargement dynamique, la plupart des solutions gardent les messages en mémoire dès le premier rendu, ce qui ajoute un surcoût important pour les applications ayant beaucoup de routes et de langues.

    Avec le chargement dynamique, vous acceptez un compromis : moins de JS initial, mais parfois une requête supplémentaire lors du changement de langue.

    Découpage du contenu (Splitting)

    Les syntaxes basées sur t('a.b.c') sont très pratiques mais encouragent souvent la conservation de gros objets JSON au runtime. Ce modèle rend le tree-shaking difficile à moins que la bibliothèque ne propose une réelle stratégie de découpage par page.

    Méthodologie

    Pour ce benchmark, nous avons comparé les bibliothèques suivantes :

    Le framework utilisé est Solid avec une application multilingue de 10 pages et 10 langues.

    Nous avons comparé quatre stratégies de chargement :

    StratégieSans namespaces (global)Avec namespaces (scoped)
    Chargement statiqueStatic : Tout en mémoire au démarrage.Scoped static : Divisé par namespace ; tout chargé au démarrage.
    Chargement dynamiqueDynamic : Chargement à la demande par locale.Scoped dynamic : Chargement granulaire par namespace et locale.

    Résumé des stratégies

    • Static : Simple ; pas de latence réseau après le chargement initial. Inconvénient : taille de bundle importante.
    • Dynamic : Réduit le poids initial (lazy-loading). Idéal lorsque vous avez de nombreuses locales.
    • Scoped static : Organise bien le code (séparation logique) sans requêtes réseau supplémentaires complexes.
    • Scoped dynamic : Meilleure approche pour le code splitting et la performance. Minimise la mémoire en ne chargeant que ce dont la vue actuelle et la locale active ont besoin.

    Ce que j'ai mesuré :

    J'ai exécuté la même application multilingue dans un vrai navigateur pour chaque stack, puis j'ai noté ce qui s'est réellement affiché sur le fil et le temps que cela a pris. Les tailles sont rapportées après une compression web normale, car c'est plus proche de ce que les gens téléchargent que les comptages de sources brutes.

    • Taille de la bibliothèque d'internationalization : Après bundling, tree-shaking et minification, la taille de la bibliothèque i18n est la taille du code des providers + hooks/primitives dans un composant vide. Elle n'inclut pas le chargement des fichiers de traduction. Elle répond à la question : à quel point la bibliothèque est-elle coûteuse avant que votre contenu ne soit pris en compte.

    • JavaScript par page : Pour chaque route de benchmark, combien de script le navigateur récupère lors de cette visite, moyenné sur les pages de la suite (et sur les locales où le rapport les agrège). Les pages lourdes sont des pages lentes.

    • Fuite d'autres locales : C'est le contenu de la même page mais dans une autre langue qui serait chargé par erreur dans la page auditée. Ce contenu est inutile et devrait être évité. (par exemple, le contenu de la page /fr/about dans le bundle de la page /en/about)

    • Fuite d'autres routes : La même idée pour les autres écrans de l'application : si leur contenu se charge quand vous n'avez ouvert qu'une seule page. (par exemple, le contenu de la page /en/about dans le bundle de la page /en/contact). Un score élevé indique un découpage faible ou des bundles trop larges.

    • Taille moyenne du bundle du composant : Les éléments d'interface communs sont mesurés un à la fois au lieu de se cacher dans un gigantesque numéro d'application. Cela montre si l'internationalization gonfle silencieusement les composants courants. Par exemple, si votre composant se rerender, il chargera toutes ces données de la mémoire. Attacher un énorme JSON à n'importe quel composant, c'est comme connecter un grand magasin de données inutilisées qui ralentira les performances de vos composants.

    • Réactivité du changement de langue : Je bascule la langue en utilisant le contrôle propre de l'application et je chronométre le temps qu'il faut jusqu'à ce que la page se soit clairement changée, ce qu'un visiteur remarquerait, et non une micro-étape de laboratoire.

    • Travail de rendu après un changement de langue : Un suivi plus étroit : combien d'effort l'interface a dû faire pour se repeindre pour la nouvelle langue une fois le changement en cours. Utile quand le temps « ressenti » et le coût du framework divergent.

    • Temps de chargement initial de la page : De la navigation à la considération par le navigateur que la page est complètement chargée pour les scénarios que j'ai testés. Bon pour comparer les démarrages à froid.

    • Temps d'hydratation : Quand l'application l'expose, le temps que le client passe à transformer le HTML du serveur en quelque chose que vous pouvez réellement cliquer. Un tiret dans les tableaux signifie que cette implémentation n'a pas fourni de chiffre d'hydratation fiable dans ce benchmark.

    Étoiles GitHub

    Les étoiles GitHub sont un indicateur fort de la popularité d'un projet, de la confiance de la communauté et de sa pertinence à long terme. Bien qu'elles ne soient pas une mesure directe de la qualité technique, elles reflètent le nombre de développeurs qui trouvent le projet utile, suivent ses progrès et sont susceptibles de l'adopter. Pour estimer la valeur d'un projet, les étoiles aident à comparer l'attraction entre les alternatives et fournissent des informations sur la croissance de l'écosystème.

    Star History Chart

    Activité des commits

    Les étoiles mesurent la popularité. Les commits mesurent le travail investi dans un projet. Au moment de l'écriture, Intlayer compte environ 7 500 commits, plus que la plupart des bibliothèques comparées ici, et environ 5 fois plus que next-intl ou next-i18next.

    • solidjs-community/solid-primitives
    • mbarzda/solid-i18next
    • opral/paraglide-js
    • tolgee/tolgee-js
    • aymericzip/intlayer

    Commits sur la branche par défaut, source : API GitHub.

    Intlayer est un monorepo : ce total inclut chaque package de framework, la CLI et la documentation. Lisez les commits comme un signal d'activité, pas de qualité.

    Téléchargements npm

    • @solid-primitives/i18n
    • @mbarzda/solid-i18next
    • @inlang/paraglide-js
    • @tolgee/web
    • solid-intlayer

    Source : API de téléchargements du registre npm.

    Le nombre de téléchargements récompense les solutions les plus anciennes, pas les meilleures. Une bibliothèque publiée il y a des années est toujours installée par chaque projet qui l'a choisie à l'époque, par chaque exécution de CI et par chaque package qui en dépend. Ce chiffre mesure l'inertie plus qu'un choix réfléchi.

    Les assistants IA amplifient cet effet. next-intl, i18next et vue-i18n sont omniprésents dans le code sur lequel ils ont été entraînés : ils les proposent donc par défaut, sans faire l'effort de comparer les alternatives. Chaque suggestion ajoute des téléchargements, qui alimentent la suggestion suivante. Comparez sur le benchmark plutôt que sur le nombre de téléchargements.

    Résultats détaillés

    1 - Solutions à éviter

    Aucune solution claire à éviter dans l'écosystème Solid.

    2 - Solutions acceptables

    (solid-i18next) (i18next@26.0.8) :

    solid-i18next est probablement l'option la plus populaire car elle fut l'une des premières à servir les besoins i18n des applications JS. Elle dispose également d'un large éventail de plugins communautaires pour des problèmes spécifiques.

    Le paquet est lourd (~14.9 Ko, soit environ 3.5× solid-intlayer).

    Pourtant, elle partage les mêmes inconvénients majeurs que les stacks basées sur t('a.b.c') : les optimisations sont possibles mais très gourmandes en temps, et les gros projets risquent de mauvaises pratiques (namespaces + chargement dynamique + types).

    (@solid-primitives/i18n) (@solid-primitives/i18n@2.2.1) :

    Solid primitive est extrêmement léger et efficace. Je recommande cette solution pour les petits projets, mais elle peut rapidement manquer de fonctionnalités pour des solutions professionnelles incluant la gestion des cookies, la redirection proxy, les formateurs, etc. Elle manque également de lazy loading et de découpage des namespaces pour l'optimisation de la taille des pages.

    (Tolgee) (@tolgee/web@7.2.0) :

    Tolgee propose une plateforme de gestion des traductions complète avec des fonctionnalités d'édition in-context.

    Sur Solid, il n'existe actuellement aucun adaptateur natif officiel (comme @tolgee/solid), ce qui oblige les développeurs à s'intégrer via @tolgee/web avec des signaux personnalisés.

    Le paquet est relativement lourd (~12.7 Ko, soit environ 3.0× solid-intlayer).

    En l'absence de découpage granulaire par namespace et par page sur Solid, toutes les traductions sont chargées en mémoire dès le démarrage en mode statique. Cela entraîne d'importantes fuites de bundle (44.5 % de fuite de locale, 90.0 % de fuite de page) et une taille moyenne de bundle de ~91.8 Ko par page (contre ~35.4 Ko pour Intlayer).

    La réactivité lors du changement de langue est très rapide (0.6 ms), profitant de la réactivité fine de Solid, bien que le temps d'hydratation soit plus élevé (~5.6 ms contre ~2.9 ms pour Intlayer).

    (Paraglide) (@inlang/paraglide-js@2.25.1) :

    Paraglide propose une approche innovante et bien pensée. Pourtant, dans ce benchmark, le tree-shaking dont leur entreprise fait la publicité n'a pas fonctionné pour mon implémentation. Le workflow et la DX sont également plus complexes d'autres options. Personnellement, je n'aime pas devoir régénérer des fichiers JS avant chaque push, ce qui crée un risque constant de conflit de fusion via les PRs. Enfin, par rapport à d'autres solutions, Paraglide n'utilise pas de store (ex: Solid signal) pour récupérer la locale actuelle afin de rendre le contenu. Pour chaque nœud analysé, il demandera la locale au localStorage / cookie etc. Cela conduit à l'exécution d'une logique inutile qui impacte la réactivité des composants.

    3 - Recommandations

    (Intlayer) (solid-intlayer@9.5.10) :

    Je ne jugerai pas personnellement solid-intlayer par souci d'objectivité, puisqu'il s'agit de ma propre solution.

    Note personnelle

    Cette note est personnelle et n'affecte pas les résultats du benchmark. Pourtant, dans le monde de l'i18n, on voit souvent un consensus autour d'un pattern comme const t = useTranslation('xx') + <>{t('xx.xx')}</> pour le contenu traduit.

    Dans les applications Solid, injecter une fonction en tant que JSX.Element est, à mon avis, un anti-pattern. Cela ajoute également une complexité évitable et un surcoût d'exécution JavaScript (même s'il est à peine perceptible).