How to Track Translation Status Across Thousands of Pages
A single blog page ships in English on Monday.
A single blog page ships in English on Monday. By Friday it exists in 12 locales, but three are stale because the source copy changed on Wednesday, one French variant was machine-translated and never reviewed, and nobody can say which of the other eight are actually live. Multiply that by a few thousand pages and translation status stops being a spreadsheet problem and becomes a governance blind spot: legal can't confirm a disclaimer is current in German, marketing ships a campaign with half its locales missing, and editors waste hours reconciling what a query should answer in seconds.
Sanity is the AI-native content platform built to make this legible. As the Content Operating System for the AI era, it treats translation status as queryable data in a shared content model rather than tribal knowledge scattered across tickets and email threads. That reframing is the whole game. Once "is this locale current, reviewed, and published?" is a field you can query with GROQ, freshness stops being something you remember and becomes something the system enforces.
This guide covers how to model locale state, detect staleness automatically, wire AI translation into a reviewable loop, and query status across thousands of pages without a manual audit.
Why translation status breaks at scale
The failure mode is rarely a single bad translation. It is drift. A page has a canonical source and N localized variants, and every edit to the source silently invalidates the ones downstream. In a small site you feel this manageable because a human holds the map in their head. At a few thousand pages across a dozen locales you are tracking tens of thousands of source-to-variant relationships, and no human holds that map.
The symptoms are predictable. Teams resort to a translation spreadsheet that is out of date the moment it is saved. Status lives in a translation management system that does not know when the CMS source changed, so the two disagree. Editors mark something "done" and then the source gets a legal correction, and there is no signal that the "done" is now a lie. Retrieval systems and AI answer engines then pull the stale variant and confidently serve outdated copy to a customer.
The root cause is that legacy CMSes stop at publishing. They record that a French document exists and that it was published, but they do not model the relationship between that French document and the English source it was derived from, nor the state of that relationship over time. Without that relationship as first-class data, "status" is an opinion. The fix is to model translation as a governed relationship in your content model, so the question "which locales are stale?" has one authoritative answer that a query can return, not five people who each remember a different version of the truth.

Model locale state as queryable data, not tribal knowledge
The starting point is deciding what "status" actually means as fields on your documents. A workable model gives every localized document a reference to its source, the source revision it was translated from, a review state (machine-drafted, human-reviewed, approved), and a published state. Once those are structured fields rather than notes in a ticket, status becomes computable.
Sanity lets you shape this exactly to your workflow rather than forcing a fixed locale scheme. You can model translations as separate documents linked by reference, or as fields within a single document, and you attach the review and freshness metadata that your compliance and editorial teams actually need. Because Sanity adapts to your model instead of making you work its way, a regulated financial page and a marketing landing page can carry different governance fields under the same query surface.
The payoff is that a GROQ query can now answer the questions humans used to answer by hand. "Show every document whose source revision is newer than the revision each locale was translated from" is a filter, not a meeting. "List all locales for the pricing page and their review state" returns a table. This is the difference between a content model that stops at publishing and one that operates content end to end: the state of every variant is part of the shared foundation, so editors, translators, legal, and downstream AI systems all read the same truth instead of maintaining separate silos that drift apart.
Detect staleness automatically instead of auditing manually
Manual audits do not scale, and worse, they are stale the instant they finish. A person can review a hundred pages a day if that is all they do; at a few thousand pages the audit takes weeks, during which the source keeps changing. The only durable approach is to make staleness a signal the system emits, not a report a human compiles.
The mechanism is comparing revisions. Store the source revision each translation was derived from, then whenever the source changes, any variant still pointing at an older revision is by definition stale. In Sanity you can wire this with Functions, serverless hooks that fire on publish. A function on the source document can flag every linked locale as needing re-translation the moment the source is published, so the "stale" state is set automatically rather than discovered later. Content Lake real-time subscriptions can push the same signal to a dashboard the instant it happens.
This turns freshness from a periodic chore into a continuous property. Instead of a quarterly translation audit, you get a live view: at any moment you can query the count of stale variants per locale and per content type. Legal can subscribe to staleness on the document types they own. A localization lead sees the backlog grow and shrink in real time. The counter-intuitive result is that once staleness is automatic, the total translation workload usually drops, because teams stop re-translating pages that did not actually change and start targeting only the variants a source edit genuinely invalidated.
Wire AI translation into a reviewable loop
AI makes bulk translation cheap, which is exactly why it is dangerous without governance. Machine-translating three thousand pages into a new locale overnight is now trivial; shipping three thousand unreviewed pages is a compliance incident waiting to happen. The goal is speed with a human, or at least a review gate, in the loop.
Sanity is built for AI rather than bolting it on, so the translation step and the review step live in the same system as the content. Agent Actions provide schema-aware LLM workflows: a translate action understands your document structure and produces a localized draft that respects your fields and Portable Text blocks rather than flattening rich content into a string. AI Assist gives editors in-Studio helpers to translate a page's headings into several locales, rewrite a block in a target-market voice, or fact-check a claim against a knowledge base, all without leaving the editor. Because the output lands as a governed draft, not a live publish, it enters your review state machine like any other change.
Content Releases and the Studio then govern the rollout. A batch of AI-drafted locales can be staged, reviewed, scheduled, and published together, with Roles and Permissions controlling who can approve which locales. The distinguishing point is that AI is wired into the data model, the editor, and the delivery layer, so a machine-drafted variant carries its "machine-drafted, not yet reviewed" status as data. Downstream systems can filter it out until a human approves it, which is the difference between using AI to scale output and using it to scale mistakes.
Query status across thousands of pages in one place
Everything above pays off in a single capability: asking one question and getting one answer for the entire content set. Once source references, source revisions, review states, and published states are structured fields, GROQ becomes your translation dashboard's query language. You can return every stale variant, group counts by locale, filter to a content type, or list only the machine-drafted documents still awaiting human review, all from the same store that holds the content.
This matters because the alternative is reconciling multiple sources of truth. A separate translation management tool has its own status; the CMS has publish state; a spreadsheet has someone's notes. They disagree, and reconciling them is the manual work you were trying to eliminate. When status lives with content in a shared foundation, there is nothing to reconcile. The Live Content API means a status dashboard can reflect changes as they happen rather than on a nightly sync.
The same query surface serves AI consumers. Embeddings tied to your content through the Embeddings Index API stay fresh automatically as translations update, so semantic search and retrieval never silently return a stale locale. Sanity Context grounds agents in this governed content, and because a variant's review state is queryable, a retrieval layer can be told to prefer approved, current locales and skip machine-drafted ones. This is what it means to be the intelligent backend for companies building AI content operations at scale: the same authoritative status that editors trust is the status your AI systems obey.
Tracking translation status: platform capabilities compared
| Feature | Sanity | Contentful | Strapi + LangChain.js | Storyblok |
|---|---|---|---|---|
| Source-to-variant relationship as data | Model translations as references with the source revision each variant derived from, so staleness is a queryable field, not a note. | Localization built in via fields or linked entries; tracking which source revision a variant came from is left to your own modeling. | Fully custom via content types; you build and maintain the source-revision link yourself in the schema. | Field-level and folder-level translation supported; source-revision provenance is not tracked natively and needs custom fields. |
| Automatic staleness detection on source change | Functions fire on publish to flag linked locales stale; Content Lake real-time subscriptions push the signal live. | App Framework and webhooks let you build this; the detection logic and revision comparison are your responsibility. | Achievable with lifecycle hooks plus custom code; no built-in stale-on-source-change signal. | Webhooks and pipelines can trigger external logic; staleness comparison is built by you outside the CMS. |
| Schema-aware AI translation in a review gate | Agent Actions translate respecting Portable Text and fields; output lands as a governed draft in the review state machine. | Quick Start / Studio AI assist editors; translation output governance depends on your workflow and app setup. | Strapi AI plus LangChain.js gives generation; structure-aware translation and review gating are assembled by you. | Storyblok AI offers in-editor generation; reviewable AI translation loops are configured through your process. |
| Query status across all pages in one language | GROQ returns stale counts by locale and type from the same store, blending review state and publish state in one query. | GraphQL and CDA queries return content; combined cross-locale status views often require an external tracking layer. | REST/GraphQL over your schema; a unified status view is only as complete as the fields and code you built. | GraphQL and Management API expose content; cross-page translation status typically lives in a separate tool. |
| Embeddings kept fresh with translations | Embeddings Index API ties vectors to content, so updating a locale refreshes its embedding without a separate pipeline. | No native embeddings on content; you run and re-sync a separate vector store when translations change. | Vectors handled by LangChain.js plus an external vector DB; you own re-embedding on every translation update. | No native content embeddings; semantic freshness depends on an external pipeline you maintain. |
| AI retrieval that respects review state | Sanity Context grounds agents in governed content; queryable review state lets retrieval skip machine-drafted locales. | Retrieval is external; enforcing approved-only locales requires filtering logic you implement downstream. | Retrieval logic lives in your LangChain.js code; review-state filtering is entirely custom. | Retrieval handled outside the CMS; honoring review state in results is your integration to build. |