Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #9726: i18n_agnostic_api.patch

File i18n_agnostic_api.patch, 36.0 kB (added by saimonmoore, 1 year ago)
  • activesupport/test/string_translation_test.rb

    old new  
     1#require 'rubygems' 
     2#gem 'ruby-debug' 
     3#require 'ruby-debug' 
     4#Debugger.start 
     5 
     6require File.dirname(__FILE__) + '/abstract_unit' 
     7 
     8class StringTranslationTest < Test::Unit::TestCase 
     9 
     10  def test_simple_string 
     11    assert_equal "A string to be translated",   "A string to be translated".t 
     12  end 
     13   
     14  def test_simple_interpolated_string 
     15    assert_equal 'This must be translated', "%s must be translated".t('This')     
     16  end 
     17   
     18  def test_simple_pluralizable_string 
     19    assert_equal 'They have 1 translation to do',  "They have %d translations to do".t(1) 
     20    assert_equal 'They have 2 translations to do', "They have %d translations to do".t(2)     
     21  end 
     22   
     23  def test_interpolated_and_pluralizable_string 
     24    assert_equal "Tommy translated 1 translation",   "%s translated %d translations".t('Tommy',1) 
     25    assert_equal "Tommy translated 2 translations",  "%s translated %d translations".t('Tommy',2) 
     26    assert_equal "Tommy translated 1 translations",  "%s translated %d translations".t('Tommy','1')         
     27  end 
     28   
     29  def test_multiple_interpolated_and_pluralizable_string 
     30    assert_equal "Tommy & Joe translated 1 translation",  "%s & %s translated %d translations".t('Tommy','Joe',1) 
     31    assert_equal "Tommy & Joe translated 2 translations", "%s & %s translated %d translations".t('Tommy','Joe',2)     
     32  end 
     33   
     34  def test_error_string 
     35    assert_equal "1 error prohibited this pizza from being saved",  "%d errors prohibited this %s from being saved".t(1,'pizza') 
     36    assert_equal "2 errors prohibited this bagel from being saved", "%d errors prohibited this %s from being saved".t(2, 'bagel')     
     37  end 
     38   
     39  def test_complex_verbal_pluralizable_string 
     40    assert_equal "There is 1 translation to do",    "There are %d translations to do".t(1) 
     41    assert_equal "There are 2 translations to do",  "There are %d translations to do".t(2)     
     42  end 
     43   
     44  def test_complex_verbal_pluralizable_string_in_question_form 
     45    assert_equal "Is there 1 translation to do?",   "Are there %d translations to do?".t(1) 
     46    assert_equal "Are there 2 translations to do?", "Are there %d translations to do?".t(2)     
     47  end 
     48   
     49  def test_pluralizable_string_with_non_whitespace_characters_after_pluralizable_word 
     50    assert_equal "Omellette recipe (1 egg)",  "Omellette recipe (%d eggs)".t(1) 
     51    assert_equal "Omellette recipe (2 eggs)", "Omellette recipe (%d eggs)".t(2)     
     52  end   
     53   
     54  def test_non_pluralizable_string_with_numeric_interpolation 
     55    assert_equal "Omellette recipe (eggs: 1)",  "Omellette recipe (eggs: %d)".t(1)     
     56    assert_equal "Omellette recipe (eggs: 3)",  "Omellette recipe (eggs: %d)".t(3)     
     57  end 
     58   
     59  def test_pluralizable_strings_with_adjectives_before_noun_dont_singularize 
     60    assert_equal("Thomas has 1 old toys", "Thomas has %d old toys".t(1)) 
     61    assert_equal("Thomas has 10 old toys", "Thomas has %d old toys".t(10)) 
     62     
     63    assert_equal("Thomas has 1 old scrabby toys", "Thomas has %d old scrabby toys".t(1)) 
     64    assert_equal("Thomas has 10 old scrabby toys", "Thomas has %d old scrabby toys".t(10))     
     65  end 
     66   
     67   
     68  def test_ignores_namespaces 
     69    assert_equal "any old string", "any old string".t(:namespace) 
     70    assert_equal "any old string", "any old %s".t(:namespace, 'string') 
     71    assert_equal "any 1 string", "any %d strings".t(:namespace, 1) 
     72    assert_equal "any 10 strings", "any %d strings".t(:namespace, 10) 
     73    assert_equal "Tommy has 1 string", "%s has %d strings".t(:namespace, 1, 'Tommy') 
     74    assert_equal "Tommy has 10 strings", "%s has %d strings".t(:namespace, 10, 'Tommy') 
     75  end 
     76 
     77end 
  • activesupport/test/date_translation_test.rb

    old new  
     1#require 'rubygems' 
     2#gem 'ruby-debug' 
     3#require 'ruby-debug' 
     4#Debugger.start 
     5 
     6require File.dirname(__FILE__) + '/abstract_unit' 
     7 
     8class DateTranslationTest < Test::Unit::TestCase 
     9 
     10  def test_simple_date 
     11    assert_equal "Thu Jan 01 1970", Date.new(1970,1,1).t.strftime('%a %b %d %Y') 
     12  end 
     13   
     14  def test_custom_translatable_time_class 
     15    Object.class_eval <<-ENDDEF 
     16      class ::ActiveSupport::Translation::TranslatableDate 
     17        def overidden_strftime(*args) 
     18          'overidden' 
     19        end 
     20        alias_method :old_strftime, :strftime         
     21        alias_method :strftime, :overidden_strftime 
     22      end       
     23    ENDDEF 
     24     
     25    assert_equal "overidden", Date.new(1970,1,1).t.strftime('%a %b %d %Y') 
     26     
     27    Object.class_eval <<-ENDDEF 
     28      class ::ActiveSupport::Translation::TranslatableDate 
     29        alias_method :strftime, :old_strftime 
     30      end       
     31    ENDDEF 
     32     
     33    assert_equal "Thu Jan 01 1970", Date.new(1970,1,1).t.strftime('%a %b %d %Y') 
     34  end 
     35end 
  • activesupport/test/date_time_translation_test.rb

    old new  
     1#require 'rubygems' 
     2#gem 'ruby-debug' 
     3#require 'ruby-debug' 
     4#Debugger.start 
     5 
     6require File.dirname(__FILE__) + '/abstract_unit' 
     7 
     8class DateTimeTranslationTest < Test::Unit::TestCase 
     9 
     10  def test_simple_date_time 
     11    assert_equal "Thu Jan 01 01:00:00 1970", DateTime.new(1970,1,1,1,0,0).t.strftime('%a %b %d %H:%M:%S %Y') 
     12  end 
     13   
     14  def test_custom_translatable_time_class 
     15    Object.class_eval <<-ENDDEF 
     16      class ::ActiveSupport::Translation::TranslatableDateTime 
     17        def overidden_strftime(*args) 
     18          'overidden' 
     19        end 
     20        alias_method :old_strftime, :strftime         
     21        alias_method :strftime, :overidden_strftime 
     22      end       
     23    ENDDEF 
     24     
     25    assert_equal "overidden", DateTime.new(1970,1,1,1,0,0).t.strftime('%a %b %d %H:%M:%S %Y') 
     26     
     27    Object.class_eval <<-ENDDEF 
     28      class ::ActiveSupport::Translation::TranslatableDateTime 
     29        alias_method :strftime, :old_strftime 
     30      end       
     31    ENDDEF 
     32     
     33    assert_equal "Thu Jan 01 01:00:00 1970", DateTime.new(1970,1,1,1,0,0).t.strftime('%a %b %d %H:%M:%S %Y') 
     34  end 
     35end 
  • activesupport/test/time_translation_test.rb

    old new  
     1#require 'rubygems' 
     2#gem 'ruby-debug' 
     3#require 'ruby-debug' 
     4#Debugger.start 
     5 
     6require File.dirname(__FILE__) + '/abstract_unit' 
     7 
     8class TimeTranslationTest < Test::Unit::TestCase 
     9 
     10  def test_simple_time 
     11    assert_equal "Thu Jan 01 01:00:00 1970", Time.at(0).t.strftime('%a %b %d %H:%M:%S %Y') 
     12  end 
     13   
     14  def test_custom_translatable_time_class 
     15    Object.class_eval <<-ENDDEF 
     16      class ::ActiveSupport::Translation::TranslatableTime 
     17        def overidden_strftime(*args) 
     18          'overidden' 
     19        end 
     20        alias_method :old_strftime, :strftime         
     21        alias_method :strftime, :overidden_strftime 
     22      end       
     23    ENDDEF 
     24     
     25    assert_equal "overidden", Time.at(0).t.strftime('%a %b %d %H:%M:%S %Y') 
     26     
     27    Object.class_eval <<-ENDDEF 
     28      class ::ActiveSupport::Translation::TranslatableTime 
     29        alias_method :strftime, :old_strftime 
     30      end       
     31    ENDDEF 
     32     
     33    assert_equal "Thu Jan 01 01:00:00 1970", Time.at(0).t.strftime('%a %b %d %H:%M:%S %Y') 
     34     
     35     
     36  end 
     37end 
  • activesupport/lib/active_support/translation/translatable_string.rb

    old new  
     1module ActiveSupport #:nodoc: 
     2  module Translation #:nodoc: 
     3    class TranslatableString #:nodoc: 
     4       
     5      class DefaultTranslatableString 
     6         
     7        PLURALIZATION_REGEXP = /(%d\s+[^\s\W]+)/ 
     8        DOWN_CASE_VERBAL_PLURALIZATION_REGEXP = /(are\s+%d\s+[^\s\W]+)/ 
     9        UP_CASE_VERBAL_PLURALIZATION_REGEXP = /(Are\s+(.*)\s+%d\s+[^\s\W]+)/ 
     10 
     11        # translates the supplied string 
     12        # 
     13        # Default implementation allows: 
     14        # 
     15        #  * simple/multiple string interpolation via %s 
     16        #      
     17        #    e.g. "%s loves rails".t('G. W. Bush') => 'G. W. Bush loves rails' 
     18        #         "%s and %s love rails".t('G. W. Bush', 'J. Edgar Hoover') => 'G. W. Bush and J. Edgar Hoover love rails' 
     19        # 
     20        #  * simple pluralization via %d (with/out string interpolation) 
     21        # 
     22        #   e.g. "%d errors prohibited this pizza from being saved".t(1) => '1 error prohibited this pizza from being saved' 
     23        #        "%d errors prohibited this pizza from being saved".t(10) => '10 errors prohibited this pizza from being saved' 
     24        # 
     25        #        "%d errors prohibited this %s from being saved".t(1,'penguin') => '1 error prohibited this penguin from being saved' 
     26        #        "%d errors prohibited this %s from being saved".t(3,'penguin') => '3 errors prohibited this penguin from being saved' 
     27        # 
     28        #  * very basic pluralization of verb 'to be' 
     29        # 
     30        #   e.g. "There are %d translations to do".t(1) => 'There is 1 translation to do' 
     31        #        "There are %d translations to do".t(3) => 'There are 3 translations to do' 
     32        # 
     33        #        "Are there %d penguins?".t(1) => 'Is there 1 penguin?' 
     34        #        "Are there %d penguins?".t(3) => 'Are there 3 penguins?'         
     35        def self.translate(string, args) 
     36           return string if args.nil? || (args.is_a?(Array) && args.compact.empty?) 
     37                       
     38           #Add support for namespaces (ns if first argument is symbol) 
     39           return string if args.is_a? Symbol 
     40           args.shift if args.first.is_a? Symbol 
     41           return string if args.is_a?(Array) && args.empty? 
     42                                  
     43           translated_string,string_interpolations, pluralization, plural = nil 
     44 
     45           case args 
     46             when String 
     47               translated_string = string % args 
     48             when Fixnum 
     49               pluralization = args 
     50             when Array 
     51               string_interpolations = args.select {|arg| arg.is_a? String} 
     52               pluralization = args.detect {|arg| arg.is_a? Fixnum} 
     53           end 
     54 
     55          if pluralization 
     56 
     57            #Handle singularization of verb 'to be' 
     58            translated_string = string.gsub(/(are)\s+/,'is ') if pluralization == 1 && string.match(DOWN_CASE_VERBAL_PLURALIZATION_REGEXP) 
     59            translated_string = string.gsub(/^(Are)\s+/,'Is ') if pluralization == 1 && string.match(UP_CASE_VERBAL_PLURALIZATION_REGEXP) 
     60 
     61            #Handle plurals 
     62            matches = translated_string ? translated_string.match(PLURALIZATION_REGEXP) : string.match(PLURALIZATION_REGEXP) 
     63            if matches 
     64              pluralizable_string = matches[1]  
     65              plural = (pluralizable_string.gsub(/%d\s+/,'') % pluralization) if pluralizable_string 
     66              plural = (pluralization == 1) ? Inflector.singularize(plural) : plural if plural 
     67 
     68              if plural 
     69                translated_string = if translated_string 
     70                    translated_string.gsub(PLURALIZATION_REGEXP, "#{pluralization} #{plural}")            
     71                  else 
     72                    string.gsub(PLURALIZATION_REGEXP, "#{pluralization} #{plural}")              
     73                  end            
     74              end            
     75            else 
     76              #If there's still a %d in the string but it's not pluralizable then just do a normal interpolation 
     77              translated_string = translated_string ? (translated_string % pluralization) : (string % pluralization) if string.match(/%d/) 
     78            end 
     79 
     80          end 
     81 
     82          #Handle string interpolations 
     83          translated_string = ((translated_string ? translated_string : string) % string_interpolations) unless string_interpolations.empty? 
     84          translated_string ? translated_string : string           
     85        end 
     86      end 
     87       
     88 
     89      # translates the supplied string 
     90      # 
     91      # (see DefaultTranslatableString for default implementation) 
     92      def self.translate(string, args) 
     93        DefaultTranslatableString.translate(string, args) 
     94      end 
     95    end 
     96  end 
     97end 
  • activesupport/lib/active_support/translation/translatable_date_time.rb

    old new  
     1module ActiveSupport #:nodoc: 
     2  module Translation #:nodoc: 
     3    class TranslatableDateTime < ::DateTime #:nodoc: 
     4      def strftime(*args) 
     5        super(*args) 
     6      end 
     7    end 
     8  end 
     9end 
  • activesupport/lib/active_support/translation/translatable_date.rb

    old new  
     1module ActiveSupport #:nodoc: 
     2  module Translation #:nodoc: 
     3    class TranslatableDate < ::Date #:nodoc: 
     4      def strftime(*args) 
     5        super(*args) 
     6      end 
     7    end     
     8  end 
     9end 
  • activesupport/lib/active_support/translation/translatable_time.rb

    old new  
     1module ActiveSupport #:nodoc: 
     2  module Translation #:nodoc: 
     3    class TranslatableTime < ::Time#:nodoc: 
     4      def strftime(*args) 
     5        super(*args) 
     6      end 
     7    end 
     8  end 
     9end 
  • activesupport/lib/active_support/translation.rb

    old new  
     1require 'active_support/translation/translatable_string' 
     2require 'active_support/translation/translatable_time' 
     3require 'active_support/translation/translatable_date' 
     4require 'active_support/translation/translatable_date_time' 
  • activesupport/lib/active_support/core_ext/date_time/translation.rb

    old new  
     1module ActiveSupport #:nodoc: 
     2  module CoreExtensions #:nodoc: 
     3    module DateTime #:nodoc: 
     4      # Define methods for handeling translation of strings. 
     5      module Translation 
     6        def t 
     7          ActiveSupport::Translation::TranslatableDateTime.civil(self.year,self.mon, self.mday, self.hour, self.min, self.sec) 
     8        end 
     9      end 
     10    end     
     11  end 
     12end 
  • activesupport/lib/active_support/core_ext/date_time.rb

    old new  
    22require "#{File.dirname(__FILE__)}/time/behavior" 
    33require "#{File.dirname(__FILE__)}/date_time/calculations" 
    44require "#{File.dirname(__FILE__)}/date_time/conversions" 
     5require "#{File.dirname(__FILE__)}/date_time/translation" 
    56 
    67class DateTime 
    78  include ActiveSupport::CoreExtensions::Time::Behavior 
    89  include ActiveSupport::CoreExtensions::DateTime::Calculations 
    910  include ActiveSupport::CoreExtensions::DateTime::Conversions 
     11  include ActiveSupport::CoreExtensions::DateTime::Translation 
    1012end 
  • activesupport/lib/active_support/core_ext/time/translation.rb

    old new  
     1module ActiveSupport #:nodoc: 
     2  module CoreExtensions #:nodoc: 
     3    module Time #:nodoc: 
     4      # Define methods for handeling translation of times. 
     5      module Translation 
     6        def t 
     7          ActiveSupport::Translation::TranslatableTime.at(self) 
     8        end 
     9      end 
     10    end 
     11  end 
     12end 
  • activesupport/lib/active_support/core_ext/time/conversions.rb

    old new  
    2424            if formatter.respond_to?(:call) 
    2525              formatter.call(self).to_s 
    2626            else 
    27               strftime(formatter) 
     27              strftime(formatter).strip 
    2828            end 
    2929          else 
    3030            to_default_s 
  • activesupport/lib/active_support/core_ext/object.rb

    old new  
    11require File.dirname(__FILE__) + '/object/extending' 
    2 require File.dirname(__FILE__) + '/object/instance_variables' 
    3 require File.dirname(__FILE__) + '/object/misc' 
     2require File.dirname(__FILE__) + '/object/misc' 
  • activesupport/lib/active_support/core_ext/string.rb

    old new  
    44require File.dirname(__FILE__) + '/string/starts_ends_with' 
    55require File.dirname(__FILE__) + '/string/iterators' unless 'test'.respond_to?(:each_char) 
    66require File.dirname(__FILE__) + '/string/unicode' 
     7require File.dirname(__FILE__) + '/string/translation' 
    78 
    89class String #:nodoc: 
    910  include ActiveSupport::CoreExtensions::String::Access 
     
    1415    include ActiveSupport::CoreExtensions::String::Iterators 
    1516  end 
    1617  include ActiveSupport::CoreExtensions::String::Unicode 
     18  include ActiveSupport::CoreExtensions::String::Translation 
    1719end 
  • activesupport/lib/active_support/core_ext/date/translation.rb

    old new  
     1module ActiveSupport #:nodoc: 
     2  module CoreExtensions #:nodoc: 
     3    module Date #:nodoc: 
     4      # Define methods for handeling translation of strings. 
     5      module Translation 
     6        def t 
     7          ActiveSupport::Translation::TranslatableDate.new(self.year,self.mon, self.mday) 
     8        end 
     9      end 
     10    end     
     11  end 
     12end 
  • activesupport/lib/active_support/core_ext/date/conversions.rb

    old new  
    1717            alias_method :to_s, :to_formatted_s 
    1818            alias_method :default_inspect, :inspect 
    1919            alias_method :inspect, :readable_inspect 
    20  
    21             # Ruby 1.9 has Date#to_time which converts to localtime only. 
    22             remove_method :to_time if base.instance_methods.include?(:to_time) 
    2320          end 
    2421        end 
    2522 
     
    2825            if formatter.respond_to?(:call) 
    2926              formatter.call(self).to_s 
    3027            else 
    31               strftime(formatter) 
     28              strftime(formatter).strip 
    3229            end 
    3330          else 
    3431            to_default_s 
    3532          end 
    3633        end 
    37  
     34         
    3835        # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005" 
    3936        def readable_inspect 
    4037          strftime("%a, %d %b %Y") 
     
    4340        # To be able to keep Times, Dates and DateTimes interchangeable on conversions 
    4441        def to_date 
    4542          self 
    46         end if RUBY_VERSION < '1.9' 
     43        end 
    4744 
    4845        # Converts self to a Ruby Time object; time is set to beginning of day 
    4946        # Timezone can either be :local or :utc  (default :local) 
    5047        def to_time(form = :local) 
    5148          ::Time.send("#{form}_time", year, month, day) 
    5249        end 
    53  
     50         
    5451        # Converts self to a Ruby DateTime object; time is set to beginning of day 
    5552        def to_datetime 
    5653          ::DateTime.civil(year, month, day, 0, 0, 0, 0, 0) 
    57         end if RUBY_VERSION < '1.9' 
     54        end 
    5855 
    5956        def xmlschema 
    6057          to_time.xmlschema 
  • activesupport/lib/active_support/core_ext/date.rb

    old new  
    22require File.dirname(__FILE__) + '/date/behavior' 
    33require File.dirname(__FILE__) + '/date/calculations' 
    44require File.dirname(__FILE__) + '/date/conversions' 
     5require File.dirname(__FILE__) + '/date/translation' 
    56 
    67class Date#:nodoc: 
    78  include ActiveSupport::CoreExtensions::Date::Behavior 
    89  include ActiveSupport::CoreExtensions::Date::Calculations 
    910  include ActiveSupport::CoreExtensions::Date::Conversions 
     11  include ActiveSupport::CoreExtensions::Date::Translation 
    1012end 
  • activesupport/lib/active_support/core_ext/time.rb

    old new  
    1111require File.dirname(__FILE__) + '/time/behavior' 
    1212require File.dirname(__FILE__) + '/time/calculations' 
    1313require File.dirname(__FILE__) + '/time/conversions' 
     14require File.dirname(__FILE__) + '/time/translation' 
    1415 
    1516class Time#:nodoc: 
    1617  include ActiveSupport::CoreExtensions::Time::Behavior 
    1718  include ActiveSupport::CoreExtensions::Time::Calculations 
    1819  include ActiveSupport::CoreExtensions::Time::Conversions 
     20  include ActiveSupport::CoreExtensions::Time::Translation 
    1921end 
  • activesupport/lib/active_support/core_ext/string/translation.rb

    old new  
     1module ActiveSupport #:nodoc: 
     2  module CoreExtensions #:nodoc: 
     3    module String #:nodoc: 
     4      # Define methods for handeling translation of strings. 
     5      module Translation 
     6        def t(*args) 
     7          ActiveSupport::Translation::TranslatableString.translate(self, args) 
     8        end 
     9      end 
     10    end     
     11  end 
     12end 
  • activesupport/lib/active_support.rb

    old new  
    4646 
    4747require 'active_support/multibyte' 
    4848 
     49require 'active_support/translation' 
     50 
  • activerecord/test/validations_test.rb

    old new  
    2525  fixtures :topics, :developers 
    2626 
    2727  def setup 
     28     
     29    Object.class_eval <<-ENDDEF 
     30      class ::ActiveSupport::Translation::TranslatableString 
     31        def self.overidden_translate(string, args) 
     32          DefaultTranslatableString.translate(string, args) 
     33        end 
     34         
     35        class << self 
     36          alias_method :old_translate, :translate         
     37          alias_method :translate, :overidden_translate 
     38        end 
     39      end       
     40    ENDDEF 
     41         
    2842    Topic.write_inheritable_attribute(:validate, nil) 
    2943    Topic.write_inheritable_attribute(:validate_on_create, nil) 
    3044    Topic.write_inheritable_attribute(:validate_on_update, nil) 
    3145  end 
     46   
     47  def tear_down 
     48    Object.class_eval <<-ENDDEF 
     49      class ::ActiveSupport::Translation::TranslatableString 
     50        class << self 
     51          alias_method :translate, :old_translate 
     52        end 
     53      end       
     54    ENDDEF 
     55         
     56  end 
    3257 
    3358  def test_single_field_validation 
    3459    r = Reply.new 
     
    130155    r.save 
    131156 
    132157    errors = [] 
    133     r.errors.each { |attr, msg| errors << [attr, msg] } 
    134  
     158    r.errors.each do |attr, msg| 
     159      txt_msg = msg.kind_of?(Array) ? msg.first.t(msg.last) : msg.first.t 
     160      errors << [attr, txt_msg] 
     161    end 
     162     
    135163    assert errors.include?(["title", "Empty"]) 
    136164    assert errors.include?(["content", "Empty"]) 
    137165  end 
     
    160188    r.errors.each_full { |error| errors << error } 
    161189 
    162190    assert_equal "Reply is not dignifying", r.errors.on_base 
    163  
    164191    assert errors.include?("Title Empty") 
    165192    assert errors.include?("Reply is not dignifying") 
    166193    assert_equal 2, r.errors.count 
  • activerecord/lib/active_record/validations.rb

    old new  
    1010    attr_reader :record 
    1111    def initialize(record) 
    1212      @record = record 
    13       super("Validation failed: #{@record.errors.full_messages.join(", ")}"
     13      super("Validation failed: %s".t(@record.errors.full_messages.join(", "))
    1414    end 
    1515  end 
    1616 
     
    5252    # Adds an error to the base object instead of any particular attribute. This is used 
    5353    # to report errors that don't tie to any specific attribute, but rather to the object 
    5454    # as a whole. These error messages don't get prepended with any field name when iterating 
    55     # with each_full, so they should be complete sentences. 
    56     def add_to_base(msg) 
    57       add(:base, msg) 
     55    # with each_full, so they should be complete sentences. The optional +num+ argument 
     56    # specifies a pluralization value for translatable messages. 
     57    def add_to_base(msg, num = nil) 
     58      add(:base, msg, num) 
    5859    end 
    5960 
    6061    # Adds an error message (+msg+) to the +attribute+, which will be returned on a call to <tt>on(attribute)</tt> 
    6162    # for the same attribute and ensure that this error object returns false when asked if <tt>empty?</tt>. More than one 
    6263    # error can be added to the same +attribute+ in which case an array will be returned on a call to <tt>on(attribute)</tt>. 
    63     # If no +msg+ is supplied, "invalid" is assumed. 
    64     def add(attribute, msg = @@default_error_messages[:invalid]) 
     64    # If no +msg+ is supplied, "invalid" is assumed. The optional +num+ argument specifies a pluralization value for translatable  
     65    # messages. 
     66    def add(attribute, msg = @@default_error_messages[:invalid], num = nil) 
    6567      @errors[attribute.to_s] = [] if @errors[attribute.to_s].nil? 
    66       @errors[attribute.to_s] << msg 
     68      @errors[attribute.to_s] << [ msg, num ] 
    6769    end 
    6870 
    6971    # Will add an error message to each of the attributes in +attributes+ that is empty. 
     
    111113    #   company.errors.on(:email)     # => "can't be blank" 
    112114    #   company.errors.on(:address)   # => nil 
    113115    def on(attribute) 
    114       errors = @errors[attribute.to_s] 
    115       return nil if errors.nil? 
    116       errors.size == 1 ? errors.first : errors 
     116      if @errors[attribute.to_s].nil? 
     117        return nil 
     118      else 
     119        msgs = @errors[attribute.to_s] 
     120        txt_msgs = msgs.map {|msg| msg.kind_of?(Array) ? msg.first.t(msg.last) : msg.first.t } 
     121        return txt_msgs.length == 1 ? txt_msgs.first : txt_msgs 
     122      end 
    117123    end 
    118124 
    119125    alias :[] :on 
     
    172178      @errors.each_key do |attr| 
    173179        @errors[attr].each do |msg| 
    174180          next if msg.nil? 
    175  
     181           
     182          # Extract the message and its quantity value for translation 
     183          msg = [ msg ].flatten 
     184          msg_text, msg_num = msg 
     185     
    176186          if attr == "base" 
    177             full_messages << msg 
     187            full_messages << msg_text.t(msg_num) 
    178188          else 
    179             full_messages << @base.class.human_attribute_name(attr) + " " + msg 
     189            full_messages << (("#{@base.class.human_attribute_name(attr)} #{msg_text}").t(msg_num)) 
    180190          end 
    181191        end 
    182192      end 
     
    546556          when :within, :in 
    547557            raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range) 
    548558 
    549             too_short = options[:too_short] % option_value.begin 
    550             too_long  = options[:too_long]  % option_value.end 
     559            too_short = options[:too_short] 
     560            too_long  = options[:too_long] 
    551561 
    552562            validates_each(attrs, options) do |record, attr, value| 
     563               
    553564              if value.nil? or value.split(//).size < option_value.begin 
    554                 record.errors.add(attr, too_short
     565                record.errors.add(attr, too_short, option_value.begin
    555566              elsif value.split(//).size > option_value.end 
    556                 record.errors.add(attr, too_long
     567                record.errors.add(attr, too_long, option_value.end
    557568              end 
    558569            end 
    559570          when :is, :minimum, :maximum 
     
    563574            validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" } 
    564575            message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long } 
    565576 
    566             message = (options[:message] || options[message_options[option]]) % option_value 
     577            message = (options[:message] || options[message_options[option]]) 
    567578 
    568579            validates_each(attrs, options) do |record, attr, value| 
    569580              if value.kind_of?(String) 
    570                 record.errors.add(attr, message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value] 
     581                record.errors.add(attr, message, option_value) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value] 
    571582              else 
    572                 record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] 
     583                record.errors.add(attr, message, option_value) unless !value.nil? and value.size.method(validity_checks[option])[option_value] 
    573584              end 
    574585            end 
    575586        end 
  • actionpack/lib/action_view/helpers/active_record_helper.rb

    old new  
    118118      # you need is significantly different from the default presentation, it makes plenty of sense to access the object.errors 
    119119      # instance yourself and set it up. View the source of this method to see how easy it is. 
    120120      def error_messages_for(*params) 
    121         options = params.extract_options!.symbolize_keys 
     121        options = params.last.is_a?(Hash) ? params.pop.symbolize_keys : {} 
    122122        objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact 
    123123        count   = objects.inject(0) {|sum, object| sum + object.errors.count } 
    124124        unless count.zero? 
     
    131131              html[key] = 'errorExplanation' 
    132132            end 
    133133          end 
    134           header_message = "#{pluralize(count, 'error')} prohibited this #{(options[:object_name] || params.first).to_s.gsub('_', ' ')} from being saved" 
     134          header_message = "%d errors prohibited this #{(options[:object_name] || params.first).to_s.gsub('_', ' ')} from being saved".t(count) 
    135135          error_messages = objects.map {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } } 
    136136          content_tag(:div, 
    137137            content_tag(options[:header_tag] || :h2, header_message) << 
    138               content_tag(:p, 'There were problems with the following fields:') << 
     138              content_tag(:p, 'There were problems with the following fields:'.t) << 
    139139              content_tag(:ul, error_messages), 
    140140            html 
    141141          ) 
  • actionpack/lib/action_view/helpers/date_helper.rb

    old new  
    6565 
    6666        case distance_in_minutes 
    6767          when 0..1 
    68             return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds 
     68            return (distance_in_minutes==0) ? 'less than a minute'.t : ('%d minutes'.t 1) unless include_seconds 
    6969            case distance_in_seconds 
    70               when 0..4   then 'less than 5 seconds' 
    71               when 5..9   then 'less than 10 seconds' 
    72               when 10..19 then 'less than 20 seconds' 
    73               when 20..39 then 'half a minute' 
    74               when 40..59 then 'less than a minute' 
    75               else             '1 minute' 
     70              when 0..4   then 'less than %d seconds'.t 5 
     71              when 5..9  then 'less than %d seconds'.t 10 
     72              when 10..19 then 'less than %d seconds'.t 20 
     73              when 20..39 then 'half a minute'.t 
     74              when 40..59 then 'less than a minute'.t 
     75              else             '%d minutes'.t 1 
    7676            end 
    7777 
    78           when 2..44           then "#{distance_in_minutes} minutes" 
    79           when 45..89          then 'about 1 hour' 
    80           when 90..1439        then "about #{(distance_in_minutes.to_f / 60.0).round} hours" 
    81           when 1440..2879      then '1 day' 
    82           when 2880..43199     then "#{(distance_in_minutes / 1440).round} days" 
    83           when 43200..86399    then 'about 1 month' 
    84           when 86400..525599   then "#{(distance_in_minutes / 43200).round} months" 
    85           when 525600..1051199 then 'about 1 year' 
    86           else                      "over #{(distance_in_minutes / 525600).round} years" 
     78          when 2..44           then '%d minutes'.t distance_in_minutes 
     79          when 45..89          then 'about %d hours'.t 1 
     80          when 90..1439        then 'about %d hours'.t((distance_in_minutes.to_f / 60.0).round) 
     81          when 1440..2879      then '%d days'.t 1 
     82          when 2880..43199     then '%d days'.t((distance_in_minutes / 1440).round) 
     83          when 43200..86399    then 'about %d months'.t 1 
     84          when 86400..525599   then '%d months'.t((distance_in_minutes / 43200).round) 
     85          when 525600..1051199 then 'about %d years'.t 1 
     86          else                      'over %d years'.t((distance_in_minutes / 525600).round) 
    8787        end 
    8888      end 
    8989 
     
    495495            end 
    496496 
    497497            month_options << ((val == month_number) ? 
    498               %(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) : 
    499               %(<option value="#{month_number}">#{month_name}</option>\n) 
     498              %(<option value="#{month_number}" selected="selected">#{month_name.to_s.t}</option>\n) : 
     499              %(<option value="#{month_number}">#{month_name.to_s.t}</option>\n) 
    500500            ) 
    501501          end 
    502502          select_html(options[:field_name] || 'month', month_options, options)