I18n.locale gets reset to: en between controller and view
I'm trying to internationalize a Rails / Spree app using a native spree_i18n
gem, but I can't seem to get it to work.
I've made a minimal app that recreates the problem here.
To shorten the long story, I have the following code in my ApplicationController:
before_action :set_locale
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
puts I18n.locale
end
And the code in my opinion that should be translated ( <%= t("whatever") %>
). But no matter what I do, the text is always output in English.
With some extra code to debug, I can see that it gets called once set_locale
, but while execution is still in the controller, the locale is correct (for example, if I find the url /?locale=es
, then the statement puts
in the above controller code outputs es
).
But by the time execution reached the view, the locale had somehow been reset to en
. (For example, adding <% raise I18n.locale.to_s %>
in the view raises the "en" message as an error message.)
I opened an issue on Spree Github because as far as I can tell I followed their instructions exactly and still didn't work, but I might still be missing something. Why is the locale not setting correctly?
(Note: I must add that Spree.t
doesn't work either, not only t
.)
EDIT: If you look at the comment on my Github issue, you can see that I got it working. However, I'm 99% sure that my solution is a hack and there is a better method I should use. Bounty goes to someone who can tell me what I'm doing wrong.
source to share
Spree I18n allows you to set the default language: on config/application.rb
with
config.i18n.default_locale = :es
And the ability to install languages to change. Perhaps onconfig/initializers/spree_i18n.rb
SpreeI18n::Config.available_locales = [:en, :es, :de]
SpreeI18n::Config.supported_locales = [:en, :es, :de]
After that, you can delete set_locale
on the ApplicationController because it has no effect.
With this in place, it works like a charm.
Edited:
I am changing the error message because I want to be sure it works:
<%= product_description(@product) rescue Spree.t(:product_has_no_description) +
' ' + Spree.t(:action) %>
And I add a new product with no description. Running the server on localhost
In English I see: "This product has no description Action"
In Spanish I see: "Este producto no tiene descripción Acción"
In deutsch I see: "Produkt hat keine Beschreibung Aktion"
Exactly expected.
You can see the source with the changes on github
source to share
It is not clear to me how it Spree
handles localization, but in yours routes.rb
you only mount the engine.
Basically, you should start localizing your application in routes.rb
by adding:
scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
# routing and engines go here
end
Now you need to support params[:locale]
across all requests, so add to your app controller:
def default_url_options(options={})
logger.debug "default_url_options is passed options: #{options.inspect}\n"
{ locale: I18n.locale }
end
Finally, define and set the locale for the current request, depending on your input:
before_filter :set_locale
def set_locale
if defined?(params) && params[:locale]
I18n.locale = params[:locale]
elsif current_user && current_user.language_id.present?
I18n.locale = current_user.language.code
elsif defined?(request)
I18n.locale = extract_locale_from_accept_language_header
end
I18n.locale ||= I18n.default_locale
I18n.locale = :en unless valid_languages.include?(I18n.locale.to_sym)
end
source to share
In app/controllers/application_controller.rb
maybe using/setting
what doesn't work:
before_action :set_locale
def set_locale
I18n.locale =
Spree::Frontend::Config[:locale] =
Spree::Backend::Config[:locale] = :LOCALE
end
In core/lib/spree/core/controller_helpers/common.rb
there is also before_filter
called set_user_language
. This filter is called and re-sets the locale to value session[:locale]
, or if not defined, it uses the default locale.
To fix the problem, set session[:locale]
=: LOCALE in your before_filter.
source to share