feat(i18n): add Lingui runtime and development tooling

- add SSR-safe I18nProvider, Translate, locale hooks, catalog activation, and typed runtime APIs

- add consumer-owned Lingui configuration helpers and a CLI for locale creation, extraction, compilation, and project discovery

- add catalog read/write services plus a Vite development API plugin scoped to each consuming application

- add the portal-based I18nDevtool, message editor, dark-theme tracking, and standalone Message Studio

- document the consumer workflow and cover runtime, configuration, catalog, CLI, and Devtool behavior with tests
This commit is contained in:
Maofeng
2026-07-29 21:23:00 +08:00
parent 011e7d8115
commit 9e3f1d6b59
39 changed files with 2897 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
import * as React from "react"
import type { I18nProjectConfig } from "../../config/lingui-config"
import { I18nProvider } from "../../runtime"
import { requestDevtoolJson } from "../api-client"
import { I18nDevtool } from "../i18n-devtool"
type ProjectState =
| { status: "loading" }
| { error: Error; status: "error" }
| { project: I18nProjectConfig; status: "ready" }
export function DevtoolApp() {
const [state, setState] = React.useState<ProjectState>({ status: "loading" })
React.useEffect(() => {
requestDevtoolJson<I18nProjectConfig>("/__i18n/project").then(
(project) => setState({ project, status: "ready" }),
(reason) =>
setState({
error:
reason instanceof Error
? reason
: new Error("Unable to load the i18n project."),
status: "error",
})
)
}, [])
if (state.status !== "ready") {
return (
<main
className="devtool-app__state"
role={state.status === "error" ? "alert" : "status"}
>
{state.status === "error"
? state.error.message
: "Loading I18n Devtool…"}
</main>
)
}
const locale = state.project.locales[0]
if (!locale) {
return (
<main className="devtool-app__state">
Add a locale with <code>workspace-i18n new &lt;locale&gt;</code>.
</main>
)
}
return (
<I18nProvider locale={locale} locales={state.project.locales}>
<I18nDevtool defaultOpen mode="standalone" />
</I18nProvider>
)
}