Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change the locale through URL?

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.

like image 374
Tintin81 Avatar asked Oct 12 '14 14:10

Tintin81


People also ask

How to change system locale in Windows 10?

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.

How to change the URL and redirect users to a different page?

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.

What is the difference between location href and location replace methods?

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.


3 Answers

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).

like image 191
Surya Avatar answered Oct 06 '22 03:10

Surya


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
like image 30
BookOfGreg Avatar answered Oct 06 '22 02:10

BookOfGreg


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)
like image 23
prcu Avatar answered Oct 06 '22 01:10

prcu