Merge pull request #4006 from scossar/set-locale-from-header

Feature: (WIP) Set locale from Accept-Language header
This commit is contained in:
Régis Hanol 2016-03-04 09:12:30 +01:00
commit 1135d2094a
8 changed files with 146 additions and 18 deletions

View File

@ -45,6 +45,8 @@ gem 'active_model_serializers', '~> 0.8.3'
gem 'onebox'
gem 'http_accept_language', '~>2.0.5'
gem 'ember-rails'
gem 'ember-source', '1.12.2'
gem 'barber'

View File

@ -127,6 +127,7 @@ GEM
htmlentities (4.3.4)
http-cookie (1.0.2)
domain_name (~> 0.5)
http_accept_language (2.0.5)
i18n (0.7.0)
image_optim (0.20.2)
exifr (~> 1.1, >= 1.1.3)
@ -426,6 +427,7 @@ DEPENDENCIES
highline
hiredis
htmlentities
http_accept_language (~> 2.0.5)
image_optim (= 0.20.2)
librarian (>= 0.0.25)
listen (= 0.7.3)

View File

@ -164,7 +164,15 @@ class ApplicationController < ActionController::Base
end
def set_locale
I18n.locale = current_user.try(:effective_locale) || SiteSetting.default_locale
if !current_user
if SiteSetting.allow_user_locale
I18n.locale = locale_from_header
else
I18n.locale = SiteSetting.default_locale
end
else
I18n.locale = current_user.effective_locale
end
I18n.ensure_all_loaded!
end
@ -309,6 +317,18 @@ class ApplicationController < ActionController::Base
private
def locale_from_header
begin
# Rails I18n uses underscores between the locale and the region; the request
# headers use hyphens.
available_locales = I18n.available_locales.map { |locale| locale.to_s.gsub(/_/, '-') }
http_accept_language.language_region_compatible_from(available_locales).gsub(/-/, '_')
rescue
# If Accept-Language headers are not set.
I18n.default_locale
end
end
def preload_anonymous_data
store_preloaded("site", Site.json_for(guardian))
store_preloaded("siteSettings", SiteSetting.client_settings_json)

View File

@ -715,7 +715,12 @@ class UsersController < ApplicationController
def user_params
params.permit(:name, :email, :password, :username, :active)
.merge(ip_address: request.remote_ip, registration_ip_address: request.remote_ip)
.merge(ip_address: request.remote_ip, registration_ip_address: request.remote_ip,
locale: user_locale)
end
def user_locale
I18n.locale
end
def fail_with(key)

View File

@ -60,7 +60,7 @@ module ApplicationHelper
end
def rtl_class
RTL.new(current_user).css_class
rtl? ? 'rtl' : ''
end
def escape_unicode(javascript)
@ -111,7 +111,7 @@ module ApplicationHelper
end
def rtl?
["ar", "fa_IR", "he"].include?(user_locale)
["ar", "fa_IR", "he"].include? I18n.locale.to_s
end
def user_locale

View File

@ -13,6 +13,10 @@ describe TopicsController do
request.env['HTTP_REFERER'] = ref
end
def set_accept_language(locale)
request.env['HTTP_ACCEPT_LANGUAGE'] = locale
end
it "doesn't store an incoming link when there's no referer" do
expect {
get :show, id: topic.id
@ -33,7 +37,7 @@ describe TopicsController do
end
it "uses the application layout even with an escaped fragment param" do
get :show, {'topic_id' => topic.id, 'slug' => topic.slug, '_escaped_fragment_' => 'true'}
get :show, {'topic_id' => topic.id, 'slug' => topic.slug, '_escaped_fragment_' => 'true'}
expect(response).to render_template(layout: 'application')
assert_select "meta[name=fragment]", false, "it doesn't have the meta tag"
end
@ -51,7 +55,7 @@ describe TopicsController do
end
it "uses the crawler layout when there's an _escaped_fragment_ param" do
get :show, topic_id: topic.id, slug: topic.slug, _escaped_fragment_: 'true'
get :show, topic_id: topic.id, slug: topic.slug, _escaped_fragment_: 'true'
expect(response).to render_template(layout: 'crawler')
assert_select "meta[name=fragment]", false, "it doesn't have the meta tag"
end
@ -114,25 +118,87 @@ describe TopicsController do
end
end
describe 'set_locale' do
it 'sets the one the user prefers' do
SiteSetting.stubs(:allow_user_locale).returns(true)
describe "set_locale" do
context "allow_user_locale disabled" do
context "accept-language header differs from default locale" do
before do
SiteSetting.stubs(:allow_user_locale).returns(false)
SiteSetting.stubs(:default_locale).returns("en")
set_accept_language("fr")
end
user = Fabricate(:user, locale: :fr)
log_in_user(user)
context "with an anonymous user" do
it "uses the default locale" do
get :show, {topic_id: topic.id}
get :show, {topic_id: topic.id}
expect(I18n.locale).to eq(:en)
end
end
expect(I18n.locale).to eq(:fr)
context "with a logged in user" do
it "it uses the default locale" do
user = Fabricate(:user, locale: :fr)
log_in_user(user)
get :show, {topic_id: topic.id}
expect(I18n.locale).to eq(:en)
end
end
end
end
it 'is sets the default locale when the setting not enabled' do
user = Fabricate(:user, locale: :fr)
log_in_user(user)
context "allow_user_locale enabled" do
context "accept-language header differs from default locale" do
before do
SiteSetting.stubs(:allow_user_locale).returns(true)
SiteSetting.stubs(:default_locale).returns("en")
set_accept_language("fr")
end
get :show, {topic_id: topic.id}
context "with an anonymous user" do
it "uses the locale from the headers" do
get :show, {topic_id: topic.id}
expect(I18n.locale).to eq(:en)
expect(I18n.locale).to eq(:fr)
end
end
context "with a logged in user" do
it "uses the user's preferred locale" do
user = Fabricate(:user, locale: :fr)
log_in_user(user)
get :show, {topic_id: topic.id}
expect(I18n.locale).to eq(:fr)
end
end
end
context "the preferred locale includes a region" do
it "returns the locale and region separated by an underscore" do
SiteSetting.stubs(:allow_user_locale).returns(true)
SiteSetting.stubs(:default_locale).returns("en")
set_accept_language("zh-CN")
get :show, {topic_id: topic.id}
expect(I18n.locale).to eq(:zh_CN)
end
end
context 'accept-language header is not set' do
it 'uses the site default locale' do
SiteSetting.stubs(:allow_user_locale).returns(true)
SiteSetting.stubs(:default_locale).returns('en')
set_accept_language('')
get :show, {topic_id: topic.id}
expect(I18n.locale).to eq(:en)
end
end
end
end

View File

@ -479,6 +479,15 @@ describe UsersController do
email: @user.email
end
context 'when creating a user' do
it 'sets the user locale to I18n.locale' do
SiteSetting.stubs(:default_locale).returns('en')
I18n.stubs(:locale).returns(:fr)
post_user
expect(User.find_by(username: @user.username).locale).to eq('fr')
end
end
context 'when creating a non active user (unconfirmed email)' do
it 'returns a 500 when local logins are disabled' do
@ -1181,6 +1190,19 @@ describe UsersController do
end
context 'a locale is chosen that differs from I18n.locale' do
it "updates the user's locale" do
I18n.stubs(:locale).returns('fr')
put :update,
username: user.username,
locale: :fa_IR
expect(User.find_by(username: user.username).locale).to eq('fa_IR')
end
end
context "with user fields" do
context "an editable field" do
let!(:user_field) { Fabricate(:user_field) }

View File

@ -84,5 +84,16 @@ describe ApplicationHelper do
end
end
describe '#rtl_class' do
it "returns 'rtl' when the I18n.locale is rtl" do
I18n.stubs(:locale).returns(:he)
expect(helper.rtl_class).to eq('rtl')
end
it 'returns an empty string when the I18n.locale is not rtl' do
I18n.stubs(:locale).returns(:zh_TW)
expect(helper.rtl_class).to eq('')
end
end
end