Adding translations for the models in the Rails application - ruby-on-rails

I am new to ROR. I am trying add translations to my application. I have added translations for the controllers.
Where to add translations for models as i am not having any /config/locales -> models folder ->en.yml file .
In the model i am having lines like
validates_presence_of :name, :message => "Name cannot be blank!"
If i want to add translations for the message "Name cannot be blank", shall i put directly as like
validates_presence_of :name, :message => I18n.t(str_name_notblank)
Please give suggestions

To add translations to your models you just need to put them under activerecord->models and activerecord->attributes. Here's an example in polish:
pl:
activerecord:
models:
patient: "Pacjent"
attributes:
patient:
first_name: "Imię"
last_name: "Nazwisko"
address: "Ulica"
postal_code: "Kod"
city: "Miejscowość"
Note that the attributes element is not under the patient element, but actually includes it again. I found this after some debugging and it actually worked for me. The Rails I18n guide suggested a different structure, but it didn't work.
The best way to translate standard Rails messages (like the ones for validation) is to download the correct translation file from Sven Fuchs' Rails Locale Data Repository (rails-18n) and put it into your config/locales folder (you can change the name). Then you'd remove your :message string and just use the standard messages, but translated to your liking.

Related

Override nested attributes name using I18n

I have two models Store and StoreDetail as the following:
class Store
has_one :store_detail, dependent: :destroy
end
And StoreDetail:
class StoreDetail
belongs_to :store, class_name: 'Store'
belongs_to :state, class_name: 'State'
belongs_to :city, class_name: 'City'
belongs_to :zip_code, class_name: 'Zip Code'
end
And I override the attribute of state as the following:
attributes:
store/store_detail:
state: "State"
city: "City"
zip_code: "Zip Code"
But I got the validation messages:
Store detail state can't be blank
Store detail city can't be blank
Store detail zip code can't be blank
I want to make it without "Store detail", as the following:
State can't be blank
How can I override nested attributes ?
This is very possible with i18n:
en:
activerecord:
errors:
models:
store_detail:
attributes:
state:
blank: State can't be blank.
city:
blank: City can't be blank.
zip_code:
blank: Zip code cant't be blank.
Very important
All of those nested labels starting with "en" and ending with "models" must be exactly as they are specified in the example.
It is essential for the model name in the en.yml (or whichever kangage file you are using)
Model name must match model.rb because this identifies the field names to be validated for activerecord
The validation field names must match your schema.rb field names, like zip_code, not zip.
The "blank:" identifier tells Rails activerecord component to do a string replace what you have in the i18n yaml file when that particular validation fails.
Debugging i18n (added)
Validate the YAML: If you don't see the en.yml validation message you defined, but the default keeps showing, your en.yml is not functioning for some reason. YAML is very picky about spaces in the file and any trailing spaces in the file, etc. But it does not show any errors, it just reverts to using Rails default messages. Here's one YAML Lint tool: http://yaml-online-parser.appspot.com/
Rails spec for i18n: http://guides.rubyonrails.org/i18n.html.
Debug i18n: Use the gem i18n-tasks to create a comprehnsive report of the your i18n components : https://github.com/glebm/i18n-tasks
Application.rb: Make sure you have i18n setup.
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
config.i18n.default_locale = :en
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
If you want custom error messages for activerecord type errors, you have to work through i18n. It isn't a tidy thing. It's not at all DRY, but it is what's available.
You can use custom validation messages:
class StoreDetail < ActiveRecord::Base
validates :state_id, presence: true,
message: I18n.t(:state_cant_be_blank)
end
And then in locales/*.yml
en:
state_cant_be_blank: State can't be blank

Inheriting Rails i18n validation error messages in the subclass

What I understand
Suppose I have a class with a handy validation like:
User < ActiveRecord::Base
validates :username, :format => {/regex/}, :message => :name_format
end
In this case, I can use i18n to make the error message translatable, by including the following in my /config/locals/en.yml:
en:
activerecord:
errors:
models:
user:
attributes:
username:
name_format: 'has the way-wrong format, bro!'
This is fine and generally really handy.
What I want to know:
My question is: What happens when I have subclasses that inherit from User:
UserSubclassOne < User
# extra stuff
end
UserSubclassTwo < User
# extra stuff
end
...
UserSubclassEnn < User
# extra stuff
end
Now the problem is that Rails can't find the translation user_subclass_one.attributes.username.name_format.
It complains:
translation missing:
en.activerecord.errors.models.user_subclass_one.attributes.username.name_format
I'd hope that Rails would look up the hierarchy of UserSubclassOne to User when searching for a string in en.yml and then notice when it gets a 'hit', but (unless I've done something horribly wrong) apparently that doesn't happen.
An obvious solution is to duplicate the data in en.yml.en.errors.models for user, user_subclass_one, user_subclass_two, etc, but my Rails-sense tells me that this is deeply wrong.
Any ideas, folks?
Potential Complication:
User is defined in a gem MyGem that is included in a Rails engine MyEngine that is included in the full-on Rails app MyApp that defines UserSubclassOne, ..., UserSubclassEnn. I don't think this should matter though, since the validations are running in MyGem::User, which is where the en.yml file lives -- just wanted to let people know in case it does.
Ultimate problem/solution:
So it turns out that the problem was namespacing. Recall that MyApp (which defines UserSubclassOne) uses MyGem (which defines User). It turns out User is actually in the namespace MyGem (this is not necessarily always the case), so the full declaration line at the beginning of User is not:
User < ActiveRecord::Base
but rather
MyGem::User < ActiveRecord::Base
.
When the i18n gem looks up the class hierarchy, it notices this namespace and searches for my_gem/user, rather than simply user, my_gem.user, my_gem: user, etc.
Thus I had to change my en.yml file to:
/config/locals/en.yml:
en:
activerecord:
errors:
models:
my_gem/user:
attributes:
username:
name_format: 'has the way-wrong format, bro!'
and bingo!
So it turns out that the problem was namespacing. Recall that MyApp (which defines UserSubclassOne) uses MyGem (which defines User). It turns out User is actually in the namespace MyGem (this is not necessarily always the case), so the full declaration line at the beginning of User is not:
User < ActiveRecord::Base
but rather
MyGem::User < ActiveRecord::Base
.
When the i18n gem looks up the class hierarchy, it notices this namespace and searches for my_gem/user, rather than simply user, my_gem.user, my_gem: user, etc.
Thus I had to change my en.yml file to:
/config/locals/en.yml:
en:
activerecord:
errors:
models:
my_gem/user:
attributes:
username:
name_format: 'has the way-wrong format, bro!'
and bingo!
According to the Rails Guides for i18n regarding Error Message Scopes (5.1.1) for Active Record validation error messages, what you're attempting to do should work:
Consider a User model with a validation for the name attribute like this:
class User < ActiveRecord::Base
validates :name, :presence => true
end
<...snip...>
When your models are additionally using inheritance then the messages are looked up in the inheritance chain.
For example, you might have an Admin model inheriting from User:
class Admin < User
validates :name, :presence => true
end
Then Active Record will look for messages in this order:
activerecord.errors.models.admin.attributes.name.blank
activerecord.errors.models.admin.blank
activerecord.errors.models.user.attributes.name.blank
activerecord.errors.models.user.blank
activerecord.errors.messages.blank
errors.attributes.name.blank
errors.messages.blank
This way you can provide special translations for various error messages at different points in your models inheritance chain and in the attributes, models, or default scopes.
So, in your case, assuming your classes look something like this:
app/models/user.rb
User < ActiveRecord::Base
validates :username, :format => {/regex/}, :message => :name_format
end
app/models/user_subclass.rb
UserSubclass < User
validates :username, :format => {/regex/}, :message => :name_format
end
and your config/locales/en.yml looks something like:
en:
activerecord:
errors:
models:
user:
attributes:
username:
name_format: 'has the way-wrong format, bro!'
then the message searching for a validation on UserSubClass should go:
activerecord.errors.models.user_sublcass.attributes.username.name_format # fail
activerecord.errors.models.user_sublcass.name_format # fail
activerecord.errors.models.user.attributes.username.name_format # success
activerecord.errors.models.user.name_format
# ...
Assuming that your model files and yaml files look similar to what's above, then the potential complication you mentioned may be the issue, but obviously I can't be certain.

Translate Rails model association - not working

Anyone has some tips as how to translate model associations in Rails?
For example: I have a Person model, which can have many Phone. However, a Person needs to have at least one Phone. I'm not able to translate that validation. The best I could do was this:
validates_presence_of :phones, :message => "At least one phone is required."
And on my YAML, I replaced this line to omit the %{attribute}:
format: ! '%{message}'
This way only my message is displayed, and I avoid the un-translated field name to be displayed.
This is causing me a lot of headache, because some gems simply don't allow me to pass :message => "something describing the error", so I wanted to configure all the error messages through my YAML.
Also, with some models I'm able to translate their attributes, while with others I'm not. For example:
activerecord:
attributes:
additional_info:
account_manager: "Manager"
This works. I can see on my form "Manager". However, when this field has an error, Rails will display it as "Additional info account manager can't be blank".
I tried this:
activerecord:
errors:
models:
additional_info:
attributes:
account_manager: "Manager"
But no luck.
I did read the docs, but no clue on why it's happening.
Here are the valid key paths for Rails 4.1:
# Basic Attribute on Model
activerecord:
attributes:
#{model_class.model_name.i18n_key}:
#{attribute_name}:
"Localized Value"
# Attribute on Nested Model
activerecord:
attributes:
#{model_class.model_name.i18n_key}/#{association_name}:
#{attribute_name}:
"Localized Value"
#{association_name}:
#{attribute_name}:
"Fallback Localized Value"
So, given this model (which has the i18n_key of :person):
class Person
has_many :friends
end
You'd have these locale definitions:
activerecord:
attributes:
person:
first_name:
"My Name"
person/friends:
first_name:
"My Friend's Name"
friends:
first_name:
"A Friend's Name"
If your model is a namespace, such as:
class MyApp::Person
has_many :friends
end
the i18n_key becomes :my_app/person and your / key starts to wear out:
activerecord:
attributes:
my_app/person:
first_name:
"My Name"
my_app/person/friends:
first_name:
"My Friend's Name"
friends:
first_name:
"A Friend's Name"
Rails 3.2 has changed this behavior. The way I've posted before is deprecated.
Now, in order to translate associations, there is the need to add a slash (instead of nesting everything). So instead of this:
activerecord:
attributes:
person:
additional_info:
account_manager: "Manager"
The correct now is:
activerecord:
attributes:
person:
additional_info/account_manager: "Manager"
Also, I figured out that has_many associations are being translated differently from that. If you want to translate those, the following example may help:
activerecord:
attributes:
emails:
address: "E-mail field"
Instead of the model name, like I did above, you need to pass the association name, in this case emails.
Check this comment and pull request for more info:
https://github.com/rails/rails/commit/c19bd4f88ea5cf56b2bc8ac0b97f59c5c89dbff7#commitcomment-619858
https://github.com/rails/rails/pull/3859

Rails 3 Customer Error message

I'm trying to do something very simple. I have a validates presence of in rails 3:
validates_presence_of [:first_nm]
When this fires, it gives the following crappy message:
"first nm cannot be blank"
I want to override the error message to give a friendly field name for "first nm"
"Please fill out your First Name"
I have seen all kinds of plugins, localization, humanized attributes tutorials, but these don't seem to work or are outdated. Is there no simple way to do this in Rails 3?
For localization, i've tried this:
# Sample localization file for English. Add more files in this directory for other locales.
# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
en:
activerecord:
errors:
messages:
taken: "has already been taken"
record_invalid: "Validation failed: %{errors}"
models:
customer:
blank: "This is a custom blank message for %{model}: %{attribute}"
attributes:
first_nm:
blank: "This is a custom blank message for first name"
Alas, no luck. My error message did not change.
On thing that might be related. I'm not inheriting from ActiveRecord, because this object is getting saved via soap, not database. Instead, I have the following:
class Customer
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations
end
Have you seen this page on ActiveRecord localization? It seems to be for Rails 3. I can't test it right now, but by the document it seems you can do:
models.user.attributes.first_nm.blank = "Please fill out your First Name"

validating presence of email address (can't be blank)- Ruby on Rails

Pretty new at all this. I have a simple form for users to enter a couple pieces of information and then input their email address and push the submit button. I want to make it mandatory that they have to fill out their email address in order to push the submit button. If they don't fill out their email address they should get an error message on the email box that says the email can't be blank. I know this is super simple but I need exact help on where to put what code. I've been researching this all night and know that part of the code should go in the application_controller and other should go in the html file where the actual text_field:email is.
I'd be grateful if someone could clearly tell me what the necessary steps are for doing this. Thanks!
It should go in your model. Add this:
class Model < ActiveRecord::Base
validates_presence_of :email
end
Check this link for more info: http://guides.rails.info/activerecord_validations_callbacks.html#validates-presence-of
In Rails 2, which I would assume you are using, validations go in the model. Which is located in $Rails_app_directory/app/model/$Classname.rb
In order to add ActiveRecord validations you can use the line
validates_presence_of :email_address
You should also consider using Rails to generate a confirmation field and filtering out ill-formatted email addresses. You could accomplish the former with:
validates_confirmation_of :email_address
with this, all you need to add to your form is a text_field for :email_address_confirmation
and the latter with a regular expression such as:
validates_format_of :email_address, :with => /\A[\w\.%\+\-]+#(?:[A-Z0-9\-]+\.)+(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)\z/i
From snipplr, place in your model
validates_format_of :email,
:with => /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i,
:message => 'email must be valid'

Resources