In my bi-lingual Rails 4 application I have a LocalesController
like this:
class LocalesController < ApplicationController
def change_locale
if params[:set_locale]
session[:locale] = params[:set_locale]
url_hash = Rails.application.routes.recognize_path URI(request.referer).path
url_hash[:locale] = params[:set_locale]
redirect_to url_hash
end
end
end
A User can change his locale through this form:
def locale_switcher
form_tag url_for(:controller => 'locales', :action => 'change_locale'), :method => 'get', :id => 'locale_switcher' do
select_tag 'set_locale', options_for_select(LANGUAGES, I18n.locale.to_s)
end
This works.
However, right now there's no way for the user to change the language via the URL.
E.g. if a user is on the page www.app.com/en/projects
and then manually changes the URL to www.app.com/fr/projects
, he should see the French version of the page, but instead nothing happens.
This may not matter in many Rails apps but in mine it is quite important.
How can it be fixed?
Thanks for any help.
Step 1: Get into Control Panel. Step 2: Tap Change date, time, or number formats to move on. Step 3: As the Region dialog appears, choose Administrative and click Change system locale. Step 4: Select a new system locale and tap OK. Step 5: Hit Restart now to make the setting effective.
So in this way, you can use the location.href method to change the URL and redirect users to a different webpage. The location.assign method works very similarly to the location.href method and allows you to redirect users to a different web page. Let’s quickly see how it works with the following example.
Although the location.replace method looks very similar to the location.href and location.assign methods of redirecting users to a different URL, there’s an important difference between them. When you use the location.replace method, the current page won’t be saved in the session, and it’s actually removed from the JavaScript History object.
This is how I did it in one of Rails 4 applications:
in config/routes.rb:
Rails.application.routes.draw do
scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
# rest of your routes here
# for example:
resources :projects
end
end
make sure in config/environments/production.rb this line is uncommented:
config.i18n.fallbacks = true
If you wish to have a default_locale
setup other than :en
, then in config/application.rb, uncomment this line:
config.i18n.default_locale = :de # and then :de will be used as default locale
Now, last part of your setup, add this method in ApplicationController
:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :set_locale
private
def set_locale
I18n.locale = params[:locale] || session[:locale] || I18n.default_locale
session[:locale] = I18n.locale
end
def default_url_options(options={})
logger.debug "default_url_options is passed options: #{options.inspect}\n"
{ locale: I18n.locale }
end
end
Now, your application can be accessed as: http://localhost:3000/en/projects
, http://localhost:3000/fr/projects
, or http://localhost:3000/projects
. The last one http://localhost:3000/projects
will use :en
as its default locale(unless you make that change in application.rb).
If you want this behaviour, you are going to have to compare the URL against the session every request. One way you might do it is like this:
before_filter :check_locale
def check_locale
if session[:locale] != params[:locale] #I'm assuming this exists in your routes.rb
params[:set_locale] = params[:locale] #Generally bad to assign things to params but it's short for the example
change_locale
end
end
Maybe it's better to set locale in routes.rb
like this:
# config/routes.rb
scope "(:locale)", locale: /en|nl/ do
resources :books
end
You can read more here http://guides.rubyonrails.org/i18n.html#setting-the-locale-from-the-url-params
UPD. If you also save locale to the session, you also need to update it on each request. You can set it in the filter as suggested in the other answer. But I prefer to use less filters:
def locale_for_request
locale = params[:locale]
if locale && I18n.locale_available?(locale)
session[:locale] = locale
else
session[:locale] || I18n.default_locale
end
end
# then use it in the around filter: I18n.with_locale(locale_for_request)
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