lingui-framework-setup

v2026.09.24

Set up Lingui in a React framework. Use when adding Lingui to a Next.js App Router, Vite, React Router 7, Remix, or TanStack Start project, when wiring locale detection, locale-prefixed URLs, or SSR locale resolution, or when a working setup breaks after a framework or build-tool upgrade.

GitHub
Install command
npx skhub add lingui/lingui-framework-setup
Markdown
SKILL.md

Lingui Framework Setup

Correct Lingui setup is framework-shaped: what works in a Vite SPA breaks in React Server Components, and a module-level i18n singleton that is fine in the browser bleeds locales across requests under SSR. This skill routes to a framework-native recipe instead of a generic I18nProvider answer.

Work in this order: detect the stack → apply the common steps → follow the framework reference → run the verification sequence.

Step 1 — Detect the stack

Read package.json and the build config before recommending anything. Never guess the compiler — the macro transform silently does nothing when wired into the wrong one.

SignalStackReference
next in deps, app/ or src/app/ with layout.tsxNext.js App Routernextjs-app-router.md
next in deps, pages/ with _app.tsx, no app/Next.js Pages RouterSupported by Lingui, brief notes in nextjs-app-router.md
@tanstack/react-start in depsTanStack Start (SSR)tanstack-start.md
@react-router/dev in devDeps + react-router.config.*React Router 7 framework mode (SSR)react-router-remix.md
@remix-run/dev ≥ 2.7 in devDeps + viteRemix v2 (Vite build, SSR)react-router-remix.md
vite + react, none of the aboveVite SPA (incl. declarative React Router, TanStack Router)vite-spa.md

Compiler detection (decides which macro-transform package to install):

SignalCompilerMacro transform
@vitejs/plugin-react-swcSWC@lingui/swc-plugin (pin exactly — see the swc-plugin-compatibility skill)
@vitejs/plugin-react ^5 or lowerBabel@lingui/babel-plugin-lingui-macro via the plugin's babel option
@vitejs/plugin-react ^6+, Vite 8Babel, standalone passv6 removed the babel option — run the macro as its own pass: @rolldown/plugin-babel + linguiTransformerBabelPreset(). Keeps the stock React plugin
@vitejs/plugin-react ^6+, Vite ≤ 7Babel, standalone passSame, via vite-plugin-babel (no Rolldown). Switching to @vitejs/plugin-react-swc also works, at the cost of an exact pin
Next.js, no .babelrcSWC@lingui/swc-plugin via experimental.swcPlugins
Next.js with .babelrcBabel@lingui/babel-plugin-lingui-macro in .babelrc (a Babel config disables Next's SWC)

One more distinction that changes everything: react-router in deps without @react-router/dev is a declarative SPA (<Routes> in JSX) — that is the Vite SPA reference, not the framework-mode one. Route-module loader/+types code written into a declarative SPA is dead on arrival.

Step 2 — Common steps (every framework)

Version gate. Lingui 6 is current: ESM-only, requires Node ≥ 22.19 (or ≥ 24). Install @lingui/core@^6 @lingui/react@^6 and dev @lingui/cli@^6. If the project cannot meet the Node requirement, pin every @lingui/* package to ^5 — do not mix majors. Do not install @lingui/macro: since v5 the macros live at @lingui/react/macro and @lingui/core/macro.

Per-stack extras (details in each reference):

StackExtra runtimeExtra dev
Next.js App Router—@lingui/swc-plugin (exact pin)
Vite SPA@lingui/detect-locale@lingui/vite-plugin + transform plugin per compiler
React Router 7 / Remix—@lingui/vite-plugin, @lingui/format-po, transform plugin
TanStack Start—@lingui/vite-plugin, transform plugin

@lingui/detect-locale is browser-only (navigator, localStorage, window.location). Never install it on an SSR stack — it throws on the server or desyncs hydration; SSR stacks resolve locale from the request (cookie / Accept-Language) instead.

Config and catalogs. Create lingui.config.ts with sourceLocale, locales, and one catalogs entry; the lingui-best-practices skill owns catalog hygiene (build-script wiring, gitignore rules, CI drift check) and the single-sourced locale module (locales.ts with resolveLocale, getDirection, localeDisplayName) — reuse both, do not re-derive them.

Two catalog-loading models. On Vite-based stacks, @lingui/vite-plugin compiles .po on import — await import('./locales/en/messages.po') just works, there are no compiled artifacts to script or gitignore. Next.js has no Vite pipeline: run lingui compile prepended to dev/build scripts and import the compiled catalogs (@lingui/loader is webpack-only and Turbopack is the Next 15/16 default, so a loader-based setup is a trap).

Step 3 — Framework reference

Read the matching reference file fully before editing the project. Every reference follows the same section contract, in order:

packages → build-tool integration → lingui.config → locale resolution → provider/layout wiring → routing strategies → language switcher → gotchas → verification

If the project needs locale-prefixed URLs, every reference offers the same three strategies — unprefixed source locale, all locales prefixed, or no URL locale (cookie/storage only). Restructuring routes is invasive: ask the user which strategy they want before moving files.

Step 4 — Verify

Run in this order; each step must pass before the next:

npx lingui extract --clean   # catalogs regenerate; count matches expectations
npx lingui compile           # only on stacks with compiled catalogs (Next.js)
npx tsc --noEmit             # types resolve, incl. catalog imports
npm run build                # macro wiring errors surface here

Then prove the transform ran. A green build does not: a mis-wired macro transform is silently a no-op and the app ships in the source language. Translate one string in a non-source catalog, run the app in that locale, and confirm the translation reaches the browser (each reference gives the stack's exact check — curl the server-rendered HTML on SSR stacks, hard-load a deep link on the SPA). The setup is done when you have seen a translated string, not when the build is green.

Raw untranslated text at that point is a compiler wiring problem — wrong plugin, bare-string SWC entry, or the @vitejs/plugin-react@6 babel trap; see the swc-plugin-compatibility skill.

Adding a new framework

Another stack (a new meta-framework, a new build tool) costs two edits: one row in the Step 1 detection table, and one file under references/ following the Step 3 section contract. Framework-specific facts go in the reference; anything true of every stack — the version gate, the two catalog-loading models, the SSR detect-locale rule — stays here, stated once. Every non-obvious rule carries a one-sentence why.

Related skills

  • lingui-best-practices — macro selection, catalog hygiene, the shared locale module. This skill assumes it; don't duplicate it.
  • swc-plugin-compatibility — SWC plugin version pinning and the silent-failure modes of a mis-wired transform.
  • migrate-i18next-to-lingui — if the project already has i18next, migrate first, then return here for framework wiring.
Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

skills/lingui-framework-setup

Default branch

main

Latest commit

a623188

Tree SHA

2c3ee38