Page MenuHomePhabricator

investigate language switching in the UI for our single page applications
Closed, ResolvedPublic1 Estimated Story Points

Description

As a user of the Mismatch Finder and Query Builder I want to work with the site in my language.

Problem:
We currently only support language switching for our Single Page Applications (specifically Mismatch Finder and Query Builder) via URL parameter. We need to also offer it via the UI. This ticket is for investigating how we can do this.

Acceptance criteria:

  • we know how our SPAs can support language switching in the UI

Notes:

  • Some discussion already happened in the comments of T323683 and T289426 that needs to be reviewed as part of this.
  • Assumptions/routes to validate:
    • 1. We can reuse the existing Language selector component implemented by the Language team in our SPAs (in use by Vector 2022);
    • 2. We can create a minimal/MVP version of a new Vue Language selector tool, and
      • 2.1. contribute it to Codex or
      • 2.2. consider it a temporary solution to be replaced later

Timeboxes:
0.5 days to investigate
0.5 days to summarize the investigation and get feedback from the team

Event Timeline

  1. We can reuse the existing Language selector component implemented by the Language team in our SPAs (in use by Vector 2022)

I think we could reuse the jquery.uls library, like we do in the Wikidata Query UI; as far as I can tell, the compact language selector in Vector 2022 is also based on this library, just with more customization.

karapayneWMDE set the point value for this task to 1.
karapayneWMDE moved this task from Unified DOT Backlog to Sprint-∞ on the Wikidata Dev Team board.

Task breakdown notes:

  • List the pros and cons of each approach.
  • Keep in mind that the target applications still use Vue 2.
  1. We can reuse the existing Language selector component implemented by the Language team in our SPAs (in use by Vector 2022)

I think we could reuse the jquery.uls library, like we do in the Wikidata Query UI; as far as I can tell, the compact language selector in Vector 2022 is also based on this library, just with more customization.

ContentTranslation (mentioned in T289426#7300692) also normally uses this library, but if the mobile frontend is used and section translation is enabled, it uses its custom language selector instead. However, that language selector also relies on an MW UI library that’s vendored in ContentTranslation (app/src/lib/mediawiki.ui/), and it’s also been migrated to Vue 3, whereas Mismatch Finder and Query Builder are still on Vue 2 for the time being.

I think we’ll probably have an easier time using jquery.uls than copying CX’s language selector or building our own; I’ll see if I can make jquery.uls work in Query Builder.

Okay, adding jquery.uls to Query Builder is possible – not very nice (we basically have to add the scripts and styles of jquery{,.uls} globally, in index.html), but possible. But that’s not enough to support switching the language, because vue-banana-i18n v1 (supporting Vue 2) is not reactive on the language; it only becomes reactive in v2 (supporting Vue 3). I have not yet found any way, even with horrible hacks and manual changes in the console, to actually change the language of any part of the app after it’s been rendered. We would somehow need to change the locale inside the i18n plugin, and get that change propagated to all child components (which all seem to have separate instances of the plugin), and also force them all to re-render themselves…

Following some discussion with the rest of the team, it seems like updating the UI language “live” (reactively) wasn’t expected to be supported, just like it’s not supported in MediaWiki (though we’ve supported it in the WDQS UI for a long time). Instead, selecting a new language will reload the page, ideally with some state being preserved across the reload (which should be especially easy to implement for query builder, where we already have the ability to serialize the full state into the URL).

My proof of concept for using jquery.uls looks like this: install the library…

diff --git a/package.json b/package.json
index ed9f5c71b6..8b5c01d4a2 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,8 @@
     "@wmde/wikit-vue-components": "^2.1.0-alpha.14",
     "autoprefixer": "^10.4.13",
     "core-js": "^3.26.1",
+    "jquery": "^3.6.2",
+    "jquery.uls": "^0.1.0",
     "lodash.debounce": "^4.0.8",
     "ress": "^5.0.2",
     "sparqljs": "^3.6.2",
diff --git a/index.html b/index.html
index 94fa8b0355..5ec7e3c31e 100644
--- a/index.html
+++ b/index.html
@@ -6,6 +6,16 @@
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <link rel="icon" href="/favicon.ico">
     <title>Wikidata Query Builder</title>
+    <script src="node_modules/jquery/dist/jquery.js"></script>
+    <script src="node_modules/jquery.uls/src/jquery.uls.data.js"></script>
+    <script src="node_modules/jquery.uls/src/jquery.uls.data.utils.js"></script>
+    <script src="node_modules/jquery.uls/src/jquery.uls.lcd.js"></script>
+    <script src="node_modules/jquery.uls/src/jquery.uls.languagefilter.js"></script>
+    <script src="node_modules/jquery.uls/src/jquery.uls.core.js"></script>
+    <link rel="stylesheet" href="node_modules/jquery.uls/css/jquery.uls.css">
+    <link rel="stylesheet" href="node_modules/jquery.uls/css/jquery.uls.grid.css">
+    <link rel="stylesheet" href="node_modules/jquery.uls/css/jquery.uls.lcd.css">
+    <link rel="stylesheet" href="node_modules/jquery.uls/css/jquery.uls.mobile.css">
 </head>
 <body>
     <noscript>

and use it:

diff --git a/src/App.vue b/src/App.vue
index 9cd280918b..5a224ddf29 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,5 +1,6 @@
 <template>
     <div id="app" :lang="lang" :dir="textDirection">
+        <button id="uls">Select Language</button>
         <QueryBuilder v-if="isi18nLoaded" />
     </div>
 </template>
@@ -31,6 +32,15 @@ export default Vue.extend( {
         this.fetchi18n();
         this.reconstructStateFromURL();
     },
+    mounted(): void {
+        const $uls = $( '#uls' );
+        $uls.uls( {
+            onSelect: ( language: string ) => {
+                // TODO implement
+            },
+            languages: { en: 'English', de: 'German' }, // TODO
+        } );
+    },
     updated() {
         const sampleElement = document.getElementById( 'directionSample' );
         if ( !sampleElement ) {

(The trigger can also be a link instead of a button.)

I think this is ready for peer review: are we happy with using jquery.uls?

Sidenote: As pointed out by a change to the description of T313357: Define core components, the current list of planned Codex components can be found at: https://www.mediawiki.org/wiki/Design_Systems_Team/Codex_Planned_Components
The LanguageSwitcher component is mentioned there, but apparently nobody is pushing it yet, and it doesn't even have a task associated with it.

Okay, adding jquery.uls to Query Builder is possible – not very nice (we basically have to add the scripts and styles of jquery{,.uls} globally, in index.html), but possible. But that’s not enough to support switching the language, because vue-banana-i18n v1 (supporting Vue 2) is not reactive on the language; it only becomes reactive in v2 (supporting Vue 3). I have not yet found any way, even with horrible hacks and manual changes in the console, to actually change the language of any part of the app after it’s been rendered. We would somehow need to change the locale inside the i18n plugin, and get that change propagated to all child components (which all seem to have separate instances of the plugin), and also force them all to re-render themselves…

Mh, this discusses multiple techniques to force a rerender: https://michaelnthiessen.com/force-re-render/ (archive link). The biggest trouble would seem to be the i18n plugin.

But "reloading" that plugin might be tricky:

Vue.use automatically prevents you from using the same plugin more than once, so calling it multiple times on the same plugin will install the plugin only once.

(from https://v2.vuejs.org/v2/guide/plugins.html)

This seems to be the code that is at the core of loading that plugin:

App.vue
			Vue.use( i18n, {
				locale: this.lang,
				messages,
				wikilinks: true,
			} );

So we would not only need to change the locale, but also the messages

Change 871134 had a related patch set uploaded (by Michael Große; author: Michael Große):

[wikidata/query-builder@master] Language switcher as Wikit Dropdown

https://gerrit.wikimedia.org/r/871134

Using jquery.uls would be ok for me, though I'm not thrilled about adding jQuery to our app. At least it is only in a confinded place.

I also added a Proof of Concept for doing this with a Wikit Dropdown in the change linked to this task. It can be tried out: https://63a587b7ceb41a5c1300d563--clicky-sparqly.netlify.app

The two preceeding changes make use of the jquery.uls.

I'm not sure that I'd be quite so happy to use a jQuery UI Widget in WiKit, especially since they will both be superseded by Codex. Also I would very much like to hear from @Sarai-WMDE since
A) She is more involved in Codex and thus might know what the future plans for language switching are
and
B) IMO this seems to be a better way to approach this, since I really don't think that the current technical implementation should dictate the design we go with.

Regarding "the future plans for language switching": the fact that the LanguageSelector component is listed as 'Other known components' in Codex's list of 'Planned components' means that the expectation is for the product team (the Language team in this case) to contribute this component to Codex. I quickly reached out to Santhosh, and he kindly provided the following information:

  • The Language team have indeed a plan to work on a new LanguageSelector on top of Vue at some point (https://phabricator.wikimedia.org/T287860). But there is currently no timeline for this, due mainly to the need for the team to assess newly detected requirements before they jump to code the next version of the component.

Santhosh recommends us to build (reuse?) something similar to this custom version rather than reuse the jQuery based ULS, which he advices against due to the existence of "tech debt, old jquery, dom hacks, bad performance when used with many languages and so on".

From a design standpoint, as long as the design of that custom component is based off of the specifications provided by the designer in the Language team, I think it's safe to go with said option. Santhosh has yet to validate this latter point and provide a link to the mentioned SPA, so I can evaluate this alternative first hand.

I uploaded a new version of my patch that now positions the language switcher a bit more nicely. You can see that at https://63b452e5da28e903d3e772ab--clicky-sparqly.netlify.app/

image.png (896×890 px, 100 KB)

Some things that I noticed that would still need doing programming-wise:

  • smarter positioning, especially on mobile
  • when we have 100+ languages there, then we probably do not want a Dropdown, but a Lookup
  • we need to get a list of language/autonyms from somewhere
  • flipping the RTL direction is broken (that is already the case, that regression was introduced in Add header logo image to Query Builder (I4449173b))
  • reretrieving Labels for already downloaded Items and Properties and using the new language for new Items/Properties
  • update the language in the URL

I uploaded a new version of my patch that now positions the language switcher a bit more nicely.
Some things that I noticed that would still need doing programming-wise:

  • when we have 100+ languages there, then we probably do not want a Dropdown, but a Lookup

I don't think neither Dropdown nor Lookup are unfortunately convenient components to enable language switching. The first – as mentioned – doesn't scale, the second is an input rather than a select (doesn't allow the visualization of available options). The only core-type component that would be fitting in this use case would be Combobox, which WiKit lacks.

I uploaded a new version of my patch that now positions the language switcher a bit more nicely.
Some things that I noticed that would still need doing programming-wise:

  • when we have 100+ languages there, then we probably do not want a Dropdown, but a Lookup

I don't think neither Dropdown nor Lookup are unfortunately convenient components to enable language switching. The first – as mentioned – doesn't scale, the second is an input rather than a select (doesn't allow the visualization of available options). The only core-type component that would be fitting in this use case would be Combobox, which WiKit lacks.

Mh, that's a good point! Though the component linked in the description of T266231 does look like something that we could adapt. Thank you for digging that up!

Change 875287 had a related patch set uploaded (by Michael Große; author: Michael Große):

[wikidata/query-builder@master] PoC: Language switcher based on T266231

https://gerrit.wikimedia.org/r/875287

I think this has been in peer review for long enough. I'm moving this to Product Verification so that it can be used to inform future decisions.

The current example of a Language Switcher built in Vue: https://875287--clicky-sparqly.netlify.app/

  • Advantages:
    • We control it completely and can adjust it to our needs
    • it fits natively into our infrastructure
  • Disadvantages:
    • we have to build a complex component (though maybe can partly reuse some other team's work?)
    • it is somehow still very slow with a lot of layout reflow, similar to the wdqs gui language switcher

There is also a jQuery based approach: POC switch language with a jQuery based language switcher (Iea54b653)

  • Advantages:
    • We don't have to build the component itself, it already works
  • Disadvantages:
    • We would introduce jQuery into our system even though we would rather get rid of that in more places
    • it looks out-of-place design-wise and it will be hard for us to change that
    • it might be tricky to make jQuery + jQuery.ULS work together with our Vite build chain (so far I didn't manage to get the preview build working)

Hi,

In the Vue option, is the Switch Language text on the button non-translatable, or has it not been translated and is falling back to English?

And would it be possible to get a screenshot of the jQuery version so we can compare?

Thanks so much :)

Hey, the "Switch Language" copy is just something I quickly hard-coded for these proofs of concept. In the final version, it would be translatable like all the other UI copy.

Here is a screenshot of what the jQuery language switcher looks like:

image.png (484×501 px, 17 KB)

Arian_Bozorg claimed this task.

Thanks so much Michael :)

The Vue option seems like the way to go.

Just a question - there seems to be a lag of about 8 seconds when opening Switch Language in the Vue option - is this only occurring in the test or will it be this slow live?

Change 871134 abandoned by Michael Große:

[wikidata/query-builder@master] PoC: Language switcher as Wikit Dropdown

Reason:

This is now done properly in T328764

https://gerrit.wikimedia.org/r/871134

Change 875287 abandoned by Michael Große:

[wikidata/query-builder@master] PoC: Language switcher based on T266231

Reason:

This is now being done properly in T328764

https://gerrit.wikimedia.org/r/875287