Skip to content

Commit 2f7b13d

Browse files
authored
fix(loader): make webpack peer dependency optional and update Rspack example (#2475)
1 parent 5339152 commit 2f7b13d

18 files changed

Lines changed: 969 additions & 784 deletions

File tree

examples/rspack/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ This project shows how to use the [Rspack JavaScript bundler](https://www.rspack
1515
1. Wrap any messages requiring translation in `<Trans>` or a related macro.
1616
2. `npm run extract` to generate message catalogs in `src/locales/{locale}/messages`.
1717
3. Translate any new messages in the catalogs.
18-
4. `npm run compile` to create runtime catalogs.
18+
4. Restart the dev server or rebuild the app. `@lingui/loader` compiles `.po` catalogs during bundling, so no separate `lingui compile` step is required.
1919

2020
## Configuration File Notes
2121

22-
- [`rspack.config.js`](./rspack.config.js) specifies the [`builtin:swc-loader`](https://www.rspack.dev/guide/builtin-swc-loader.html#builtinswc-loader) should transcompile all `.tsx` files using the Lingui SWC plugin, ensuring transcompilation of [Lingui Macros](https://lingui.dev/ref/macro) like `<Trans>` into their respective React components. When using Lingui SWC plugin, ensure version compatibility with `@rspack/core`. Refer to the [compatibility guide](https://github.com/lingui/swc-plugin#compatibility) for selecting the appropriate plugin version.
22+
- [`rspack.config.js`](./rspack.config.js) configures both the [`builtin:swc-loader`](https://www.rspack.dev/guide/builtin-swc-loader.html#builtinswc-loader) and `@lingui/loader`. The SWC plugin transpiles [Lingui Macros](https://lingui.dev/ref/macro) like `<Trans>` into their React runtime equivalents, while `@lingui/loader` turns imported `.po` catalogs into runtime messages at build time. When using Lingui SWC plugin, ensure version compatibility with `@rspack/core`. Refer to the [compatibility guide](https://github.com/lingui/swc-plugin#compatibility) for selecting the appropriate plugin version.
23+
24+
- [`src/i18n.ts`](./src/i18n.ts) lazy-loads locale catalogs from `src/locales/{locale}/messages.po`, which lets `rspack` split translations into separate chunks and compile them through `@lingui/loader`.
2325

2426
- [`lingui.config.ts`](./lingui.config.ts) specifies the available locales, defaults, and paths where the message catalogs are stored.
2527

examples/rspack/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@
55
"scripts": {
66
"dev": "rspack serve",
77
"build": "rspack build",
8-
"extract": "lingui extract",
9-
"compile": "lingui compile --typescript"
8+
"extract": "lingui extract"
109
},
1110
"dependencies": {
12-
"@lingui/core": "^5.9.0",
13-
"@lingui/react": "^5.9.0",
11+
"@lingui/core": "^5.9.5",
12+
"@lingui/react": "^5.9.5",
1413
"react": "^18.2.0",
1514
"react-dom": "^18.2.0"
1615
},
1716
"devDependencies": {
18-
"@lingui/cli": "^4.7.2",
17+
"@lingui/cli": "^5.9.5",
18+
"@lingui/loader": "^5.9.5",
1919
"@lingui/swc-plugin": "^5.10.0",
20-
"@rspack/cli": "^1.7.4",
21-
"@rspack/core": "^1.7.4",
20+
"@rspack/cli": "^1.7.11",
21+
"@rspack/core": "^1.7.11",
2222
"@types/react": "^18.2.79",
23-
"@types/react-dom": "18.2.1",
23+
"@types/react-dom": "^18.2.1",
2424
"typescript": "^5.9.3"
2525
}
2626
}

examples/rspack/rspack.config.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ module.exports = {
1717
test: /\.svg$/,
1818
type: "asset",
1919
},
20+
{
21+
test: /\.po$/,
22+
use: [
23+
{
24+
loader: "@lingui/loader",
25+
options: {
26+
failOnCompileError: true,
27+
},
28+
},
29+
],
30+
},
2031
{
2132
test: /\.(jsx?|tsx?)$/,
2233
exclude: /node_modules/,

examples/rspack/src/Inbox.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
import { useLingui } from "@lingui/react"
2-
3-
import { Plural, Trans } from "@lingui/react/macro"
4-
1+
import { useLingui, Plural, Trans } from "@lingui/react/macro"
52
import LocaleSwitcher from "./LocaleSwitcher"
63

74
export default function Inbox() {
85
const messages = [{}, {}]
96
const messagesCount = messages.length
107
const lastLogin = new Date()
8+
9+
const { i18n, t } = useLingui()
10+
1111
const markAsRead = () => {
12-
alert("Marked as read.")
12+
alert(t`Marked as read.`)
1313
}
14-
const { i18n } = useLingui()
1514

1615
return (
1716
<div>
@@ -23,7 +22,7 @@ export default function Inbox() {
2322
<Trans>
2423
See all <a href="/unread">unread messages </a>
2524
{" or "}
26-
<a onClick={markAsRead}>mark them</a> as read.
25+
<button onClick={markAsRead}>mark them</button> as read.
2726
</Trans>
2827
</p>
2928
<p>
Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,43 @@
1-
import React from 'react';
2-
import { useLingui } from '@lingui/react';
3-
import Locale from './locales';
1+
import { useState } from "react";
2+
import { useLingui } from "@lingui/react";
3+
4+
import { dynamicActivate } from "./i18n";
5+
import Locale from "./locales";
46

57
function LocaleSwitcher() {
6-
const { i18n } = useLingui();
8+
const { i18n } = useLingui();
9+
const [isLoading, setIsLoading] = useState(false);
10+
11+
const handleLocaleChange = async (newLocale: Locale) => {
12+
if (isLoading || newLocale === i18n.locale) {
13+
return;
14+
}
15+
16+
setIsLoading(true);
717

8-
const handleLocaleChange = (newLocale: Locale) => {
9-
i18n.activate(newLocale);
10-
};
18+
try {
19+
await dynamicActivate(i18n, newLocale);
20+
} finally {
21+
setIsLoading(false);
22+
}
23+
};
1124

12-
return (
13-
<div>
14-
<button onClick={() => handleLocaleChange(Locale.ENGLISH)}>English</button>
15-
<button onClick={() => handleLocaleChange(Locale.FRENCH)}>Français</button>
16-
{/* Add more buttons for other supported locales */}
17-
</div>
18-
);
25+
return (
26+
<div>
27+
<button
28+
disabled={isLoading || i18n.locale === Locale.ENGLISH}
29+
onClick={() => void handleLocaleChange(Locale.ENGLISH)}
30+
>
31+
English
32+
</button>
33+
<button
34+
disabled={isLoading || i18n.locale === Locale.FRENCH}
35+
onClick={() => void handleLocaleChange(Locale.FRENCH)}
36+
>
37+
Français
38+
</button>
39+
</div>
40+
);
1941
}
2042

2143
export default LocaleSwitcher;

examples/rspack/src/i18n.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type { I18n, Messages } from "@lingui/core";
2+
3+
import Locale from "./locales";
4+
5+
type CatalogModule = {
6+
messages: Messages;
7+
};
8+
9+
const catalogs: Record<Locale, () => Promise<CatalogModule>> = {
10+
[Locale.ENGLISH]: () => import("./locales/en/messages.po"),
11+
[Locale.FRENCH]: () => import("./locales/fr/messages.po"),
12+
};
13+
14+
export async function loadCatalog(locale: Locale) {
15+
const { messages } = await catalogs[locale]();
16+
17+
return messages;
18+
}
19+
20+
export async function dynamicActivate(i18n: I18n, locale: Locale) {
21+
const messages = await loadCatalog(locale);
22+
23+
i18n.loadAndActivate({ locale, messages });
24+
}

examples/rspack/src/locales/en/messages.d.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

examples/rspack/src/locales/en/messages.po

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,23 @@ msgstr ""
1313
"Language-Team: \n"
1414
"Plural-Forms: \n"
1515

16-
#: src/Inbox.tsx:30
16+
#: src/Inbox.tsx:29
1717
msgid "{messagesCount, plural, one {There's # message in your inbox.} other {There are # messages in your inbox.}}"
1818
msgstr "{messagesCount, plural, one {There's # message in your inbox.} other {There are # messages in your inbox.}}"
1919

20-
#: src/Inbox.tsx:32
20+
#. placeholder {0}: i18n.date(lastLogin)
21+
#: src/Inbox.tsx:37
2122
msgid "Last login on {0}."
2223
msgstr "Last login on {0}."
2324

24-
#: src/Inbox.tsx:21
25+
#: src/Inbox.tsx:12
26+
msgid "Marked as read."
27+
msgstr "Marked as read."
28+
29+
#: src/Inbox.tsx:19
2530
msgid "Message Inbox"
2631
msgstr "Message Inbox"
2732

28-
#: src/Inbox.tsx:23
29-
msgid "See all <0>unread messages </0>or <1>mark them</1> as read."
30-
msgstr "See all <0>unread messages </0>or <1>mark them</1> as read."
33+
#: src/Inbox.tsx:22
34+
msgid "See all <0>unread messages </0> or <1>mark them</1> as read."
35+
msgstr "See all <0>unread messages </0> or <1>mark them</1> as read."

examples/rspack/src/locales/en/messages.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

examples/rspack/src/locales/fr/messages.d.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)