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
Improved localization APIs #327
Comments
I love the idea. Perhaps these two can come as improvement in the future:
I dislike the |
Hi, may I ask about the code snippet within the file: entrypoints/popup/App.vue?
Even though the code still returns the expected result, in Visual Studio Code, it consistently shows a red underline under 'browser.' I am curious to know what the issue is with Visual Studio Code. |
@ongnxco you may have to restart the typescript server after running I don't know specifically why your VSCode might not respect the file generated in the |
@dvlden plural forms can come later, but interpolation is a part of the existing As for
But I could be convinced otherwise lol. I really don't like the built-in APIs and formats, but need to leverage them to avoid inflating the final bundle size.
|
Oh so I think making a tiny custom wrapper to support curly braces is well worth it. The output then can contain $'s... I guess it's more unnecessary work, but considering that WXT is opinionated, I think it should be built in for cleaner syntax. Regarding migration, perhaps the invers cli, that they can run, that would take all I can try to tackle this outside of WXT, to see how simple it could be achieved? |
@dvlden Sure, if you want to take a crack at, I'll leave it to you! |
After some investigation and playing, I thought that it'd be nice if in this opinionated approach, we drop In this case, So instead of transforming this: {
"manifestStyle": {
"message": "This is the translated text",
"description": "This is a description to give translators more context (it's never translated)"
}
} Into the exact same output, we can do this: {
// This is a description to give translators more context (it's never translated)
"manifestStyle": "This is the translated text"
} Keeping it readable and avoid nesting... However, after further reading, I realised that browser also supports {
"manifestStyle": {
"message": "This is the translated text with {somevar} here",
"placeholders": {
"somevar": {
"content": "dynamic content placeholder"
}
}
}
} We do this instead? {
"manifestStyle": ["This is the translated text with {somevar} here", {
"somevar": "dynamic content placeholder"
}]
} I'm just trying to minimize nesting that native api implementation does. With lots of So for my use-case, I think I can build custom script for now that I can use internally to have clean locale files that would be ran before I will play a bit more to see if I can get comments and placeholders to work the way I'd want it and give you a link to a repo, as I am trying it randomly with Node, outside of WXT for simplicity. |
The main reason I allowed the original manifest style is so people can migrate to WXT easily, without changing anything. I'd rather we continue allowing that style. If an object has 3 or less keys, and all the keys belong to There are obviously edge cases here with "reserved" key names, but I'm not too concerned because the typescript support will basically tell them if something's wrong. I'd also prefer we auto-detect placeholders, so we don't have to define them at all in the source translation files, and generate them in the output JSON files. If someone wants to define placeholder information, they should use the original style. I don't think your array style is very readable, someone new to the framework would not recognize what the second object is for. |
I've updated the issue's description with valid JSON that we need to transform the file into. Some things that changed:
|
Here's a basic example that includes the JSON from above. i18n-example.zip I don't know why I thought the import { WxtI18n } from "wxt/browser";
export default defineBackground(() => {
printMessage("simple");
printMessage("manifestStyle");
printMessage("namedInterpolation", ["Joe", "John"]);
printMessage("arrayInterpolation", ["Joe", "John"]);
printMessage("some_nested_translation");
printMessage("escapeTheDollarSign");
printMessage("pluralForm", ["0"]);
printMessage("pluralForm", ["1"]);
printMessage("pluralForm", ["4"]);
});
const printMessage: WxtI18n["getMessage"] = (key, substitutions, options) => {
const str = browser.i18n.getMessage(key, substitutions, options);
console.log(key, "-", str);
return str;
}; |
Oh yea, looks like "named parameter" is only for placeholder use-case. I am not sure how is one being used, if there are multiple placeholders? Shouldn't it accept an K/V object to know where to place each dynamic value? |
My understanding is that named placeholders are just inserted into the message where stated. The placeholders don't have to include interpolated parameters, they can be constant strings. Google provides a reason for this:
So maybe we can't support named substitutions like A couple work-arounds I can think of:
So I would say we go with option 1. Add types for substitutions and use named tuples instead of anonymous tuples. |
Or a third option, stop using Main concern here is performance loss. I imagine the browser is doing some kind of optimization in it's native code as well, so doing the replacements at runtime is probably not a good idea. So I still say we go with option 1 from the previous message. We're stuck with arrays :/ |
Ah I think we're not on the same page here. My thinking is, that we can create a script that would be used during development and/or production build. This script would take It'd be a wishful thinking implementation, that WXT would handle in the background and the output of the build, would actually be the files that browser.i18n understands. So people would use I am not sure if I am explaining this well enough? Does that make any sense, is it worth it at all? |
OK, so you're just considering the translation between the two file types. That's fine, but I'm also considering writing a better API than IE: How would we implement this? const i18n = createI18n();
i18n.t("namedInterpolation", { name1: "John", name2: "Joe" }) // Hello John, my name is Joe
i18n.t("arrayInterpolation", ["John", "Joe"]) // Hello John, my name is Joe |
It seems UI framework agnostic? I want to know how to change locale if I use it in React? |
@yunsii The built-in localization APIs provided to chrome extensions do not provide a way to change the current language. Since WXT's wrapper will use those APIs internally, the API discussed here will not support changing languages either. If you're using react, you can use a library like https://github.com/wxt-dev/wxt-examples/tree/main/examples/vue-i18n#readme I'd recommend reading this one as well to get a better understanding of how to use the built-in APIs. https://github.com/wxt-dev/wxt-examples/tree/main/examples/vanilla-i18n#readme |
Got it, thanks very much. |
That's actually great... Can you make an alpha release, so I can test it within my extension? |
@dvlden will do 👍 |
Will unassign myself as you already got it. It's not what I wanted, but it's still cool and useful. |
Feature Request
Instead of using
browser.i18n.getMessage
directly, include a customi18n
API that can be used in it's place.It should:
<srcDir>/locales/[country-code].(json|json5|yaml|yml)
.output/[target]/_locales/[country-code]/messages.json
filesBasically, for message files that look like this:
Would be translated to look like this:
The API would look something like this:
Acceptance Criteria
browser.i18n.getMessage
to make sure the keys passed in are type-safe. Let's keep this logic, but how it is generated will be different.wxt/src/core/utils/building/generate-wxt-dir.ts
Lines 96 to 98 in ab6a34a
localesDir
to the config to allow customization<srcDir>/<localesDir>/*
, transform them, and output them to.output/[target]/_locales/[country-code]/messages.json
. Public assets are copied here:wxt/src/core/utils/building/build-entrypoints.ts
Line 28 in ab6a34a
i18n.t
count
, to detect keys that are plural$
correctlyWhat are the alternatives?
See #217 for a discussion of alternative methods.
Additional context
Created based on #217 (comment)
The text was updated successfully, but these errors were encountered: