Swedish? meta just showed me the UI in Swedish

AI-generated summary

A user encountered an issue where the Discourse UI displayed in Swedish, despite not having it selected in their browser. kpfleming reported this issue, and simon suggested it might be related to the locale file being served through a CDN.

sam identified the issue as a missing cache buster for locales in the anonymous cache middleware. codinghorror asked where to add the fix, and sam initially offered to fix it later that day. However, sam later found the issue more complicated than expected, as adding a cache buster would make the anonymous cache less efficient.

sam proposed several options to resolve the issue, including moving the enabling and disabling of the feature into GlobalSetting, disabling the feature for anonymous users, or building a system to access SiteSettings without database access. riking suggested reducing the header to the top supported language and caching the key off that. sam noted that this would introduce extra work for all anonymous requests.

codinghorror decided to leave the feature default off and mark it as EXPERIMENTAL in the site setting copy description. simon proposed a solution that would add a global setting and parse the accept-language header before using it in the cache key, which could mitigate the issue.

I opened my browser, clicked ‘log out’ on the drop-down menu (because my browser doesn’t recover Discourse sessions properly when I log in), and got the anonymous home page. The buttons and top header were in Swedish (“Logga in” instead of “Login”). I do not have Swedish selected in my browser and never have.

1 « J'aime »

I’m not sure if this is related, but I’ve noticed on meta that when, as an anonymous use, I change my browser’s language preference, I often need to refresh the page several times before the new locale file is served. Does this have anything to do with the locale file being served through a CDN? On my own forum, without a CDN, the new locale file is served on the first request.

This is a strong indicator that anonymous cache middlewere has a missing cache buster for locales

2 « J'aime »

Can we add this? Where exactly would it go?

I will fix it later today

4 « J'aime »

OK this is fiendish to fix and I am not sure what to do:

Trivially we can add env['HTTP_ACCEPT_LANGUAGE'] to:

Trouble is that our anonymous cache will automatically become much less efficient, every permutation out there of accept language will force a new entry in the cache.

The anon cache middleware is VERY early in the stack, at that point we don’t even have safe access to Site Settings, so we can’t even figure out if this feature is enabled.

So now, the existence of this feature is forcing us to do extra work for every anon request. Some options:

  1. Move enabling and disabling into to GlobalSetting, then people must opt for this extra work on every request.

  2. Disable the feature for anon (simplest but not fun)

  3. Build a system for reaching into SiteSettings when there is no access to database in a multisite scenario (complicated, but doable)

  4. Just shove the accpet header and deal with a terrible anon cache … mine is HTTP_ACCEPT_LANGUAGE: en-US,en;q=0.8,he;q=0.6 very few have this.

Only 2) is easy, so @codinghorror we need to decide what amount of effort we need to invest here.

I estimate its half a day to a day to get 1 or 3 to work perfectly.

5 « J'aime »

Another option would be to reduce the header to the “top supported language” and cache key off that. So you have ~20-30 variations max, and you might need to keep them around even if the feature’s off.

1 « J'aime »

You would reduce it down to the locales discourse supports but it introduces some extra work unconditionally for all anon requests from now on

1 « J'aime »

Given that the cost here is so extreme we are

  • doing nothing at the moment, leaving the feature default off

  • marking the feature as EXPERIMENTAL in the site setting copy description

cc: @simon

3 « J'aime »

It wouldn’t be as bad if a global setting was added and the accept-language header was parsed before it was used in the cache_key. Something like this?

# lib/anonymous_locale.rb

class AnonymousLocale
  def self.locale(accept_language_header)
    if GlobalSetting.locale_from_header
      begin
        require 'http_accept_language' unless defined? HttpAcceptLanguage
        available_locales = I18n.available_locales.map { |locale| locale.to_s.gsub(/_/, '-') }
        parser = HttpAcceptLanguage::Parser.new(accept_language_header)
        parser.language_region_compatible_from(available_locales).gsub(/-/, '_')
      rescue
        I18n.default_locale
      end
    else
      I18n.default_locale
    end
  end
end

And then in anonymous_cache:

def cache_key
  @cache_key ||= "ANON_CACHE_#{@env["HTTP_ACCEPT"]}_#{AnonymousLocale.locale(@env["HTTP_ACCEPT_LANGUAGE"])}_#{@env["HTTP_HOST"]}#{@env["REQUEST_URI"]}|m=#{is_mobile?}|c=#{is_crawler?}"
end
2 « J'aime »