FIX: Include resolved locale in anonymous cache key (#10289)

This only applies when set_locale_from_accept_language_header is enabled
This commit is contained in:
David Taylor 2020-07-22 18:00:07 +01:00 committed by GitHub
parent bcb0e62363
commit c09b5807f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 13 deletions

View File

@ -530,17 +530,7 @@ class ApplicationController < ActionController::Base
private private
def locale_from_header def locale_from_header
begin HttpLanguageParser.parse(request.env["HTTP_ACCEPT_LANGUAGE"])
# Rails I18n uses underscores between the locale and the region; the request
# headers use hyphens.
require 'http_accept_language' unless defined? HttpAcceptLanguage
available_locales = I18n.available_locales.map { |locale| locale.to_s.tr('_', '-') }
parser = HttpAcceptLanguage::Parser.new(request.env["HTTP_ACCEPT_LANGUAGE"])
parser.language_region_compatible_from(available_locales).tr('-', '_')
rescue
# If Accept-Language headers are not set.
I18n.default_locale
end
end end
def preload_anonymous_data def preload_anonymous_data

View File

@ -1425,7 +1425,7 @@ en:
delete_old_hidden_posts: "Auto-delete any hidden posts that stay hidden for more than 30 days." delete_old_hidden_posts: "Auto-delete any hidden posts that stay hidden for more than 30 days."
default_locale: "The default language of this Discourse instance. You can replace the text of system generated categories and topics at <a href='%{base_path}/admin/customize/site_texts' target='_blank'>Customize / Text</a>." default_locale: "The default language of this Discourse instance. You can replace the text of system generated categories and topics at <a href='%{base_path}/admin/customize/site_texts' target='_blank'>Customize / Text</a>."
allow_user_locale: "Allow users to choose their own language interface preference" 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. (EXPERIMENTAL, does not work with anonymous cache)" set_locale_from_accept_language_header: "set interface language for anonymous users from their web browser's language headers"
support_mixed_text_direction: "Support mixed left-to-right and right-to-left text directions." support_mixed_text_direction: "Support mixed left-to-right and right-to-left text directions."
min_post_length: "Minimum allowed post length in characters" min_post_length: "Minimum allowed post length in characters"
min_first_post_length: "Minimum allowed first post (topic body) length in characters" min_first_post_length: "Minimum allowed first post (topic body) length in characters"

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
module HttpLanguageParser
def self.parse(header)
# Rails I18n uses underscores between the locale and the region; the request
# headers use hyphens.
require 'http_accept_language' unless defined? HttpAcceptLanguage
available_locales = I18n.available_locales.map { |locale| locale.to_s.tr('_', '-') }
parser = HttpAcceptLanguage::Parser.new(header)
matched = parser.language_region_compatible_from(available_locales)&.tr('-', '_')
matched || SiteSetting.default_locale
end
end

View File

@ -3,6 +3,7 @@
require_dependency "mobile_detection" require_dependency "mobile_detection"
require_dependency "crawler_detection" require_dependency "crawler_detection"
require_dependency "guardian" require_dependency "guardian"
require_dependency "http_language_parser"
module Middleware module Middleware
class AnonymousCache class AnonymousCache
@ -13,7 +14,8 @@ module Middleware
c: 'key_is_crawler?', c: 'key_is_crawler?',
b: 'key_has_brotli?', b: 'key_has_brotli?',
t: 'key_cache_theme_ids', t: 'key_cache_theme_ids',
ca: 'key_compress_anon' ca: 'key_compress_anon',
l: 'key_locale'
} }
end end
@ -89,6 +91,14 @@ module Middleware
@has_brotli == :true @has_brotli == :true
end end
def key_locale
if SiteSetting.set_locale_from_accept_language_header
HttpLanguageParser.parse(@env["HTTP_ACCEPT_LANGUAGE"])
else
"" # No need to key, it is the same for all anon users
end
end
def is_crawler? def is_crawler?
@is_crawler ||= @is_crawler ||=
begin begin

View File

@ -46,6 +46,32 @@ describe Middleware::AnonymousCache::Helper do
end end
end end
context "with header-based locale locale" do
it "handles different languages" do
# Normally does not check the language header
french1 = new_helper("HTTP_ACCEPT_LANGUAGE" => "fr").cache_key
french2 = new_helper("HTTP_ACCEPT_LANGUAGE" => "FR").cache_key
english = new_helper("HTTP_ACCEPT_LANGUAGE" => SiteSetting.default_locale).cache_key
none = new_helper.cache_key
expect(none).to eq(french1)
expect(none).to eq(french2)
expect(none).to eq(english)
SiteSetting.allow_user_locale = true
SiteSetting.set_locale_from_accept_language_header = true
french1 = new_helper("HTTP_ACCEPT_LANGUAGE" => "fr").cache_key
french2 = new_helper("HTTP_ACCEPT_LANGUAGE" => "FR").cache_key
english = new_helper("HTTP_ACCEPT_LANGUAGE" => SiteSetting.default_locale).cache_key
none = new_helper.cache_key
expect(none).to eq(english)
expect(french1).to eq(french2)
expect(french1).not_to eq(none)
end
end
context 'force_anonymous!' do context 'force_anonymous!' do
before do before do
RateLimiter.enable RateLimiter.enable