lingui-best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLingui Best Practices
Lingui 最佳实践
Lingui is a powerful internationalization (i18n) framework for JavaScript. This skill covers best practices for implementing i18n in React and vanilla JavaScript applications.
Lingui是一款功能强大的JavaScript国际化(i18n)框架。本文档涵盖了在React和原生JavaScript应用中实现i18n的最佳实践。
Quick Start Workflow
快速开始流程
The standard Lingui workflow consists of these steps:
- Wrap your app in
I18nProvider - Mark messages for translation using macros (,
Trans, etc.)t - Extract messages:
lingui extract - Translate the catalogs
- Compile catalogs:
lingui compile - Load and activate locale in your app
标准的Lingui工作流程包含以下步骤:
- 使用包裹应用
I18nProvider - 使用宏(、
Trans等)标记需要翻译的消息t - 提取消息:
lingui extract - 翻译目录文件
- 编译目录:
lingui compile - 在应用中加载并激活本地化语言
Core Packages
核心包
Import from these packages:
jsx
// 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";从以下包中导入:
jsx
// React宏(推荐)
import { Trans, Plural, Select, useLingui } from "@lingui/react/macro";
// 原生JS核心宏
import { t, msg, plural, select } from "@lingui/core/macro";
// 运行时(很少直接使用)
import { I18nProvider } from "@lingui/react";
import { i18n } from "@lingui/core";Setup I18nProvider
配置I18nProvider
Wrap your application with :
I18nProviderjsx
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>
);
}使用包裹你的应用:
I18nProviderjsx
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}>
{/* 你的应用内容 */}
</I18nProvider>
);
}Translating UI Text
翻译UI文本
Use Trans for JSX Content
对JSX内容使用Trans
The macro is the primary way to translate JSX:
Transjsx
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.
Transjsx
import { Trans } from "@lingui/react/macro";
// 简单文本
<Trans>Hello World</Trans>
// 带变量
<Trans>Hello {userName}</Trans>
// 带组件(富文本)
<Trans>
查看 <a href="/docs">文档</a> 获取更多信息。
</Trans>
// 提取后为:"查看 <0>文档</0> 获取更多信息。"适用场景:JSX元素中的任何可翻译文本。
Use useLingui for Non-JSX
对非JSX内容使用useLingui
For strings outside JSX (attributes, alerts, function calls):
jsx
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.
对于JSX之外的字符串(属性、提示框、函数调用):
jsx
import { useLingui } from "@lingui/react/macro";
function MyComponent() {
const { t } = useLingui();
const handleClick = () => {
alert(t`操作完成!`);
};
return (
<div>
<img src="..." alt={t`图片描述`} />
<button onClick={handleClick}>{t`点击我`}</button>
</div>
);
}适用场景:元素属性、提示框、函数参数、任何非JSX字符串。
Use msg for Lazy Translations
对延迟翻译使用msg
When you need to define messages at module level or in arrays/objects:
jsx
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.
当你需要在模块级别或数组/对象中定义消息时:
jsx
import { msg } from "@lingui/core/macro";
import { useLingui } from "@lingui/react";
// 模块级常量
const STATUSES = {
active: msg`活跃`,
inactive: msg`非活跃`,
pending: msg`待处理`,
};
function StatusList() {
const { _ } = useLingui();
return Object.entries(STATUSES).map(([key, message]) => (
<div key={key}>{_(message)}</div>
));
}适用场景:模块级常量、消息数组、条件消息选择。
Pluralization
复数处理
Use the macro for quantity-dependent messages:
Pluraljsx
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.
#使用宏处理与数量相关的消息:
Pluraljsx
import { Plural } from "@lingui/react/macro";
<Plural
value={messageCount}
one="你有 # 条消息"
other="你有 # 条消息"
/>#Exact Matches
精确匹配
Use syntax for exact number matches (takes precedence over plural forms):
_Njsx
<Plural
value={count}
_0="No messages"
one="One message"
other="# messages"
/>使用语法匹配精确数值(优先级高于复数形式):
_Njsx
<Plural
value={count}
_0="暂无消息"
one="1条消息"
other="#条消息"
/>With Variables and Components
结合变量与组件
Combine with for complex messages:
Transjsx
<Plural
value={count}
one={`You have # message, ${userName}`}
other={
<Trans>
You have <strong>#</strong> messages, {userName}
</Trans>
}
/>与结合使用以处理复杂消息:
Transjsx
<Plural
value={count}
one={`你有 # 条消息,${userName}`}
other={
<Trans>
你有 <strong>#</strong> 条消息,{userName}
</Trans>
}
/>Formatting Dates and Numbers
日期与数字格式化
Use and for locale-aware formatting:
i18n.date()i18n.number()jsx
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 API for proper locale formatting.
Intl使用和实现本地化格式化:
i18n.date()i18n.number()jsx
import { useLingui } from "@lingui/react/macro";
function MyComponent() {
const { i18n } = useLingui();
const lastLogin = new Date();
return (
<Trans>
上次登录:{i18n.date(lastLogin)}
</Trans>
);
}这些方法使用浏览器的 API实现正确的本地化格式化。
IntlMessage IDs and Context
消息ID与上下文
Explicit IDs
显式ID
Provide a custom ID for stable message keys:
jsx
<Trans id="header.welcome">Welcome to our app</Trans>提供自定义ID以确保消息键的稳定性:
jsx
<Trans id="header.welcome">欢迎使用我们的应用</Trans>Context for Disambiguation
用于消歧的上下文
When the same text has different meanings, use :
contextjsx
<Trans context="direction">right</Trans>
<Trans context="correctness">right</Trans>These create separate catalog entries.
当相同文本有不同含义时,使用:
contextjsx
<Trans context="方向">右</Trans>
<Trans context="正确性">正确</Trans>这些会生成独立的目录条目。
Comments for Translators
给翻译人员的注释
Add context for translators:
jsx
<Trans comment="Greeting shown on homepage">Hello World</Trans>添加注释为翻译人员提供上下文:
jsx
<Trans comment="首页显示的问候语">Hello World</Trans>Configuration
配置
Basic :
lingui.config.jsjs
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.
基础的:
lingui.config.jsjs
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/**"],
},
],
});有关详细的配置模式,请参阅configuration.md。
Best Practices
最佳实践
Always Use Macros
始终使用宏
Prefer macros over runtime components. Macros are compiled at build time, reducing bundle size:
jsx
// ✅ Good - uses macro
import { Trans } from "@lingui/react/macro";
// ❌ Avoid - runtime only
import { Trans } from "@lingui/react";优先使用宏而非运行时组件。宏在构建时编译,可减小包体积:
jsx
// ✅ 推荐 - 使用宏
import { Trans } from "@lingui/react/macro";
// ❌ 避免 - 仅运行时
import { Trans } from "@lingui/react";Keep Messages Simple
保持消息简洁
Avoid complex expressions in messages - they'll be replaced with placeholders:
jsx
// ❌ 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}"避免在消息中使用复杂表达式,它们会被替换为占位符:
jsx
// ❌ 不推荐 - 丢失上下文
<Trans>Hello {user.name.toUpperCase()}</Trans>
// 提取后为:"Hello {0}"
// ✅ 推荐 - 变量名清晰
const userName = user.name.toUpperCase();
<Trans>Hello {userName}</Trans>
// 提取后为:"Hello {userName}"Use Trans for JSX, t for Strings
对JSX使用Trans,对字符串使用t
Choose the right tool:
jsx
// ✅ For JSX content
<h1><Trans>Welcome</Trans></h1>
// ✅ For string values
const { t } = useLingui();
<img alt={t`Profile picture`} />选择合适的工具:
jsx
// ✅ 适用于JSX内容
<h1><Trans>欢迎</Trans></h1>
// ✅ 适用于字符串值
const { t } = useLingui();
<img alt={t`头像`} />Don't Use Macros at Module Level
不要在模块级别使用宏
Macros need component context - use instead:
msgjsx
// ❌ 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`];宏需要组件上下文 - 改用:
msgjsx
// ❌ 不推荐 - 无法正常工作
import { t } from "@lingui/core/macro";
const LABELS = [t`红色`, t`绿色`, t`蓝色`];
// ✅ 推荐 - 对延迟翻译使用msg
import { msg } from "@lingui/core/macro";
const LABELS = [msg`红色`, msg`绿色`, msg`蓝色`];Use the ESLint Plugin
使用ESLint插件
Install and configure to catch common mistakes automatically:
eslint-plugin-linguibash
npm install --save-dev eslint-plugin-linguijs
// eslint.config.js
import pluginLingui from "eslint-plugin-lingui";
export default [
pluginLingui.configs["flat/recommended"],
];安装并配置以自动捕获常见错误:
eslint-plugin-linguibash
npm install --save-dev eslint-plugin-linguijs
// eslint.config.js
import pluginLingui from "eslint-plugin-lingui";
export default [
pluginLingui.configs["flat/recommended"],
];Common Patterns
常见模式
Dynamic Locale Switching
动态切换本地化语言
jsx
import { i18n } from "@lingui/core";
async function changeLocale(locale) {
const { messages } = await import(`./locales/${locale}/messages`);
i18n.load(locale, messages);
i18n.activate(locale);
}jsx
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
动态加载目录
jsx
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>;
}jsx
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
结合useLingui使用记忆化
When using memoization, use the function from the macro version:
tjsx
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>;
}使用记忆化时,使用宏版本的函数:
tjsx
import { useLingui } from "@lingui/react/macro";
import { msg } from "@lingui/core/macro";
import { useMemo } from "react";
const welcomeMessage = msg`欢迎!`;
function MyComponent() {
const { t } = useLingui(); // 宏版本 - 引用随语言环境变化
// ✅ 安全 - t引用随语言环境更新
const message = useMemo(() => t(welcomeMessage), [t]);
return <div>{message}</div>;
}Troubleshooting
故障排除
If you encounter issues:
- Messages not extracted: Check patterns in
includelingui.config.js - Translations not applied: Ensure catalogs are compiled with
lingui compile - Runtime errors: Verify wraps your app
I18nProvider - Type errors: Run for TypeScript projects
lingui compile --typescript
For detailed common mistakes and pitfalls, see common-mistakes.md.
如果遇到问题:
- 消息未提取:检查中的
lingui.config.js规则include - 翻译未生效:确保已使用编译目录
lingui compile - 运行时错误:验证是否包裹了整个应用
I18nProvider - 类型错误:对于TypeScript项目,运行
lingui compile --typescript
有关详细的常见错误和陷阱,请参阅common-mistakes.md。