Lingui.js 是一个轻量级且功能强大的 JavaScript 和 React 应用国际化 (i18n) 框架。它使用行业标准的 PO (Portable Object) 文件作为翻译目录,提供强大的编译时宏以实现简洁的开发体验,并生成小于 2 kB 的优化包。本指南涵盖了从项目设置到 PO 文件工作流、复数形式以及使用 l10n.dev 实现翻译自动化的所有内容。
Lingui.js 因其在开发体验、性能和专业翻译工作流方面的出色表现,在 JavaScript i18n 库中脱颖而出:
安装 Lingui 的核心包和开发工具。运行时包 (@lingui/core 和 @lingui/react) 在生产环境中是必需的,而 CLI、Vite 插件和 Babel 宏仅用于开发:
npm install @lingui/core @lingui/react
npm install --save-dev @lingui/cli @lingui/vite-plugin @lingui/babel-plugin-lingui-macroLingui 需要两个配置文件:Lingui 配置(定义语言环境和目录路径)以及构建工具配置(以启用编译时宏)。
在项目根目录下创建一个 lingui.config.js 文件。它定义了源语言、目标语言、PO 目录存储位置以及目录格式。PO 格式是默认且推荐的选择:
// lingui.config.js
import { defineConfig } from "@lingui/cli";
import { formatter } from "@lingui/format-po";
export default defineConfig({
sourceLocale: "en",
locales: ["en", "fr", "de", "ja", "es", "zh-CN"],
catalogs: [
{
path: "<rootDir>/src/locales/{locale}/messages",
include: ["src"],
},
],
format: formatter({ lineNumbers: false }),
});如果您使用 Vite,请将 Lingui 插件与 React 插件及 Babel 宏一起添加。这可以启用编译时的消息转换和即时目录编译:
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { lingui } from "@lingui/vite-plugin";
export default defineConfig({
plugins: [
react({
babel: {
plugins: ["@lingui/babel-plugin-lingui-macro"],
},
}),
lingui(),
],
});PO (Portable Object) 是源自 GNU gettext 系统的行业标准翻译文件格式。Lingui 使用 PO 作为其默认目录格式,因为它受到全球翻译工具、TMS 平台和专业翻译人员的广泛支持。
#: src/components/WelcomeBanner.js:6
msgid "Welcome to our platform"
msgstr ""
#: src/components/WelcomeBanner.js:8
msgid "Hello {userName}, check out your <0>dashboard</0> to get started."
msgstr ""
#: src/components/CartSummary.js:5
msgid "{itemCount, plural, =0 {Your cart is empty} one {You have # item in your cart} other {You have # items in your cart}}"
msgstr ""翻译完成后,每个 msgstr 都会填入本地化版本。Lingui 在所有翻译中保留 ICU MessageFormat 语法、React 组件的索引标签以及占位符变量。
#: src/components/WelcomeBanner.js:6
msgid "Welcome to our platform"
msgstr "Bienvenue sur notre plateforme"
#: src/components/WelcomeBanner.js:8
msgid "Hello {userName}, check out your <0>dashboard</0> to get started."
msgstr "Bonjour {userName}, consultez votre <0>tableau de bord</0> pour commencer."
#: src/components/CartSummary.js:5
msgid "{itemCount, plural, =0 {Your cart is empty} one {You have # item in your cart} other {You have # items in your cart}}"
msgstr "{itemCount, plural, =0 {Votre panier est vide} one {Vous avez # article dans votre panier} other {Vous avez # articles dans votre panier}}"将 PO 目录组织在 locales 文件夹中,每个语言环境一个子文件夹。Lingui CLI 会在提取过程中自动创建和更新这些文件。编译后的 JS 模块在构建时生成,不应手动编辑。
src/
├── locales/
│ ├── en/
│ │ └── messages.po ← Source (English)
│ ├── fr/
│ │ └── messages.po ← French
│ ├── de/
│ │ └── messages.po ← German
│ ├── ja/
│ │ └── messages.po ← Japanese
│ ├── es/
│ │ └── messages.po ← Spanish
│ └── zh-CN/
│ └── messages.po ← Chinese Simplified
├── components/
├── i18n.ts
├── App.tsx
└── ...Lingui 提供了两种标记消息的主要方法:用于组件内容的 JSX 宏和用于命令式字符串的 useLingui 钩子。两者都是产生优化输出的编译时宏。
将任何 JSX 内容包裹在 Trans 宏中即可使其可翻译。完全支持变量、HTML 元素和 React 组件——宏会自动将它们转换为带有索引标签的 ICU MessageFormat。
import { Trans } from "@lingui/react/macro";
function WelcomeBanner({ userName }) {
return (
<div>
<h1>
<Trans>Welcome to our platform</Trans>
</h1>
<p>
<Trans>
Hello {userName}, check out your <a href="/dashboard">dashboard</a> to
get started.
</Trans>
</p>
</div>
);
}对于 JSX 之外的字符串(如警告消息、aria 标签、属性值或任何命令式代码),请使用带有标签模板字面量的 useLingui 宏钩子:
import { useLingui } from "@lingui/react/macro";
function NotificationButton() {
const { t } = useLingui();
const showAlert = () => {
alert(t`Your changes have been saved.`);
};
return (
<button onClick={showAlert} aria-label={t`Save changes`}>
<Trans>Save</Trans>
</button>
);
}Lingui 支持两种消息标识方法:自动生成 ID(源自源消息内容)和显式 ID(开发者定义的键)。两种方法都适用于 PO 文件。
import { Trans } from "@lingui/react/macro";
// Auto-generated ID (from message content)
<Trans>Welcome to our platform</Trans>
// Explicit ID (developer-defined key)
<Trans id="nav.welcome">Welcome to our platform</Trans>在任何宏上使用 comment 属性来添加描述。此注释会被提取到 PO 文件中作为翻译人员备注,提供关于消息出现位置和方式的关键上下文。
import { Trans } from "@lingui/react/macro";
<Trans comment="Shown on the homepage hero section above the fold">
Start building with confidence
</Trans>Lingui 使用 ICU MessageFormat 进行复数处理,支持所有 CLDR 复数类别。Plural 宏可以轻松地在 JSX 中直接处理不同的复数形式:
import { Plural } from "@lingui/react/macro";
function CartSummary({ itemCount }) {
return (
<p>
<Plural
value={itemCount}
_0="Your cart is empty"
one="You have # item in your cart"
other="You have # items in your cart"
/>
</p>
);
}提取并编译消息后,设置 i18n 实例并将您的应用包裹在 I18nProvider 中。
创建一个动态加载已编译消息目录的 i18n 模块。Lingui Vite 插件支持直接导入 PO 文件,这些文件会在开发过程中即时编译:
// src/i18n.ts
import { i18n } from "@lingui/core";
export async function loadCatalog(locale: string) {
const { messages } = await import(`./locales/${locale}/messages.po`);
i18n.load(locale, messages);
i18n.activate(locale);
}
// Initialize with default locale
loadCatalog("en");
export default i18n;用 I18nProvider 包裹整个应用,以便通过 React 上下文使所有组件都能使用翻译:
// src/App.tsx
import { I18nProvider } from "@lingui/react";
import { i18n } from "./i18n";
function App() {
return (
<I18nProvider i18n={i18n}>
<YourAppContent />
</I18nProvider>
);
}切换语言非常简单:加载新目录,激活语言环境,React 会自动重新渲染所有已翻译的内容。这是一个完整的语言切换组件:
import { useState } from "react";
import { loadCatalog } from "./i18n";
import { Trans } from "@lingui/react/macro";
const LANGUAGES = {
en: "English",
fr: "Français",
de: "Deutsch",
ja: "日本語",
es: "Español",
};
function LanguageSwitcher() {
const [currentLocale, setCurrentLocale] = useState("en");
const handleChange = async (locale: string) => {
await loadCatalog(locale);
setCurrentLocale(locale);
};
return (
<select
value={currentLocale}
onChange={(e) => handleChange(e.target.value)}
>
{Object.entries(LANGUAGES).map(([code, name]) => (
<option key={code} value={code}>
{name}
</option>
))}
</select>
);
}Lingui 的 CLI 提供了两个核心命令,构成了您翻译工作流的基础:extract(从源代码中提取消息到 PO 目录)和 compile(将 PO 文件转换为生产环境所需的优化 JavaScript 模块)。
# Extract messages from source code into PO catalogs
npx lingui extract
# Translate your PO files (manually, with a TMS, or with AI)
# Compile PO catalogs into optimized JS modules for production
npx lingui compilel10n.dev 提供对 PO 文件的原生支持,使其成为 Lingui.js 项目的完美伴侣。上传您的源 PO 目录并收回准确翻译的文件:
使用 ai-l10n npm 包从命令行或作为 CI/CD 流水线的一部分翻译您的 Lingui PO 目录。安装一次,即可通过单条命令翻译成任意数量的语言。
# Install the CLI
npm install ai-l10n
# Translate your source PO file to multiple languages
npx ai-l10n translate src/locales/en/messages.po \
--languages fr,de,ja,zh-CN,es,ko将 ai-l10n 直接集成到您的 Lingui 构建过程中,确保翻译始终保持最新。将提取、翻译和编译结合在一个工作流中。
将提取、翻译和编译添加为脚本并串联起来。i18n 脚本运行整个流水线;在预构建中使用它,以确保在发布前翻译始终是最新的。
{
"scripts": {
"extract": "lingui extract",
"compile": "lingui compile",
"translate": "ai-l10n translate src/locales/en/messages.po --languages fr,de,ja,zh-CN,es,ko --update",
"i18n": "npm run extract && npm run translate && npm run compile",
"prebuild": "npm run i18n",
"build": "vite build",
"dev": "vite"
}
}如果您的团队使用 Make,请将提取、翻译和编译声明为具有适当依赖关系的独立目标:
LANGUAGES = fr,de,ja,zh-CN,es,ko
extract:
npx lingui extract
translate:
npx ai-l10n translate src/locales/en/messages.po --languages $(LANGUAGES) --update
compile:
npx lingui compile
i18n: extract translate compile
dev: i18n
npx vite
build: i18n
npx vite build有关 CI/CD 集成、增量更新、跨多个文件的批量翻译以及 GitHub Actions 工作流示例,请参阅 本地化自动化指南。
l10n.dev VS Code 扩展将 PO 文件翻译直接带入您的编辑器。无需离开 VS Code 即可翻译您的 Lingui 目录。
准备好接触全球用户了吗?直接在 l10n.dev 工作区翻译您的 Lingui PO 文件,使用 npm CLI 自动化,或直接在 VS Code 中翻译:
感谢您使用 l10n.dev 本地化您的 Lingui.js 项目!🚀
如果本指南对您有帮助,请分享给其他需要使用 PO 文件进行应用国际化的 React 开发者。
让我们共同努力,使 JavaScript 应用更具可访问性,并为全球受众做好准备。