lingui-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Lingui 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:
  1. Wrap your app in
    I18nProvider
  2. Mark messages for translation using macros (
    Trans
    ,
    t
    , etc.)
  3. Extract messages:
    lingui extract
  4. Translate the catalogs
  5. Compile catalogs:
    lingui compile
  6. Load and activate locale in your app
标准的Lingui工作流程包含以下步骤:
  1. 使用
    I18nProvider
    包裹应用
  2. 使用宏(
    Trans
    t
    等)标记需要翻译的消息
  3. 提取消息:
    lingui extract
  4. 翻译目录文件
  5. 编译目录:
    lingui compile
  6. 在应用中加载并激活本地化语言

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
I18nProvider
:
jsx
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>
  );
}
使用
I18nProvider
包裹你的应用:
jsx
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
Trans
macro is the primary way to translate JSX:
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.
Trans
宏是翻译JSX内容的主要方式:
jsx
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
Plural
macro for quantity-dependent messages:
jsx
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.
使用
Plural
宏处理与数量相关的消息:
jsx
import { Plural } from "@lingui/react/macro";

<Plural 
  value={messageCount}
  one="你有 # 条消息"
  other="你有 # 条消息"
/>
#
占位符会被实际数值替换。

Exact Matches

精确匹配

Use
_N
syntax for exact number matches (takes precedence over plural forms):
jsx
<Plural
  value={count}
  _0="No messages"
  one="One message"
  other="# messages"
/>
使用
_N
语法匹配精确数值(优先级高于复数形式):
jsx
<Plural
  value={count}
  _0="暂无消息"
  one="1条消息"
  other="#条消息"
/>

With Variables and Components

结合变量与组件

Combine with
Trans
for complex messages:
jsx
<Plural
  value={count}
  one={`You have # message, ${userName}`}
  other={
    <Trans>
      You have <strong>#</strong> messages, {userName}
    </Trans>
  }
/>
Trans
结合使用以处理复杂消息:
jsx
<Plural
  value={count}
  one={`你有 # 条消息,${userName}`}
  other={
    <Trans>
      你有 <strong>#</strong> 条消息,{userName}
    </Trans>
  }
/>

Formatting Dates and Numbers

日期与数字格式化

Use
i18n.date()
and
i18n.number()
for locale-aware formatting:
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
Intl
API for proper locale formatting.
使用
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>
  );
}
这些方法使用浏览器的
Intl
API实现正确的本地化格式化。

Message 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
context
:
jsx
<Trans context="direction">right</Trans>
<Trans context="correctness">right</Trans>
These create separate catalog entries.
当相同文本有不同含义时,使用
context
jsx
<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.js
:
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.
基础的
lingui.config.js
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/**"],
    },
  ],
});
有关详细的配置模式,请参阅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
msg
instead:
jsx
// ❌ 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`];
宏需要组件上下文 - 改用
msg
jsx
// ❌ 不推荐 - 无法正常工作
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
eslint-plugin-lingui
to catch common mistakes automatically:
bash
npm install --save-dev eslint-plugin-lingui
js
// eslint.config.js
import pluginLingui from "eslint-plugin-lingui";

export default [
  pluginLingui.configs["flat/recommended"],
];
安装并配置
eslint-plugin-lingui
以自动捕获常见错误:
bash
npm install --save-dev eslint-plugin-lingui
js
// 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
t
function from the macro version:
jsx
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>;
}
使用记忆化时,使用宏版本的
t
函数:
jsx
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:
  1. Messages not extracted: Check
    include
    patterns in
    lingui.config.js
  2. Translations not applied: Ensure catalogs are compiled with
    lingui compile
  3. Runtime errors: Verify
    I18nProvider
    wraps your app
  4. Type errors: Run
    lingui compile --typescript
    for TypeScript projects
For detailed common mistakes and pitfalls, see common-mistakes.md.
如果遇到问题:
  1. 消息未提取:检查
    lingui.config.js
    中的
    include
    规则
  2. 翻译未生效:确保已使用
    lingui compile
    编译目录
  3. 运行时错误:验证
    I18nProvider
    是否包裹了整个应用
  4. 类型错误:对于TypeScript项目,运行
    lingui compile --typescript
有关详细的常见错误和陷阱,请参阅common-mistakes.md