Lingui.js是一个轻量级且功能强大的JavaScript和React应用程序国际化(i18n)框架。它使用行业标准的PO(可移植对象)文件作为翻译目录,采用强大的编译时宏以提供简洁的开发者体验,并生成小于2 kB的优化包。本指南涵盖了从项目设置到PO文件工作流程、复数形式以及使用l10n.dev自动化翻译的所有内容。
Lingui.js在JavaScript国际化库中脱颖而出,因为它结合了开发者体验、性能和专业的翻译工作流程:
安装Lingui的核心软件包和开发工具。运行时软件包(@lingui/core和@lingui/react)在生产环境中是必需的,而命令行界面、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(可移植对象)是源自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消息格式语法、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命令行界面会在提取过程中自动创建和更新这些文件。编译后的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消息格式。
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支持两种消息识别方法:自动生成键(源自源消息内容)和显式键(开发者定义的标识符)。两种方法都适用于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消息格式进行复数处理,支持所有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的命令行界面提供了两个关键命令,构成了您翻译工作流程的核心: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脚本运行整个管道;在prebuild中使用它以确保翻译在发布前始终是最新的。
{
"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操作工作流程示例,请参阅本地化自动化指南。
l10n.dev VS Code扩展将PO文件翻译直接引入您的编辑器。无需离开VS Code即可翻译您的Lingui目录。
准备好触达全球用户了吗?直接在l10n.dev工作区翻译您的Lingui PO文件,使用npm命令行界面进行自动化,或者直接在VS Code内进行翻译:
感谢您使用l10n.dev来本地化您的Lingui.js项目!🚀
如果本指南对您有所帮助,请将其分享给其他需要使用PO文件进行应用程序国际化的React开发者。
让我们携手合作,让JavaScript应用程序更易于访问并面向全球受众。