# @workspace/i18n Reusable Lingui runtime, Devtool, Vite plugin, and CLI. This package does not own application locales or catalogs: every consuming application keeps its own `i18n.config.json`, `lingui.config.ts`, and generated message files. ## Consumer setup Install the package in an application and add scripts that invoke its CLI: ```json { "dependencies": { "@lingui/core": "^6", "@workspace/i18n": "workspace:*" }, "scripts": { "i18n": "workspace-i18n", "i18n:compile": "workspace-i18n compile", "i18n:extract": "workspace-i18n extract", "i18n:ui": "workspace-i18n ui" } } ``` Create `i18n.config.json` in that application: ```json { "sourceLocale": "en", "locales": ["en", "zh-Hans"], "catalogPath": "src/locales/{locale}/messages", "include": ["src"], "exclude": ["**/*.test.{ts,tsx}"] } ``` Then expose it as a Lingui configuration: ```ts import project from "./i18n.config.json" with { type: "json" } import { createLinguiConfig } from "@workspace/i18n/lingui-config" export default createLinguiConfig(project) ``` Mount the API plugin in the consuming application's Vite configuration: ```ts import { i18n } from "@workspace/i18n/vite" import { defineConfig } from "vite" export default defineConfig({ plugins: [i18n()], }) ``` ## Runtime Compiled Lingui catalogs are passed to the provider synchronously, so the first client render and SSR render use the same locale. ```tsx import { messages as en } from "@/locales/en/messages" import { messages as zhHans } from "@/locales/zh-Hans/messages" import { I18nProvider, Translate, useLocale, useLocales, useMessage, useTranslate, } from "@workspace/i18n" import { I18nDevtool } from "@workspace/i18n/devtool" function Root({ children, locale }: React.PropsWithChildren<{ locale: string }>) { return ( {children} {import.meta.env.DEV && } ) } function Greeting() { const locale = useLocale() const locales = useLocales() const title = useMessage("dashboard.title") const translate = useTranslate() return ( <> {title} ) } ``` `Translate` is a thin wrapper around Lingui's runtime `Trans` component. It does not add a DOM wrapper and retains `values`, `components`, `formats`, `component`, and `render`. The generated Lingui configuration points `runtimeConfigModule.Trans` at `Translate`, so explicit `` usages are found by `lingui extract`. ## Devtool `I18nDevtool` must be mounted inside `I18nProvider`. It reads the active locale and available locales from the provider, while the Vite `i18n()` plugin serves catalog reads, updates, extraction, and compilation. ```tsx {import.meta.env.DEV && } ``` The `dark` value can be a class name such as `ui\:dark`, or a CSS selector such as `[data-theme="dark"]`. The Devtool observes document theme changes and renders through a portal, so application overflow and stacking contexts do not clip it. Lower-level `MessagePanel`, `MessageRepositoryProvider`, and repository types remain available from `@workspace/i18n/devtool`. ## CLI Run inside the consuming application so the CLI discovers that application's `i18n.config.json`: ```sh bun run i18n new ja bun run i18n extract bun run i18n compile bun run i18n ui ``` Commands: - `new ` validates and canonicalizes a BCP-47 locale, updates `i18n.config.json`, and asks Lingui to extract its catalog. - `extract` extracts application messages into its catalogs. - `compile` compiles application catalogs to TypeScript modules. - `ui` starts Message Studio. It reads and writes PO catalogs through Lingui's catalog API, and provides Extract and Compile actions. All commands accept `--project ` when invoked outside the application. ## Catalog workflow ```sh cd apps/web bun run i18n:extract bun run i18n:compile ``` The application's `i18n.config.json` is the machine-editable source of truth. Its `lingui.config.ts` maps that manifest to Lingui's configuration format.