2014-10-12 5 views
3

В моем двуязычном приложении Rails 4 У меня есть LocalesController вроде этого:Как изменить локаль через URL?

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 

Пользователя может изменить свою локаль через эту форму:

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 

Это работает.

Однако, теперь у пользователя нет возможности изменить язык по URL-адресу.

E.g. если пользователь находится на странице www.app.com/en/projects, а затем вручную изменяет URL-адрес на www.app.com/fr/projects, он должен посмотреть французскую версию страницы, но вместо этого ничего не происходит.

Это может не иметь значения во многих приложениях Rails, но в моем случае это очень важно.

Как это можно исправить?

Спасибо за любую помощь.

+0

Вам нужно будет проверить и настроить соответствующие правила маршрутизации для обработки специфических для локали путей. –

ответ

6

Это, как я это сделал в одном из приложений Rails 4:

в конфигурации/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 

убедитесь, что в конфигурация/окружающая среда/production.rb эта линия раскоментирована:

config.i18n.fallbacks = true 

Если вы хотите иметь default_locale установки другой, чем :en, то в конфигурации/application.rb, раскомментируйте эту строку:

config.i18n.default_locale = :de # and then :de will be used as default locale 

Теперь, последняя часть вашей установки, добавьте этот метод в 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 

Теперь приложение можно обращаться как: http://localhost:3000/en/projects, http://localhost:3000/fr/projects или http://localhost:3000/projects.Последний http://localhost:3000/projects будет использовать :en в качестве локали по умолчанию (если вы не внесете это изменение в application.rb).

+0

Это, оказывается, работает очень хорошо. Я думаю, что ключ заключается в том, чтобы всегда проводить сеанс, независимо от того, кто или что. Таким образом, всегда сохраняется правильная локаль. Это то, что я пропустил раньше. – Tintin81

+0

Я пропустил что-то здесь, когда я сделал выше, я получаю следующее: http: // localhost: 3000/sign_in? Locale = en' –

2

Может, лучше установить локаль в routes.rb, как это:

# config/routes.rb 
scope "(:locale)", locale: /en|nl/ do 
    resources :books 
end 

Вы можете прочитать здесь http://guides.rubyonrails.org/i18n.html#setting-the-locale-from-the-url-params

UPD. Если вы также сохраняете языковой стандарт на сеанс, вам также необходимо обновить его по каждому запросу. Вы можете установить его в фильтре, как предложено в другом ответе. Но я предпочитаю использовать меньше фильтров:

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) 
+0

Да, у меня это уже есть. И я прочитал все проводники. – Tintin81

+1

@ Tintin81 Я согласен с prcu, если вы хотите, чтобы URL-адрес определял локаль «true», вы должны использовать локаль URL, заданную в маршрутах. На самом деле нет смысла записывать его обратно в сеанс, если он все еще находится в URL-адресе. – BookOfGreg

+1

@ Tintin81 Если вы используете необязательный язык в ротах, то да, вы можете сохранить локаль в сеансе. Это поможет установить языковой стандарт для пользователя, который вернулся к URL-адресу без языкового стандарта. Я обновил свой ответ для этого случая. – prcu

2

Если вы хотите этого, вы будете иметь, чтобы сравнить URL на сессии каждый запрос. Один из способов вы можете сделать это, как это:

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 
Смежные вопросы