I am trying to develop a dual language app.
However, I found that the locale change is not persistent by the default i18n gem.
I have this index page and provided a link to change the default language.
<% if I18n.locale == I18n.default_locale %>
<%= link_to "English", :locale=>'en'%>
<% else %>
<%= link_to "Français", :locale=>'fr'%>
<%end%>
The problem is that when I login to another page, the locale falls back to the default language.
So, I just wonder how to keep the user language choice and using that locale persistently until the user logs out.
Thanks in advance.
I recommend you to read this Rails guides about I18n to understand how I18n works in Rails. It's obvious that change of I18n.locale
is temporary, and will be reset per session.
According to your requirement, you can store the selected locale in session
. Here is the sample code:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_locale
def set_locale
I18n.locale = params[:locale] || session[:locale] || I18n.default_locale
session[:locale] = I18n.locale
end
end
Then you can clear the session[:locale]
when user signed out.
# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def sign_out
# ...
session.delete :locale
end
end
If you look at docs
it says
You may be tempted to store the chosen locale in a session or a cookie, however do not do this. The locale should be transparent and a part of the URL. This way you won't break people's basic assumptions about the web itself: if you send a URL to a friend, they should see the same page and content as you.
If you set your locals in domain name or url then it has several advantages
1. The locale is an obvious part of the URL.
2. People intuitively grasp in which language the content will be displayed.
3. It is very trivial to implement in Rails.
4. Search engines seem to like that content in different languages lives at different, inter-linked domains.
Fix
a. You can pass locals in urls and then set it a filter:
In this case your url will look like www.example.com/books?locale=ja or www.example.com/ja/books
then in application controller you can set your local in a filter
before_action :set_locale
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
To include an explicit option in every URL (e.g. link_to( books_url(locale: I18n.locale))) would be tedious and probably impossible so you can override rails default_url_options by something like this in application controller
# app/controllers/application_controller.rb
def default_url_options(options={})
logger.debug "default_url_options is passed options: #{options.inspect}\n"
{ locale: I18n.locale }
end
This will allow every helper method dependent on url_for (e.g. helpers for named routes like root_path or root_url, resource routes like books_path or books_url, etc.) will now automatically include the locale in the query string, like this: http://www.example.com/?locale=ja.
but if you prefer to use your urls to look like www.example.com/en/books
for that you'll need to override default_url_options
method as well as you'll have to scope your routes like this:
# config/routes.rb
scope "(:locale)", locale: /en|nl/ do
resources :books
end
b. Setting the Locale from the Client Supplied Information:
People may set Accept-Language in their browser or other clients (such as curl) and you can use utilize it like this in application controller:
def set_locale
logger.debug "* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}"
I18n.locale = extract_locale_from_accept_language_header
logger.debug "* Locale set to '#{I18n.locale}'"
end
private
def extract_locale_from_accept_language_header
request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first
end
Good practice is to set locale and add that locale to default_url_options
a in ApplicationController
:
before_filter :set_locale
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
def default_url_options(options={})
{ locale: I18n.locale }
end
Then add scope to route.rb:
scope "/:locale", locale: /en|fr/ do
your routes goes here
end
And in your layouts/application.html.erb:
<%= link_to "English", { locale: :en }%>
<%= link_to "French", { locale: :fr } %>
Have a nice day.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With