Marketing international

L'internationalisation dans Rails : des URL au JavaScript

L'internationalisation dans Rails : des URL au JavaScript
Mis à jour le
18 mai 2026

Rails intègre d'emblée un framework d'internationalisation. Il ne vous en faut pas beaucoup plus pour vous lancer : l'API I18n fait partie intégrante de la pile et gère efficacement les fonctions de base : traduction des chaînes statiques, mise en forme des dates et des nombres, et gestion du pluriel selon les paramètres régionaux.

Mais « intégré » ne signifie pas « complet ». Dès que vos besoins s'étendent aux URL localisées, aux traductions JavaScript ou SEO multilingue, vous sortez du cadre de ce que Rails offre en natif. Ces lacunes nécessitent des choix architecturaux mûrement réfléchis.

Passons en revue ces deux niveaux : ce que gère l'API I18n de Rails, et les aspects que vous devrez développer vous-même – ou déléguer.

Ce que couvre Rails I18n et ses limites

L'API I18n met à votre disposition deux méthodes principales : I18n.t pour la traduction des chaînes de caractères et I18n.l pour la localisation des dates et des nombres. Ces deux méthodes lisent les fichiers YAML ou Ruby situés dans le répertoire config/locales/, et Rails les charge automatiquement au démarrage.

Dès l'installation, cela couvre les chaînes d'interface utilisateur statiques, le formatage des dates et des nombres, ainsi que les messages de validation ActiveRecord. Pour la plupart des projets impliquant une seule langue source et une seule langue cible, cela suffit pour la mise en production.

Les lacunes apparaissent rapidement dès qu'on va plus loin.

Rails I18n ne se prononce pas sur la structure des URL : pas de routes localisées, pas de détection des sous-domaines, ni de préfixes de chemin. Il ne dispose d'aucun mécanisme permettant de traduire le contenu stocké dans la base de données, comme les noms de produits ou les articles de blog. Les fichiers JavaScript se situent entièrement en dehors du pipeline. Quant SEO multilingue, les éléments tels que les balises hreflang, les slugs traduits et les plans de site spécifiques à chaque langue nécessitent un travail distinct dont le framework ne s'occupe pas.

Il faut savoir où se trouve la limite avant de commencer à construire.

Mise en place de la base I18n

Vous pouvez commencer par le gem rails-i18n.

Rails ne fournit que des données de localisation en anglais ; par conséquent, sans celles-ci, la fonction `I18n.l(Date.today)` ne fonctionne pas dans les locales non anglophones, et les chaînes de caractères au niveau du framework, telles que les messages de validation d'Active Record, restent en anglais quelle que soit la locale actuelle.

# Gemfile

gem "rails-i18n"

Configurez ensuite les paramètres par défaut de votre application :

# config/application.rb

config.i18n.default_locale = :en

config.i18n.available_locales = [:en, :fr]

config.i18n.enforce_available_locales = true

La valeur « enforce_available_locales = true » génère une erreur si votre application tente de définir une locale ne figurant pas dans cette liste. Sans cette configuration, une faute de frappe ou un paramètre d'URL mal formé peut entraîner, sans avertissement, la définition d'une locale non prise en charge en production.

Bien que Rails moderne analyse un seul niveau de profondeur, il lui arrive souvent de ne pas détecter les dossiers profondément imbriqués (comme config/locales/views/products/). L'ajout de cette ligne garantit que tous les sous-répertoires seront pris en compte à mesure que votre application se développe :

config.i18n.load_path += Dir[Rails.root.join("config", "locales", "**", « *.{rb,yml} »)]

Cela vous permet de classer les fichiers de traduction par domaine :

config/locales/  
	fr/    
		models.yml    
		views.yml    
		mailers.yml  
	fr/    
		models.yml    
		views.yml    
		mailers.yml

⚠️ YAML interprète les valeurs telles que « true » et « false » comme des booléens. Si vous souhaitez les utiliser sous forme de texte littéral, mettez-les explicitement entre guillemets. Les versions récentes de Ruby/YAML traitent désormais « yes » et « no » comme des chaînes de caractères, mais il reste prudent de les mettre entre guillemets pour des raisons de compatibilité :

fr:  
	réponses :    
		affirmatif : « oui »    
		négatif: « non »

Cela permet de détecter un type de bug qui n'apparaît que lorsqu'une traduction renvoie « true » au lieu de « oui » et que votre vue n'affiche rien, ou pire encore, la chaîne « true ».

Aides à la traduction et recherche par défaut dans les vues

Dans les vues, t et l sont les deux fonctions d'aide que vous utiliserez sans cesse.

La fonction `l` localise les dates, les heures et les nombres en fonction des paramètres régionaux actuels. Une fois `rails-i18n` installé, les définitions de format pour plus de 100 paramètres régionaux sont fournies. Sans cet extension, l'appel de `l(Date.today)` dans un environnement non anglophone renverra généralement une chaîne « traduction manquante » ou une date non formatée, car Rails ne dispose pas des modèles de format localisés nécessaires.

<%= l(Date.today) %>

<%= l(Date.today, format: :long) %>

t traduit les chaînes par clé. La forme complète est t("products.index.title"), mais dans les vues, vous pouvez utiliser la syntaxe abrégée de recherche différée :

<%= t(".title") %>

Le point initial indique à Rails de résoudre la clé par rapport au chemin d'accès de la vue actuelle. Dans app/views/products/index.html.erb, t(".title") se transforme automatiquement en t("products.index.title"). Cela permet de garder des clés courtes et d'appliquer une convention de nommage cohérente sans effort supplémentaire.

For interpolation, use %{variable} in your YAML and pass the value as a keyword argument:

en:  
	welcome: "Hello, %{name}"
<%= t(".welcome", name: current_user.name) %>

Si une traduction contient du code HTML que vous jugez fiable, ajoutez « _html » à la fin du nom de la clé. Rails le marque automatiquement comme sûr, sans qu'il soit nécessaire d'appeler la méthode `html_safe`.

en:  
	notice_html: "Please <strong>confirm</strong> your email."

La recherche différée ne fonctionne que lorsque Rails peut déduire le chemin d'accès à la vue, ce qui signifie qu'elle ne fonctionne pas dans les tâches en arrière-plan ni dans les contrôleurs API. Dans ces cas-là, utilisez systématiquement la clé complète.

Choisir une stratégie de détection des paramètres régionaux

Avant de commencer à écrire du code de détection de la locale, choisissez une stratégie. Il existe cinq approches principales, et celle qui vous convient dépendra de la structure de votre application et de vos besoins en matière de référencement.

Stratégie Exemple Idéal pour
Paramètre d'URL /products?locale=fr Outils internes, prototypage rapide
Préfixe de chemin /fr/produits Sites publics nécessitant SEO multilingue
Sous-domaine fr.example.com Des marques régionales distinctes
TLD exemple.fr Noms de domaine nationaux que vous possédez déjà
Préférences de la base de données Enregistré dans la fiche utilisateur Applications authentifiées avec paramètres utilisateur

Le préfixe de chemin, tel que /fr/products, est le choix le plus courant pour les applications Rails destinées au grand public. Il permet d'indiquer explicitement la langue dans chaque URL, ce qui permet aux moteurs de recherche de les indexer séparément pour chaque langue.

Les stratégies basées sur les sous-domaines et les TLD sont efficaces lorsque l'on souhaite renforcer l'identité régionale, mais elles impliquent une charge supplémentaire en termes de configuration DNS et de certificats SSL.

Les paramètres d'URL, tels que /products?locale=fr, conviennent parfaitement aux outils internes pour lesquels le référencement naturel n'a pas d'importance.

Les préférences enregistrées dans la base de données fonctionnent pour les applications authentifiées lorsque les paramètres régionaux suivent l'utilisateur, et non l'URL.

Quelle que soit la stratégie que vous choisissiez, il existe une erreur de mise en œuvre qui peut entraîner des bugs discrets en production : l'utilisation directe de `I18n.locale =`.

# Don't do this

before_action { I18n.locale = params[:locale] }

I18n.locale = écrit dans Thread.current.

Si vous utilisez un serveur web Puma, celui-ci réutilise les threads d'une requête à l'autre. Si une requête ne définit pas explicitement les paramètres régionaux, elle hérite de ceux laissés par la requête précédente.

En développement local en mode monothread, ce problème ne se manifeste jamais. En production, il provoque des réponses dans une langue incorrecte, de manière intermittente, qui sont difficiles à reproduire et encore plus difficiles à tracer.

Utilisez plutôt I18n.with_locale à l'intérieur d'une action « around_action » :

around_action :switch_locale‍d


ef switch_locale(&action)  
	locale = params[:locale] || I18n.default_locale  
	I18n.with_locale(locale, &action)
end

with_locale rétablit les paramètres régionaux précédents à la fin du bloc, quelle que soit la manière dont la requête se termine.

Mise en œuvre des itinéraires localisés et de la détection des sous-domaines

Définissez vos routes sous /:locale et remplacez la valeur de default_url_options afin que Rails ajoute automatiquement la locale actuelle au début de chaque aide-URL :

# config/routes.rb
scope "/:locale" do
  resources :products
  root "home#index"
end

# app/controllers/application_controller.rb
around_action :switch_locale

def switch_locale(&action)
  locale = params[:locale]
  # Fallback to default if the param is missing or unsupported
  valid_locale = I18n.available_locales.map(&:to_s).include?(locale) ? locale : I18n.default_locale
  I18n.with_locale(valid_locale, &action)
end

def default_url_options
  { locale: I18n.locale }
end

Lorsque l'option `default_url_options` est définie, le chemin `products_path` s'affiche automatiquement sous la forme ` /fr/products` lorsque la locale actuelle est :fr.

Si vous souhaitez que la locale par défaut omette le préfixe, rendez le segment facultatif en lui attribuant la portée « (:locale) ». Cela permet d'afficher /products pour l'anglais et /fr/products pour le français, mais crée une ambiguïté. Un chemin tel que /about pourrait correspondre soit à une locale manquante, soit à un contrôleur nommé about, selon l'ordre de vos routes.

Pour la détection des sous-domaines, lisez la valeur de `request.subdomains.first` et vérifiez-la par rapport à `available_locales` avant de définir quoi que ce soit :

def extraire_la_langue_à_partir_du_sous-domaine
  sous-domaine = request.subdomains.first
  return nil si subdomain.blank? || subdomain == "www"
  sous-domaine si I18n.available_locales.map(&:to_s).include?(sous-domaine)
end

La vérification « www » empêche qu'il soit traité comme une locale. Sur localhost, request.subdomains renvoie un tableau vide ; la détection des sous-domaines échoue donc en mode développement, à moins d'utiliser un serveur Pow ou d'ajouter des entrées au fichier /etc/hosts.

Il y a un élément à configurer séparément : la variable `default_url_options` définie dans `ApplicationController` ne se répercute pas sur les envois d'e-mails ni sur les tâches en arrière-plan. Définissez-la explicitement pour ces contextes :

Rails.application.routes.default_url_options = { host: "example.com", locale: :en }

Les routes localisées vous fournissent la structure des URL, mais les balises hreflang, les slugs traduits et les plans de site multilingues restent entièrement à gérer manuellement une fois cette configuration effectuée.

L'intégration du proxy inverse Weglot gère automatiquement cette couche, en générant des balises hreflang et des URL spécifiques à chaque langue sans configuration supplémentaire.

Pluralisation, solutions de repli et le gem rails-i18n

La formation du pluriel en anglais est simple. Une forme pour le singulier, une autre pour tous les autres cas.

en:
  messages:
    one: "%{count} message"
    other: "%{count} messages"

La plupart des langues ne sont pas si simples que ça.

En bulgare, par exemple, certains mots au masculin ont un pluriel régulier et un « pluriel de dénombrement » particulier. Ainsi, ден (jour) devient normalement дни (plusieurs jours), mais два дена (deux jours) lorsqu’on les compte.

bg:
  cities:
    one: "%{count} ден"
    few: "%{count} дена"
    many: "%{count} дни"

Sans rails-i18n, Rails n'a pas connaissance de ces règles. Vos traductions en bulgare généreraient des erreurs ou reviendraient à l'autre forme pour chaque nombre.

Gem intègre une logique de pluralisation pour plus de 100 langues, ce qui permet un affichage correct en bulgare, en russe, en arabe, en polonais et dans toute autre langue dont les règles de plural ne sont pas celles de l'anglais.

Les solutions de secours constituent un cas à part et sont désactivées par défaut. Sans elles, toute clé de traduction manquante entraîne l'affichage d'un message « traduction manquante » en production. C'est le genre de problème qui se glisse dans la version finale et apparaît sur les captures d'écran.

Activez les solutions de secours et définissez une destination par défaut dans le fichier config/application.rb:

config.i18n.fallbacks = [I18n.default_locale]

Lorsque l'option `fallbacks = true` est activée, une clé manquante dans la locale actuelle est remplacée par celle de la locale par défaut. Pour les variantes régionales, vous pouvez définir des chaînes explicites :

config.i18n.fallbacks = { "fr-CA": :fr, "en-GB": :en }

Pensez à le configurer dès le début. Il est plus difficile d'intégrer a posteriori un comportement de secours dans une application dont certaines parties sont déjà traduites et en production que de le mettre en place dès le départ.

Transmission des traductions aux contrôleurs Stimulus et à JavaScript

JavaScript n'a pas accès au pipeline I18n de Rails.

Il n'existe ni aide-mémoire « t », ni chargeur YAML, ni passerelle intégrée entre vos fichiers de traduction et vos contrôleurs Stimulus. Vous devez transmettre les traductions explicitement depuis le côté serveur.

L'approche la plus simple avec Stimulus consiste à utiliser l'API des valeurs. Définissez la traduction en tant que valeur dans le contrôleur, définissez-la dans le code HTML et récupérez-la en JavaScript :

# app/views/products/index.html.erb
<div data-controller="notification"
     data-notification-message-value="<%= t('.success_message') %>">

La valeur est générée côté serveur à l'aide de l'assistant t standard, elle respecte donc automatiquement les paramètres régionaux actuels. Côté JavaScript, déclarez-la comme une valeur statique et récupérez-la via l'API values :

// app/javascript/controllers/notification_controller.js
export default class extends Controller {
  static values = { message: String }

  show() {
    alert(this.messageValue)
  }
}

Chaque traduction est explicite et limitée au contrôleur qui en a besoin. Rien ne se propage dans l'espace de noms global.

Si un contrôleur a besoin de plusieurs traductions à la fois, il est plus clair de les regrouper sous forme d'attribut de données JSON plutôt que d'ajouter des définitions de valeur individuelles pour chaque chaîne :

<div data-controller="cart"
     data-cart-i18n-value="<%= { add: t('.add'), remove: t('.remove') }.to_json %>">

Du côté JavaScript, déclarez i18n comme une valeur de type Object et accédez directement aux clés individuelles :

static values = { i18n: Object }

add() {
  console.log(this.i18nValue.add)
}

Pour les applications où JavaScript doit pouvoir accéder à l'ensemble des données de localisation dans de nombreux contrôleurs, le gem i18n-js exporte vos fichiers YAML vers un objet JavaScript que vous pouvez interroger sous la forme I18n.t("clé").

Cela fonctionne, mais cela ajoute une étape de compilation et envoie l'intégralité de votre ensemble de traductions au client. Utilisez cette méthode lorsque les deux premières approches deviennent répétitives, et non par défaut.

Lorsque vous utilisez des Turbo Frames, si l'URL source d'un Turbo Frame ne comporte pas le préfixe de locale, la requête échouera généralement avec une erreur de routage (404), car elle ne correspondra pas au modèle de votre scope « /:locale ». Utilisez toujours des aides de chemin tenant compte de la locale pour les sources de frames.

Il ne s'agit pas d'un bug de Turbo. Il s'agit plutôt d'une erreur de routage, et l'action `around_action` de la section de détection de la locale permet de l'éviter tant que chaque URL du cadre utilise un assistant de chemin tenant compte de la locale.

Le proxy inverse Weglot adopte une approche totalement différente. Il traduit le DOM généré une fois la page chargée, ce qui permet de prendre en charge le contenu généré par Stimulus et les chaînes insérées dynamiquement sans nécessiter aucune configuration particulière.

Ce que l'I18n de Rails ne prend pas en charge

Trois catégories échappent totalement à la gestion de Rails I18n :

  • SEO multilingue Dans Rails, i18n traduit les chaînes de caractères mais ne génère pas de balises hreflang, de plans de site spécifiques à chaque langue ni de métadonnées traduites. Ces tâches nécessitent un travail manuel en plus de la configuration i18n.
  • Le contenu stocké dans la base de données, comme les noms de produits et les articles de blog, ne peut pas être enregistré dans des fichiers YAML. Il est recommandé d'utiliser le gem Mobility à cet effet, car il prend en charge plusieurs backends de stockage. Traco constitue une alternative plus légère pour les modèles de petite taille comportant des traductions par colonne.
  • Le flux de travail de traduction dans Rails repose sur des fichiers YAML. La gestion du processus de traduction, des cycles de révision et des mises à jour, ainsi que la synchronisation des traductions avec l'application, doivent être assurées en dehors du framework.

Weglot traite tous ces aspects au niveau de la couche de sortie plutôt qu'au niveau du code :

  • Au lieu de s'intégrer au pipeline I18n de Rails, il traduit le code HTML généré par votre application. Cela signifie que le contenu de la base de données, les chaînes générées par JavaScript et les traductions statiques sont tous traités de la même manière.
  • SEO multilingue est inclus : les balises hreflang, les URL traduites et les plans de site sont générés automatiquement.
  • Le processus de traduction s'effectue via le tableau de bord Weglot plutôt que par le biais de cycles d'exportation YAML.

Cela dit, il y a quelques limites qu'il convient de connaître avant de l'évaluer :

  • snippet JavaScript n'est pas prise en compte par les moteurs de recherche ; vous devez configurer le proxy inverse pour que les pages traduites apparaissent dans les résultats de recherche.
  • Le routage personnalisé vers des sous-répertoires, particulièrement utile si vous disposez déjà d'une configuration CDN ou Nginx, est réservé à la version Enterprise.
  • Contrairement aux traductions intégrées à votre code, Weglot un abonnement actif pour que le contenu traduit reste visible.

Choisir votre architecture d'internationalisation (i18n) pour Rails

Toute implémentation de l'internationalisation (i18n) dans Rails revient à prendre les mêmes décisions, dans un ordre à peu près identique.

Commencez par définir votre stratégie d'URL avant d'écrire le moindre code de détection de la langue. Les segments de chemin d'accès conviennent à la plupart des applications grand public. Les sous-domaines sont utiles lorsque l'identité régionale est importante. Les préférences enregistrées dans la base de données conviennent aux applications nécessitant une authentification, où la langue suit l'utilisateur plutôt que l'URL.

Deuxièmement, déterminez comment JavaScript récupère les traductions. L'API Stimulus values couvre la plupart des cas. Les attributs JSON sont utiles lorsqu'un contrôleur a besoin de plusieurs chaînes de caractères à la fois.

Troisièmement, déterminez ce que vous souhaitez développer manuellement. Rails gère bien les chaînes de caractères statiques. La couche SEO, le flux de travail de traduction et le contenu de la base de données nécessitent tous des décisions distinctes. Vous pouvez développer chacun de ces éléments vous-même, ou confier la couche de sortie à un outil tel que Weglot consacrer votre temps de développement à l'application elle-même.

Ignorez complètement la couche de sortie. Testez Weglot pendant 14 jours et bénéficiez SEO multilingue, d'URL traduites et de la détection automatique du contenu sans toucher à votre code d'internationalisation.

Icône de direction
Découvrez Weglot

Rejoignez plus de 110 000 marques qui traduisent déjà leurs sites avec Weglot

Traduisez votre site web instantanément grâce à l'IA, peaufinez le texte avec une révision humaine et mettez-le en ligne en quelques minutes.

Dans cet article, vous allez découvrir :
Icône fusée

Qu'attendez-vous pour vous lancer ?

La meilleure façon de comprendre la puissance de Weglot de le tester par vous-même. Essayez-le gratuitement et sans engagement.

Un site web de démonstration est disponible dans votre tableau de bord si vous n'êtes pas encore prêt à connecter votre site web.

Autres articles qui pourraient vous intéresser

Icône FAQ

Questions fréquentes

Aucun élément trouvé.

Flèche bleue

Flèche bleue

Flèche bleue