在我的Rails应用程序中,我有这种方法,用户可以通过该方法更改其语言环境:
# locales_controller.rb
class LocalesController < ApplicationController
def change_locale
new_locale = params[:set_locale]
if new_locale
session[:locale] = new_locale
url_hash = Rails.application.routes.recognize_path URI(request.referer).path
url_hash[:locale] = new_locale
redirect_to url_hash
end
end
end
# routes.rb
MyApp::Application.routes.draw do
scope "(:locale)", locale: /#{DEFINED_LANGUAGES.join("|")}/ do
get 'change_locale', :to => 'locales#change_locale'
...
end
# application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_locale
def set_locale
I18n.locale = params[:locale] || session[:locale] || extract_locale_from_accept_language_header || I18n.default_locale
session[:locale] = I18n.locale
end
def extract_locale_from_accept_language_header
http_accept_language.compatible_language_from(DEFINED_LANGUAGES) # => e.g. 'de'
end
...
end
# application_helper.rb
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
end
不幸的是,当用户选择另一个区域设置时,此时URL中存在的所有其他参数都将丢失。有办法规避吗?
答案 0 :(得分:2)
目前,您的区域设置切换器会将所需的区域设置发布到新路线。这使得很难将用户重定向回发布请求的页面,同时更改URL的部分内容。
此外,无法使表单操作指向包含查询参数的URL,并使此表单通过get
方法发送其内容。表单submit
只会删除所有现有查询参数,只添加在表单中定义的键/值对。
要解决这个问题,我们需要做两件事:
为了避免在Rails帮助程序中嵌套内容标记中使用已清理的HTML,我建议在应用程序中添加一个新的部分。请注意,我内联onchange
JavaScript以删除外部依赖项。
# in app/views/shared/_locale_switcher.html.erb
<%= form_tag url_for(params), method: 'get' do %>
<% request.query_parameters.each do |key, value| %>
<%= hidden_field_tag(key, value)
<% end %>
<%= select_tag(:new_locale,
options_for_select(LANGUAGES, I18n.locale.to_s),
onchange: 'this.form.submit()') %>
<% end %>
您可以使用以下行将新的locale_switcher
部分呈现到每个其他视图或布局文件中:
<%= render 'shared/locale_switcher' %>
最后一步:向before_action
添加ApplicationContoller
方法,如果新的和当前的区域设置不匹配,则触发重定向:
before_action :check_for_locale_change
before_action :set_locale
def check_for_locale_change
new_locale = params[:new_locale]
if new_locale.present? && new_locale != params[:locale]
redirect_to url_for(params.merge(locale: new_locale, set_locale: nil))
end
end
def set_locale
I18n.locale = params[:locale] || session[:locale] || extract_locale_from_accept_language_header || I18n.default_locale
session[:locale] = I18n.locale
end