From 45d41f0dadd9fa171f306ff356770c4492726f30 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Thu, 19 Jun 2008 16:25:27 +0200 Subject: integrating I18n into Rails --- activerecord/lib/active_record/validations.rb | 184 +++++++++++++++----------- 1 file changed, 108 insertions(+), 76 deletions(-) (limited to 'activerecord/lib/active_record/validations.rb') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index c4e370d017..f54fb80137 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -23,30 +23,30 @@ module ActiveRecord @base, @errors = base, {} end - @@default_error_messages = { - :inclusion => "is not included in the list", - :exclusion => "is reserved", - :invalid => "is invalid", - :confirmation => "doesn't match confirmation", - :accepted => "must be accepted", - :empty => "can't be empty", - :blank => "can't be blank", - :too_long => "is too long (maximum is %d characters)", - :too_short => "is too short (minimum is %d characters)", - :wrong_length => "is the wrong length (should be %d characters)", - :taken => "has already been taken", - :not_a_number => "is not a number", - :greater_than => "must be greater than %d", - :greater_than_or_equal_to => "must be greater than or equal to %d", - :equal_to => "must be equal to %d", - :less_than => "must be less than %d", - :less_than_or_equal_to => "must be less than or equal to %d", - :odd => "must be odd", - :even => "must be even" - } - - # Holds a hash with all the default error messages that can be replaced by your own copy or localizations. - cattr_accessor :default_error_messages + # @@default_error_messages = { + # :inclusion => "is not included in the list", + # :exclusion => "is reserved", + # :invalid => "is invalid", + # :confirmation => "doesn't match confirmation", + # :accepted => "must be accepted", + # :empty => "can't be empty", + # :blank => "can't be blank", + # :too_long => "is too long (maximum is %d characters)", + # :too_short => "is too short (minimum is %d characters)", + # :wrong_length => "is the wrong length (should be %d characters)", + # :taken => "has already been taken", + # :not_a_number => "is not a number", + # :greater_than => "must be greater than %d", + # :greater_than_or_equal_to => "must be greater than or equal to %d", + # :equal_to => "must be equal to %d", + # :less_than => "must be less than %d", + # :less_than_or_equal_to => "must be less than or equal to %d", + # :odd => "must be odd", + # :even => "must be even" + # } + # + # # Holds a hash with all the default error messages that can be replaced by your own copy or localizations. + # cattr_accessor :default_error_messages # Adds an error to the base object instead of any particular attribute. This is used @@ -61,27 +61,34 @@ module ActiveRecord # for the same attribute and ensure that this error object returns false when asked if empty?. More than one # error can be added to the same +attribute+ in which case an array will be returned on a call to on(attribute). # If no +msg+ is supplied, "invalid" is assumed. - def add(attribute, msg = @@default_error_messages[:invalid]) - @errors[attribute.to_s] = [] if @errors[attribute.to_s].nil? - @errors[attribute.to_s] << msg - end + def add(attribute, message = nil) + message ||= :"active_record.error_messages.invalid".t + @errors[attribute.to_s] ||= [] + @errors[attribute.to_s] << message + end # Will add an error message to each of the attributes in +attributes+ that is empty. - def add_on_empty(attributes, msg = @@default_error_messages[:empty]) + def add_on_empty(attributes, custom_message = nil) for attr in [attributes].flatten value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s] - is_empty = value.respond_to?("empty?") ? value.empty? : false - add(attr, msg) unless !value.nil? && !is_empty + is_empty = value.respond_to?("empty?") ? value.empty? : false + add(attr, generate_message(attr, :empty, :default => custom_message)) unless !value.nil? && !is_empty end end # Will add an error message to each of the attributes in +attributes+ that is blank (using Object#blank?). - def add_on_blank(attributes, msg = @@default_error_messages[:blank]) + def add_on_blank(attributes, custom_message = nil) for attr in [attributes].flatten value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s] - add(attr, msg) if value.blank? + add(attr, generate_message(attr, :blank, :default => custom_message)) if value.blank? end end + + def generate_message(attr, key, options = {}) + scope = [:active_record, :error_messages] + key.t(options.merge(:scope => scope + [:custom, @base.class.name.downcase, attr])) || + key.t(options.merge(:scope => scope)) + end # Returns true if the specified +attribute+ has errors associated with it. # @@ -166,22 +173,25 @@ module ActiveRecord # company = Company.create(:address => '123 First St.') # company.errors.full_messages # => # ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Address can't be blank"] - def full_messages + def full_messages(options = {}) full_messages = [] + locale = options[:locale] @errors.each_key do |attr| - @errors[attr].each do |msg| - next if msg.nil? - + @errors[attr].each do |message| + next unless message + if attr == "base" - full_messages << msg + full_messages << message else - full_messages << @base.class.human_attribute_name(attr) + " " + msg + key = :"active_record.human_attribute_names.#{@base.class.name.underscore.to_sym}.#{attr}" + attr_name = key.t(locale) || @base.class.human_attribute_name(attr) + full_messages << attr_name + " " + message end end end full_messages - end + end # Returns true if no errors have been added. def empty? @@ -388,15 +398,18 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_confirmation_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:confirmation], :on => :save } + configuration = { :on => :save } configuration.update(attr_names.extract_options!) attr_accessor(*(attr_names.map { |n| "#{n}_confirmation" })) validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message]) unless record.send("#{attr_name}_confirmation").nil? or value == record.send("#{attr_name}_confirmation") + unless record.send("#{attr_name}_confirmation").nil? or value == record.send("#{attr_name}_confirmation") + message = record.errors.generate_message(attr_name, :confirmation, :default => configuration[:message]) + record.errors.add(attr_name, message) + end end - end + end # Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example: # @@ -422,7 +435,7 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_acceptance_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:accepted], :on => :save, :allow_nil => true, :accept => "1" } + configuration = { :on => :save, :allow_nil => true, :accept => "1" } configuration.update(attr_names.extract_options!) db_cols = begin @@ -434,7 +447,10 @@ module ActiveRecord attr_accessor(*names) validates_each(attr_names,configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message]) unless value == configuration[:accept] + unless value == configuration[:accept] + message = record.errors.generate_message(attr_name, :accepted, :default => configuration[:message]) + record.errors.add(attr_name, message) + end end end @@ -461,7 +477,7 @@ module ActiveRecord # method, proc or string should return or evaluate to a true or false value. # def validates_presence_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:blank], :on => :save } + configuration = { :on => :save } configuration.update(attr_names.extract_options!) # can't use validates_each here, because it cannot cope with nonexistent attributes, @@ -505,11 +521,7 @@ module ActiveRecord # method, proc or string should return or evaluate to a true or false value. def validates_length_of(*attrs) # Merge given options with defaults. - options = { - :too_long => ActiveRecord::Errors.default_error_messages[:too_long], - :too_short => ActiveRecord::Errors.default_error_messages[:too_short], - :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length] - }.merge(DEFAULT_VALIDATION_OPTIONS) + options = {}.merge(DEFAULT_VALIDATION_OPTIONS) options.update(attrs.extract_options!.symbolize_keys) # Ensure that one and only one range option is specified. @@ -531,15 +543,14 @@ module ActiveRecord when :within, :in raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range) - too_short = options[:too_short] % option_value.begin - too_long = options[:too_long] % option_value.end - validates_each(attrs, options) do |record, attr, value| value = value.split(//) if value.kind_of?(String) if value.nil? or value.size < option_value.begin - record.errors.add(attr, too_short) + message = record.errors.generate_message(attr, :too_short, :default => options[:too_short], :count => option_value.begin) + record.errors.add(attr, message) elsif value.size > option_value.end - record.errors.add(attr, too_long) + message = record.errors.generate_message(attr, :too_long, :default => options[:too_long], :count => option_value.end) + record.errors.add(attr, message) end end when :is, :minimum, :maximum @@ -549,11 +560,14 @@ module ActiveRecord validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" } message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long } - message = (options[:message] || options[message_options[option]]) % option_value - validates_each(attrs, options) do |record, attr, value| value = value.split(//) if value.kind_of?(String) - record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] + unless !value.nil? and value.size.method(validity_checks[option])[option_value] + key = message_options[option] + custom_message = options[:message] || options[key] + message = record.errors.generate_message(attr, key, :default => custom_message, :count => option_value) + record.errors.add(attr, message) + end end end end @@ -595,7 +609,7 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_uniqueness_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:taken], :case_sensitive => true } + configuration = { :case_sensitive => true } configuration.update(attr_names.extract_options!) validates_each(attr_names,configuration) do |record, attr_name, value| @@ -654,8 +668,11 @@ module ActiveRecord if configuration[:case_sensitive] && finder_class.columns_hash[attr_name.to_s].text? found = results.any? { |a| a[attr_name.to_s] == value } end - - record.errors.add(attr_name, configuration[:message]) if found + + if found + message = record.errors.generate_message(attr_name, :taken, :default => configuration[:message]) + record.errors.add(attr_name, message) + end end end end @@ -685,13 +702,16 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_format_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save, :with => nil } + configuration = { :on => :save, :with => nil } configuration.update(attr_names.extract_options!) raise(ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash") unless configuration[:with].is_a?(Regexp) validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message] % value) unless value.to_s =~ configuration[:with] + unless value.to_s =~ configuration[:with] + message = record.errors.generate_message(attr_name, :invalid, :default => configuration[:message], :value => value) + record.errors.add(attr_name, message) + end end end @@ -715,7 +735,7 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_inclusion_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:inclusion], :on => :save } + configuration = { :on => :save, :with => nil } configuration.update(attr_names.extract_options!) enum = configuration[:in] || configuration[:within] @@ -723,7 +743,10 @@ module ActiveRecord raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?") validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message] % value) unless enum.include?(value) + unless enum.include?(value) + message = record.errors.generate_message(attr_name, :inclusion, :default => configuration[:message], :value => value) + record.errors.add(attr_name, message) + end end end @@ -747,7 +770,7 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_exclusion_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:exclusion], :on => :save } + configuration = { :on => :save, :with => nil } configuration.update(attr_names.extract_options!) enum = configuration[:in] || configuration[:within] @@ -755,7 +778,10 @@ module ActiveRecord raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?") validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message] % value) if enum.include?(value) + if enum.include?(value) + message = record.errors.generate_message(attr_name, :exclusion, :default => configuration[:message], :value => value) + record.errors.add(attr_name, message) + end end end @@ -791,12 +817,14 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_associated(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save } + configuration = { :on => :save } configuration.update(attr_names.extract_options!) validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message]) unless - (value.is_a?(Array) ? value : [value]).inject(true) { |v, r| (r.nil? || r.valid?) && v } + unless (value.is_a?(Array) ? value : [value]).inject(true) { |v, r| (r.nil? || r.valid?) && v } + message = record.errors.generate_message(attr_name, :invalid, :default => configuration[:message], :value => value) + record.errors.add(attr_name, message) + end end end @@ -844,7 +872,8 @@ module ActiveRecord if configuration[:only_integer] unless raw_value.to_s =~ /\A[+-]?\d+\Z/ - record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number]) + message = record.errors.generate_message(attr_name, :not_a_number, :value => raw_value, :default => configuration[:message]) + record.errors.add(attr_name, message) next end raw_value = raw_value.to_i @@ -852,7 +881,8 @@ module ActiveRecord begin raw_value = Kernel.Float(raw_value.to_s) rescue ArgumentError, TypeError - record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number]) + message = record.errors.generate_message(attr_name, :not_a_number, :value => raw_value, :default => configuration[:message]) + record.errors.add(attr_name, message) next end end @@ -860,10 +890,12 @@ module ActiveRecord numericality_options.each do |option| case option when :odd, :even - record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[option]) unless raw_value.to_i.method(ALL_NUMERICALITY_CHECKS[option])[] + unless raw_value.to_i.method(ALL_NUMERICALITY_CHECKS[option])[] + message = record.errors.generate_message(attr_name, option, :value => raw_value, :default => configuration[:message]) + record.errors.add(attr_name, message) + end else - message = configuration[:message] || ActiveRecord::Errors.default_error_messages[option] - message = message % configuration[option] if configuration[option] + message = record.errors.generate_message(attr_name, option, :default => configuration[:message], :value => raw_value, :count => configuration[option]) record.errors.add(attr_name, message) unless raw_value.method(ALL_NUMERICALITY_CHECKS[option])[configuration[option]] end end -- cgit v1.2.3