Comment traduire les messages d’erreurs de Ruby on Rails

Publié le 07 Mai 2007 par snoza

Rails nous offre beaucoup de fonctions et d’outils qui facilitent et accélère le développement d’un site. Prenez l’affichage des messages d’erreurs de saisie par exemple. Il suffit d’ajouter <%= error_messages_for(“nom_du_modele”) %> à notre page afin que s’affiche « auto-magiquement » le ou les messages d’erreurs à l’usager. Le problème ici c’est qu’Auto, le magicien, semble être unilingue anglais.

La technique décrite dans cet article vous permettra de traduire les messages d’erreurs rendus par la fonction error_messages_for. Cependant, il faut souligner que cette méthode ne servira que dans le cadre d’un site unilingue. Si vous souhaitez créer un site multilingue, vous devriez considérer une librairie complète de localisation telle que Globalize. Cela dit, quoique possible, je crois que l’utilisation d’un tel plug-in pour la gestion d’une seule langue générerait beaucoup d’ overhead inutile (recherche des mots et formats d’affichages dans la BD ou fichiers YAML) comparativement à la méthode qui sera décrite ici.

Anatomie du message d’erreur

Avant de commencer à traduire les messages d’erreurs, il faut savoir d’où provient l’information affichée (donc, à traduire). Alors, voici comment se présente un message d’erreur rendu par la fonction error_messages_for :

image 1

L’ensemble du code XHTML, incluant le titre et sous-titre, provient évidemment de la fonction error_messages_for (ActionView::Helpers::ActiveRecordHelper). La collection de messages d’erreurs, en vert, est retournée par la fonction full_messages (ActiveRecord::Errors). En bleu, c’est le nom du champ humanisé via la fonction humanize (ActiveSupport::CoreExtensions::String::Inflections). Le message de validation, en jaune, provient de la collection de messages default_error_messages qui se trouve également dans la classe ActiveRecord::Errors.

Traduction des messages de validations

La première étape consiste à redéfinir les messages d’erreurs de validation qui sont utilisés lorsque des validations faites via les méthodes validates_presence_of ou validates_uniqueness_of par exemple, échouent. Ces messages peuvent être redéfinis comme suit :

module ActiveRecord
  class Errors
    @@default_error_messages.update( {
      :inclusion => "n'est pas inclut dans la liste",
      :exclusion => "est réservé",
      :invalid => "est invalide",
      :confirmation => "ne correspond pas à la confirmation",
      :accepted => "doit être accepté",
      :empty => "ne peut pas être vide",
      :blank => "est requis",
      :too_long => "est trop long (%d caractères maximum)",
      :too_short => "est trop court(%d caractères minimum)",
      :wrong_length => "n'est pas de la bonne longueur (devrait être de %d caractères)",
      :taken => "est déjà  prit",
      :not_a_number => "n'est pas un nombre",
    })
  end
end

Attention, si vous définissez un message personnalisé via l’attribut :message, ce message ne sera pas traduit (ou retraduit si vous changez de langue). Il serait préférable d’ajouter le message personnalisé à la collection default_error_messages. Aussi, lorsque vous faites des validations via les événements d’un modèle, vous pouvez utiliser les messages de la collection via ActiveRecord::Errors::default_error_messages[:key]. Voici un exemple :

def validate_on_create
  if self.password.empty?
    errors.add(:password, ActiveRecord::Errors::default_error_messages[:empty])
  end
end

Après implémentation, notre message d’erreur ressemble à ceci :

image 2

Traduction et « Humanisation » des noms de champs

L’objet modèle des versions antérieures à Rails 1.2 exposait une fonction nommée « human_attribute_name ». Pour traduire et/ou donner un nom d’affichage plus significatif à vos champs, il suffisait d’ overrider cette méthode afin qu’elle retourne le nom désiré selon l’attribut demandé. Puisqu’elle n’existe plus, il suffit de la créer :

module ActiveRecord
  class Errors
    class Base
      class << self
        def localized_human_attribute_name(attr)
          attr.humanize
        end
      end
    end
  end
end

Si elle n’est pas overridée par votre modèle, la fonction localized_human_attribute_name retournera le nom du champ « humanisé » (comportement standard de Rails 1.2). Cependant, pour chaque modèle qui requiert des noms de champs traduits, nous devons redéfinir la fonction comme suit:

class User < ActiveRecord::Base
  def self.localized_human_attribute_name(attr)
    return case attr
      when "email" then "Adresse courriel"
      when "name" then "Nom"
      when "password" then "Mot de passe"
      else attr.humanize
    end
  end
end

Traduction des messages d’erreurs

Le message d’erreur complet (composé du nom du champ et de l’erreur de validation) provient de la collection de messages retournée par la fonction full_messages (ActiveRecord::Errors). Il s’agit donc de redéfinir cette fonction afin que le nom localisé et/ou « humanisé » du champ (retourné par localized_human_attribute_name) soit utilisé lors de la construction d’un message d’erreur :

module ActiveRecord
  class Errors
    def full_messages
      full_messages = []
      @errors.each_key do |attr|
        @errors[attr].each do |msg|
          next if msg.nil?
          if attr == "base"
            full_messages << msg
          else
            full_messages << @base.class.localized_human_attribute_name(attr) + " " + msg
          end
        end
      end
      full_messages
    end  
  end
end

Les messages d’erreurs de validation affichés sont à présent, complètement traduits :

image 3

Traduction du Titre et sous-titre

La dernière étape consiste à traduire le titre et le sous-titre. Pour ce faire, nous devons redéfinir la fonction error_messages_for.

module ActionView
  module Helpers
    module ActiveRecordHelper
      def error_messages_for(object_name, options = {})
        options = options.symbolize_keys
        object = instance_variable_get("@#{object_name}")
        unless object.errors.empty?
          content_tag("div",
            content_tag(
              options[:header_tag] || "h2",
              "#{pluralize(object.errors.count, "erreurs")} empêche(nt) cette forme d'être sauvegardée"
            ) +
            content_tag("p", "Veuillez vérifier les informations et apporter les modifications aux champs suivants :"
            ) +
            content_tag("ul", object.errors.full_messages.collect { |msg| content_tag("li", "Le champ " + msg) }),
            "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
          )
        end
      end
    end
  end
end

Ici, comme vous pouvez le constater, vous avez également la possibilité de modifier les balises qui sont utilisées à la construction du message d’erreur.

Note : Puisqu’il serait plus complexe de gérer le genre du nom des modèles dans un message d’erreur (« ce livre n’a pu être sauvegardé » versus « cette photo n’a pu être sauvegardée »), j’ai remplacé le nom du modèle par « forme » dans le titre du message. Si vous désirez utiliser le nom du modèle, remplacer « forme » par #{object_name.to_s.gsub(”_”, ” “)}.

Notre message d’erreurs est maintenant traduit :

image 4

Implémentation

Il vous suffit de placer le code dans le répertoire /lib de votre application et d’ajouter la ligne suivante à la fin de votre fichier /config/environment.rb :

require 'french_errors_localization'

Labels

Syndication

Folksonomie

Il y a 0 commentaires pour cet article

La discussion est fermée pour les non-membres. Vous pouvez lire les commentaires. Pour ajouter votre commentaire, vous devrez vous identifier ou vous enregistrer si vous n'êtes pas déjà membre.