skip to content
Logo I like chickens.
they're persistent.
Faust
you better try google.com...
EN

Astro博客的多语言适配

/

最近给博客加了个英文版,因为不想引入太复杂的 i18n 框架,所以采用了最朴素的方案:直接分目录。

1. 目录结构

简单粗暴,直接在 content 下面新建对应的 en 目录。 post 放中文,post-en 放英文。

src/content/
├── note
├── note-en # 新增
├── post
└── post-en # 新增

2. 配置 Collection

src/content.config.ts 里直接把原来的 schema 复用一下就行。

// 英文翻译文章集合(复用 post schema)
const postEn = defineCollection({
loader: glob({ base: "./src/content/post-en", pattern: "**/*.{md,mdx}" }),
schema: ({ image }) =>
baseSchema.extend({
// ...配置和中文版一样
}),
});
// 还有 noteEn 同理
export const collections = { post, note, postEn, noteEn };

3. 路由与工具

手写了个 i18n.ts 来处理路径。 核心逻辑就是判断 URL 是不是以 /en 开头。

export function getLocaleFromPath(path: string): Locale {
if (path.startsWith("/en/") || path === "/en") {
return "en";
}
return "zh-CN";
}

切换语言的时候,简单的字符串替换:

export function getLocalizedPath(path: string, targetLocale: Locale): string {
if (targetLocale === "en") {
return `/en${path}`;
}
return path.replace(/^\/en/, "") || "/";
}

4. 翻译

UI 上的文本(像“首页”、“关于”这些)搞了个简单的字典对象。

至于文章内容,懒得手动翻,直接写了个脚本调 DeepLX。 部署的时候自动跑,检测到新的中文文章就自动生成英文版放进 post-en。 虽然会把 build 时间拖长一点(毕竟要一个个请求接口),但胜在省心,全自动。

具体实现拆成了两个文件:

  • src/integrations/astro-translate.ts:Astro 集成入口,在执行 npm run build 打包的时候自动运行,负责翻译,和写入翻译文件。
  • src/utils/translate.ts:负责干活的工具类,封装 DeepLX API 调用。

集成脚本大概长这样:

src/integrations/astro-translate.ts
import type { AstroIntegration } from "astro";
import { translateMarkdown } from "../utils/translate"; // 核心逻辑在这
export function astroTranslate(options: { enabled?: boolean } = {}): AstroIntegration {
const { enabled = true } = options;
return {
name: "astro-translate",
hooks: {
// 在 config 完成后、content 同步前执行,确保生成的文件被正确读取
"astro:config:done": async ({ logger }) => {
if (!enabled) return;
// 检查环境变量
const apiKey = process.env.DEEPLX_API_KEY;
// ... 遍历文件、调用 translateMarkdown、写入文件 ...
},
},
};
}

工具里就是纯粹的 fetch 请求,API 地址格式是 https://api.deeplx.org/<api-key>/translate

src/utils/translate.ts
export async function translateText(text: string, options: TranslateOptions) {
const { apiKey } = options;
// API URL 格式:https://api.deeplx.org/<api-key>/translate
const apiUrl = `https://api.deeplx.org/${apiKey}/translate`;
const response = await fetch(apiUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text, source_lang: "ZH", target_lang: "EN" })
});
// ...
}

只要在 Vercel 环境变量里塞个 DEEPLX_API_KEY 就行。


BTW,看着地址栏的 /en/ 感觉还挺像模像样的。 收工。