-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Add eslint rule for localization issues #10397
Conversation
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.
The changes overall look good to me, I'll let @colin-grant-work review as well and take a deeper look into the code:
- warns when
localizeByDefault
is used incorrectly (no value exists) - warns when there is a typo, for instance a string does not exist but is close
- warns when
localize
is used whenlocalizeByDefault
can be used
While potentially difficult, will there be plans to have user facing strings checked if they can also be localized, potentially in the future?
49148a0
to
89b8dd1
Compare
@vince-fugnitto No plans so far, due to the difficulty. Perhaps there's some good idea on how to accomplish that, but I have no idea how one would do that without flagging a ton of false positives. I would be glad to contribute that, if we come up with a good solution for that. |
@msujew I don't really have a good solution other than creating "hint" or "info" markers in the frontend for all strings as reminders for devs if they want to/should localize. The issue is even as a hint devs might find it is too verbose or distracting. |
One question that this raises for me is how to handle new strings that don't appear in VSCode. There are a few places where we differ in irreconcilable ways, and I've seen some examples of |
@colin-grant-work I think I went over most of this during this weeks dev-meeting. New strings will be extracted using the
Genuinely new strings should just use the |
@@ -14,6 +14,8 @@ | |||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | |||
********************************************************************************/ | |||
|
|||
/* eslint-disable @theia/localization-check */ |
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.
Perhaps add a second commit fixing these? it looks like it's mainly suggestions to use byDefault
in place of the keyed version. For that violation, it might make sense to add a fixer to the plugin.
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.
Well, this file is a weird case anyway. This file uses it's own "implementation" (if one can say so), since it's in the node
directory and has no actual localizations available:
namespace nls { | |
export function localize(key: string, _default: string): string { | |
return _default; | |
} | |
} |
This code has been there for quite a long time, or at least way before I started working on i18n in Theia. Actually, looking further into it, nothing that's exported in this file is referenced somewhere else. It seems to be dead code from before the vscode-extension time of Theia. I would remove this in a separate PR.
@@ -109,6 +109,7 @@ export namespace GitFileStatus { | |||
case GitFileStatus.New: return !!staged ? nls.localize('theia/git/added', 'Added') : nls.localize('theia/git/unstaged', 'Unstaged'); | |||
case GitFileStatus.Renamed: return nls.localize('theia/git/renamed', 'Renamed'); | |||
case GitFileStatus.Copied: return nls.localize('theia/git/copied', 'Copied'); | |||
// eslint-disable-next-line @theia/localization-check |
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.
Is this the solution for things that are VSCode but aren't in our JSON (yet)?
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.
Well, in this particular case the Modified
value seems to exist somewhere in the nls.metadata.json
(our version). However, I worry about semantics here, since the Modified
that exists inside of vscode is used for modified preferences. I assume that this particular context does not translate correctly into other language when used for git related modifications.
Also you perhaps have noticed the key to vscode.git
, which is the builtin extension, that is also translated in the language pack. As this isn't localized text from the actual vscode codebase, it doesn't appear inside of the nls.metadata.json
. Now that we use localizeByDefault
basically everywhere, I would be fine with using theia/*
keys for these instead of relying on the extension translations. There are only around ~20 instances of these cases in Theia. WDYT?
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.
I guess my target would be a one-tiered world: everything uses localizeByDefault
. If we find that the thing translated doesn't exist in the JSON, there are two possible causes: it's a typo / rephrase, or it hasn't been translated by language packs. In the former case, we should correct it, because then it will be translated correctly. In the latter case, rewriting localizeByDefault
to localize('some/theia/key')
doesn't actually get us any closer to getting the thing translated, so I don't see the point. Instead, whenever we are able to create new translations ourselves, we can traverse the code base, find any uses of localizeByDefault
that aren't currently working, translate them, and add it to the JSON (creating an automatic key, if that's necessary to make things work, something like theia/<package>/<file>/<first word or two as necessary>
). If we want a system that requires investigating the actual origin of a particular string to determine its key and checking the JSON to see if that source is covered, then we'll need a lot more documentation about when and how to do that.
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.
Interesting approach. I like the simplicity (for the user, hidden behind a bit of technical complexity). I'll create a draft for this, and add it as an additional commit to this PR.
7cdf340
to
5504e0c
Compare
@msujew, I don't remember whether my latest comment was before or after you requested my review - ping me if / when you'd like me take another look. |
48d0d48
to
0299576
Compare
@colin-grant-work It took me a while to get back to this, since I was busy with other stuff and waiting for #10187 to get merged. So, I think having a one-tiered approach to this (only using
Therefore, I believe the two-tiered approach makes it clear which method to use, especially when the eslint rule shows errors on misused Do you mind looking into my rebased changes? :) |
@msujew, now that there are real translations of the non-VSCode strings in Theia (or at least the potential to create them, and an associated procedure), I think it makes sense to distinguish between the two systems. I'll take a look at the code again in the next day or two. |
0299576
to
7fc298b
Compare
@msujew, first thing on my agenda this morning! |
7fc298b
to
95eae50
Compare
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.
The behavior looks correct to me, and the check is quite quick.
- Detected bad use of
byDefault
and offered a suggestion. - Automatically inserted the suggestion when triggered to do so.
- Detected use of
.localize
whenbyDefault
was possible. - Correctly rewrote call to
byDefault
when triggered.
Minor comment re: variable names. It also doesn't trigger on nls.localizeByDefault('')
(empty string). I'm not sure whether that's because the empty string is in the metadata.json
, and I'm not sure whether it's desirable to trigger in that case, but it does seem like an odd input.
95eae50
to
518fed8
Compare
Thanks @colin-grant-work, the empty string issue was triggered by a faulty |
What it does
Adds a new eslint rule that helps developers of Theia to correctly localize the application:
nls.localizeByDefault
which use a default value which does not exist inside of thenls.metadata.json
file. Once such a call is detected, the rule tries to find the best fitting existing default value using the levenshtein distance.nls.localize
which could be replaced bynls.localizeByDefault
.How to test
yarn lint
does not yield any errors (CI is green)localizeByDefault
call slightly should lead to an eslint error and a quickfix is provided.localizeByDefault(default)
call tolocalize(key, default)
should lead to an eslint error and a quickfix is provided here as well.Review checklist
Reminder for reviewers