I have a model with custom validations. I return the validation
errors to the view as JSON using AJAX.
I need to show the error
messages with the right locale but the messages
show in English (default) for each locale.
When I return I18n.locale
itself instead of the message (for troubleshooting) it shows "en" no matter what is the set locale.
I18n in controllers or views works as expected, this problem
occurs only in the model.
The only configuration that I've made regarding locale is setting the default locale in the application config and setting the locale before each action in the application controller.
Another thing that I've noticed is that when I use root_path without providing the locale, it's using the default locale instead keeping the current locale like it should. I think those issues are connected
Edit:
When I print the locale parameter in controller#create, I get nil. For some reason I don't have the locale parameter at all.
model file:
validate :relevant_date_time
def relevant_date_time
errors.add(:date_error, I18n.t("validations.date_error")) unless date_time_is_relevant?
end
application_controller:
before_action :set_locale
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
Am I forgetting something?
Information I reviewed:
http://guides.rubyonrails.org/i18n.html
Access translation file (i18n) from inside rails model
Rails 3 translations within models in production
http://www.eq8.eu/blogs/10-translating-locales-for-rails-model-errors
https://lingohub.com/frameworks-file-formats/rails5-i18n-ruby-on-rails/
Change locale at runtime in Rails 3
If you set locale at application_controller.rb, it will only have scope in all controllers and views NOT in models.
So you have to set locale inside model too. Same as you did at controller.
At controller
Model.new(params.merge(locale: I18n.locale))
Inside model
attr_accessible :locale
before_validation() do
I18n.local = locale
end
def relevant_date_time
errors.add(:date_error, I18n.t("validations.date_error")) unless date_time_is_relevant?
end
I18n locale in controllers/views only applies to the action's context, it does not change your app's default locale setting, which is where your model is getting its locale from (as you have discovered).
The step you are missing is to pass the locale into your model from your action, which you could do by adding an attr_accessor :locale to your model, and then passing the locale through when creating/updating it in your controller:
# e.g. app/controllers/users_controller.rb
# user_params = { email: test#mail.com, password: 12345678 }
User.new(user_params.merge(locale: I18n.locale))
Then in your validation method you would be able to access the current locale with locale, so all you need to do is pass it to I18n.t:
errors.add(:date_error, I18n.t("validations.date_error", locale: locale)) unless date_time_is_relevant?
Solved by adding the following method in application controller:
def default_url_options(options={})
{ locale: I18n.locale }
end
For anyone who is struggling with I18n in model validation, the solution could be not including any custom message keys in the models but
en:
activerecord:
errors:
models:
model_name:
attributes:
attr_name:
taken: << or whatever error message like blank, too_long, too_short etc.
Credit t:
https://stackoverflow.com/a/4453350/267693
Related
I am new to Ruby on Rails. I am trying to I18N my website by allowing the user to set the locale from user preferences.
Following the instructions from this guide, I have created a switch_locale method in application_controller.rb
around_action :switch_locale
def switch_locale(&action)
locale = current_user.try(:locale) || I18n.default_locale
I18n.with_locale(locale, &action)
end
I would like to test this function by creating a link or a button that allows a user to select which locale they want. Is there a way to call this method from a view without changing the route?
I know I can change the ActiveRecord names in a locale file, but is there a way to change them based on context rather than locale (while still leveraging locale files in the application)?
For a simple example (I have multiple circumstances where I need to accomplish this), if I have an address form in a wizard and a user selects a country, how could I change the label/error messages for a :zipcode attribute to display "Zipcode" to those who have selected United States, and "Postcode" to those who have selected United Kingdom?
Edit: What I mean is when a model attribute (country) changes, how to change the human readable attributes for (zipcode) based on the country selection. The users locale won't change (I am already making use of locale files for translations).
Best way to localize is to use I18n, check this post: https://guides.rubyonrails.org/i18n.html#setup-the-rails-application-for-internationalization
Basic I18n
First add locales in you application.rb controller
config.i18n.available_locales = ["en-GB", "en-US"]
config.i18n.default_locale = "en-US"
Then create 2 files en-US.yml and en-GB.yml under config/locales
# en-GB.yml
en-Gb:
zipcode: "PostCode"
# en-US.yml
en-US:
zipcode: "ZipCode"
Then in your controller, you will need to set dictionary that will be used for translation. It is defined with the I18n.locale variable.
# example when locale is passing through params
before_action :set_locale
def set_locale
I18n.locale = I18n.available_locales.include?(params[:locale]) ? params[:locale] : I18n.default_locale
end
And finaly in your views:
<%= t('zipcode') %>
Or if you need in you ruby files:
I18n.t('zipcode')
Localize ActiveRecord Attributes
Same as above, you can create a active_record.en-US.yml under config/locales
# active_record.en-US.yml
en-US:
activerecord:
attributes:
your_model_name:
zipcode: 'ZipCode'
I accepted the other answer as I did end up using locale files as part of my solution.
What I did was a bit hacky, however:
Set locale to {language}-{selected_country} before the necessary request
Have specific overrides in those YAML files where necessary, fall back to standard attributes in base language file whenever possible.
Make use of alias_attributes in the FormObject to minimise the need for the above hack.
I'm developing a internationalized application, and sometimes I need to get some messages in a language that is not my default, like this:
I18n.t("my_message.some_attribute", :locale => :ptBR)
The problem is: I have an API method that creates and active record object, and I would like to render the error message from the method full_messages, like this:
my_object.errors.full_messages.uniq.to_sentence
The problem is, in that case, I get the message for my default language. How could I get that sentence in another language?
Thanks!
Got my answer... since the language come as a param to my api, in my app controller I set the locale before_action:
before_action :set_locale
def set_locale
I18n.locale = params[:lang] || "en"
end
This works for me
I am trying to set the local of my users via a field in my user model called locale.
However, the I18n methods do not seem to be working. I'm not sure if I've missed some configuration or something. (I'm still new to rails.) I find that this also happens with many gems that I try to use. Possible that I am initializing things incorrectly?
undefined method default_locale for nil:NilClass
In my Application Controller:
before_filter :set_locale
private
def set_locale # Sets the users language via the locale index.
I18n.default_local = 'en'
I18n.locale = current_user.locale if current_user.locale.present? || I18n.default_locale
end
I am pretty sure that your current_user is nil. Just make sure that the current_user is set before you call locale on it.
I have a problem with a Rails 2.3.8 application. I'm using rails i18n to make the site in different languages. Everything works perfect, everywhere, except one place.
After successful signup, I do:
flash[:notice] = t 'path.to.locale.key'
Just as I do everywhere else.
But that renders the following:
translation missing: 'locale.path.to.locale.key' not found
It seems it's not loading the current locale (or else it will say 'en', or 'es', or whatever instead of 'locale').
Any idea that could be causing this?
Thanks
Maybe you overwrite it somewhere down that yml file. Maybe you did too many nesting. Maybe that key has subkeys.
Delete everything from that locale.yml and place only that message and see if it works.
The problem you are having happens to me every now and then, and it's always something I messed up in yml file.
Try setting a default locale in your ApplicationController, for example with a before_filter:
I18n.locale = params[:locale] || 'en'
Well, this happened to me in mailer classes after I upgraded to Rails 4.1. It was working correctly on Rails 3 and there was no change on yml files. Somehow i18n did not see the default locale.
So I've added this line on mailer class to fix out.
I18n.locale = I18n.default_locale
class ProviderMailer < ActionMailer::Base
include Resque::Mailer
default from: APP_CONFIG.mailer.from
def registration_email(provider)
#provider = provider
I18n.locale = I18n.default_locale
#provider_url = "#{APP_CONFIG.base_url}/hizmetsgl/#{provider['_id']}"
#howto_url = "#{APP_CONFIG.base_url}/hizmetverenler"
mail(to: provider["business_email"], subject: t('provider_mailer.registration_email.subject'))
end
end