可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have attributes with special validation where I use the message clause to display a special message just for that validation. Here is one example:
validates :email, presence: true, length: { maximum: 60 },
format: { with: valid_email_regex, message: "is not a valid email address format." },
uniqueness: { case_sensitive: false }
I would like to translate the message here but I am not sure how to do it.
I have seen examples where they type something like this: message: t("some_value_here"). I'm not sure about the designation. I tried something like this message: t(:bad_email). I did the following in my yaml file just to try something.
activemodel:
errors:
bad_email: "is not a valid email address format."
When I tried to access my Rails application I got the following error:
ActionView::Template::Error (undefined method `t' for #<Class:0x007fefc1b709e0>)
I also tried this in my yaml file:
activemodel:
errors:
user:
bad_email: "is not a valid email address format."
I have been researching this off and on all day long. All I can find is to replace built-in error hashes like blank or empty. Is there a way for me to have custom error hashes and replace them in the model? At this point I cannot get the t to work as coded. My hope is that the problem is how I have my yaml file set up. I have seen varying versions of how to set this up. I am not sure if I should put this under activemodel or activerecord. I assumed activemodel since that is where the custom message is that I want to translate.
Any help would be appreciated. This is the last piece I need to figure out before launching my first translation of the application.
UPDATE 7/29/2013 7:30 pm CDT
bgates gave me a very good start with how to setup my model files to receive the custom message in the YAML file. However I ended up having to do the following setup in my yaml file for the custom messages to be found.
activerecord:
errors:
models:
user:
attributes:
bio:
no_links: "cannot contain email addresses or website links (URLs)."
email:
bad_email: "is not a valid email address format."
username:
bad_username: "can only contain numbers and letters. No special characters or spaces."
回答1:
Use a symbol for the message:
validates :email, presence: true, length: { maximum: 60 },
format: { with: valid_email_regex, message: :bad_email },
uniqueness: { case_sensitive: false }
then in the yaml file
[lang]:
activerecord:
errors:
messages:
bad_email: "just ain't right"
If there's a translation specific to this model, it will override the general one above:
[lang]:
activerecord:
errors:
models:
model_name: # or namespace/model_name
attributes:
email:
bad_email: "model-specific message for invalid email"
If you write custom validations, add_error(:email, :bad_email)
will do the lookup above, but errors[:email] << :bad_email
will not.
回答2:
I just walked through all this and found the rails guides for custom validators too hard-coded... I'm posting this here even though it's not exactly what you asked, but the Q title fits perfectly (which is why I read this post for my problem).
Custom validation with i18n message:
validate :something_custom?, if: :some_trigger_condition
def something_custom?
if some_error_condition
errors.add(:some_field_key, :some_custom_msg)
end
end
# en.yml
activerecord:
errors:
models:
some_model:
some_custom_msg: "This is i18n controlled. yay!"
回答3:
The solution to this does not need to be custom; The format
validator message already maps to the :invalid
symbol. You need only set the invalid in translation.
en:
activerecord:
errors:
models:
some_model:
attributes:
email:
invalid: "FOO"
Reference: http://edgeguides.rubyonrails.org/i18n.html#error-message-interpolation
回答4:
I will give a complete example.
To make your models cleaner, you can create a custom validation helper method in an entirely new directory - app/validations
, which will be autoloaded by Rails.
I'll call my file time_validator.rb
, located at app/validations/time_validator.rb
My file has the following code, which validates user-entered time - that it is actually time.
# frozen_string_literal: true
class TimeValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
Time.parse(value).strftime('%H:%M')
rescue ArgumentError
record.errors.add(attribute, :invalid_time)
end
end
You can read more about creating custom ActiveRecord validations here
Our main point of concern is the record.errors
line. Note that it's attribute
and not :attribute
, where attribute
is the column in your model.
:invalid_time
is the key that retrieves your translated content from your locales file. In my case, this is the en
file:
en
activerecord:
errors:
models:
home:
attributes:
check_in_time:
invalid_time: Please enter valid time
check_out_time:
invalid_time: Please enter valid time
Then in the home
model:
validates :check_in_time, time: { allow_blank: true }
validates :check_out_time, time: { allow_blank: true }
time
automatically gets mapped to the class TimeValidator
, and the methods therein get run.
Incase this is violated, ActiveRecord will throw an error right below the column name.
Hope this helps!