Overriding model attribute names using I18n - can't get this working - ruby-on-rails

I'm trying to override the string used to describe the 'login' attribute of my User model to be "User name" instead. I thought that this was set in vendor/rails/activerecord/lib/active_record/locale/en.yml. I've tried changing it here and in my config/locales/en.yml file, and in neither case does it work (i restart the server after every change).
In both cases it's done like this:
en:
...
activerecord:
attributes:
user:
login: User Name
When i test it out, eg having f.label :login in my new user form, it comes out as "Login" not "User Name". Am i labouring under some fundamental error about how this stuff works, or is it genuinely not working? Either way, can anyone tell me how to fix it? thanks, max

In case if any of you have trouble the translation aren't loaded, I debugged like this:
First I use the script in https://stackoverflow.com/a/10211540/474597 to setup logging.
Then as I run the server and render the pages, I can see in that log the keys used to get the translations. Then I can check if the keys I use are correct or not.
One pitfall is that, the first key isn't necessarily the key they will use. I have seen cases where it loads the correct key, and then looks for another key which does not have translation, resulting in the English translation. I had to put the translation in those two keys.
For example: my Foo has_many Bar, and Bar has_many Duu, and Duu has a price column.
In order to translate that price column, I have to have the following for it to work:
activerecord:
attributes:
'foo/bar/duu':
price: "price"
Even though the log has this:
:duu
:"activerecord.attributes.duu.text"
:"activerecord.errors.models.duu.attributes.text.blank"
:"activerecord.errors.models.duu.blank"
:"activerecord.errors.messages.blank"
:"errors.attributes.text.blank"
:"errors.messages.blank"
:"activerecord.attributes.foo/bars/duus.text"

I'm answering this here on request of someone... I did fix this and didn't update my question, sorry. I was on the right lines in my question but didn't have the right "path" down to the keys: the names of fields, as they are displayed, are called "labels" and they have their own section outside of the :activerecord part of the yaml tree.
The correct way to do it is
en:
user:
labels:
login: "User Name"
email: "Email Address"
where "user" is a lowercased model name and login and email are fields.

I think you can find what you are looking for here:
http://guides.rubyonrails.org/i18n.html#translations-for-active-record-models

You may store your "User Name" string under any name in your en.yml file:
en:
user:
user_name: User Name
and in your view
<%= f.label :login, t('user.user_name') %>

Related

Rails own config/initializers updated and doesn't display changes

I work on a web app that was already coded, and I have to bring some new features to improve it. I have to add 2 field in the rails admin, and there are some file type that I have never work with like .yml files.
I have a file called : simple_form.fr.yml, that permit to use on the view : human_attribute_name on a class. but I made a modification on a line (change "hello" to "hello world" for example) and I can't see the modification on the view ...
Should I did a command line to make modifications available ?
Thank ! (don't hesitate to ask if you need more precisions / code, I'll update my question)
EDIT
The yml document :
fr:
simple_form:
labels:
school:
code_online_access: "Accès code en ligne"
the line that I change is code_online_access, I juste change the content of the string and in the view I have this line :
<%= School.human_attribute_name("code_online_access") %>
The problem is that you're changing a label for simple_form, but expect the change to show up in human_attribute_name. This method does not look in simple_form's section.
Take a look at this section of I18n rails guide to learn correct place to put your translations to.
en:
activerecord:
models:
user: Dude
attributes:
user:
login: "Handle"
# will translate User attribute "login" as "Handle"
then
User.human_attribute_name("login") # => 'Handle'

Rails: i18n parameters that are also translated

I'm having difficulty finding the answer for my question, but it may just be that I have no idea how to phrase it. In svenfuchs's yml files in his rails-i18n repo, he has this listed under error:
format: #{attribute}#{message}
and below that he specifies possible error messages. It's really nifty, as it automatically translated error messages for me.
I'd like to use this format to translate headers and buttons. In Japanese, we'd say "FAQ Create" while in English we'd say "Create FAQ", so I can't just print out those translations and I'd like to not have to make each button's translation myself (a.k.a. create_faq: FAQを作る).
So far I've got in my view: t('button.format'), :attribute => "faq", :message => "create"
ja.yml:
model:
faq: FAQ
button:
format: #{attribute}#{message}
messages:
create: を作る
But that just prints out faqcreate for Japanese. What I'm trying to do is access the translations of model.faq and button.messages.create to pass as the parameters. Anybody know how?
p.s. messages: was also plural in the working errors message.
I'm sorry, I'm so stupid, I keep answering my questions right after I finally decided to ask for help;;; for anybody interested, just pass in another t(' '), so:
t('button.format', :attribute t('model.faq'), :message t('button.messages.create'))

Hook into Rails' I18n

I've written a little library to hold translated content in model attributes. All you have to do is add the following to a model:
class Page < ActiveRecord::Base
i18n_attributes :title, :content
end
By convention, the data is written to the real attributes i18n_title and i18n_content as a hash (or hstore hash for Postgres). And a number of getters and setters give you access to "localized virtual attributes":
page = Page.new
page.title_en = 'Hello'
page.title_es = 'Hola'
page.i18n_title # => { en: "Hello", es: "Hola" }
I18n.locale = :es
page.title # => "Hola"
page.title_en # => "Hello"
You can use these virtual attributes in forms as well, but there's a downside: The form builder uses I18n to get the label and translate attribute validation errors. And it does of course look for keys such as activerecord.attributes.page.title_en if you use title_enin the form.
It would be very cumbersome to replicate the same translation for every available_locale in the locales/en.yml etc files:
activerecord:
attributes:
page:
title_en: "Title"
title_es: "Title"
...
What I'd like to do is execute some code after Rails has loaded all locales in the boot process and then clone translations for these keys. Is there a way to do this? Maybe a hook which gets called after the translations have been loaded from the YAML files? (The translations are not yet loaded when my lib loads.)
Or do you see another way to tackle this problem? (I've tried to alias I18n.translate, but I'm afraid this might cause major headache in the future.)
Thanks for your hints!
Although you dropped this approach, please let me share my thoughts:
I don't think it is incredible useful to add other locale strings into a translation file for a specific localization. Since a config/locales/$locale.yml usually starts (at least in my case) with
$locale:
...
there is no need for activerecord.attributes.page.title_es in an English localization file. I'd just put it in es.yml as activerecord.attributes.page.title.
I mean: isn't that the whole purpose of separate localization files? (Or from the developer/translator point of view: In which file should I search for .title_es, in en.yml, es.yml or both?)

Nested Models attribute localization for error messages in Rails 3.1

I have a deeply nested models form.
When a nested model attribute is in error the error messages is displaying:
List items identifier url may not be blank.
Which is:
Model_name + attribute + localization file error message
The correct message should be:
Item link url may not be blank.
ruby-1.9.2-p290 :014 > ListItem.human_attribute_name("identifier")
=> "Item Link"
Localization is otherwise working fine except for nested model attribute names in error messages.
Looks like it was a bug in 2.3.4 that was fixed, but I can't figure it out.
the following is working for me. I've a Course model and a OfflineCourse Model. OfflineCourse is nested in Course.
The following YAML works correctly form me. Hope this helps
course:
title: Titolo
subtitle: Sottotitolo
description: Descrizione
abstract: Abstract
audience: A chi è rivolto?
topic: Argomenti
typology: Tipologia
stars: Stelle
course/offline_courses:
start_date: Data inizio
end_date: Data fine
location: Luogo
schedule: Programma
visible: Visibile
city: Città
Not sure if this the the "proper" way to solve this, but this will work.
In your localization file, you probably have something like this:
en:
activerecord:
attributes:
list_item:
identifier: Item Link
This will work as long as you address it from the nested model directly. Rails validations appears to go via the parent model, so you need something like:
en:
activerecord:
attributes:
list_item:
identifier: Item Link
parent_model:
list_item:
identifier: Item Link
To me this seems to break the DRY principle because you have to repeat the human readable name at the nested level too, but this should work for you.

remove field name from object validation message

I've got a simple active record validation on an object using this within a form:
form.error_messages({:message => '', :header_message => ''})
This in turn outputs something like "FieldName My Custom message"
What i need to do is remove the field name from the error message but leave my custom message.
Can anyone point me in the right direction for this.
In rails 3.2.6, you can set this in a locale file (e.g., config/locales/en.yml):
en:
errors:
format: "%{message}"
Otherwise, the default format is "%{attribute} %{message}".
One way to have complete control over the messages is to use a custom validate block in the model. e.g. to check that a field is not blank it would be like this:
class MyModel < ActiveRecord::Base
validate do |model|
model.errors.add_to_base("My Custom message") if user.field.blank?
end
end
add_to_base is intended for adding messages that aren't related to a particular individual field (e.g. if a combination of multiple fields is illegal). This means that the CSS to highlight your invalid field won't get added. You can work arround this by also adding a nil message to the errors for your field e.g.
model.errors.add(:field, nil)
Alternatively, check out custom-err-message plugin - this plugin gives you the option to not have your custom validation error message prefixed with the attribute name.
Update:
add_to_base is deprecated since Rails 3. The following can be used instead:
model_instance.errors.add(:base, "Msg")
Ref: https://apidock.com/rails/ActiveRecord/Errors/add_to_base
You can use errors.add_to_base http://api.rubyonrails.org/classes/ActiveRecord/Errors.html#M001712
You can access the object's errors instance directly if you need full control over how the messages are presented.

Resources