TL;DR: Paraglide.js 是一款编译时国际化库,在构建阶段提取消息,生成针对各语言优化的包,零运行时开销。传统的 i18n 库(如 react-intl、i18next)会将所有翻译发送给客户端,而 Paraglide 只交付用户所需的语言包。本文涵盖面向多语言 SaaS 的生产级模式,涉及英语、德语和中文三种语言。
为什么选择 Paraglide?
| 功能 | Paraglide.js | react-intl | i18next | react-i18next |
|---|---|---|---|---|
| 包体积 | ~0 KB(编译后) | ~30 KB | ~35 KB | ~40 KB |
| 运行时开销 | 无(编译时) | 消息解析 | 运行时查找 | 运行时查找 |
| 类型安全 | ✅ 完整(生成 TS) | 部分 | 部分 | 部分 |
| Tree-shakeable | ✅(死代码消除) | ❌ | ❌ | ❌ |
| 懒加载 | 内置(按语言分割) | 手动 | 手动 | 手动 |
| ICU 消息 | ✅ | ✅ | 部分 | 部分 |
| SSR 兼容 | ✅ | ✅ | ✅ | ✅ |
安装配置
npm install @inlang/paraglide-js
npx paraglide-js init
// project.inlang/settings.json
{
"sourceLanguageTag": "en",
"languageTags": ["en", "zh", "de"],
"modules": ["https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@latest/dist/index.js"],
"plugin.inlang.messageFormat": {
"pathPattern": "./messages/{languageTag}.json"
}
}
消息文件
// messages/en.json
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"app_title": "TanStack Ship",
"nav_home": "Home",
"nav_pricing": "Pricing",
"nav_docs": "Docs",
"hero_heading": "Build Your SaaS Faster",
"hero_subheading": "A production-ready SaaS starter with auth, billing, and multi-language support.",
"cta_start": "Get Started",
"cta_learn": "Learn More",
"footer_copyright": "© 2026 TanStack Ship. All rights reserved.",
"pricing_monthly": "Monthly",
"pricing_yearly": "Yearly",
"pricing_save": "Save {discount}%",
"welcome_back": "Welcome back, {name}!",
"items_count": "{count} {count, plural, one {item} other {items}}"
}
// messages/zh.json
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"app_title": "TanStack Ship",
"nav_home": "首页",
"nav_pricing": "定价",
"nav_docs": "文档",
"hero_heading": "更快地构建您的 SaaS",
"hero_subheading": "一个生产就绪的 SaaS 启动套件,支持认证、计费和多语言。",
"cta_start": "开始使用",
"cta_learn": "了解更多",
"footer_copyright": "© 2026 TanStack Ship。保留所有权利。",
"pricing_monthly": "月付",
"pricing_yearly": "年付",
"pricing_save": "节省 {discount}%",
"welcome_back": "欢迎回来,{name}!",
"items_count": "{count} 个{count, plural, other {项目}}"
}
在 React 组件中使用
基础用法
// 构建时由 Paraglide 生成
import * as m from "../paraglide/messages"
function HeroSection() {
return (
<section className="hero">
<h1>{m.hero_heading()}</h1>
<p>{m.hero_subheading()}</p>
<div className="ctas">
<Button>{m.cta_start()}</Button>
<Button variant="secondary">{m.cta_learn()}</Button>
</div>
</section>
)
}
参数与复数处理
function WelcomeBanner({ userName, itemCount }: { userName: string; itemCount: number }) {
return (
<div className="welcome">
<h2>{m.welcome_back({ name: userName })}</h2>
<p>{m.items_count({ count: itemCount })}</p>
{/* English: "Welcome back, Alice!" / "5 items" */}
{/* Chinese: "欢迎回来,Alice!" / "5 个项目" */}
</div>
)
}
语言切换
使用 TanStack Router 搜索参数
// src/routes/__root.tsx
import { useRouter } from "@tanstack/react-router"
function LocaleSwitcher() {
const router = useRouter()
const switchLocale = async (locale: "en" | "zh" | "de") => {
// 设置 Paraglide 的语言
await setLocale(locale)
// 更新 URL 而不重新加载页面
router.navigate({
to: router.state.location.pathname,
search: { locale },
replace: true,
})
}
return (
<select onChange={(e) => switchLocale(e.target.value as any)}>
<option value="en">English</option>
<option value="zh">中文</option>
<option value="de">Deutsch</option>
</select>
)
}
服务端语言检测
// server/middleware/locale.ts
export const resolveLocale = createServerFn({ method: "GET" }).handler(
async ({ request, context }) => {
// 优先级:URL 参数 > Cookie > Accept-Language 头 > 默认值
const urlParam = new URL(request.url).searchParams.get("locale")
if (urlParam && ["en", "zh", "de"].includes(urlParam)) {
return urlParam
}
const cookie = request.headers.get("Cookie")
const cookieLocale = cookie?.match(/locale=(\w+)/)?.[1]
if (cookieLocale && ["en", "zh", "de"].includes(cookieLocale)) {
return cookieLocale
}
const acceptLanguage = request.headers.get("Accept-Language")
if (acceptLanguage?.startsWith("zh")) return "zh"
if (acceptLanguage?.startsWith("de")) return "de"
return "en" // 默认语言
}
)
SEO 集成
hreflang 标签
// 由 Paraglide 的语言标签生成
function HreflangTags() {
const locales = ["en", "zh", "de"]
return (
<>
{locales.map((locale) => (
<link
key={locale}
rel="alternate"
hrefLang={locale}
href={`https://tanstackship.com/${locale}`}
/>
))}
<link rel="alternate" hrefLang="x-default" href="https://tanstackship.com" />
</>
)
}
各语言规范 URL
// TanStack Router 路由配置
export const Route = createFileRoute("/pricing")({
loader: async ({ context }) => {
const locale = context.locale ?? "en"
const messages = await loadMessages(locale)
return {
meta: {
title: messages.page_title_pricing,
description: messages.page_desc_pricing,
canonical: `https://tanstackship.com/${locale}/pricing`,
hreflang: ["en", "zh", "de"].map((l) => ({
lang: l,
url: `https://tanstackship.com/${l}/pricing`,
})),
},
}
},
})
优化的包分割
Paraglide 的编译时方案按语言生成独立的包:
# 构建产物 — 各语言独立缓存
dist/
paraglide/
en.js # 3.2 KB — 英文消息
zh.js # 3.5 KB — 中文消息
de.js # 3.4 KB — 德语消息
仅加载用户选择的语言:
// 根据语言动态导入
// Paraglide 在构建时自动处理
import(`../paraglide/${locale}.js`)
数字与日期格式化
function PriceDisplay({ amount, locale }: { amount: number; locale: string }) {
const formatter = new Intl.NumberFormat(locale, {
style: "currency",
currency: "USD",
})
return <span>{formatter.format(amount)}</span>
// en: "$29.00" | zh: "US$29.00" | de: "29,00 $"
}
function DateDisplay({ date, locale }: { date: Date; locale: string }) {
return (
<time dateTime={date.toISOString()}>
{new Intl.DateTimeFormat(locale, {
dateStyle: "long",
}).format(date)}
</time>
// en: "June 16, 2026" | zh: "2026年6月16日" | de: "16. Juni 2026"
)
}
翻译管理
Inlang IDE 插件
使用 Inlang VS Code 插件进行内联消息编辑:
// 在 VS Code 中,将鼠标悬停在 m.hero_heading() 上即可查看翻译
// 点击即可直接在 IDE 中编辑
function HeroSection() {
return (
<h1>{m.hero_heading()}</h1>
// 按 Cmd+. 打开翻译编辑器
)
}
面向译员的导出/导入
# 将所有消息导出为 CSV 供译员使用
npx paraglide-js export --format csv
# 导入已翻译的消息
npx paraglide-js import translated_messages.csv
生产环境检查清单
- 所有面向用户的字符串均使用 Paraglide 消息函数
- 语言切换不触发整页重新加载
- 语言偏好持久化至 Cookie 和数据库
- 所有支持语言均设置 hreflang 标签
- 规范 URL 包含语言前缀
- 服务端语言检测处理 Accept-Language 头
- 数字和日期格式化使用
IntlAPI(非硬编码) - 翻译文件有审核工作流
- 缺失翻译回退至源语言(英语)
- 如适用,检查 RTL 支持(阿拉伯语、希伯来语)
结语
Paraglide.js 代表了 React 应用 i18n 的下一代方案。其编译时方案消除了运行时开销,同时提供完整的类型安全性和优化的包分割。结合 TanStack Start,语言检测与切换可自然融入服务端函数和路由架构中。关于进入全球市场的更广泛视角,请参阅 SaaS 全球化策略。
Paraglide 对 SaaS 的核心优势:
- 零运行时成本 — 翻译在构建时编译进包
- 类型安全 — 缺失消息在构建时被捕获,而非运行时
- 优化交付 — 用户仅下载其语言的消息
- SEO 就绪 — hreflang、规范 URL 和 sitemap 集成
关于涵盖 hreflang、规范 URL 及跨市场内容本地化的完整多语言 SEO 策略,请参阅 多语言 SEO 完整策略 和 hreflang 标签终极指南。