为基于经典 Vite 技术栈的 Lovable 应用做本地化,最佳方式是把硬编码字符串提取到提交至仓库的 Lingui PO 目录中,而不是外挂运行时翻译挂件。你的 Lovable 应用是客户端渲染的 React SPA,没有可挂接的服务端渲染,因此可持续的方案是让翻译文件放在自己的仓库里,随构建一同发布。globalize.now 是 AI 驱动的本地化基础设施,负责提取并在每次 Git 推送时保持这些目录同步,配置一次,从此不必再手动管理语言文件。


你的 Lovable 应用用的是哪种技术栈,经典 Vite 还是 TanStack Start?

先看一下文件树,因为 Lovable 提供两种不同的技术栈,各自的 i18n 配置方式也不同。如果你看到 src/pages/Index.tsx、src/main.tsx 和 vite.config.ts,说明你用的是经典的 Vite + React SPA 技术栈,这是 Lovable 的默认选项。TanStack Start 项目则包含 src/routes/、src/router.tsx、src/routeTree.gen.ts 和 src/server.ts。

技术栈在创建项目时就已确定,之后无法切换,所以这个选择其实早已定好。经典 Vite 技术栈完全在浏览器中渲染,默认不做服务端数据获取。本文针对的就是这种经典 Vite SPA。如果你的文件符合 TanStack Start 的结构,请改看我们的 Lovable 的 TanStack Start i18n 指南,因为服务端渲染会改变翻译的加载方式。


为什么 Vite SPA 的 Lovable 应用总被 i18n 工具忽略?

因为工具厂商的注意力转向了 Lovable 较新的 TanStack Start + SSR 默认方案,经典 Vite SPA 反而被冷落,尽管它仍是最常见的 Lovable 技术栈。过去几个月,面向 Lovable 的本地化工具,包括 Lovalingo、Intlayer 和 Paraglide,都把指南转向了带服务端渲染的 TanStack Start。

这就留下了空白。客户端渲染的 SPA 有着 SSR 指南完全不考虑的现实约束:没有服务端渲染来注入已翻译的标记,整个 bundle 在浏览器中加载,任何延迟加载的脚本都会盖在英文 UI 之上。好消息是,经典技术栈有一套干净且支持完善的方案,只是大多数开发者从没听说过,因为声量最大的工具都在追逐另一套技术栈。


已提交的翻译目录与运行时翻译插件有什么区别?

已提交的翻译目录是检入你仓库、在构建时打包的翻译文件;运行时插件则是第三方脚本,在英文 UI 加载完成后才在浏览器里替换文本。这个差别决定了 Vite SPA 的三件大事。

第一,闪烁与布局偏移:插件先显示英文再改写,用户会看到明显的切换,布局也可能跳动;已提交的翻译目录则在首次渲染时就呈现正确的语言。第二,可索引性:打包进构建产物的字符串属于源码的一部分,而插件注入的文本加载较晚,爬虫更难读取。第三,所有权:已提交的翻译目录是你仓库里的自有文件,不依赖任何外部服务保持在线,你的应用就能一直讲德语或日语。


如何使用 Lingui 为 Lovable Vite 应用添加 i18n?

引入 Lingui 作为 i18n 层,包裹字符串,再让它的 Vite 插件编译目录。Lingui 是轻量级 i18n 框架,提供专用的 Vite 插件和基于 PO 的目录格式,正好契合客户端渲染的 SPA。

首先安装依赖包。Lingui 将 CLI、Vite 插件和 React 运行时拆分为不同的包:

npm install --save-dev @lingui/cli @lingui/vite-plugin @rolldown/plugin-babel
npm install @lingui/core @lingui/react

接着在 vite.config.ts 中注册插件,并添加 lingui.config.ts,将其指向源码和 locales 文件夹:

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { lingui } from "@lingui/vite-plugin";

export default defineConfig({
  plugins: [react(), lingui()],
});
// lingui.config.ts
import { defineConfig } from "@lingui/cli";

export default defineConfig({
  locales: ["en", "de", "fr"],
  sourceLocale: "en",
  catalogs: [
    {
      path: "src/locales/{locale}/messages",
      include: ["src"],
    },
  ],
});

然后用 Trans 宏包裹 JSX 中的硬编码文本,不要留下裸字符串:

// before
<h1>Create your account</h1>

// after
import { Trans } from "@lingui/react/macro";
<h1><Trans>Create your account</Trans></h1>

现在提取。CLI 会扫描 src 目录,并为每个 locale 生成一个 PO 目录,例如 src/locales/en/messages.po:

npx lingui extract

为每种语言填写 msgstr 字段,或者把这一步交给自动化层(见下一节)。你不需要单独运行编译命令,因为 @lingui/vite-plugin 会在开发和构建时即时编译 PO 目录。

最后,通过在运行时激活 locale 来添加语言切换器:

import { i18n } from "@lingui/core";
i18n.activate("de");

这就是经典 Vite 技术栈的完整流程:安装、包裹、提取、翻译、切换。除译文本身外,其余一切都在你的仓库里。


globalize.now 如何在每次推送时自动完成这些工作?

globalize.now 监听你的仓库,在每次 Git 推送时替你完成手动的提取和填充步骤。它会找出 Lovable 代码库中新增的硬编码字符串,生成 Lingui 所需的键和 PO 条目,产出译文,并把更新后的目录提交回仓库,所以你的 src/locales 文件夹始终是最新的,无需运行任何命令。

在 globalize.now 连接一次仓库,它就会开始监听。如果想从编辑器中配置,可以安装这些 Skill:

npx skills add globalize-now/globalize-skills

具体到 Lovable,在工作区中添加 lovable-i18n Skill,然后提示 Lovable 配置 i18n。运行时仍是 Lingui,应用的渲染方式不会有任何变化。变化的是,你不用再盯着语言文件了。我们的 vibe coder 工作流 和 开发者配置 都基于同一套模式:配置一次,每次推送自动同步。

对独立开发者来说,定价很简单:每个工作区每月 €20,不按席位收费,也不按语言收费,另加你实际用到的翻译用量。新工作区注册即送 €5 额度,无需绑卡,足够把一个小型应用从头到尾翻译一遍。


该改用运行时插件吗?Lovalingo 的教训

如果你希望翻译不受单一供应商存亡的影响,就不要。运行时翻译插件一开始很方便,但它让你的应用依赖别人的服务器保持在线,而这种依赖有真实存在的失败场景。

Lovalingo 是 Lovable 开发者常用的一款运行时插件,已宣布将于 2026 年 8 月 31 日关闭,不再接受新用户注册,也没有指定的继任者。它自己的迁移建议是让用户转向项目自有的国际化,这正是本文介绍的已提交翻译目录方案。插件供应商一旦关停,注入的翻译就会失效,UI 退回英文。而仓库里的文件不会。如果你已经在用插件,可以参考我们的 Lovalingo 关停迁移指南 完成迁移;而 每次推送都会破坏翻译的问题 也正是已提交的翻译目录更适合 AI 构建应用的原因。

globalize.now 把硬编码的应用文案转换为可直接翻译的语言文件,并在你持续发布时保持同步更新。

免费试用 globalize.now