Currently I use this code as suggested by the Rails guide:
# application_controller.rb
around_action :switch_locale
def switch_locale(&action)
locale = params[:locale] || I18n.default_locale
I18n.with_locale(locale, &action)
end
This works perfectly for the application... but not for all Devise messages! Some are translated, others are not. Devise keeps using the default language for some messages (even if the translated YML files are present).
Possibly related:
https://github.com/heartcombo/devise/issues/5246
In order to reproduce the issue:
default_locale set in the environment files, not the current one set in application controller)If you log in successfully, instead, the flash message is in the correct language (the language set in application controller).
I have also tried to copy the official YML file from Devise and translate it, but I have the same issue: some translations appear, other do not.
Devise should always use the current locale.
cool, seems like im not the only one haha
I think it's a pretty common issue unfortunately. See https://github.com/heartcombo/devise/issues/3052#issuecomment-49881222
I think the best solution is to set the locale in a middleware rather than in the application controller, and also ensure that this middleware is loaded before warden, so it sets the locale before the warden middleware sets any flash messages. https://github.com/heartcombo/devise/issues/4823#issuecomment-388112897
The Rails guides were updated to use around_action but it wasn't for threadsafety. There's discussion here about it: https://github.com/rails/rails/pull/34356
It's safe to use:
before_action :set_locale
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
I'm having this same problem. First I tried before_action :set_locale which seemed to work for a while, but then stopped working, I'm unsure why. Changing it to prepend_before_action :set_locale works for the time being, but I'm uncertain whether this is the final or correct way to solve the problem. The middleware is in my case not an issue, as the Locale middleware is not used.
Update: it seems as if prepend_before_action is the correct solution. The actions without prepend are in this order:
verify_signed_out_user
allow_params_authentication!
require_no_authentication
assert_is_devise_resource!
75720
set_xhr_redirected_to
set_request_method_cookie
verify_authenticity_token
staging_basic_auth
set_gon_controller
ensure_signup_complete
check_terms_agreement
clear_search_mode
configure_permitted_parameters
set_locale
, several of which are devise related, and will by default be executed before set_locale.
@dssjoblom that's right, you need to make sure set_locale is called before anything Devise related there, as it may set a flash message by that time. So prepend_before_action or around_action should generally be preferable.
That said, the issue originally described here with I18n.with_locale exists, I have a possible reproduction and fix in the works (it happens because I18n is set back to the default locale before leaving the controller, and Devise's failure app runs afterwards so it has no awareness of the I18n locale set by the controller.). For the time being, using I18n.locale = should work.
@carlosantoniodasilva Do you have any suggestions other than using I18n.locale=? We would like to keep using I18n.with_locale to avoid any leak issues and may go the route of customizing the devise failure app but wanted to check to see if there was something in the works here.
@sam-kim I have a WIP/possible fix here: https://github.com/heartcombo/devise/compare/ca-fix-i18n-locale-failure-app, haven't been able to wrap it up yet, but if you'd like to give it a shot let me know how it goes. Other than that, no ideas off the top of my head.
Looks like that worked perfectly! Thank you for that and the quick response 馃槂
Cool, thanks for confirming. I'll try to wrap that up and push to master soon.
@carlosantoniodasilva I tried the above fix.
But I think there are two more things that need to be fixed.
human_attribute_name(key, locale: warden_options[:locale])
throw :warden, scope: scope, message: record.inactive_message, locale: locale: I18n.locale
Thanks @unosk! Definitely agree on the first one, I was actually thinking about wrapping the failure app with I18n.with_locale, although that might be a bit more of a breaking change I guess for people using I18n, but perhaps better overall. (and maybe even more expected.)
I'll have to check on the second one, but at a glance seems reasonable. :+1:
Cross posting https://github.com/heartcombo/devise/commit/70828da732afbd9085c44676eb65502d45ab8d8c#commitcomment-46435559 for my future reference:
Thank you! I'm using Rails 6.0 with Devise 4.7.3 and I introduced I18n as it is recommended in the Rails I18n guide, with around_action :switch_locale in ApplicationController. I also followed the advice from https://github.com/heartcombo/devise/wiki/How-To:--Redirect-with-locale-after-authentication-failure .
Excerpt from routes:
The i18n always works fine when a route is called directly, no matter whether a user is logged-in, not logged in, or visiting the login page. See this set of tests:
i18n.feature.txtThe only scenario that fails is "Locale persists after Devise redirects as Forbidden", so when a non-logged in user tries to access a page that is limited to logged-in users and Devise redirects to the login page.
After some tinkering today, namely inserting
locale = helpers.get_locale_from_path(session[:user_return_to]) I18n.locale = locale if localeinto SessionsController 'new' method, the login page displays in the correct language, too, but the flash message "You need to sign in or sign up before continuing." (line 21 of the test file) still shows in the wrong language. And on the whole this solution seems quite hacky - shouldn't Devise support i18n out of the box??
Most helpful comment
@sam-kim I have a WIP/possible fix here: https://github.com/heartcombo/devise/compare/ca-fix-i18n-locale-failure-app, haven't been able to wrap it up yet, but if you'd like to give it a shot let me know how it goes. Other than that, no ideas off the top of my head.