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 Context 將翻譯提供給所有元件:
// 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 建置流程中,確保翻譯永遠保持最新。將提取、翻譯與編譯整合在單一工作流程中。
將 extract、translate 與 compile 加入指令碼並串聯起來。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 Actions 工作流程範例,請參閱 本地化自動化指南。
l10n.dev VS Code 擴充功能將 PO 檔案翻譯直接帶入您的編輯器。無需離開 VS Code 即可翻譯您的 Lingui 目錄。
準備好觸及全球使用者了嗎?直接在 l10n.dev 工作區翻譯您的 Lingui PO 檔案,使用 npm CLI 自動化,或直接在 VS Code 內進行翻譯:
感謝您使用 l10n.dev 來進行 Lingui.js 專案的本地化!🚀
如果本指南對您有幫助,請與其他需要使用 PO 檔案進行應用程式國際化的 React 開發者分享。
讓我們共同努力,讓 JavaScript 應用程式更具親和力,並為全球受眾做好準備。