diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 429f04f633a..1a85257d713 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1737,6 +1737,7 @@ en: allow_user_locale: "Allow users to choose their own language interface preference" set_locale_from_accept_language_header: "set interface language for anonymous users from their web browser's language headers" set_locale_from_cookie: "Allows setting an anonymous user's locale via the 'locale' browser cookie" + set_locale_from_param: "Allows setting an anonymous user's locale via the 'lang' URL param, e.g. ?lang=es" support_mixed_text_direction: "Support mixed left-to-right and right-to-left text directions." min_post_length: "Minimum allowed post length in characters (excluding personal messages)" min_first_post_length: "Minimum allowed first post (topic body) length (excluding personal messages)" diff --git a/config/site_settings.yml b/config/site_settings.yml index 95a25e390af..60790e87f67 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -154,6 +154,10 @@ basic: default: false client: true validator: "AllowUserLocaleEnabledValidator" + set_locale_from_param: + default: false + client: true + validator: "AllowUserLocaleEnabledValidator" support_mixed_text_direction: client: true default: false diff --git a/lib/discourse.rb b/lib/discourse.rb index 86066c50c10..d15869e11bd 100644 --- a/lib/discourse.rb +++ b/lib/discourse.rb @@ -1215,13 +1215,11 @@ module Discourse end def self.anonymous_locale(request) - locale = - HttpLanguageParser.parse(request.cookies["locale"]) if SiteSetting.set_locale_from_cookie + locale = request.params["lang"] if SiteSetting.set_locale_from_param + locale ||= request.cookies["locale"] if SiteSetting.set_locale_from_cookie locale ||= - HttpLanguageParser.parse( - request.env["HTTP_ACCEPT_LANGUAGE"], - ) if SiteSetting.set_locale_from_accept_language_header - locale + request.env["HTTP_ACCEPT_LANGUAGE"] if SiteSetting.set_locale_from_accept_language_header + HttpLanguageParser.parse(locale) end # For test environment only diff --git a/spec/requests/application_controller_spec.rb b/spec/requests/application_controller_spec.rb index 2cec38288c8..242c7b373f8 100644 --- a/spec/requests/application_controller_spec.rb +++ b/spec/requests/application_controller_spec.rb @@ -1126,6 +1126,44 @@ RSpec.describe ApplicationController do end end end + + context "with set_locale_from_param enabled" do + context "when param locale differs from default locale" do + before do + SiteSetting.allow_user_locale = true + SiteSetting.set_locale_from_param = true + SiteSetting.default_locale = "en" + end + + context "with an anonymous user" do + it "uses the locale from the param" do + get "/latest?lang=es" + expect(response.status).to eq(200) + expect(locale_scripts(response.body)).to contain_exactly("/assets/locales/es.js") + expect(I18n.locale.to_s).to eq(SiteSettings::DefaultsProvider::DEFAULT_LOCALE) # doesn't leak after requests + end + end + + context "when the preferred locale includes a region" do + it "returns the locale and region separated by an underscore" do + get "/latest?lang=zh-CN" + expect(response.status).to eq(200) + expect(locale_scripts(response.body)).to contain_exactly("/assets/locales/zh_CN.js") + end + end + end + + context "when locale param is not set" do + it "uses the site default locale" do + SiteSetting.allow_user_locale = true + SiteSetting.default_locale = "en" + + get "/latest" + expect(response.status).to eq(200) + expect(locale_scripts(response.body)).to contain_exactly("/assets/locales/en.js") + end + end + end end describe "vary header" do