-
Notifications
You must be signed in to change notification settings - Fork 56
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
Per-extension language preferences #258
Comments
I have had this similar issue with the i18n library. This caused use to have to write a custom solution that manually fetchs locales based on the user's selection. This would be a greatly welcomed feature in web extensions for my team and I. |
Cool idea! |
browser.i18n.getMessage()
Today, Google publishes a video on Android YouTube channel: Per-app language preferences. I recommend everyone to watch this video in its entirety, which is only 5 minutes. This video is my final purpose for this issue (just replace Android with Browser, and replace app with extension). So I changed the title to "Per-extension language preferences". If browsers support Further more, browsers can supply a built-in language menu for users, like below: And supply a related api for developers to integrate this function in their language select menu in extension. For example: |
browser.i18n.getMessage()
I like the idea of being able to call Comparing with |
Yes, I implemented this solution before. First, async read user's language preference from |
Yes, such a solution would be valuable. |
I also prefer the |
The original comment mentions that "if the extension would like to supply a language selecting menu in the extension settings, it can't use const locale = 'en_US';
const messages = await (await fetch(chrome.runtime.getURL(`/_locales/${locale}/messages.json`))).json()
const message = messages[message_name]; This does not seem too bad and overall this feature is trivially polyfillable even currently. The only caveat is that this workaround would be async while Also, turns out this exact idea was proposed back in 2016 (comment 5, code example it links to), so compatibility should be good.
Would this persist across browser restarts/extension reloads? What should happen when a locale is removed during the extension update? |
@bershanskiy you've forgot to process the "placeholders" :). The |
Sure, this is basic POC example. A better polyfil would also check for actual existence of the file, would provide a list of available languages, etc. Also, there are a few other considerations:
Yes, it is. However, it seems like making
That makes sense. But also it would make sense to make |
@bershanskiy As I said, the feature has workaround, but it is not trivial. This is why I made this proposal. I also explained it at comment-10 4 years ago. In my personal solution, I even move The other issues you mentioned, I think they are all specification/implementation details.
Here is an introduction to Android Per-app language preferences as reference. |
Just to clarify, I originally imagined this to be a solution for the common use-case when user wants to change a language:
Then when the extension re/starts, browser loads the selected language (or default if the selected doesn't exist anymore), fully async, blocking only the extension. I imagine it already works like this just the selected language doesn't come from the user preference. But now that I'm thinking about it, all this could be done by the browser without any extension interaction. Something like the extension keyboard shortcuts, just less hidden :). |
Yes, just like the picture I drew at #issuecomment-1236272054. Developers just use current i18n api without doing anything else (except update already opened extension pages). The new api is only used to integrate it with the developer-self-supplied language select menu. |
In order to express this proposal completely and clearly, I reorganized the content at the first post of this issue. |
One more nitpick about the proposal: should the language selection sync to user browser account (like |
Good question. Local or sync? I often encounter this problem in the development process. In other words, does the same person use different extension languages on different devices? My personal answer is: maybe (like dev/testers) , but most users would probably prefer sync. I think this is left to browsers to decide. There are some other similar settings in the browser, like the Pin status per extensions. |
Looks good @hanguokai! Some remarks: Per-language syntaxConsidering the browser needs to load one or more locale files to initialise i18n.getMessage, having an async initialiser method could be a solution to this. Something like the following:
@bershanskiy Using API namesTo better express what each API does, some different set of method names seems to make sense: If we do not want to lock the method names to extensions, we can rename Extension to Runtime. AsyncConsidering the stand from Google on sync/async code: It makes sense to make Remove custom-set-languageAs we already experienced issues with the behaviour of Custom language scopeIt is not yet clear in what parts of the UI browsers should use the per-extension language. Should the language also be changed for other parts of the UI like:
Language tagAs for language tag syntax. An underscore (_) has been used for folder structures only while the the hyphen (-) is the standard. Other APIs like Language labelsHow will browsers get the language labels for each language tag for First thought is to translate them in their own language as this is most likely understandable by the user. |
Would this also need to change the languages returned by the web |
@xeenon at the moment the navigator APIs are not dependent on the browser UI language. They are dependent on the acceptLanguages header / browser preference. So there seems no reason for the language of navigator APIs to be changed with this proposal. |
@carlosjeurissen My replies is below.
I see this is moved to #274
The name should follow existing naming conventions. In my option,
async is Ok for me.
I'm willing to listen to other people for these edge cases. My opinion is:
Developers should use the tags and labels returned by
IMO, |
Thanks for your replies @hanguokai ! My replies are below.
Correct. We concluded in the meeting it makes sense to split the issue in half and put the getMessage proposal in a separate issue as this could be implemented separately and has a higher chance of being implemented short term. We can continue discussion in #274. Would love to hear your feedback.
During the meeting today it seemed some members were confused about the intention of the method. And thought it would set the language of the whole browser, not just the extension scope. Considering this adding extension can add added clarity to what the method is doing.
My proposal was not to ditch The browser might want to do some work in figuring out if the language tag being passed is valid. That is why I think it makes sense to reject the promise with an error stating the passed language tag is invalid or unavailable, versus directly throwing an exception when calling the method.
Now you mention action badge text and extension contextMenus, it seems to make most sense to keep them as is, and let it be the extension developers responsibility to update the labels if the extensions language changes.
This would be good indeed. However, we should define what getAllLanguages should return and how it comes up with the names. That was what my original comment about language tag labels was about. |
Because the browser UI part is optional for this proposal, I removed the "chrome-opposed" label and added the "follow-up" label for further discussion. |
Thank you for the detailed response, @hanguokai ! I'm still not entirely on board that there's a major effective difference between the two versions of code to create the HTML that were included -- in all likelihood, we'd recommend any developers that wanted to support that to just write a wrapper around i18n like getMessageInPreferredLanguage(), which abstracts out the getLanguageResource(). There would be a difference between one version being sync (ish, due to browser implementation details) and another being async, but I think in the majority of cases that developers are dynamically generating HTML like that, it would depend on other async data (e.g. retrieving other settings, retrieving user data, etc), so the difference becomes less impactful. The browser caching is an interesting point, but is also very dependent on browser implementation details, and I'd be hesitant to design (or introduce) APIs based on that behavior if we think it may change. However, when discussing this more with Oliver, I did remember another part of this that I don't think has been brought up here. In addition to setting the value returned by chrome.i18n.getMessage() (which could be worked around by allowing the extension to get a message from another language), we also allow embedding localized messages in other resources, such as CSS files. In Chrome, these are rewritten on-the-fly as they're fetched from the extension, using the user's current preferred locale. If the extension wanted to replicate this behavior with custom language preferences, they would need to dynamically generate these resources when they otherwise wouldn't. While I don't think the additional wrapping in JS adds significant complexity, I do think that requiring styles to be dynamically generated through JS instead of packaged as CSS is a significant burden. I think that's enough to convince me that this is worthwhile doing -- I agree the other use cases are valuable and it's a nice-to-have for extension developers, and combined with that, I think there's sufficient justification for this. I'm still opposed to introducing browser UI for this at this time. While I understand the utility and desire behind it, I think we should hold off on anything that requires standardizing UI between different browsers. With this, I think the set of API methods we would need would be |
Thank you for discussing this issue during the meeting(2024/05/09). This proposal consists of two parts: the API part and the Browser UI part. Now, all browsers are supportive of the API part. I will add corresponding labels. Next, we hope to see a formal proposal that includes the behavior of the API and some details. I plan to write a formal proposal in the coming weeks. We can discuss the details in the proposal. |
If getCurrentLanguage is added, its format will be supported by
I agree browser UI implementation for changing languages should not block the implementation of the API (there's nothing preventing an UI to be created for this later on) |
@xPaw currently the extension language will always match the browser language which can be fetched using |
I think yes, because both this api and
I think this is not true. For example, the language of the browser UI is English,
|
You are right indeed. Messages from getMessage() would only be in the language of getUILanguage if the extension has messages in this language defined. Just double checked and i18n.getMessage('@@ui_locale') also returns the UI language (yet in Chrome it returns a This gives motivation to already have an
With the above comment I was referring to the current state of affairs. Not a hypothetical future situation in which |
Yes, |
It should indeed probably be separate from #569. My suggestion would be to create a joined proposal for the methods |
Thanks for suggestion. However, in this proposal (#comment-0), it already contains |
The point I was trying to make is that |
This proposal only has 4 simple and intuitive methods, which is not a lot. In addition, proposal and implementation are two different things, no one requires all implementations at once. It is common in Web standards. So, don't worry, I'll get it done soon. |
I just create a formal version of the proposal at #641 |
I was wondering if a simpler approach (if not already discussed) would work. Browsers get the i18n.getMessage() based on the browser locale which falls back to the default_locale. Since extensions would need to display ONE locale at a time, per-extension language preferences can be achieved by setting an browser.i18n.setLanguage()(
'en', // string
)
browser.i18n.unsetLanguage()
// or
browser.i18n.clearLanguage() The fallback process would be: extension_locale -> browser locale -> default_locale Switching LocaleSwitching locale would be applied when refreshing the page, without the need for a live-replacement or additional change listeners. Missing LocaleIn case a locale is set that is not available, the next fallback is used without breaking errors. i18n.getAllLanguages()
|
It is actually the reverse. Having a separate i18n.setLanguage method seems to make more sense as it happens at the start of the fallback chain. In this situation one may wonder if including the browser language in the fallback chain would be a good thing as it could result in an extension potentially being displayed in three languages. |
I will update my post. |
@erosman Thanks! Do you think the |
The purpose of Therefore, it has no place in the
Indeed.... I will change the method to |
Thanks for clarifying. Apologies for the misunderstandings. That makes sense! |
Update: In order to express it completely and clearly, I reorganized the proposal and edited it many times after 2022-09-12.
Summary
Currently,
browser.i18n
only display one default language to users. Users can't change the language to other extension supported languages independently. Developers need to use their own solutions to provide users with multiple language select menu.It makes sense for an app to use another language independently of the operating system. For example, Android supports per-app language preferences (here is its docs and video). The same goes for extensions. This proposal brings per-app language preferences to browser extensions.
Tracking bugs: Chromium-1365283 , Firefox-1791356
Main Content
1. Browser built-in supply a language select menu per extension
Since this is a general purpose feature for all users and extensions, browser built-in support is best.
If browsers built-in support a language select menu per extensions, all developers, all existing extensions and users can get this benefit right away. Ideally, developers just use current i18n api without doing anything. Another benefit is that it's much easier for developers to test i18n.
2. New APIs for developers
Ideally, developers just use current i18n api without doing anything if there is a browser-supplied language select menu. The new api is only used to integrate this feature with the developer-supplied language select menu. For example, in the extension's options page, developers use
get/setCurrentLanguage
andgetAllLanguages
to create a language select menu for users.i18n.setCurrentLanguage(code)
is persistent. It is a setting per extensions which saved by browsers. If the extension remove a language in the new version and current language is that, then browser fall back to the default language.code
is standard language code, like 'en-US', not 'en_US'(folder name).How to get language display names? Use Intl.DisplayNames, for example:
After changing the language, the browser triggers a
onLanguageChanged
event. This event is useful for updating UI for already opened extension pages and other UI parts like badgeText, badgeTitle and context menu.3. Another New API (optional for implementation)
At present,
i18n.getMessage()
doesn't allow specifying a different language. I suggest add a new property to specify a language in the options parameter(the 3rd parameter which already support a "escapeLt" property). Maybe it is useful for some developers or some use cases.Related References
https://developer.chrome.com/docs/extensions/reference/i18n/
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/i18n
https://crbug.com/660704
#252
The text was updated successfully, but these errors were encountered: