lingui-best-practices
Skill439 starsChanged 6 months agoMITView on GitHub
Implement internationalization with Lingui in React and JavaScript applications. Use when adding i18n, translating UI, working with Trans/useLingui/Plural, extracting messages, compiling catalogs, or when the user mentions Lingui, internationalization, i18n, translations, locales, message extraction, ICU MessageFormat, or working with .po files.
- Installs packages
3 other projects use a version of this, 2 of them edited.
Adopted by
Most recently taken up by
- Adonis0123/adonis-skillsedited, first seen Nov 7, 2026
- nhattran998/better-proxyword for word, first seen Oct 11, 2026
- lingui/skillsedited, first seen Sep 2, 2026
Other versions3 projects use a version of this.
Word for word · 1
- nhattran998/better-proxy★ 0100% same
Edited · 2
- lingui/skills★ 1035% same
- Adonis0123/adonis-skills★ 478% same
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository22 other files it gives its agents.
- AGENTS.mdAGENTS.md
- .claude/CLAUDE.mdCLAUDE.md
- aspire-restartSkill
- aspire-stopSkill
- buildSkill
- commitSkill
- create-prdSkill
- create-pull-requestSkill
- db-querySkill
- e2eSkill
- enhanced-message-contextSkill
- fix-e2e-testsSkill
- formatSkill
- lintSkill
- pull-platformplatform-changesSkill
- rebrandSkill
- rebuild-branchSkill
- swc-plugin-compatibilitySkill
- team-interruptSkill
- testSkill
- ultra-reviewSkill
- upgrade-packagesSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
15 rules. About 0 are common, 6 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 23
Import from these packages:
- Distinctive: line 110
When you need to define messages at module level or in arrays/objects:
- Very specific: line 136
Use the Plural macro for quantity-dependent messages:
- Very specific: line 152
Use _N syntax for exact number matches (takes precedence over plural forms):
- Very specific: line 181
Use i18n.date() and i18n.number() for locale-aware formatting:
- Very specific: line 212
When the same text has different meanings, use context:
- Distinctive: line 223
Add context for translators:
- Distinctive: line 255
Prefer macros over runtime components.
- Distinctive: line 267
Avoid complex expressions in messages - they'll be replaced with placeholders:
- Very specific: line 362
When using memoization, use the t function from the macro version:
- Distinctive: line 383
If you encounter issues:
- Very specific: line 385
Messages not extracted: Check include patterns in lingui.config.js
- Very specific: line 386
Translations not applied: Ensure catalogs are compiled with lingui compile
- Very specific: line 387
Runtime errors: Verify I18nProvider wraps your app
- Very specific: line 388
Type errors: Run lingui compile --typescript for TypeScript projects
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Lingui Best Practices
Lingui is a powerful internationalization (i18n) framework for JavaScript. This skill covers best practices for implementing i18n in React and vanilla JavaScript applications.
Quick Start Workflow
The standard Lingui workflow consists of these steps:
- Wrap your app in
I18nProvider - Mark messages for translation using macros (
Trans,t, etc.) - Extract messages:
lingui extract - Translate the catalogs
- Compile catalogs:
lingui compile - Load and activate locale in your app
Core Packages
Import from these packages:
// React macros (recommended)
import { Trans, Plural, Select, useLingui } from "@lingui/react/macro";
// Core macros for vanilla JS
import { t, msg, plural, select } from "@lingui/core/macro";
// Runtime (rarely used directly)
import { I18nProvider } from "@lingui/react";
import { i18n } from "@lingui/core";Setup I18nProvider
Wrap your application with I18nProvider:
import { I18nProvider } from "@lingui/react";
import { i18n } from "@lingui/core";
import { messages } from "./locales/en/messages";
i18n.load("en", messages);
i18n.activate("en");
function App() {
return (
<I18nProvider i18n={i18n}>
{/* Your app */}
</I18nProvider>
);
}Translating UI Text
Use Trans for JSX Content
The Trans macro is the primary way to translate JSX:
import { Trans } from "@lingui/react/macro";
// Simple text
<Trans>Hello World</Trans>
// With variables
<Trans>Hello {userName}</Trans>
// With components (rich text)
<Trans>
Read the <a href="/docs">documentation</a> for more info.
</Trans>
// Extracted as: "Read the <0>documentation</0> for more info."When to use: For any translatable text in JSX elements.
Use useLingui for Non-JSX
For strings outside JSX (attributes, alerts, function calls):
import { useLingui } from "@lingui/react/macro";
function MyComponent() {
const { t } = useLingui();
const handleClick = () => {
alert(t`Action completed!`);
};
return (
<div>
<img src="..." alt={t`Image description`} />
<button onClick={handleClick}>{t`Click me`}</button>
</div>
);
}When to use: Element attributes, alerts, function parameters, any non-JSX string.
Use msg for Lazy Translations
When you need to define messages at module level or in arrays/objects:
import { msg } from "@lingui/core/macro";
import { useLingui } from "@lingui/react";
// Module-level constants
const STATUSES = {
active: msg`Active`,
inactive: msg`Inactive`,
pending: msg`Pending`,
};
function StatusList() {
const { _ } = useLingui();
return Object.entries(STATUSES).map(([key, message]) => (
<div key={key}>{_(message)}</div>
));
}When to use: Module-level constants, arrays of messages, conditional message selection.
Pluralization
Use the Plural macro for quantity-dependent messages:
import { Plural } from "@lingui/react/macro";
<Plural
value={messageCount}
one="You have # message"
other="You have # messages"
/>The # placeholder is replaced with the actual value.
Exact Matches
Use _N syntax for exact number matches (takes precedence over plural forms):
<Plural
value={count}
_0="No messages"
one="One message"
other="# messages"
/>With Variables and Components
Combine with Trans for complex messages:
<Plural
value={count}
one={`You have # message, ${userName}`}
other={
<Trans>
You have <strong>#</strong> messages, {userName}
</Trans>
}
/>Formatting Dates and Numbers
Use i18n.date() and i18n.number() for locale-aware formatting:
import { useLingui } from "@lingui/react/macro";
function MyComponent() {
const { i18n } = useLingui();
const lastLogin = new Date();
return (
<Trans>
Last login: {i18n.date(lastLogin)}
</Trans>
);
}These use the browser's Intl API for proper locale formatting.
Message IDs and Context
Explicit IDs
Provide a custom ID for stable message keys:
<Trans id="header.welcome">Welcome to our app</Trans>Context for Disambiguation
When the same text has different meanings, use context:
<Trans context="direction">right</Trans>
<Trans context="correctness">right</Trans>These create separate catalog entries.
Comments for Translators
Add context for translators:
<Trans comment="Greeting shown on homepage">Hello World</Trans>Configuration
Basic lingui.config.js:
import { defineConfig } from "@lingui/cli";
export default defineConfig({
sourceLocale: "en",
locales: ["en", "es", "fr", "de"],
catalogs: [
{
path: "<rootDir>/src/locales/{locale}/messages",
include: ["src"],
exclude: ["**/node_modules/**"],
},
],
});For detailed configuration patterns, see configuration.md.
Best Practices
Always Use Macros
Prefer macros over runtime components. Macros are compiled at build time, reducing bundle size:
// ✅ Good - uses macro
import { Trans } from "@lingui/react/macro";
// ❌ Avoid - runtime only
import { Trans } from "@lingui/react";Keep Messages Simple
Avoid complex expressions in messages - they'll be replaced with placeholders:
// ❌ Bad - loses context
<Trans>Hello {user.name.toUpperCase()}</Trans>
// Extracted as: "Hello {0}"
// ✅ Good - clear variable name
const userName = user.name.toUpperCase();
<Trans>Hello {userName}</Trans>
// Extracted as: "Hello {userName}"Use Trans for JSX, t for Strings
Choose the right tool:
// ✅ For JSX content
<h1><Trans>Welcome</Trans></h1>
// ✅ For string values
const { t } = useLingui();
<img alt={t`Profile picture`} />Don't Use Macros at Module Level
Macros need component context - use msg instead:
// ❌ Bad - won't work
import { t } from "@lingui/core/macro";
const LABELS = [t`Red`, t`Green`, t`Blue`];
// ✅ Good - use msg for lazy translation
import { msg } from "@lingui/core/macro";
const LABELS = [msg`Red`, msg`Green`, msg`Blue`];Use the ESLint Plugin
Install and configure eslint-plugin-lingui to catch common mistakes automatically:
npm install --save-dev eslint-plugin-lingui// eslint.config.js
import pluginLingui from "eslint-plugin-lingui";
export default [
pluginLingui.configs["flat/recommended"],
];Common Patterns
Dynamic Locale Switching
import { i18n } from "@lingui/core";
async function changeLocale(locale) {
const { messages } = await import(`./locales/${locale}/messages`);
i18n.load(locale, messages);
i18n.activate(locale);
}Loading Catalogs Dynamically
import { useEffect } from "react";
import { i18n } from "@lingui/core";
function loadCatalog(locale) {
return import(`./locales/${locale}/messages`);
}
function App() {
useEffect(() => {
loadCatalog("en").then(catalog => {
i18n.load("en", catalog.messages);
i18n.activate("en");
});
}, []);
return <I18nProvider i18n={i18n}>{/* ... */}</I18nProvider>;
}Memoization with useLingui
When using memoization, use the t function from the macro version:
import { useLingui } from "@lingui/react/macro";
import { msg } from "@lingui/core/macro";
import { useMemo } from "react";
const welcomeMessage = msg`Welcome!`;
function MyComponent() {
const { t } = useLingui(); // Macro version - reference changes with locale
// ✅ Safe - t reference updates with locale
const message = useMemo(() => t(welcomeMessage), [t]);
return <div>{message}</div>;
}Troubleshooting
If you encounter issues:
- Messages not extracted: Check
includepatterns inlingui.config.js - Translations not applied: Ensure catalogs are compiled with
lingui compile - Runtime errors: Verify
I18nProviderwraps your app - Type errors: Run
lingui compile --typescriptfor TypeScript projects
For detailed common mistakes and pitfalls, see common-mistakes.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

