mysociety / alaveteli

Provide a Freedom of Information request system for your jurisdiction
https://alaveteli.org
Other
387 stars 195 forks source link

Site not respecting user locale preference from browser #5080

Open lizconlan opened 5 years ago

lizconlan commented 5 years ago

Many dutch speaker users complain that Transparencia.be does not detect their browser Dutch language

2 problems here:

Firstly, our code is not working as intended as when we call set_gettext_locale when the user visits the homepage for the first time - so the locale is not being passed in as part of the URL - we are forcibly providing the default locale rather than allowing a null value. This takes precedence so that the language doesn't constantly flip back after you've chosen one so the browser value is never considered[1].

Secondly, when we ask FastGetText to pick the best match using the browser-supplied string, if it gets something like "nl,en-GB;q=0.7,en;q=0.3" (mine, from Firefox, after adding Dutch for testing purposes), it's not going to match "nl" to "nl_BE" (it handles a string with nl-BE just fine but we should handle both).

(When fixed, check the site is configured with use_default_browser_language)


[1] Applies when the site is configured so that the default locale is not included in the URL otherwise the browser settings will never be considered as there is, legitimately, always a locale param - that's a different, and currently theoretical, problem which is not addressed here.

garethrees commented 3 years ago

Now that we have improved fallback handling (https://github.com/mysociety/alaveteli/commit/bdf842350d507ee1f2cc722edf17656faeb19b82) we should be able to use these to find the closest locale from the browser string – something like:

diff --git a/lib/alaveteli_localization.rb b/lib/alaveteli_localization.rb
index 55883e8d5..61b044936 100644
--- a/lib/alaveteli_localization.rb
+++ b/lib/alaveteli_localization.rb
@@ -34,6 +34,7 @@ class AlaveteliLocalization
     # rubocop:disable Naming/AccessorMethodName
     def set_session_locale(*args)
       requested = args.compact.delete_if(&:empty?).first
+      requested = Locale.parse(requested).i18n_fallbacks
       new_locale = FastGettext.best_locale_in(requested) || default_locale
       locale = Locale.parse(new_locale)

Might need to consider the case where the browser locale is set to a non-regionalised locale (e.g. en) but the site only has a regional version of that locale available:

# User has 'en-GB' set – likely to find a good fallback
AlaveteliLocalization::Locale.parse('en-GB').i18n_fallbacks
# => [:"en-GB", :en_GB, :en]

# User has 'en' set – wouldn't necessarily match an available regionalised locale
AlaveteliLocalization::Locale.parse('en').i18n_fallbacks
# => [:en]