New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use client side translation for public login page #20520
Conversation
8c6d419
to
2afe066
Compare
Having to specify an id for each translatable element to grab it via JS, then list all translatable strings in one place in the JS and keep that list in sync with the correct element id will become tedious fast. It is also error prone. I propose an alternative approach. I didn't find exact documentation for this in i18next itself, but I gathered enough information from examples in stackoverflow and some hints from the i18next-parser. Take for example the login form: <form id="loginform">
<div class="row">
<label for="username" id="usernameLabel">Username</label><br />
<input type="text" id="username" name="username" autocomplete="username" required />
</div>
<div class="row">
<label for="password" id="passwordLabel">Password</label><br />
<input type="password" id="password" name="password" autocomplete="current-password" required />
</div>
<div class="row">
<input type="submit" id="loginButton" value="Login" />
</div>
</form> Let's drop the <form id="loginform">
<div class="row">
<label for="username" data-i18n="Username" class="translatable">Username</label><br />
<input type="text" id="username" name="username" autocomplete="username" required />
</div>
<div class="row">
<label for="password" data-i18n="Password" class="translatable">Password</label><br />
<input type="password" id="password" name="password" autocomplete="current-password" required />
</div>
<div class="row">
<input type="submit" data-i18n="Login" class="translatable" value="Login" />
</div>
</form> Now on the JS side, after the translations are fetched you assign the strings with something like this: const elements = document.getElementsByClassName("translatable");
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
const k = element.getAttribute("data-i18n");
element.innerHTML = i18next.t(k);
} String extraction into the .json filesIf you read the docs of i18next-parser further down where they talk about the options each lexer takes, you'll see that the HTMLLexer supports the What do you think? |
@Chocobo1 |
Only to the login page. It is written in the PR title. For now, I have not considered applying to the whole WebUI and I'm not sure how that will turn out. |
Is it acceptable to use different translation methods at the same time? |
It is ok but hopefully it can transition to only one method eventually. |
Won't this complicate the job of translators?
Wouldn't it make sense to provide instructions on how to switch the source code to another translation method so that it would be easier for someone else to contribute to such a gradual transition? |
PR updated. Adopted suggestion from #20520 (comment)
There will be 2 sources of translation strings of course. If you are talking about this PR adding another source then I'm not concerned of it. It has only 5 strings and the login page probably won't see many changes in the future.
Would a few basic instructions help? I don't know, it still sounds like a monumental task. There are probably some edge cases and requires specific handling to make it work. |
@@ -6,13 +6,15 @@ | |||
"url": "https://github.com/qbittorrent/qBittorrent.git" | |||
}, | |||
"scripts": { | |||
"extract_translation": "i18next -c public/i18next-parser.config.mjs public/index.html public/scripts/login.js", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, do we need to add each file here separately later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might support wildcards though.
Also it would be better to append another command to this script: ... && i18next -c private/i18next-parser.config.mjs private/*.html ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it supports globbing patterns as evidenced in their readme examples: https://github.com/i18next/i18next-parser
Or maybe add all the necessary scripts and settings to allow translate files from private folder? |
You are really interested? I can try lay down the foundations for private folder and leave the string migrations to others. (In another PR of course) |
I would just like to "open the doors wider" for other contributors to speed up this process as much as possible. |
I would prefer there be an option to enable this behavior. (and off by default) |
I am not sure currently how we choose the language to display. |
This PR currently detects the preferred language via
IMO it would be OK to load the translation resource on demand in this case. I.e user select a language then the client tries to load it instead of loading all translation resources at once at start. |
@Chocobo1 I pushed two commits into your branch, because it was faster for me to implement it than try to explain it here/request it. The first commit implements a script that will migrate translated strings from the .ts files to the .json files. The second commit has pulled the translated strings as they existed before the merging of f265eb0. If you like, you can squash the second commit into your own. However, I would like my first commit to be as-is unless you want to work on the code/name/whatever more. |
@glassez I was wrong. This code doesn't request every single language file. It requests the user's locales (and it's variations) plus the english locale. eg |
My final objection is in regards of the |
@Chocobo1 as an optimization I don't think you need to ever load the |
I honestly don't have better ideas. Do you really insist on it? The public page only has 5 strings so far and is very unlikely to be more in the future. The public login page is intentionally kept dead simple.
Do you mean exporting json of the private folder and use it for public folder? But won't the translation file become unnecessarily big for the public folder? |
I assumed the |
IMO, the general question is should we keep maintaining this separation of assets of private and public? The really private data is provided via API only. |
I have slept on it and I propose the following workflow.
The 2 first will contain the generated .json files for all locales for private/public part. Via a script the |
I consider giving free access for any assets is a bad idea generally, even if they are insignificant.
Looks doable to me. I'm OK If you are OK with the additional steps when syncing translations. |
I implemented the new tool and squashed it into my previous commit. Then I force pushed to your branch (preserving your new commit) but the PR hasn't updated. |
If I somehow broke Github, then you are free to drop my commits and resubmit your own changes (and address the rest of the review comments). Then I'll reintroduce my commits in a new PR. |
It looks OK to me. I can see the 2 python scripts. |
@Chocobo1 let me explain my intended workflow which makes the CI change unneeded. On some interval, I'll pull the translations from Transifex. These will be dropped into
So now we need just one resource on Transifex. Since the old WebUI translations will still be active we can't reuse the same name for the resource. |
And to add to the above: |
@sledgehammer999 |
The translation strings are meant to be synced from Transifex.
I'll probably merge this in the next hours so it can be included in the unstable build. |
The translation strings are meant to be synced from Transifex.