edge
Plus sur rubyonrails.org: Plus de Ruby on Rails

API d'internationalisation de Rails (I18n)

Le gem Ruby I18n (abréviation de internationalisation) qui est livré avec Ruby on Rails (à partir de Rails 2.2) fournit un framework facile à utiliser et extensible pour traduire votre application dans une langue personnalisée unique autre que l'anglais ou pour fournir une prise en charge multilingue dans votre application.

Le processus d'"internationalisation" consiste généralement à abstraire toutes les chaînes de caractères et autres éléments spécifiques à la localité (comme les formats de date ou de devise) de votre application. Le processus de "localisation" consiste à fournir des traductions et des formats localisés pour ces éléments.1

Ainsi, dans le processus d'internationalisation de votre application Rails, vous devez :

Dans le processus de localisation de votre application, vous voudrez probablement faire les trois choses suivantes :

Ce guide vous guidera à travers l'API I18n et contient un tutoriel sur la façon d'internationaliser une application Rails dès le départ.

Après avoir lu ce guide, vous saurez :

NOTE : Le framework Ruby I18n vous fournit tous les moyens nécessaires pour l'internationalisation/localisation de votre application Rails. Vous pouvez également utiliser divers gems disponibles pour ajouter des fonctionnalités ou des caractéristiques supplémentaires. Consultez le gem rails-i18n pour plus d'informations.

1 Fonctionnement de l'I18n dans Ruby on Rails

L'internationalisation est un problème complexe. Les langues naturelles diffèrent de tant de façons (par exemple, dans les règles de pluriel) qu'il est difficile de fournir des outils pour résoudre tous les problèmes en même temps. C'est pourquoi l'API I18n de Rails se concentre sur :

  • fournir une prise en charge de l'anglais et des langues similaires dès le départ
  • faciliter la personnalisation et l'extension de tout pour les autres langues

Dans le cadre de cette solution, chaque chaîne de caractères statique dans le framework Rails - par exemple, les messages de validation Active Record, les formats de date et d'heure - a été internationalisée. La localisation d'une application Rails consiste à définir des valeurs traduites pour ces chaînes dans les langues souhaitées.

Pour localiser, stocker et mettre à jour le contenu de votre application (par exemple, traduire des articles de blog), consultez la section Traduction du contenu du modèle.

1.1 Architecture globale de la bibliothèque

Ainsi, le gem Ruby I18n est divisé en deux parties :

  • L'API publique du framework I18n - un module Ruby avec des méthodes publiques qui définissent le fonctionnement de la bibliothèque
  • Un backend par défaut (qui est intentionnellement nommé backend Simple) qui implémente ces méthodes

En tant qu'utilisateur, vous ne devriez toujours accéder qu'aux méthodes publiques du module I18n, mais il est utile de connaître les capacités du backend.

NOTE : Il est possible de remplacer le backend Simple fourni par un backend plus puissant, qui stockerait les données de traduction dans une base de données relationnelle, un dictionnaire GetText, ou similaire. Voir la section Utilisation de différents backends ci-dessous.

1.2 L'API publique de l'I18n

Les méthodes les plus importantes de l'API I18n sont :

translate # Recherche de traductions de texte
localize  # Localisation des objets Date et Time aux formats locaux

Elles ont les alias #t et #l, vous pouvez donc les utiliser comme ceci :

I18n.t 'store.title'
I18n.l Time.now

Il y a aussi des lecteurs et des écrivains d'attributs pour les attributs suivants :

load_path                 # Annoncez vos fichiers de traduction personnalisés
locale                    # Obtenir et définir la localité actuelle
default_locale            # Obtenir et définir la localité par défaut
available_locales         # Localités autorisées disponibles pour l'application
enforce_available_locales # Appliquer les autorisations de localité (true ou false)
exception_handler         # Utiliser un gestionnaire d'exceptions différent
backend                   # Utiliser un backend différent

Alors, internationalisons une application Rails simple à partir de zéro dans les prochains chapitres !

2 Configurer l'application Rails pour l'internationalisation

Il y a quelques étapes à suivre pour mettre en place la prise en charge de l'I18n pour une application Rails.

2.1 Configurer le module I18n

Suivant la philosophie de convention plutôt que configuration, Rails I18n fournit des chaînes de traduction par défaut raisonnables. Lorsque des chaînes de traduction différentes sont nécessaires, elles peuvent être remplacées.

Rails ajoute tous les fichiers .rb et .yml du répertoire config/locales au chemin de chargement des traductions, automatiquement.

Le fichier en.yml par défaut de ce répertoire contient une paire d'exemples de chaînes de traduction :

en:
  hello: "Hello world"

Cela signifie que, dans la locale :en, la clé hello sera associée à la chaîne Hello world. Toute chaîne dans Rails est internationalisée de cette manière, voyez par exemple les messages de validation d'Active Model dans le fichier activemodel/lib/active_model/locale/en.yml ou les formats de date et d'heure dans le fichier activesupport/lib/active_support/locale/en.yml. Vous pouvez utiliser YAML ou des Hashes Ruby standard pour stocker les traductions dans le backend par défaut (Simple).

La bibliothèque I18n utilisera l'anglais comme locale par défaut, c'est-à-dire que si une locale différente n'est pas définie, :en sera utilisée pour rechercher les traductions.

NOTE : La bibliothèque i18n adopte une approche pragmatique pour les clés de locale (après quelques discussions), en incluant uniquement la partie locale ("langue"), comme :en, :pl, et non la partie région, comme :"en-US" ou :"en-GB", qui sont traditionnellement utilisées pour séparer "langues" et "paramètres régionaux" ou "dialectes". De nombreuses applications internationales n'utilisent que l'élément "langue" d'une locale telle que :cs, :th ou :es (pour le tchèque, le thaï et l'espagnol). Cependant, il existe également des différences régionales au sein de différents groupes linguistiques qui peuvent être importantes. Par exemple, dans la locale :"en-US", vous auriez $ comme symbole de devise, tandis que dans :"en-GB", vous auriez £. Rien ne vous empêche de séparer les paramètres régionaux et autres de cette manière : vous devez simplement fournir une locale "Anglais - Royaume-Uni" complète dans un dictionnaire :"en-GB".

Le chemin de chargement des traductions (I18n.load_path) est un tableau de chemins vers les fichiers qui seront chargés automatiquement. La configuration de ce chemin permet de personnaliser la structure du répertoire des traductions et le schéma de nommage des fichiers.

NOTE : Le backend charge les traductions de manière paresseuse lorsqu'une traduction est recherchée pour la première fois. Ce backend peut être remplacé par autre chose même après que les traductions aient déjà été annoncées.

Vous pouvez modifier la locale par défaut ainsi que configurer les chemins de chargement des traductions dans config/application.rb de la manière suivante :

config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
config.i18n.default_locale = :de

Le chemin de chargement doit être spécifié avant que les traductions ne soient recherchées. Pour changer la locale par défaut à partir d'un initialiseur au lieu de config/application.rb :

# config/initializers/locale.rb

# Où la bibliothèque I18n doit rechercher les fichiers de traduction
I18n.load_path += Dir[Rails.root.join('lib', 'locale', '*.{rb,yml}')]

# Locales autorisées disponibles pour l'application
I18n.available_locales = [:en, :pt]

# Définir la locale par défaut sur autre chose que :en
I18n.default_locale = :pt

Notez que l'ajout direct à I18n.load_path au lieu de la configuration I18n de l'application ne remplacera pas les traductions des gemmes externes.

2.2 Gérer la locale entre les requêtes

Une application localisée devra probablement prendre en charge plusieurs locales. Pour cela, la locale doit être définie au début de chaque requête afin que toutes les chaînes soient traduites en utilisant la locale souhaitée pendant la durée de cette requête.

La locale par défaut est utilisée pour toutes les traductions sauf si I18n.locale= ou I18n.with_locale est utilisé.

I18n.locale peut se propager dans les requêtes ultérieures servies par le même thread/processus s'il n'est pas défini de manière cohérente dans chaque contrôleur. Par exemple, l'exécution de I18n.locale = :es dans une requête POST aura des effets sur toutes les requêtes ultérieures vers les contrôleurs qui ne définissent pas la locale, mais uniquement dans ce thread/processus particulier. Pour cette raison, au lieu de I18n.locale =, vous pouvez utiliser I18n.with_locale qui n'a pas ce problème de propagation.

La locale peut être définie dans une around_action dans le ApplicationController :

around_action :switch_locale

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

Cet exemple illustre cela en utilisant un paramètre de requête URL pour définir la locale (par exemple http://example.com/books?locale=pt). Avec cette approche, http://localhost:3000?locale=pt affiche la localisation portugaise, tandis que http://localhost:3000?locale=de charge une localisation allemande.

La locale peut être définie de différentes manières.

2.2.1 Définir la locale à partir du nom de domaine

Une option que vous avez est de définir la locale à partir du nom de domaine où s'exécute votre application. Par exemple, nous voulons que www.example.com charge la locale anglaise (ou par défaut), et www.example.es charge la locale espagnole. Ainsi, le nom de domaine de premier niveau est utilisé pour définir la locale. Cela présente plusieurs avantages : * La localisation est une partie évidente de l'URL. * Les gens comprennent intuitivement dans quelle langue le contenu sera affiché. * C'est très trivial à implémenter dans Rails. * Les moteurs de recherche semblent apprécier que le contenu dans différentes langues soit présent sur des domaines différents et interconnectés.

Vous pouvez l'implémenter de cette manière dans votre ApplicationController :

around_action :switch_locale

def switch_locale(&action)
  locale = extract_locale_from_tld || I18n.default_locale
  I18n.with_locale(locale, &action)
end

# Obtenir la locale à partir du domaine de premier niveau ou renvoyer +nil+ si cette locale n'est pas disponible
# Vous devez ajouter quelque chose comme :
#   127.0.0.1 application.com
#   127.0.0.1 application.it
#   127.0.0.1 application.pl
# dans votre fichier /etc/hosts pour tester cela localement
def extract_locale_from_tld
  parsed_locale = request.host.split('.').last
  I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
end

Nous pouvons également définir la locale à partir du sous-domaine de manière très similaire :

# Obtenir le code de la locale à partir du sous-domaine de la requête (comme http://it.application.local:3000)
# Vous devez ajouter quelque chose comme :
#   127.0.0.1 gr.application.local
# dans votre fichier /etc/hosts pour tester cela localement
def extract_locale_from_subdomain
  parsed_locale = request.subdomains.first
  I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
end

Si votre application inclut un menu de changement de locale, vous auriez alors quelque chose comme ceci :

link_to("Deutsch", "#{APP_CONFIG[:deutsch_website_url]}#{request.env['PATH_INFO']}")

en supposant que vous définissiez APP_CONFIG[:deutsch_website_url] à une valeur telle que http://www.application.de.

Cette solution présente les avantages mentionnés précédemment, cependant, vous pourriez ne pas être en mesure ou ne pas vouloir fournir différentes localisations ("versions linguistiques") sur différents domaines. La solution la plus évidente serait d'inclure le code de la locale dans les paramètres de l'URL (ou le chemin de la requête).

2.2.2 Définir la locale à partir des paramètres de l'URL

La manière la plus courante de définir (et de transmettre) la locale serait de l'inclure dans les paramètres de l'URL, comme nous l'avons fait avec I18n.with_locale(params[:locale], &action) dans le premier exemple. Nous aimerions avoir des URLs comme www.example.com/books?locale=ja ou www.example.com/ja/books dans ce cas.

Cette approche présente presque les mêmes avantages que la définition de la locale à partir du nom de domaine : elle est RESTful et conforme au reste du World Wide Web. Cependant, elle nécessite un peu plus de travail à mettre en œuvre.

Obtenir la locale à partir de params et la définir en conséquence n'est pas difficile ; l'inclure dans chaque URL et donc la transmettre à travers les requêtes l'est. Inclure une option explicite dans chaque URL, par exemple link_to(books_url(locale: I18n.locale)), serait fastidieux et probablement impossible.

Rails contient une infrastructure pour "centraliser les décisions dynamiques concernant les URLs" dans son ApplicationController#default_url_options, ce qui est utile précisément dans ce scénario : cela nous permet de définir des "valeurs par défaut" pour url_for et les méthodes d'assistance qui en dépendent (en implémentant/remplaçant default_url_options).

Nous pouvons inclure quelque chose comme ceci dans notre ApplicationController :

# app/controllers/application_controller.rb
def default_url_options
  { locale: I18n.locale }
end

Toute méthode d'assistance dépendant de url_for (par exemple, les assistants pour les routes nommées comme root_path ou root_url, les routes de ressources comme books_path ou books_url, etc.) inclura maintenant automatiquement la locale dans la chaîne de requête, comme ceci : http://localhost:3001/?locale=ja.

Vous pouvez être satisfait de cela. Cependant, cela affecte la lisibilité des URLs lorsque la locale "traîne" à la fin de chaque URL de votre application. De plus, du point de vue architectural, la locale est généralement hiérarchiquement supérieure aux autres parties du domaine de l'application : et les URLs devraient refléter cela.

Vous voulez probablement que les URLs ressemblent à ceci : http://www.example.com/en/books (qui charge la locale anglaise) et http://www.example.com/nl/books (qui charge la locale néerlandaise). Cela est réalisable avec la stratégie de "surcharge de default_url_options" mentionnée ci-dessus : vous devez simplement configurer vos routes avec scope :

# config/routes.rb
scope "/:locale" do
  resources :books
end

Maintenant, lorsque vous appelez la méthode books_path, vous devriez obtenir "/en/books" (pour la locale par défaut). Une URL comme http://localhost:3001/nl/books devrait charger la locale néerlandaise, puis, les appels suivants à books_path devraient renvoyer "/nl/books" (parce que la locale a changé).

ATTENTION. Étant donné que la valeur de retour de default_url_options est mise en cache par requête, les URLs dans un sélecteur de locale ne peuvent pas être générées en invoquant des assistants dans une boucle qui définit la I18n.locale correspondante à chaque itération. Au lieu de cela, laissez I18n.locale inchangé et passez une option :locale explicite à l'assistant, ou modifiez request.original_fullpath.

Si vous ne souhaitez pas imposer l'utilisation d'une locale dans vos routes, vous pouvez utiliser une portée de chemin facultative (indiquée par les parenthèses) comme ceci :

# config/routes.rb
scope "(:locale)", locale: /en|nl/ do
  resources :books
end

Avec cette approche, vous n'obtiendrez pas d'erreur de routage lors de l'accès à vos ressources telles que http://localhost:3001/books sans localisation. Cela est utile lorsque vous souhaitez utiliser la localisation par défaut lorsqu'elle n'est pas spécifiée.

Bien sûr, vous devez prendre des précautions particulières pour l'URL racine (généralement "homepage" ou "dashboard") de votre application. Une URL comme http://localhost:3001/nl ne fonctionnera pas automatiquement, car la déclaration root to: "dashboard#index" dans votre routes.rb ne prend pas en compte la localisation. (Et à juste titre: il n'y a qu'une seule URL "racine".)

Vous devriez probablement mapper des URL comme celles-ci:

# config/routes.rb
get '/:locale' => 'dashboard#index'

Faites particulièrement attention à l'ordre de vos routes, afin que cette déclaration de route ne "mange" pas les autres. (Vous voudrez peut-être l'ajouter directement avant la déclaration root :to.)

Jetez un œil à diverses gemmes qui simplifient le travail avec les routes: routing_filter, route_translator.

2.2.3 Définition de la localisation à partir des préférences de l'utilisateur

Une application avec des utilisateurs authentifiés peut permettre aux utilisateurs de définir une préférence de localisation via l'interface de l'application. Avec cette approche, la localisation préférée sélectionnée par un utilisateur est persistée dans la base de données et utilisée pour définir la localisation des requêtes authentifiées par cet utilisateur.

around_action :switch_locale

def switch_locale(&action)
  locale = current_user.try(:locale) || I18n.default_locale
  I18n.with_locale(locale, &action)
end

2.2.4 Choix d'une localisation implicite

Lorsqu'une localisation explicite n'a pas été définie pour une requête (par exemple, via l'une des méthodes ci-dessus), une application doit essayer de déduire la localisation souhaitée.

2.2.4.1 Déduction de la localisation à partir de l'en-tête de langue

L'en-tête HTTP Accept-Language indique la langue préférée pour la réponse de la requête. Les navigateurs définissent cette valeur d'en-tête en fonction des paramètres de préférence de langue de l'utilisateur, ce qui en fait un bon premier choix pour déduire une localisation.

Une implémentation triviale de l'utilisation d'un en-tête Accept-Language serait:

def switch_locale(&action)
  logger.debug "* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}"
  locale = extract_locale_from_accept_language_header
  logger.debug "* Locale set to '#{locale}'"
  I18n.with_locale(locale, &action)
end

private
  def extract_locale_from_accept_language_header
    request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first
  end

En pratique, un code plus robuste est nécessaire pour le faire de manière fiable. La bibliothèque http_accept_language de Iain Hecker ou le middleware Rack locale de Ryan Tomayko fournissent des solutions à ce problème.

2.2.4.2 Déduction de la localisation à partir de la géolocalisation IP

L'adresse IP du client effectuant la requête peut être utilisée pour déduire la région du client et donc sa localisation. Des services tels que GeoLite2 Country ou des gemmes comme geocoder peuvent être utilisés pour mettre en œuvre cette approche.

En général, cette approche est beaucoup moins fiable que l'utilisation de l'en-tête de langue et n'est pas recommandée pour la plupart des applications web.

2.2.5 Stockage de la localisation à partir de la session ou des cookies

AVERTISSEMENT: Vous pourriez être tenté de stocker la localisation choisie dans une session ou un cookie. Cependant, ne le faites pas. La localisation doit être transparente et faire partie de l'URL. De cette façon, vous ne briserez pas les hypothèses de base des utilisateurs sur le web lui-même: si vous envoyez une URL à un ami, il devrait voir la même page et le même contenu que vous. Un terme à la mode pour cela serait que vous êtes RESTful. Lisez-en plus sur l'approche RESTful dans les articles de Stefan Tilkov. Parfois, il y a des exceptions à cette règle et elles sont discutées ci-dessous.

3 Internationalisation et localisation

OK! Maintenant, vous avez initialisé la prise en charge de l'internationalisation pour votre application Ruby on Rails et vous lui avez indiqué quelle localisation utiliser et comment la conserver entre les requêtes.

Ensuite, nous devons internationaliser notre application en abstrayant chaque élément spécifique à la localisation. Enfin, nous devons localiser en fournissant les traductions nécessaires pour ces abstractions.

Prenons l'exemple suivant:

# config/routes.rb
Rails.application.routes.draw do
  root to: "home#index"
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  around_action :switch_locale

  def switch_locale(&action)
    locale = params[:locale] || I18n.default_locale
    I18n.with_locale(locale, &action)
  end
end
# app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
    flash[:notice] = "Hello Flash"
  end
end
<!-- app/views/home/index.html.erb -->
<h1>Hello World</h1>
<p><%= flash[:notice] %></p>

rails i18n demo untranslated

3.1 Abstraction du code localisé

Dans notre code, il y a deux chaînes écrites en anglais qui seront rendues dans notre réponse ("Hello Flash" et "Hello World"). Pour internationaliser ce code, ces chaînes doivent être remplacées par des appels à l'assistant #t de Rails avec une clé appropriée pour chaque chaîne:

# app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
    flash[:notice] = t(:hello_flash)
  end
end
<!-- app/views/home/index.html.erb -->
<h1><%= t :hello_world %></h1>
<p><%= flash[:notice] %></p>

Maintenant, lorsque cette vue est rendue, elle affichera un message d'erreur qui vous indique que les traductions pour les clés :hello_world et :hello_flash sont manquantes.

rails i18n demo translation missing

NOTE : Rails ajoute une méthode d'aide t (translate) à vos vues afin que vous n'ayez pas besoin d'écrire I18n.t tout le temps. De plus, cette méthode d'aide interceptera les traductions manquantes et enveloppera le message d'erreur résultant dans un <span class="translation_missing">.

3.2 Fournir des traductions pour les chaînes internationalisées

Ajoutez les traductions manquantes dans les fichiers de dictionnaire de traduction :

# config/locales/en.yml
en:
  hello_world: Hello world!
  hello_flash: Hello flash!
# config/locales/pirate.yml
pirate:
  hello_world: Ahoy World
  hello_flash: Ahoy Flash

Comme la default_locale n'a pas changé, les traductions utilisent la locale :en et la réponse affiche les chaînes anglaises :

rails i18n demo translated to English

Si la locale est définie via l'URL sur la locale pirate (http://localhost:3000?locale=pirate), la réponse affiche les chaînes pirates :

rails i18n demo translated to pirate

NOTE : Vous devez redémarrer le serveur lorsque vous ajoutez de nouveaux fichiers de locale.

Vous pouvez utiliser des fichiers YAML (.yml) ou Ruby simple (.rb) pour stocker vos traductions dans SimpleStore. YAML est l'option préférée des développeurs Rails. Cependant, il présente un inconvénient majeur. YAML est très sensible aux espaces et aux caractères spéciaux, il se peut donc que l'application ne charge pas correctement votre dictionnaire. Les fichiers Ruby feront planter votre application lors de la première requête, vous permettant ainsi de trouver facilement ce qui ne va pas. (Si vous rencontrez des problèmes "bizarres" avec les dictionnaires YAML, essayez de mettre la partie pertinente de votre dictionnaire dans un fichier Ruby.)

Si vos traductions sont stockées dans des fichiers YAML, certaines clés doivent être échappées. Il s'agit de :

  • true, on, yes
  • false, off, no

Exemples :

# config/locales/en.yml
en:
  success:
    'true':  'True!'
    'on':    'On!'
    'false': 'False!'
  failure:
    true:    'True!'
    off:     'Off!'
    false:   'False!'
I18n.t 'success.true'  # => 'True!'
I18n.t 'success.on'    # => 'On!'
I18n.t 'success.false' # => 'False!'
I18n.t 'failure.false' # => Translation Missing
I18n.t 'failure.off'   # => Translation Missing
I18n.t 'failure.true'  # => Translation Missing

3.3 Passage de variables aux traductions

Une considération clé pour internationaliser avec succès une application est d'éviter de faire des hypothèses incorrectes sur les règles de grammaire lors de l'abstraction du code localisé. Les règles de grammaire qui semblent fondamentales dans une locale peuvent ne pas être vraies dans une autre.

Une mauvaise abstraction est illustrée dans l'exemple suivant, où des hypothèses sont faites sur l'ordre des différentes parties de la traduction. Notez que Rails fournit une méthode d'aide number_to_currency pour gérer le cas suivant.

<!-- app/views/products/show.html.erb -->
<%= "#{t('currency')}#{@product.price}" %>
# config/locales/en.yml
en:
  currency: "$"
# config/locales/es.yml
es:
  currency: "€"

Si le prix du produit est de 10, la traduction appropriée en espagnol est "10 €" au lieu de "€10", mais l'abstraction ne peut pas le donner.

Pour créer une abstraction correcte, la gemme I18n est livrée avec une fonctionnalité appelée interpolation de variables qui vous permet d'utiliser des variables dans les définitions de traduction et de passer les valeurs de ces variables à la méthode de traduction.

Une abstraction correcte est illustrée dans l'exemple suivant :

<!-- app/views/products/show.html.erb -->
<%= t('product_price', price: @product.price) %>
# config/locales/en.yml
en:
  product_price: "$%{price}"
# config/locales/es.yml
es:
  product_price: "%{price} €"

Toutes les décisions grammaticales et de ponctuation sont prises dans la définition elle-même, de sorte que l'abstraction peut donner une traduction appropriée.

NOTE : Les mots-clés default et scope sont réservés et ne peuvent pas être utilisés comme noms de variables. S'ils sont utilisés, une exception I18n::ReservedInterpolationKey est levée. Si une traduction attend une variable d'interpolation, mais que celle-ci n'a pas été passée à #translate, une exception I18n::MissingInterpolationArgument est levée.

3.4 Ajout de formats de date/heure

OK ! Maintenant, ajoutons un horodatage à la vue, afin de pouvoir également présenter la fonctionnalité de localisation de la date/heure. Pour localiser le format de l'heure, vous passez l'objet Time à I18n.l ou (de préférence) utilisez l'aide #l de Rails. Vous pouvez choisir un format en passant l'option :format - par défaut, le format :default est utilisé.

<!-- app/views/home/index.html.erb -->
<h1><%= t :hello_world %></h1>
<p><%= flash[:notice] %></p>
<p><%= l Time.now, format: :short %></p>

Et dans notre fichier de traductions pirate, ajoutons un format d'heure (il est déjà présent dans les valeurs par défaut de Rails pour l'anglais) :

# config/locales/pirate.yml
pirate:
  time:
    formats:
      short: "arrrround %H'ish"

Cela donnerait donc :

rails i18n demo localized time to pirate

CONSEIL : À l'heure actuelle, vous devrez peut-être ajouter quelques formats de date/heure supplémentaires pour que le backend I18n fonctionne comme prévu (au moins pour la locale 'pirate'). Bien sûr, il y a de fortes chances que quelqu'un ait déjà fait tout le travail en traduisant les valeurs par défaut de Rails pour votre locale. Consultez le dépôt rails-i18n sur GitHub pour une archive de différents fichiers de locale. Lorsque vous placez de tels fichiers dans le répertoire config/locales/, ils seront automatiquement prêts à être utilisés.

3.5 Règles d'inflection pour d'autres locales

Rails vous permet de définir des règles d'inflection (telles que des règles de singulier et de pluriel) pour des locales autres que l'anglais. Dans config/initializers/inflections.rb, vous pouvez définir ces règles pour plusieurs locales. L'initialiseur contient un exemple par défaut pour spécifier des règles supplémentaires pour l'anglais ; suivez ce format pour les autres locales selon vos besoins.

3.6 Vues localisées

Disons que vous avez un BooksController dans votre application. Votre action index affiche du contenu dans le modèle app/views/books/index.html.erb. Lorsque vous placez une variante localisée de ce modèle : index.es.html.erb dans le même répertoire, Rails affichera le contenu de ce modèle lorsque la locale est définie sur :es. Lorsque la locale est définie sur la locale par défaut, la vue générique index.html.erb sera utilisée. (Les futures versions de Rails pourraient bien apporter cette localisation automagique aux ressources dans public, etc.)

Vous pouvez utiliser cette fonctionnalité, par exemple, lorsque vous travaillez avec une grande quantité de contenu statique, qui serait maladroit à mettre dans des dictionnaires YAML ou Ruby. Gardez à l'esprit, cependant, que toute modification que vous souhaitez apporter ultérieurement au modèle doit être propagée à tous les modèles.

3.7 Organisation des fichiers de locale

Lorsque vous utilisez le SimpleStore par défaut fourni avec la bibliothèque i18n, les dictionnaires sont stockés dans des fichiers texte sur le disque. Mettre les traductions pour toutes les parties de votre application dans un fichier par locale peut être difficile à gérer. Vous pouvez stocker ces fichiers dans une hiérarchie qui vous semble logique.

Par exemple, votre répertoire config/locales pourrait ressembler à ceci :

|-defaults
|---es.yml
|---en.yml
|-models
|---book
|-----es.yml
|-----en.yml
|-views
|---defaults
|-----es.yml
|-----en.yml
|---books
|-----es.yml
|-----en.yml
|---users
|-----es.yml
|-----en.yml
|---navigation
|-----es.yml
|-----en.yml

De cette façon, vous pouvez séparer les noms de modèle et d'attribut de modèle du texte à l'intérieur des vues, et tout cela des "valeurs par défaut" (par exemple, les formats de date et d'heure). D'autres magasins pour la bibliothèque i18n pourraient fournir des moyens différents de cette séparation.

REMARQUE : Le mécanisme de chargement de la locale par défaut dans Rails ne charge pas les fichiers de locale dans les dictionnaires imbriqués, comme nous en avons ici. Donc, pour que cela fonctionne, nous devons explicitement dire à Rails de chercher plus loin :

# config/application.rb
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]

4 Aperçu des fonctionnalités de l'API I18n

Vous devriez maintenant avoir une bonne compréhension de l'utilisation de la bibliothèque i18n et savoir comment internationaliser une application Rails de base. Dans les chapitres suivants, nous couvrirons ses fonctionnalités plus en détail.

Ces chapitres montreront des exemples utilisant à la fois la méthode I18n.translate et la méthode d'aide de vue translate (en notant les fonctionnalités supplémentaires fournies par la méthode d'aide de vue).

Seront abordées des fonctionnalités telles que :

  • recherche de traductions
  • interpolation de données dans les traductions
  • pluriel des traductions
  • utilisation de traductions HTML sécurisées (uniquement avec la méthode d'aide de vue)
  • localisation des dates, des nombres, de la monnaie, etc.

4.1 Recherche de traductions

4.1.1 Recherche de base, portées et clés imbriquées

Les traductions sont recherchées par des clés qui peuvent être à la fois des symboles ou des chaînes de caractères, donc ces appels sont équivalents :

I18n.t :message
I18n.t 'message'

La méthode translate prend également une option :scope qui peut contenir une ou plusieurs clés supplémentaires qui seront utilisées pour spécifier un "espace de noms" ou une portée pour une clé de traduction :

I18n.t :record_invalid, scope: [:activerecord, :errors, :messages]

Cela recherche le message :record_invalid dans les messages d'erreur d'Active Record.

De plus, la clé et les portées peuvent être spécifiées sous forme de clés séparées par des points, comme ceci :

I18n.translate "activerecord.errors.messages.record_invalid"

Ainsi, les appels suivants sont équivalents :

I18n.t 'activerecord.errors.messages.record_invalid'
I18n.t 'errors.messages.record_invalid', scope: :activerecord
I18n.t :record_invalid, scope: 'activerecord.errors.messages'
I18n.t :record_invalid, scope: [:activerecord, :errors, :messages]

4.1.2 Valeurs par défaut

Lorsqu'une option :default est donnée, sa valeur sera renvoyée si la traduction est manquante :

I18n.t :missing, default: 'Not here'
# => 'Not here'

Si la valeur :default est un symbole, il sera utilisé comme clé et traduit. On peut fournir plusieurs valeurs par défaut. La première qui donne une valeur sera renvoyée.

Par exemple, le code suivant essaie d'abord de traduire la clé :missing, puis la clé :also_missing. Comme les deux ne donnent pas de résultat, la chaîne "Not here" sera renvoyée :

I18n.t :missing, default: [:also_missing, 'Not here']
# => 'Not here'

4.1.3 Recherche en vrac et dans un espace de noms

Pour rechercher plusieurs traductions en une seule fois, un tableau de clés peut être passé : ```ruby I18n.t [:odd, :even], scope: 'errors.messages'

=> ["doit être impair", "doit être pair"]


De plus, une clé peut être traduite en un hash de traductions regroupées (potentiellement imbriquées). Par exemple, on peut obtenir **toutes** les messages d'erreur d'Active Record sous forme de hash avec :

```ruby
I18n.t 'errors.messages'
# => {:inclusion=>"n'est pas inclus dans la liste", :exclusion=> ... }

Si vous souhaitez effectuer une interpolation sur un hash de traductions en vrac, vous devez passer deep_interpolation: true en paramètre. Lorsque vous avez le dictionnaire suivant :

en:
  welcome:
    title: "Bienvenue !"
    content: "Bienvenue sur %{app_name}"

alors l'interpolation imbriquée sera ignorée sans le paramètre :

I18n.t 'welcome', app_name: 'librairie'
# => {:title=>"Bienvenue !", :content=>"Bienvenue sur %{app_name}"}

I18n.t 'welcome', deep_interpolation: true, app_name: 'librairie'
# => {:title=>"Bienvenue !", :content=>"Bienvenue sur librairie"}

4.1.4 Recherche "paresseuse"

Rails implémente une manière pratique de rechercher la locale à l'intérieur des vues. Lorsque vous avez le dictionnaire suivant :

es:
  books:
    index:
      title: "Título"

vous pouvez rechercher la valeur de books.index.title à l'intérieur du modèle app/views/books/index.html.erb de cette manière (notez le point) :

<%= t '.title' %>

NOTE : La recherche automatique de la portée de traduction par partial n'est disponible qu'à partir de la méthode d'aide à la vue translate.

La recherche "paresseuse" peut également être utilisée dans les contrôleurs :

en:
  books:
    create:
      success: Livre créé !

Cela est utile pour définir des messages flash par exemple :

class BooksController < ApplicationController
  def create
    # ...
    redirect_to books_url, notice: t('.success')
  end
end

4.2 Pluralisation

Dans de nombreuses langues - y compris l'anglais - il n'y a que deux formes, singulier et pluriel, pour une chaîne donnée, par exemple "1 message" et "2 messages". D'autres langues (arabe, japonais, russe et bien d'autres) ont des grammaires différentes qui ont des formes plurielles supplémentaires ou moins de formes plurielles. Ainsi, l'API I18n fournit une fonctionnalité de pluralisation flexible.

La variable d'interpolation :count joue un rôle spécial car elle est à la fois interpolée dans la traduction et utilisée pour choisir une pluralisation parmi les traductions en fonction des règles de pluralisation définies dans le backend de pluralisation. Par défaut, seules les règles de pluralisation anglaises sont appliquées.

I18n.backend.store_translations :en, inbox: {
  zero: 'aucun message', # facultatif
  one: 'un message',
  other: '%{count} messages'
}
I18n.translate :inbox, count: 2
# => '2 messages'

I18n.translate :inbox, count: 1
# => 'un message'

I18n.translate :inbox, count: 0
# => 'aucun message'

L'algorithme de pluralisation en :en est aussi simple que :

lookup_key = :zero if count == 0 && entry.has_key?(:zero)
lookup_key ||= count == 1 ? :one : :other
entry[lookup_key]

La traduction désignée par :one est considérée comme singulière, et :other est utilisée comme plurielle. Si le compte est zéro et qu'une entrée :zero est présente, elle sera utilisée à la place de :other.

Si la recherche de la clé ne renvoie pas un hash adapté à la pluralisation, une exception I18n::InvalidPluralizationData est levée.

4.2.1 Règles spécifiques à la locale

La gem I18n fournit un backend de pluralisation qui peut être utilisé pour activer des règles spécifiques à la locale. Incluez-le dans le backend Simple, puis ajoutez les algorithmes de pluralisation localisés au magasin de traduction, en tant que i18n.plural.rule.

I18n::Backend::Simple.include(I18n::Backend::Pluralization)
I18n.backend.store_translations :pt, i18n: { plural: { rule: lambda { |n| [0, 1].include?(n) ? :one : :other } } }
I18n.backend.store_translations :pt, apples: { one: 'un ou aucun', other: 'plus d'un' }

I18n.t :apples, count: 0, locale: :pt
# => 'un ou aucun'

Alternativement, la gem séparée rails-i18n peut être utilisée pour fournir un ensemble plus complet de règles de pluralisation spécifiques à la locale.

4.3 Définition et passage d'une locale

La locale peut être définie de manière pseudo-globale sur I18n.locale (qui utilise Thread.current de la même manière que, par exemple, Time.zone) ou peut être passée en tant qu'option à #translate et #localize.

Si aucune locale n'est passée, I18n.locale est utilisée :

I18n.locale = :de
I18n.t :foo
I18n.l Time.now

Passage explicite d'une locale :

I18n.t :foo, locale: :de
I18n.l Time.now, locale: :de

I18n.locale est par défaut I18n.default_locale qui est par défaut :en. La locale par défaut peut être définie comme ceci :

I18n.default_locale = :de

4.4 Utilisation de traductions HTML sécurisées

Les clés avec un suffixe '_html' et les clés nommées 'html' sont marquées comme étant sécurisées en HTML. Lorsque vous les utilisez dans les vues, le HTML ne sera pas échappé.

# config/locales/en.yml
en:
  welcome: <b>bienvenue !</b>
  hello_html: <b>bonjour !</b>
  title:
    html: <b>titre !</b>
<!-- app/views/home/index.html.erb -->
<div><%= t('welcome') %></div>
<div><%= raw t('welcome') %></div>
<div><%= t('hello_html') %></div>
<div><%= t('title.html') %></div>

L'interpolation s'échappe si nécessaire. Par exemple, étant donné :

en:
  welcome_html: "<b>Bienvenue %{username} !</b>"

vous pouvez passer en toute sécurité le nom d'utilisateur tel que défini par l'utilisateur :

<%# Ceci est sûr, il sera échappé si nécessaire. %>
<%= t('welcome_html', username: @current_user.username) %>

Les chaînes sécurisées, en revanche, sont interpolées telles quelles.

REMARQUE : La conversion automatique en texte de traduction sécurisé HTML n'est disponible qu'à partir de la méthode d'aide translate (ou t). Cela fonctionne dans les vues et les contrôleurs.

i18n demo HTML safe

4.5 Traductions pour les modèles Active Record

Vous pouvez utiliser les méthodes Model.model_name.human et Model.human_attribute_name(attribute) pour rechercher de manière transparente les traductions pour votre modèle et vos noms d'attributs.

Par exemple, lorsque vous ajoutez les traductions suivantes :

en:
  activerecord:
    models:
      user: Client
    attributes:
      user:
        login: "Identifiant"
      # traduira l'attribut "login" de l'utilisateur par "Identifiant"

Alors User.model_name.human renverra "Client" et User.human_attribute_name("login") renverra "Identifiant".

Vous pouvez également définir une forme plurielle pour les noms de modèles, en ajoutant ce qui suit :

en:
  activerecord:
    models:
      user:
        one: Client
        other: Clients

Alors User.model_name.human(count: 2) renverra "Clients". Avec count: 1 ou sans paramètres, cela renverra "Client".

Si vous avez besoin d'accéder à des attributs imbriqués dans un modèle donné, vous devez les imbriquer sous model/attribute au niveau du modèle de votre fichier de traduction :

en:
  activerecord:
    attributes:
      user/role:
        admin: "Administrateur"
        contributor: "Contributeur"

Alors User.human_attribute_name("role.admin") renverra "Administrateur".

REMARQUE : Si vous utilisez une classe qui inclut ActiveModel et n'hérite pas de ActiveRecord::Base, remplacez activerecord par activemodel dans les chemins de clés ci-dessus.

4.5.1 Espaces de noms des messages d'erreur

Les messages d'erreur de validation d'Active Record peuvent également être traduits facilement. Active Record vous offre quelques espaces de noms où vous pouvez placer vos traductions de messages afin de fournir des messages et des traductions différents pour certains modèles, attributs et/ou validations. Il prend également en compte de manière transparente l'héritage de table unique.

Cela vous donne des moyens assez puissants pour ajuster de manière flexible vos messages en fonction des besoins de votre application.

Considérez un modèle User avec une validation pour l'attribut name comme ceci :

class User < ApplicationRecord
  validates :name, presence: true
end

La clé pour le message d'erreur dans ce cas est :blank. Active Record recherchera cette clé dans les espaces de noms suivants :

activerecord.errors.models.[nom_du_modèle].attributes.[nom_de_l_attribut]
activerecord.errors.models.[nom_du_modèle]
activerecord.errors.messages
errors.attributes.[nom_de_l_attribut]
errors.messages

Ainsi, dans notre exemple, il essaiera les clés suivantes dans cet ordre et renverra le premier résultat :

activerecord.errors.models.user.attributes.name.blank
activerecord.errors.models.user.blank
activerecord.errors.messages.blank
errors.attributes.name.blank
errors.messages.blank

Lorsque vos modèles utilisent également l'héritage, les messages sont recherchés dans la chaîne d'héritage.

Par exemple, vous pourriez avoir un modèle Admin héritant de User :

class Admin < User
  validates :name, presence: true
end

Alors Active Record recherchera les messages dans cet ordre :

activerecord.errors.models.admin.attributes.name.blank
activerecord.errors.models.admin.blank
activerecord.errors.models.user.attributes.name.blank
activerecord.errors.models.user.blank
activerecord.errors.messages.blank
errors.attributes.name.blank
errors.messages.blank

De cette manière, vous pouvez fournir des traductions spéciales pour divers messages d'erreur à différents points de la chaîne d'héritage de votre modèle et dans les attributs, modèles ou espaces de noms par défaut.

4.5.2 Interpolation des messages d'erreur

Le nom de modèle traduit, le nom d'attribut traduit et la valeur sont toujours disponibles pour l'interpolation en tant que model, attribute et value respectivement.

Ainsi, par exemple, au lieu du message d'erreur par défaut "ne peut pas être vide", vous pourriez utiliser le nom de l'attribut comme ceci : "Veuillez remplir votre %{attribute}".

  • count, le cas échéant, peut être utilisé pour la pluralisation s'il est présent :
validation avec l'option message interpolation
confirmation - :confirmation attribute
acceptance - :accepted -
presence - :blank -
absence - :present -
length :within, :in :too_short count
length :within, :in :too_long count
length :is :wrong_length count
length :minimum :too_short count
length :maximum :too_long count
uniqueness - :taken -
format - :invalid -
inclusion - :inclusion -
exclusion - :exclusion -
associated - :invalid -
non-optional association - :required -
numericality - :not_a_number -
numericality :greater_than :greater_than count
numericality :greater_than_or_equal_to :greater_than_or_equal_to count
numericality :equal_to :equal_to count
numericality :less_than :less_than count
numericality :less_than_or_equal_to :less_than_or_equal_to count
numericality :other_than :other_than count
numericality :only_integer :not_an_integer -
numericality :in :in count
numericality :odd :odd -
numericality :even :even -
comparison :greater_than :greater_than count
comparison :greater_than_or_equal_to :greater_than_or_equal_to count
comparison :equal_to :equal_to count
comparison :less_than :less_than count
comparison :less_than_or_equal_to :less_than_or_equal_to count
comparison :other_than :other_than count

4.6 Traductions pour les sujets des e-mails d'Action Mailer

Si vous ne passez pas de sujet à la méthode mail, Action Mailer essaiera de le trouver dans vos traductions. La recherche effectuée utilisera le modèle <mailer_scope>.<action_name>.subject pour construire la clé.

# user_mailer.rb
class UserMailer < ActionMailer::Base
  def welcome(user)
    #...
  end
end
en:
  user_mailer:
    welcome:
      subject: "Bienvenue dans Rails Guides !"

Pour envoyer des paramètres à l'interpolation, utilisez la méthode default_i18n_subject sur le mailer.

# user_mailer.rb
class UserMailer < ActionMailer::Base
  def welcome(user)
    mail(to: user.email, subject: default_i18n_subject(user: user.name))
  end
end
en:
  user_mailer:
    welcome:
      subject: "%{user}, bienvenue dans Rails Guides !"

4.7 Aperçu des autres méthodes intégrées qui fournissent une prise en charge de l'internationalisation

Rails utilise des chaînes de caractères fixes et d'autres localisations, telles que des chaînes de format et d'autres informations de format, dans quelques helpers. Voici un bref aperçu.

4.7.1 Méthodes d'aide d'Action View

  • distance_of_time_in_words traduit et pluriélise son résultat et interpole le nombre de secondes, minutes, heures, etc. Voir les traductions de datetime.distance_in_words.

  • datetime_select et select_month utilisent les noms des mois traduits pour remplir la balise select résultante. Voir les traductions de date.month_names. datetime_select recherche également l'option d'ordre dans date.order (sauf si vous passez explicitement l'option). Tous les helpers de sélection de date traduisent le message d'invite en utilisant les traductions dans la portée datetime.prompts si applicable.

  • Les helpers number_to_currency, number_with_precision, number_to_percentage, number_with_delimiter et number_to_human_size utilisent les paramètres de formatage des nombres situés dans la portée number.

4.7.2 Méthodes Active Model

  • model_name.human et human_attribute_name utilisent les traductions des noms de modèle et des noms d'attributs si elles sont disponibles dans la portée activerecord.models. Ils prennent également en charge les traductions des noms de classe hérités (par exemple, pour une utilisation avec STI) comme expliqué ci-dessus dans "Scopes des messages d'erreur".

  • ActiveModel::Errors#generate_message (utilisé par les validations Active Model mais peut également être utilisé manuellement) utilise model_name.human et human_attribute_name (voir ci-dessus). Il traduit également le message d'erreur et prend en charge les traductions des noms de classe hérités comme expliqué ci-dessus dans "Scopes des messages d'erreur".

  • ActiveModel::Error#full_message et ActiveModel::Errors#full_messages préfixent le nom de l'attribut au message d'erreur en utilisant un format recherché dans errors.format (par défaut : "%{attribute} %{message}"). Pour personnaliser le format par défaut, remplacez-le dans les fichiers de localisation de l'application. Pour personnaliser le format par modèle ou par attribut, voir config.active_model.i18n_customize_full_message.

4.7.3 Méthodes Active Support

  • Array#to_sentence utilise les paramètres de format tels qu'ils sont donnés dans la portée support.array.

5 Comment stocker vos traductions personnalisées

Le backend Simple fourni avec Active Support vous permet de stocker les traductions à la fois en Ruby pur et en format YAML.2

Par exemple, un Hash Ruby fournissant des traductions peut ressembler à ceci :

{
  pt: {
    foo: {
      bar: "baz"
    }
  }
}

Le fichier YAML équivalent ressemblerait à ceci :

pt:
  foo:
    bar: baz

Comme vous pouvez le voir, dans les deux cas, la clé de premier niveau est la locale. :foo est une clé d'espace de noms et :bar est la clé de la traduction "baz".

Voici un exemple "réel" du fichier de traductions YAML en.yml d'Active Support :

en:
  date:
    formats:
      default: "%Y-%m-%d"
      short: "%b %d"
      long: "%B %d, %Y"

Ainsi, toutes les recherches équivalentes suivantes renverront le format de date :short "%b %d" :

I18n.t 'date.formats.short'
I18n.t 'formats.short', scope: :date
I18n.t :short, scope: 'date.formats'
I18n.t :short, scope: [:date, :formats]

En général, nous recommandons d'utiliser le format YAML pour stocker les traductions. Il y a des cas, cependant, où vous voulez stocker des lambdas Ruby en tant que partie de vos données de localisation, par exemple pour des formats de date spéciaux.

6 Personnalisez votre configuration I18n

6.1 Utilisation de différents backends

Pour plusieurs raisons, le backend Simple fourni avec Active Support ne fait que la "chose la plus simple qui pourrait fonctionner" pour Ruby on Rails3 ... ce qui signifie qu'il est garanti de fonctionner uniquement pour l'anglais et, par effet secondaire, pour les langues très similaires à l'anglais. De plus, le backend simple est uniquement capable de lire les traductions mais ne peut pas les stocker dynamiquement dans un format quelconque.

Cela ne signifie pas que vous êtes coincé avec ces limitations. Le gem Ruby I18n facilite grandement l'échange de l'implémentation du backend Simple avec autre chose qui convient mieux à vos besoins, en passant une instance de backend au setter I18n.backend=.

Par exemple, vous pouvez remplacer le backend Simple par le backend Chain pour chaîner plusieurs backends ensemble. Cela est utile lorsque vous souhaitez utiliser des traductions standard avec un backend Simple mais stocker des traductions d'application personnalisées dans une base de données ou d'autres backends. Avec le backend Chain, vous pouvez utiliser le backend Active Record et revenir au backend Simple (par défaut) :

I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n.backend)

6.2 Utilisation de différents gestionnaires d'exceptions

L'API I18n définit les exceptions suivantes qui seront levées par les backends lorsque les conditions inattendues correspondantes se produisent :

Exception Raison
I18n::MissingTranslationData aucune traduction n'a été trouvée pour la clé demandée
I18n::InvalidLocale la locale définie sur I18n.locale est invalide (par exemple, nil)
I18n::InvalidPluralizationData une option de comptage a été passée mais les données de traduction ne conviennent pas à la pluralisation
I18n::MissingInterpolationArgument la traduction attend un argument d'interpolation qui n'a pas été passé
I18n::ReservedInterpolationKey la traduction contient un nom de variable d'interpolation réservée (c'est-à-dire l'un des suivants : scope, default)
I18n::UnknownFileType le backend ne sait pas comment traiter un type de fichier qui a été ajouté à I18n.load_path

6.2.1 Personnalisation de la gestion de I18n::MissingTranslationData

Si config.i18n.raise_on_missing_translations est true, les erreurs I18n::MissingTranslationData seront levées. Il est conseillé de l'activer dans votre environnement de test, afin de repérer les endroits où des traductions manquantes sont demandées.

Si config.i18n.raise_on_missing_translations est false (la valeur par défaut dans tous les environnements), le message d'erreur de l'exception sera affiché. Celui-ci contient la clé/scope manquant(e) afin que vous puissiez corriger votre code.

Si vous souhaitez personnaliser davantage ce comportement, vous devez définir config.i18n.raise_on_missing_translations = false et ensuite mettre en œuvre un I18n.exception_handler. Le gestionnaire d'exceptions personnalisé peut être une procédure ou une classe avec une méthode call :

# config/initializers/i18n.rb
module I18n
  class RaiseExceptForSpecificKeyExceptionHandler
    def call(exception, locale, key, options)
      if key == "special.key"
        "traduction manquante !" # retourne ceci, ne le lève pas
      elsif exception.is_a?(MissingTranslation)
        raise exception.to_exception
      else
        raise exception
      end
    end
  end
end

I18n.exception_handler = I18n::RaiseExceptForSpecificKeyExceptionHandler.new

Cela lèverait toutes les exceptions de la même manière que le gestionnaire par défaut, sauf dans le cas de I18n.t("special.key").

7 Traduction du contenu du modèle

L'API I18n décrite dans ce guide est principalement destinée à la traduction des chaînes d'interface. Si vous souhaitez traduire le contenu du modèle (par exemple, des articles de blog), vous aurez besoin d'une solution différente pour vous aider.

Plusieurs gemmes peuvent vous aider :

  • Mobility : Fournit une prise en charge pour stocker les traductions dans de nombreux formats, y compris les tables de traduction, les colonnes JSON (PostgreSQL), etc.
  • Traco : Colonnes traduisibles stockées dans la table du modèle lui-même

8 Conclusion

À ce stade, vous devriez avoir une bonne vue d'ensemble de la façon dont la prise en charge de l'internationalisation (I18n) fonctionne avec Ruby on Rails et être prêt à commencer à traduire votre projet.

9 Contribuer à Rails I18n

La prise en charge de l'internationalisation (I18n) dans Ruby on Rails a été introduite dans la version 2.2 et est encore en évolution. Le projet suit la bonne tradition de développement de Ruby on Rails, qui consiste à faire évoluer les solutions dans des gemmes et de véritables applications en premier, puis à sélectionner les meilleures fonctionnalités les plus largement utiles pour les inclure dans le noyau.

Nous encourageons donc tout le monde à expérimenter de nouvelles idées et fonctionnalités dans des gemmes ou d'autres bibliothèques et à les rendre disponibles à la communauté. (N'oubliez pas d'annoncer votre travail sur notre liste de diffusion !)

Si vous constatez que votre propre locale (langue) est absente de notre exemple de données de traduction pour Ruby on Rails, veuillez forker le dépôt, ajouter vos données et envoyer une demande d'extraction.

10 Ressources

11 Auteurs

12 Notes de bas de page

1 Ou, pour citer Wikipédia : "L'internationalisation est le processus de conception d'une application logicielle de manière à ce qu'elle puisse être adaptée à différentes langues et régions sans modifications techniques. La localisation est le processus d'adaptation d'un logiciel à une région ou une langue spécifique en ajoutant des composants spécifiques à la locale et en traduisant le texte."

2 D'autres backends peuvent permettre ou nécessiter l'utilisation d'autres formats, par exemple un backend GetText peut permettre de lire des fichiers GetText.

3 Une des raisons est que nous ne voulons pas impliquer de charge inutile pour les applications qui n'ont pas besoin de capacités d'internationalisation, nous devons donc garder la bibliothèque I18n aussi simple que possible pour l'anglais. Une autre raison est qu'il est pratiquement impossible de mettre en œuvre une solution unique pour tous les problèmes liés à l'internationalisation pour toutes les langues existantes. Une solution qui nous permet d'échanger facilement l'ensemble de l'implémentation est donc appropriée de toute façon. Cela facilite également l'expérimentation de fonctionnalités et d'extensions personnalisées.

Retour d'information

Vous êtes encouragé à contribuer à l'amélioration de la qualité de ce guide.

Veuillez contribuer si vous trouvez des fautes de frappe ou des erreurs factuelles. Pour commencer, vous pouvez lire notre contribution à la documentation section.

Vous pouvez également trouver du contenu incomplet ou des informations qui ne sont pas à jour. Veuillez ajouter toute documentation manquante pour la version principale. Assurez-vous de vérifier Edge Guides d'abord pour vérifier si les problèmes ont déjà été résolus ou non sur la branche principale. Consultez les Directives des guides Ruby on Rails pour le style et les conventions.

Si pour une raison quelconque vous repérez quelque chose à corriger mais ne pouvez pas le faire vous-même, veuillez ouvrir un problème.

Et enfin, toute discussion concernant la documentation de Ruby on Rails est la bienvenue sur le Forum officiel de Ruby on Rails.