无头CMS多语言支持是一个未解决的问题。
Sanity有国际化插件。Contentful有语言环境。但它们都不翻译您的内容——只是以多种语言存储。填充这些语言槽仍然是手动过程。导出英文内容,使用会破坏富文本或JSON结构的翻译工具翻译,修正输出,导入回去,针对每种语言重复。对于定期发布的活跃内容团队,这种工作流程无法扩展。对于大多数较小的设置,这种流程根本不存在,意味着内容根本不会被翻译。
无头CMS架构将内容管理与内容交付分离。这有利于灵活性。但也造成了一个空白:CMS存储语言变体,但没有任何东西填充这些语言变体的翻译内容。您必须自己构建这层。
大多数团队最终处于两种情况之一:手动翻译内容,复制到DeepL再粘贴回来(慢、易错、无法扩展),或者编写自定义集成调用翻译API并需长期维护。两者都不是好方案。PolyLingo是一个干净的第三种选择。
PolyLingo是您的CMS缺失的翻译层。
PolyLingo直接集成到您的CMS发布工作流程。设置一个内容发布时触发的Webhook,将内容传给PolyLingo,接收每种语言的翻译版本,再写回CMS。对于Sanity,只需几行服务器操作代码。对于Contentful,是一个Webhook处理程序。对于自定义设置,是一个HTTP调用。翻译模型理解您的内容格式——Markdown、HTML、JSON、富文本——并始终保留结构。
该模式在每个CMS中一致:获取源语言内容,调用PolyLingo API并传入所有目标语言,通过CMS管理API写回翻译内容。此过程可作为构建时脚本、CI任务或Webhook处理程序运行——根据您的工作流程选择。
PolyLingo支持Markdown、HTML和纯文本,因此适用于您的CMS用于富内容的任何格式。结构化字段(标题、正文、摘要)可单独翻译,给予您对翻译字段的细粒度控制。
Sanity + PolyLingo
Sanity的文档国际化插件为每个语言环境创建链接的文档变体。下面的脚本获取英文基础文档,并自动为每个目标语言创建翻译变体。
支持文档级i18n模式(每个语言一个文档)和字段级模式(所有语言在一个文档中)。字段级模式请循环字段而非文档。
// scripts/translate-sanity.mjs
// Fetches published posts and translates each to all target languages
import { createClient } from '@sanity/client'
const sanity = createClient({
projectId: process.env.SANITY_PROJECT_ID,
dataset: 'production',
token: process.env.SANITY_TOKEN,
apiVersion: '2024-01-01',
useCdn: false,
})
const posts = await sanity.fetch(`*[_type == "post" && __i18n_lang == "en"]`)
for (const post of posts) {
const response = await fetch('https://api.usepolylingo.com/v1/translate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.POLYLINGO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
content: post.body_markdown,
format: 'markdown',
targets: ['es', 'fr', 'de', 'ja', 'zh'],
}),
})
const { translations } = await response.json()
for (const [lang, content] of Object.entries(translations)) {
await sanity.create({
_type: 'post',
__i18n_lang: lang,
__i18n_base: { _type: 'reference', _ref: post._id },
title: translations[lang + '_title'] || post.title,
slug: { current: `${post.slug.current}-${lang}` },
body_markdown: content,
})
}
}Contentful + PolyLingo
Contentful将语言变体作为同一条目的字段存储。下面的脚本使用Contentful管理API获取英文条目,翻译后直接写入语言特定字段——无需手动复制粘贴。
Contentful使用BCP 47语言代码(例如es-ES而非es)。请相应映射PolyLingo的ISO 639-1代码到您的Contentful语言环境配置。
// scripts/translate-contentful.mjs
// Translates Contentful entries to all target locales
import contentful from 'contentful-management'
const client = contentful.createClient({
accessToken: process.env.CONTENTFUL_MANAGEMENT_TOKEN,
})
const space = await client.getSpace(process.env.CONTENTFUL_SPACE_ID)
const env = await space.getEnvironment('master')
const entries = await env.getEntries({ content_type: 'blogPost', locale: 'en-US' })
for (const entry of entries.items) {
const enBody = entry.fields.body['en-US']
const response = await fetch('https://api.usepolylingo.com/v1/translate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.POLYLINGO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
content: enBody,
format: 'markdown',
targets: ['es-ES', 'fr-FR', 'de-DE'],
}),
})
const { translations } = await response.json()
for (const [locale, content] of Object.entries(translations)) {
entry.fields.body[locale] = content
}
await entry.update()
await entry.publish()
}Webflow + PolyLingo
Webflow的本地化API(CMS和商务计划可用)支持语言特定字段内容。下面的脚本获取CMS集合项,翻译HTML正文字段,并通过Webflow v2 API写回每个语言变体。
Webflow将富文本字段存储为HTML。PolyLingo的HTML翻译保留所有Webflow生成的标记——自定义类、属性和嵌入元素——不受影响。
// scripts/translate-webflow.mjs
// Webflow Localization API + PolyLingo
const headers = {
'Authorization': `Bearer ${process.env.WEBFLOW_API_TOKEN}`,
'accept-version': '2.0.0',
'Content-Type': 'application/json',
}
// Fetch English CMS items
const itemsRes = await fetch(
`https://api.webflow.com/v2/collections/${process.env.WEBFLOW_COLLECTION_ID}/items`,
{ headers }
)
const { items } = await itemsRes.json()
for (const item of items) {
const response = await fetch('https://api.usepolylingo.com/v1/translate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.POLYLINGO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
content: item.fieldData['body-html'],
format: 'html',
targets: ['es', 'fr', 'de'],
}),
})
const { translations } = await response.json()
// Write translated content back to Webflow locale fields
for (const [lang, content] of Object.entries(translations)) {
await fetch(
`https://api.webflow.com/v2/collections/${process.env.WEBFLOW_COLLECTION_ID}/items/${item.id}/locales/${lang}`,
{ method: 'PATCH', headers, body: JSON.stringify({ fieldData: { 'body-html': content } }) }
)
}
}PolyLingo为无头CMS用户带来的功能
- ✓Sanity — 通过Webhook在发布时翻译,写回文档语言环境
- ✓Contentful — 英文语言环境更新时自动翻译条目
- ✓Webflow — 通过API翻译CMS集合项
- ✓任何带API的无头CMS — 集成模式相同
- ✓富文本、Markdown和HTML均正确保留
- ✓一次请求支持全部36种语言 — 无需逐语言调用
- ✓支持任何带管理API的CMS
- ✓每次发布都可重新翻译内容——无需手动同步
标准多语言CMS工作流程
用源语言撰写内容
用英文(或您的源语言)创建并发布内容。您的CMS将其存储为权威版本。您无需更改编辑工作流程。
触发翻译脚本
手动运行脚本、定时运行,或通过CMS内容发布事件触发的Webhook运行。脚本每个文档调用PolyLingo一次,传入所有目标语言,然后一次性写回所有翻译。
部署——翻译内容上线
您的前端照常从CMS读取语言特定内容。无需更改前端代码。翻译内容会在对应语言路由正确显示。
适用对象
Sanity或Contentful的内容团队
您的编辑人员用英文发布。翻译内容自动出现在所有语言环境,无需编辑团队使用翻译工具。
构建多语言网站的代理机构
您构建的每个客户网站都需要多语言支持。PolyLingo为您提供可复用、可计费的集成,适用于您技术栈中的任何无头CMS。
拥有本地化产品内容的电商
产品描述、分类页面和博客内容——发布时自动翻译。结合语言特定定价,提供完整本地化购物体验。
关于无头CMS多语言的常见问题
PolyLingo支持这里未列出的CMS吗?
支持。任何带管理API的CMS都可以用相同模式集成——获取内容,调用PolyLingo,写回。Prismic、Storyblok、DatoCMS、Strapi、Ghost和Directus都有管理API,适用此方法。上面Sanity、Contentful和Webflow的集成示例说明了该模式。
我可以翻译带嵌入图片和链接的富文本吗?
可以。HTML翻译保留所有嵌入元素,包括图片(正确处理src和alt属性)、链接(保留href,翻译链接文本)和iframe。唯一例外是明确标记为不翻译的内容——例如代码块永不翻译。
如何处理不应翻译的内容?
对于带有不可翻译字段(slug、日期、技术标识符)的结构化内容,只发送需要翻译的字段。对于富文本中混合可翻译和不可翻译部分,使用HTML格式——PolyLingo会自动翻译文本内容,同时保留代码块和其他结构元素。
如果我的CMS有嵌套内容类型怎么办?
对于深度嵌套内容(文档引用其他文档),请独立翻译每种文档类型。这样避免循环引用,并让您清晰控制翻译内容。文档间引用由CMS维护——PolyLingo只处理字段内容,不触及文档关系。
源内容变更时如何保持翻译同步?
推荐模式是在每次发布事件通过CMS webhook触发翻译脚本。确保源内容变更时翻译内容同步更新。对于更新频率较低的内容,夜间定时运行脚本或每次生产部署前运行同样有效。
有没有办法标记翻译为“需要审核”而非自动发布?
这取决于您的CMS。Contentful和Sanity都支持草稿状态——您可以将翻译内容写为草稿而非发布,允许人工审核后再上线。上面脚本示例使用立即发布;您可修改最后一步改为创建草稿,实现审核流程。