Skip to content

Commit 5821ae0

Browse files
authored
feat: New @wxt-dev/i18n package (#758)
1 parent 751706d commit 5821ae0

File tree

30 files changed

+2002
-81
lines changed

30 files changed

+2002
-81
lines changed

.github/workflows/release.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ on:
77
default: wxt
88
type: choice
99
options:
10-
- wxt
10+
- auto-icons
11+
- i18n
1112
- module-react
12-
- module-vue
13-
- module-svelte
1413
- module-solid
15-
- auto-icons
14+
- module-svelte
15+
- module-vue
16+
- wxt
1617

1718
jobs:
1819
validate:

docs/.vitepress/config.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ export default defineConfig({
130130
menuGroup('Extension APIs', '/guide/extension-apis/', [
131131
menuItem('Storage', 'storage'),
132132
menuItem('Messaging', 'messaging'),
133+
menuItem('I18n', 'i18n'),
133134
menuItem('Scripting', 'scripting'),
134135
menuItem('Others', 'others'),
135136
]),
@@ -148,6 +149,13 @@ export default defineConfig({
148149
menuGroup('Upgrade Guide', '/guide/upgrade-guide/', [
149150
menuItem('wxt', 'wxt'),
150151
]),
152+
menuGroup('@wxt-dev/i18n', '/guide/i18n/', [
153+
menuItem('Introduction', 'introduction.md'),
154+
menuItem('Installation', 'installation.md'),
155+
menuItem('Messages File Format', 'messages-file-format.md'),
156+
menuItem('Build Integrations', 'build-integrations.md'),
157+
menuItem('Editor Support', 'editor-support.md'),
158+
]),
151159
]),
152160
'/api/': menuRoot([
153161
menuGroup('CLI', '/api/cli/', [

docs/guide/extension-apis/i18n.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Internationalization
2+
3+
This guide is for using the vanilla, `browser.i18n` APIs. There are two other alternatives:
4+
5+
1. [`@wxt-dev/i18n`](/guide/i18n/installation) - a wrapper around `browser.i18n` APIs with additional features, a simplified localization file format, and editor support
6+
2. Third party packages - You can use any i18n package on NPM, most of which are more feature rich than `browser.i18n` and `@wxt-dev/i18n`
7+
8+
:::info
9+
Currently, using the `browser.i18n` APIs are the recommended approach. WXT has some built-in support for them and they work well enough. `@wxt-dev/i18n` was recently released, and it will become the recommended approach after some of the bugs have been worked out. Head over to [it's docs](/guide/i18n/introduction.md) to learn more.
10+
:::
11+
12+
## Setup
13+
14+
First familiarize yourself with [Chrome's docs](https://developer.chrome.com/docs/extensions/reference/api/i18n). The only difference when using these APIs with WXT is where you put the localization files - in the [`public` directory](/guide/directory-structure/public/).
15+
16+
```
17+
<srcDir>/
18+
└─ public/
19+
└─ _locales/
20+
├─ en/
21+
│ └─ messages.json
22+
├─ de/
23+
│ └─ messages.json
24+
└─ ko/
25+
└─ messages.json
26+
```
27+
28+
Next, to set a `default_locale` on your manifest, add it to your `wxt.config.ts` file:
29+
30+
```ts
31+
// wxt.config.ts
32+
export default defineConfig({
33+
manifest: {
34+
default_locale: 'en',
35+
name: '__MSG_extName__',
36+
description: '__MSG_extDescription__',
37+
},
38+
});
39+
```
40+
41+
> You can localize the `name` and `description` of your extension from the `manifest` config as well.
42+
43+
Finally, to get a translation, call `browser.i18n.getMessage`:
44+
45+
```ts
46+
browser.i18n.getMessage('extName');
47+
browser.i18n.getMessage('extDescription');
48+
browser.i18n.getMessage(/* etc */);
49+
```
50+
51+
## Examples
52+
53+
See the official localization examples for more details:
54+
55+
- [I18n](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vanilla-i18n#readme)
56+
- [Vue I18n](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vue-i18n#readme)

docs/guide/i18n/build-integrations.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Build Integrations
2+
3+
To use the custom messages file format, you'll need to use `@wxt-dev/i18n/build` to transform the custom format to the one expected by browsers.
4+
5+
Here's a list of build tools that already have an integration:
6+
7+
[[toc]]
8+
9+
:::info
10+
If you want to contribute, please do! In particular, an `unplugin` integration would be awesome!
11+
:::
12+
13+
## WXT
14+
15+
See [Installation with WXT](./installation#with-wxt).
16+
17+
But TLDR, all you need is:
18+
19+
```ts
20+
// wxt.config.ts
21+
export default defineConfig({
22+
modules: ['@wxt-dev/i18n/module'],
23+
});
24+
```
25+
26+
Types are generated whenever you run `wxt prepare` or another build command:
27+
28+
```sh
29+
wxt prepare
30+
wxt
31+
wxt build
32+
wxt zip
33+
# etc
34+
```
35+
36+
## Custom
37+
38+
If you're not using WXT, you'll have to pre-process the localization files yourself. Here's a basic script to generate the `_locales/.../messages.json` and `wxt-i18n-structure.d.ts` files:
39+
40+
```ts
41+
// build-i18n.js
42+
import {
43+
parseMessagesFile,
44+
generateChromeMessagesFile,
45+
generateTypeFile,
46+
} from '@wxt-dev/i18n/build';
47+
48+
// Read your localization files
49+
const messages = {
50+
en: await parseMessagesFile('path/locales/en.yml'),
51+
de: await parseMessagesFile('path/locales/de.yml'),
52+
// ...
53+
};
54+
55+
// Generate JSON files for the browser
56+
await generateChromeMessagesFile('dist/_locales/en/messages.json', messages.en);
57+
await generateChromeMessagesFile('dist/_locales/de/messages.json', messages.de);
58+
// ...
59+
60+
// Generate a types file based on your default_locale
61+
await generateTypeFile('wxt-i18n-structure.d.ts', messages.en);
62+
```
63+
64+
Then run the script:
65+
66+
```sh
67+
node generate-i18n.js
68+
```
69+
70+
If your build tool has a dev mode, you'll also want to rerun the script whenever you change a localization file.
71+
72+
### Type Safety
73+
74+
Once you've generated `wxt-i18n-structure.d.ts` (see the [Custom](#custom) section), you can use it to pass the generated type into `createI18n`:
75+
76+
```ts
77+
import type { WxtI18nStructure } from './wxt-i18n-structure';
78+
79+
export const i18n = createI18n<WxtI18nStructure>();
80+
```
81+
82+
And just like that, you have type safety!

docs/guide/i18n/editor-support.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Editor Support
2+
3+
For better DX, you can configure your editor with plugins and extensions.
4+
5+
[[toc]]
6+
7+
## VS Code
8+
9+
Install the [I18n Ally Extension](https://marketplace.visualstudio.com/items?itemName=lokalise.i18n-ally) to:
10+
11+
- Go to translation definition
12+
- Inline previews of text
13+
- Hover to see other translations
14+
15+
You'll need to configure it the extension so it knows where your localization files are and what function represents getting a translation:
16+
17+
`.vscode/i18n-ally-custom-framework.yml`:
18+
19+
```yml
20+
# An array of strings which contain Language Ids defined by VS Code
21+
# You can check available language ids here: https://code.visualstudio.com/docs/languages/identifiers
22+
languageIds:
23+
- typescript
24+
25+
# Look for t("...")
26+
usageMatchRegex:
27+
- "[^\\w\\d]t\\(['\"`]({key})['\"`]"
28+
29+
# Disable other built-in i18n ally frameworks
30+
monopoly: true
31+
```
32+
33+
`.vscode/settings.json`:
34+
35+
```json
36+
{
37+
"i18n-ally.localesPaths": ["src/locales"],
38+
"i18n-ally.keystyle": "nested"
39+
}
40+
```
41+
42+
## Zed
43+
44+
As of time of writing, Aug 18, 2024, no extensions exist for Zed to add I18n support.
45+
46+
## IntelliJ
47+
48+
Unknown - Someone who uses IntelliJ will have to open a PR for this!

docs/guide/i18n/installation.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Installation
2+
3+
[[toc]]
4+
5+
### With WXT
6+
7+
1. Install `@wxt-dev/i18n` via your package manager:
8+
9+
```sh
10+
pnpm i @wxt-dev/i18n
11+
```
12+
13+
2. Add the WXT module to your `wxt.config.ts` file and setup a default locale:
14+
15+
```ts
16+
export default defineConfig({
17+
modules: ['@wxt-dev/i18n/module'],
18+
manifest: {
19+
default_locale: 'en',
20+
},
21+
});
22+
```
23+
24+
3. Create a localization file at `<srcDir>/locales/<default_locale>.yml` or move your existing localization files there.
25+
26+
```yml
27+
# <srcDir>/locales/en.yml
28+
helloWorld: Hello world!
29+
```
30+
31+
:::tip
32+
`@wxt-dev/i18n` supports the standard messages format, so if you already have localization files at `<srcDir>/public/_locale/<lang>/messages.json`, you don't need to convert them to YAML or refactor them - just move them to `<srcDir>/locales/<lang>.json` and they'll just work out of the box!
33+
:::
34+
35+
4. To get a translation, use the auto-imported `i18n` object or import it manually:
36+
37+
```ts
38+
import { i18n } from '#i18n';
39+
40+
i18n.t('helloWorld'); // "Hello world!"
41+
```
42+
43+
And you're done! Using WXT, you get type-safety out of the box.
44+
45+
### Without WXT
46+
47+
1. Install `@wxt-dev/i18n` via your package manager:
48+
49+
```sh
50+
pnpm i @wxt-dev/i18n
51+
```
52+
53+
2. Create a messages file at `_locales/<lang>/messages.json` or move your existing translations there:
54+
55+
```json
56+
{
57+
"helloWorld": {
58+
"message": "Hello world!"
59+
}
60+
}
61+
```
62+
63+
:::info
64+
For the best DX, you should to integrate `@wxt-dev/i18n` into your build process. This enables:
65+
66+
1. Plural forms
67+
2. Simple messages file format
68+
3. Type safety
69+
70+
See [Build Integrations](./build-integrations) to set it up.
71+
:::
72+
73+
3. Create the `i18n` object, export it, and use it wherever you want!
74+
75+
```ts
76+
import { createI18n } from '@wxt-dev/i18n';
77+
78+
export const i18n = createI18n();
79+
80+
i18n.t('helloWorld'); // "Hello world!";
81+
```

docs/guide/i18n/introduction.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Introduction
2+
3+
:::info
4+
You don't have to use `wxt` to use this package - it will work in any bundler setup. See [Installation without WXT](./installation#without-wxt) for more details.
5+
:::
6+
7+
`@wxt-dev/i18n` is a simple, type-safe wrapper around the `browser.i18n` APIs. It provides several benefits over the standard API:
8+
9+
1. Simple messages file format
10+
2. Plural form support
11+
3. Integrates with the [I18n Ally VS Code extension](./editor-support#vscode)
12+
13+
It also provides several benefits over other non-web extension specific i18n packages:
14+
15+
1. Does not bundle localization files into every entrypoint
16+
2. Don't need to fetch the localization files asynchronously
17+
3. Can localize extension name in manifest
18+
4. Can access localized strings inside CSS files
19+
20+
However, it does have one major downside:
21+
22+
1. Like the `browser.i18n` API, to change the language, users must change the browser's language

0 commit comments

Comments
 (0)