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 'onebox'
gem 'http_accept_language', '~>2.0.5'
gem 'ember-rails' gem 'ember-rails'
gem 'ember-source', '1.12.2' gem 'ember-source', '1.12.2'
gem 'barber' gem 'barber'

View File

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

View File

@ -164,7 +164,15 @@ class ApplicationController < ActionController::Base
end end
def set_locale 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! I18n.ensure_all_loaded!
end end
@ -309,6 +317,18 @@ class ApplicationController < ActionController::Base
private 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 def preload_anonymous_data
store_preloaded("site", Site.json_for(guardian)) store_preloaded("site", Site.json_for(guardian))
store_preloaded("siteSettings", SiteSetting.client_settings_json) store_preloaded("siteSettings", SiteSetting.client_settings_json)

View File

@ -715,7 +715,12 @@ class UsersController < ApplicationController
def user_params def user_params
params.permit(:name, :email, :password, :username, :active) 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 end
def fail_with(key) def fail_with(key)

View File

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

View File

@ -13,6 +13,10 @@ describe TopicsController do
request.env['HTTP_REFERER'] = ref request.env['HTTP_REFERER'] = ref
end 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 it "doesn't store an incoming link when there's no referer" do
expect { expect {
get :show, id: topic.id get :show, id: topic.id
@ -114,10 +118,54 @@ describe TopicsController do
end end
end end
describe 'set_locale' do describe "set_locale" do
it 'sets the one the user prefers' do context "allow_user_locale disabled" do
SiteSetting.stubs(:allow_user_locale).returns(true) 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
context "with an anonymous user" do
it "uses the default locale" do
get :show, {topic_id: topic.id}
expect(I18n.locale).to eq(:en)
end
end
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
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
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(:fr)
end
end
context "with a logged in user" do
it "uses the user's preferred locale" do
user = Fabricate(:user, locale: :fr) user = Fabricate(:user, locale: :fr)
log_in_user(user) log_in_user(user)
@ -125,16 +173,34 @@ describe TopicsController do
expect(I18n.locale).to eq(:fr) expect(I18n.locale).to eq(:fr)
end end
end
end
it 'is sets the default locale when the setting not enabled' do context "the preferred locale includes a region" do
user = Fabricate(:user, locale: :fr) it "returns the locale and region separated by an underscore" do
log_in_user(user) 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} get :show, {topic_id: topic.id}
expect(I18n.locale).to eq(:en) expect(I18n.locale).to eq(:en)
end end
end end
end
end
describe "read only header" do describe "read only header" do
it "returns no read only header by default" do it "returns no read only header by default" do

View File

@ -479,6 +479,15 @@ describe UsersController do
email: @user.email email: @user.email
end 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 context 'when creating a non active user (unconfirmed email)' do
it 'returns a 500 when local logins are disabled' do it 'returns a 500 when local logins are disabled' do
@ -1181,6 +1190,19 @@ describe UsersController do
end 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 "with user fields" do
context "an editable field" do context "an editable field" do
let!(:user_field) { Fabricate(:user_field) } let!(:user_field) { Fabricate(:user_field) }

View File

@ -84,5 +84,16 @@ describe ApplicationHelper do
end end
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 end