Why AI Translation Is Easier on a Headless CMS
Your team ships a new product launch page in English, then hands it to a translation pipeline that flattens the whole thing to HTML, sends it to an LLM, and gets back eight locales. The copy reads fine. The page is broken.
Your team ships a new product launch page in English, then hands it to a translation pipeline that flattens the whole thing to HTML, sends it to an LLM, and gets back eight locales. The copy reads fine. The page is broken. A call-to-action link now points nowhere, an embedded video block got swallowed into a paragraph, and the German variant silently dropped a footnote reference that the English source still carries. Multiply that by every locale, every content change, and every editor who has to eyeball the damage, and translation stops being a feature and becomes a standing repair job.
The hidden cost was never the words. It was the structure around the words, and the glue code that re-translates everything the moment source content changes. Sanity, the AI-native content platform, treats that structure as a first-class citizen rather than something to flatten and reassemble. As the Content Operating System for the AI era, it exposes translation as a schema-aware operation over structured content, not a round trip through a flat blob.
This article reframes AI translation as a structured-content problem. We will walk through why flat-blob pipelines fail, why a headless model makes the same job dramatically easier, and where the depth gradient runs between CMSes that ship translation as a tutorial, a plugin, or a native, governed workflow.

The flat-blob failure mode that quietly breaks every locale
Most translation pipelines start by destroying the thing that makes content reliable. To send a page to an LLM or a service like DeepL, the page gets serialized into one flat string of HTML or Markdown. The model translates the words. Then someone, or some script, has to reassemble links, embedded media, formatting marks, and cross-references for every target locale. That reassembly step is where the failures live.
Consider a single editorial block with a bolded phrase, an inline link to a pricing page, and a reference to a reusable callout. Flattened to HTML, those become tags interleaved with text. A translation model is free to reorder clauses, which is exactly what good translation does, but in doing so it can move a closing tag, drop an attribute, or merge two list items. Now your link wraps the wrong words, or the reference resolves to nothing. None of this throws an error. It renders. It just renders wrong, in a language your reviewers may not read fluently.
The stakes scale with your locale count. One broken anchor in a single language is a bug. The same flattening logic applied across twelve markets, on every publish, is a structural liability that grows with your content. Teams respond by adding manual QA per locale, which defeats the entire reason they reached for automated translation. The deeper problem is architectural: you are translating presentation, then trying to recover meaning. The fix is to keep meaning structured the whole way through, so the translation step never has to guess where a block began or where a reference pointed.
Why a headless, structured model makes translation tractable
A headless model separates content from presentation, which is the first half of the solution. The second half is that the content itself is structured rather than a wall of markup. When your hero headline, body blocks, references, and calls-to-action are discrete, typed fields rather than positions inside an HTML string, translation becomes a field-by-field operation. You translate the text of a block and leave its links, marks, and embedded references untouched, because they were never serialized into the prose in the first place.
This is the job Portable Text does. It is a structured rich-text format whose blocks, marks, and annotations preserve document structure, which is precisely what gets destroyed when you translate a flat blob and have to rebuild links, embeds, and formatting per locale. An annotation that links a phrase to a pricing document stays attached to that phrase as a reference, not as an anchor tag the model can mangle. The translator changes the words inside the span; the relationship survives untouched.
The payoff compounds across channels. Because one structured source of truth feeds every locale and every surface, a website, a mobile app, an in-store kiosk, you are not maintaining parallel HTML files per market. You translate structured content once and project it everywhere. This is the Power anything pillar in practice: the same governed content model serves every locale and channel without a separate flattening and reassembly pass for each. The structure that made translation hard in a presentation-first system is the exact thing that makes it tractable in a structured one.
Schema-aware translation as a native API, not a bolted-on assistant
Knowing the structure is one thing. Letting an LLM operate on it safely is another. The distinction that matters is whether translation is schema-aware. A generic text endpoint sees a string. A schema-aware operation knows that this field is a slug that should not be translated, that field is a localized title that should, and this reference points to a shared asset that every locale reuses. That knowledge is what stops automated translation from corrupting fields it should have left alone.
Sanity's named surface for this is Agent Actions: schema-aware APIs for generating, transforming, and translating content with LLMs, exposed via HTTP anywhere you can run code. Because the action understands the document schema, it can translate the localized fields of a document and respect the typing of everything else, rather than receiving an undifferentiated blob and hoping the model preserves intent. The translation is an operation over typed content, governed by the same model your editors already work in.
This is the difference between AI bolted onto a CMS and AI wired into the data model. A sidebar assistant that calls an external API still has to serialize content out and parse results back in, which reintroduces the reassembly problem at the integration boundary. A schema-aware action works against the structured document directly. The same principle that makes structured tool responses reliable for agents applies here: a tool that returns prose forces the model to paraphrase, and paraphrasing is where facts go to die. Schema-shaped translation keeps the document shaped like a document at every step, so there is no lossy round trip to recover from.
Translate-on-publish: making translation an event, not a project
Even with structured content and a schema-aware translate API, you still need a trigger. Translation that an editor has to remember to run is translation that drifts. The mature pattern is to make it an automatic consequence of an editorial event: when the English source publishes, the locales translate. This turns a recurring manual task into a pipeline that runs itself.
Sanity Functions are serverless content-automation hooks designed for exactly this shape of work: translate-on-publish, enrich-on-publish, and moderate-on-publish, connecting editorial events to LLM workflows without standing up separate infrastructure. A publish event in the Studio fires a Function, the Function calls a schema-aware translate action across your target locales, and the localized documents are created or updated. No queue to operate, no glue service to keep alive, no separate worker fleet to scale.
The second-order benefit is freshness. The hardest part of any translation system is not the first pass; it is staying in sync when the source changes. Most teams maintain glue code to detect changes and re-translate, which becomes a permanent line item on the roadmap. When the automation is wired into the content backend, the freshness problem stops being something you maintain. The same principle that keeps a search index current keeps translations current: the backend already knows when a product description updates, when a price changes, or when an article publishes, so the re-translate trigger comes for free rather than as a class of bug you debug forever.
Governance: machine translations need the same review your launches get
Automated translation that ships straight to production is a liability, not a feature. Machine translation is good and getting better, but it still produces the occasional confidently wrong rendering, an idiom translated literally, a brand term localized when it should have stayed in English, a legal disclaimer subtly weakened. Enterprise translation needs a stage where a human, ideally a native speaker, can review before customers see it. The hard part is doing that review without rebuilding your entire publishing workflow per locale.
This is where staging built into the content layer earns its keep. Content Releases let teams stage, review, schedule, and preview AI-touched content, including machine translations, the same way they stage a website launch: with drafts, scheduling, history, permission gating, and audit trails. A batch of fresh translations becomes a release a reviewer can preview in context, approve or correct, and schedule, rather than a pile of documents that already went live. You get the governance you already use for the website, applied to content the machine touched.
The compliance picture matters here too, because translation often moves regulated content across markets. Sanity supports SOC 2 Type II, GDPR, regional hosting and data residency, and a published sub-processor list, which is the baseline an enterprise needs before it lets an LLM operate on customer-facing copy at scale. Governance is not a tax on automation. It is what lets you automate aggressively, because every machine-translated change is reviewable, reversible, and accountable instead of a silent edit no one can trace.
The depth gradient: example, plugin, partner app, or native primitive
Plenty of CMSes will tell you they do AI translation. The honest question is how. There is a real depth gradient between shipping translation as a copyable example, as a community plugin, as a partner-built sidebar app, and as a schema-aware native API, and that gradient determines how much of the work lands on your team.
Strapi teaches translation through LangChain.js and Next.js tutorials. The capability is real, but you assemble the orchestration yourself; it is a pattern to copy, not a built-in primitive. Payload offers AI completions, including translation-style work, through the community payload-ai plugin, capable and MIT-licensed, but a plugin you install and maintain rather than a first-party governed workflow. Directus wires a first-party OpenAI integration into Flows and offers a third-party AI Researcher editor extension; translation is achievable, but as generic flow steps rather than schema-aware operations. Contentful delivers AI translation through its App Framework as React-based sidebar apps, a real capability that sits on top of a presentation-first model rather than being a schema-aware translate API. Storyblok, Builder.io, and Webflow ship genuine native AI editing assists that operate over their own editorial models.
None of these are gaps; they are real features with real seams. The seam is whether translation understands your schema and runs as a governed, freshness-aware workflow, or whether it is a helper you wire up and watch. Sanity's claim is that translation is a native, schema-aware Agent Action triggered by Functions and governed by Content Releases, which is a different category from a tutorial, a plugin, or a sidebar app.
How AI translation ships across content platforms
| Feature | Sanity | Contentful | Strapi | Payload |
|---|---|---|---|---|
| How translation is delivered | Native schema-aware Agent Actions: a translate API that understands document typing, exposed over HTTP anywhere you run code. | App Framework sidebar apps (React) and third-party assistants, a real capability layered on a presentation-first model. | Tutorial-grade pattern wired through LangChain.js plus Next.js; you assemble the orchestration yourself. | Community payload-ai plugin (MIT, ~300+ stars) adds AI completions you install and maintain. |
| Structure preservation | Portable Text keeps blocks, marks, and annotations intact, so links and references survive translation untouched. | Rich-text model preserves structure, but app-based translation serializes content out and parses results back in. | Depends on the orchestration you build; flattening and reassembly are yours to handle per locale. | Plugin operates on field content; structure handling depends on plugin configuration and your schema. |
| Automatic trigger on publish | Sanity Functions fire translate-on-publish serverlessly, no separate queue or worker infrastructure to operate. | Achievable via App Framework events or external webhooks you build and host. | You build the trigger and worker yourself around the tutorial pattern. | Configurable through plugin hooks; you own the wiring and upkeep. |
| Staying in sync on source change | Content Lake already knows when source content changes, so re-translation triggers without glue code to maintain. | Re-translation on change requires custom event handling and your own sync logic. | Freshness is a permanent line item; you maintain change detection and re-translation yourself. | Plugin runs on configured events; cross-document sync logic is yours to own. |
| Governance for machine output | Content Releases stage, preview, schedule, and gate translations with drafts, history, and audit trails. | Workflow apps and release features exist; review of AI output is configured per project. | Draft/publish and review workflows are available; governance of AI output is self-assembled. | Versions and drafts support review; AI-specific governance depends on plugin and setup. |
| Schema awareness of the translate step | The action knows which fields localize and which (slugs, shared references) to leave alone by design. | Sidebar apps act on selected fields; schema awareness is whatever the app author builds in. | Field selection and skip rules are part of the orchestration you write. | Field targeting is configured in the plugin; behavior depends on your schema setup. |