Custom Header Link for Changing Language behaves oddly with logged out users

(Michael Pinkard) #1

I’m working on a forum for a non-profit here in SF. It’s current state can be found here: https://forum.sfhepbfree.org/. The folks I’m working with want the forum in Chinese and English, so I’ve been working on a plugin for their use-case. I’ve followed a lot of the patterns documented on this site for developing a multi-lingual forum, but one thing that was requested were clearly visible buttons in the header to change the language, whether or not a user is logged in or logged out. In order to make this work, I used the Discourse Brand Header theme component to create empty links (href="#"). I then bound an onclick event to the links via javascript:

const onClickFunction = (lang) => (event) => {
  event.stopPropagation();
  document.cookie = `custom_translation_locale=${lang}`;
  location.reload(true);
  return false;
}

const languages = { 'English': 'en', 'Chinese': 'zh_TW' };

function initializePlugin(api) {

...

api.onPageChange(() => {
    const widgetLinks = document.querySelectorAll(`.widget-link`);
    widgetLinks.forEach((node) => {
      Object.keys(languages).forEach(language => {
        const child = node.querySelector(`svg.d-icon-${language}`);
        if (child) {
          node.onclick = onClickFunction(languages[language]);
        }
      });
    });
  });
}

This function sets a cookie, which I can then read in Ruby in order to set the locale when the page is reloaded when the button is clicked:

after_initialize do

  require_dependency "application_controller"
  ApplicationController.class_eval do
    def set_locale
      locale_cookie = cookies[:custom_translation_locale]
      if locale_cookie and I18n.locale_available?(locale)
        I18n.locale = locale_cookie
      else 
        I18n.locale = :en
      end
      I18n.ensure_all_loaded!
    end
  end

I followed the pattern that I saw in the initial localization plugin, before it was merged into the Discourse codebase.

This all works great for users that are logged in. The strange thing is that when users are logged out, clicking one of the two buttons (either English or Chinese) and reloading the page does not immediately change the UI language, though it updates the cookie and reloads the page. I have also wired up the site so that I am setting the <html/>'s lang tag (i.e.: <html lang="en"/>) based on the cookie that I set via the JS onclick event. My custom translated content updates appropriately.

Now, if I wait a minute or so and then reload the page again, the UI language changes based on the cookie. This leads me to believe that there is some caching going on in Discourse or Rails. I should add that, on my local Discourse environment, I do not have this problem.

Is there some caching going on under the hood that could be causing this delay? Are there other ideas why this might be happening? Would there be a better way to implement this?

(Michael Pinkard) #2

Seems like something similar to this CDN issue is probably the issue. Can I, as a plugin developer, modify caching at all for my purposes?

(Simon Cossar) #3

If you are using a CDN, then that’s probably the issue.

I have not looked at this code since 2016, but it might be useful as a starting point for what you’re doing: localized-anonymous-cache/plugin.rb at master · scossar/localized-anonymous-cache · GitHub

1 Like
(Michael Pinkard) #4

I am actually not on a CDN. I am using one server hosted by Ramnode. Would the solution be any different?

(Penar Musaraj) #5

You might want to try setting a _bypasse_cache cookie (untested). See discourse/anonymous_cache.rb at master · discourse/discourse · GitHub for more details.

4 Likes
(Michael Pinkard) #6

Omg you’re my hero :+1:

Works like a charm

2 Likes