Rails internationalization - removing validation message prefix

Current ActiveRecord implementation always prepends an error message with the attribute name. This is because of design weakness in the handling of human messages in Rails.

The data should be always interpolated into the message, string concatenation should be never used.


MY_MESSAGE = '%{attribute} is invalid'
return MY_MESSAGE % {:attribute => 'email'}


MY_MESSAGE = 'is invalid'
return MY_MESSAGE + ' ' + 'email'

… because the correct order of the words in a sentence depends on language.

Generally it is not possible to create a message in human language by string concatenation. Only interpolation universally works!

Still bad (from validations.rb):

attr_name + I18n.t('activerecord.errors.format.separator', 
  :default => ' ') + message

I18n.t would not help, if you use +.

Our custom message ‘Gadget should have at least one screenshot.’ is corrupted by a prefix to ‘Screenshots Gadget should have at least one screenshot.’

I hope one day it can be fixed in Rails by substantially refactoring the ActiveRecord validations and internationalization subsystem. For now I’m fixing it with a dash of metaprogramming and monkey patching.

module ActiveRecord
  class Errors

    # allow a proc as a user defined message
    def add(attribute, message = nil, options = {})
      if options[:default].is_a?(Proc) # this is new
        message = options[:default].call(attribute)
        def message.full? do
      message ||= :invalid
      message = generate_message(attribute, message, options) if 
      @errors[attribute.to_s] ||= []
      @errors[attribute.to_s] << message

    def full_messages(options = {})
      full_messages = []

      @errors.each_key do |attr|
        @errors[attr].each do |message|
          next unless message

          if attr == "base"
            full_messages << message
            attr_name = @base.class.human_attribute_name(attr)
            if message.respond_to? :full? and message.full? # new switch
              full_messages << message
              # messages for humans based on string concatenation are 
              # inherently broken - should not be used!
              full_messages << attr_name + 
                  :default => ' ') + message



  • copy a paste the code into a initializer (underneath config/initializers folder)
  • all translated messages created by a proc get the special full? tag which is later used in full_messages to bypass the attr_name addition
  • you can use attribute name in your proc to interpolate into the localized error message

This dirty hack is only needed because of design weekness of rails. Some conceptial thoughts:

Short and full error messages

Distinction between short and full error message does not make sence

  • one can not be universarly infered from another for every human language
  • specifing both manually hardly makes sense So there should be just error message with optional placeholder for the attribute name.

String interpolation everywhere

The data should be always interpolated into the error messages, never concatenated, because the order of the words in a sentence and gramatical rules differs from language to language.

Non-programmer capable translation files

YAML files and ruby symbol driven translation keys are unsuitable for non-programmers and people without deep knowledge of the application to be translated.

See GNU gettext for a deeper explanation of internationalization concepts that work!


blog comments powered by Disqus