A translated Sanity Studio document can exist, pass an editorial review and still fail to appear on the right language page. People searching Sanity document internationalization , Sanity translation metadata , Sanity GROQ language query , or Sanity localized documents not showing are often dealing with one practical question: which document did the website fetch, and how does the system know that document is the approved translation? The efficient fix begins with document identity and query behavior, not a fresh translation of text that already exists.
Current Sanity localization guidance distinguishes document-level translation from field-level localization. The @sanity/document-internationalization plugin can connect separate language documents through references, while the internationalized-array approach stores multiple language values inside one document. This article concentrates on the first strategy, because its characteristic errors involve separate identities, reference links, publication and GROQ selection. Field-level localization appears only where that contrast helps establish why a query fails.
On this page
Quick answer: prove the document, link and result
Choose one source document and one target language. Record the source ID, target document ID, document type, exact language code, current published status and the URL that should display it. Retrieve the target document by its own identity and by the same language-filtered GROQ logic the website uses. Then check the translation metadata relation connecting siblings. If the intended document exists but the website does not retrieve it, your problem is likely query, route or reference behavior rather than lexical translation.
A reliable investigation answers four questions in order. Does a target document exist? Does it contain the intended language field and approved copy? Is it part of the correct translation group? Can a public query and the page renderer retrieve it? The answers create a narrow fault boundary. Do not change the source text, copy fields again or rebuild the schema until you know which boundary is broken. The shortest path is usually an explicit read-only comparison of two records and one query.
Why one document per language changes the workflow
In document-level localization, English and French content are separate Sanity documents. They can have different titles, body structures, slugs and publication timing. That independence is valuable when a French editor needs to approve a page after the English original has gone live. It also creates a coordination task: the site must recognize the documents as language versions of the same underlying subject without treating them as interchangeable records.
A common mistake is to assume that article._id = 123 remains the same for all languages. With separate documents, the Japanese article has its own ID. What connects the documents is explicit model data or an internationalization metadata record, depending on the chosen architecture. If the frontend tries to invent a translated ID from the English ID, it can fetch the wrong content or nothing at all. QA should inspect the actual model rather than assuming the site follows one platform-wide identity rule.
Separate Sanity Studio’s interface language from content language
Sanity Studio can present interface controls in languages independently of how your content documents are translated. A translator seeing menus in Japanese is not evidence that the open document is the Japanese version of an article. Conversely, a Japanese article can be authored while Studio itself runs in English. Treat the editor interface locale and the document’s content locale as separate state variables whenever someone reports that a translation appears in the wrong place.
Inspect the language field on the actual document and compare it with the wording in title and body. If the field says ja while the content is still English because it was cloned and not translated, the technical routing may be correct while editorial work is unfinished. If the text is Japanese but the field says en, the route can be wrong even though the paragraph itself reads properly. Do not conflate user interface language, document metadata and linguistic content.
The role of the document-internationalization plugin
Sanity’s documentation recommends the @sanity/document-internationalization plugin for projects that keep translated versions as separate documents. It relates them through references and manages a language field according to configuration. In the commonly documented approach, a translation.metadata document links language versions. This provides a discoverable translation group without forcing every article into one giant record containing every language.
The plugin is an authoring aid, not a guarantee that any particular website will query or render the right version. It cannot make a route map sensible if the frontend treats fr and fr-CA as equivalent. It cannot certify an editorial translation that remains an English copy. It also does not remove the need for publication checks. Understand what the plugin creates, then compare that with what application code expects to read. A plugin configuration and a frontend query must describe the same relationship model.
A translation.metadata record is not another language version of the article body. It is a relationship object used to connect documents. When a reviewer searches by the title of the French lesson and sees the target document, that does not prove it has been attached to the English lesson’s translation group. The metadata record may be missing, outdated or referencing the wrong sibling. An unrelated document with similar wording can easily look legitimate in a list view.
For a single case, inspect the metadata record associated with the source and read the referenced document IDs and language codes. Compare each referenced ID with the actual document’s _type, language, title and subject. A correct group should contain the intended siblings, not just any documents with matching language labels. If an incorrect reference points to a different lesson, a language switcher may send the reader to the wrong topic even when each individual document is fluent.
Use an explicit language filter in GROQ
Sanity’s official example queries documents using conditions such as _type == "lesson" && language == $language. The exact field name is configurable and must match the installed schema. This explicit filter is essential because a plain query for the first lesson document may return whichever record the dataset and ordering happen to provide. The correct title in Studio is irrelevant if the page’s production query does not specify the language and appropriate identity.
A simple teaching example is *[_type == "lesson" && language == $language && slug.current == $slug][0]. This is not a universal production query; it illustrates three independent constraints: content type, language and route identifier. If slugs are translated, $slug must refer to the target-language slug. If slugs are shared, the architecture must document that decision. The aim is to make the selection explicit enough that a tester can reproduce the intended record.
A concrete GROQ inspection before changing content
Suppose a Japanese route displays the English version of an article about fractions. Query a small sample of lesson records with their _id, language, title and slug fields. Look for the approved Japanese title, then run the site’s language-filtered query using the exact ja value. If the result is empty, ask whether the record is unpublished, the language code differs or the slug constraint is wrong. If the result is correct, the fault lies farther downstream.
Then retrieve the translation metadata linking the English and Japanese records. The official Sanity documentation shows a pattern using a nested query over translation.metadata and references(^._id), followed by dereferencing the translation values. The relationship query can supply sibling URLs for a language selector. A separate page query selects the actual content. Test them individually. Otherwise a working page may conceal a broken language switcher, or a correct list of siblings may conceal a faulty page fetch.
Why slugs need an explicit locale decision
Some sites keep the same slug for all language documents and put the language in a URL prefix. Other sites translate the slug itself. Both approaches can be made coherent, but the query and route parser must agree. An English source study-plans may correspond to a French plans-de-revision. Copying the English slug into every localized record without a plan can create a route that works internally yet looks unnatural to visitors; translating slugs without updating the lookup logic can lead to 404 pages.
Record the policy for one content type. If route lookup is by localized slug, test the French page using that French value and ensure references point to its actual URL. If the slug is shared, verify that the frontend applies the language filter before selecting a record. Never assume the slug alone uniquely identifies a document across all languages. A duplicate slug within a multilingual collection is often legitimate only when the language is part of the uniqueness condition.
Worked example: the Japanese page appears under the English URL
A lesson page has a correct Japanese document linked to the English original. The site’s router, however, constructs links from the English sibling’s slug and forgets the /ja/ locale prefix. A visitor selects Japanese, sees a brief Japanese flash during client navigation, then lands back on an English route after a reload. The translation has not vanished; the generated link identifies the wrong destination. Editing Japanese copy would only introduce another irrelevant change.
Inspect the language switcher’s output as a real clickable URL, not merely its displayed label. Compare target record language, slug, route prefix, resulting HTML language and page content. Build links from the actual sibling document selected by the relationship query, using the agreed locale URL policy. After the fix, test direct navigation, refresh, copied-link access and internal navigation from another page. A robust translation route must survive a full browser load, not just a state transition inside an app.
Worked example: two French lessons share a language group
Imagine a school publishing two different fractions lessons. An editor duplicates the French version of Lesson A to start Lesson B, but its translation metadata still associates it with Lesson A’s English source. The French Lesson B content itself is accurate. Yet the English button on Lesson B routes to Lesson A, confusing students who believe the language selector keeps them on the same topic. This is a relationship defect, not a translation error.
For the failing page, compare the group membership of both the source and target documents. Read the referenced IDs, not only the titles. Repair the association through the approved Studio workflow or documented metadata process rather than editing raw documents blindly. Then verify the English-to-French and French-to-English paths and inspect any other siblings in the group. A bidirectional check is useful because one directional link can appear correct even while the metadata collection is malformed.
Worked example: a translated document has never been published
The Japanese author finishes a draft and confirms that it looks correct inside Studio. A frontend query aimed at published content returns no Japanese record. A generic fallback function then retrieves the English original. A reviewer concludes that the translation engine failed, but the document never crossed the publication boundary. The correct response is to verify the editorial approval and publish the intended variant through normal controls, not to regenerate the text.
Test using the perspective and dataset access appropriate to the public website. Studio’s draft view can reveal unpublished work that the public client should not expose. Keep a checklist of source ID, target ID, language field, approved status and actual public response. Do not use a preview token on a production page simply to make the missing article appear. That risks exposing incomplete content and obscures the release defect instead of solving it.
Distinguish drafts, published records and preview perspectives
Sanity clients can be configured to query different content perspectives, and authorization also affects what a request can see. A production website should not be assumed to share the editorial view. When a translation is invisible, record which client, perspective, dataset and permissions were involved. If the same query finds the target in an editorial preview but not in public delivery, check publication status before editing text or changing locale filters.
Avoid presenting one API response as universal proof unless it matches the consumer’s configuration. A server-rendered page may fetch through a backend client while a preview panel uses an authenticated Studio client. Those are different observations. For QA, write down which path is being tested and why. A correct publication workflow keeps unfinished target copy private, which means an empty public result can sometimes be the correct behavior rather than a platform malfunction.
Field localization is a different answer to a different design problem
Sanity also supports localized fields or arrays inside one document. Its current guidance describes the internationalized-array plugin, which stores values tagged by language and makes multilingual fields easier to edit. That design differs from document-level localization: there is no separate published article identity per language for each such field. A query selects values from an array rather than selecting a sibling document and following a translation relationship.
Do not mix query recipes. A GROQ expression that expects title[language == $language][0].value works for a suitably modeled localized array, not for a plain string title on separate French and English documents. Conversely, filtering the whole document on a language field cannot select a subfield translation that lives inside one shared document. Before troubleshooting, identify which pattern the specific content type uses. A Sanity site may legitimately combine both strategies in different areas, making documentation essential.
Why a source-language fallback in code can hide missing records
Developers often use a fallback to keep page rendering stable: if a Japanese document lookup returns nothing, fetch the English sibling. That may be appropriate for selected content, but it can also turn a missing target record into a misleadingly normal page. The user has requested Japanese, yet the application has delivered an English body under a Japanese URL. The page may load without errors while failing the actual language promise.
Document the intended behavior for each route. Should an unpublished target return a not-found page, show a clearly labeled English alternative, or render selected shared details? Avoid an invisible fallback that pretends an English response is localized. Add logging or test output that records requested language and resolved document language without exposing private content. This makes missing translations observable and allows editors to prioritize work instead of relying on visitors to report unexpected English paragraphs.
Build a small document-pair ledger
For each high-value article, store the translation group identity, English document ID, target document IDs, language codes, publication states and target URLs. Add the last substantive source revision and local review status. This is not a substitute for Sanity’s own content model; it is a release ledger that a coordinator can audit without navigating several unrelated views. It lets the team see whether a Japanese page is missing because no target exists, because it is still a draft, or because a link is broken.
Keep the ledger lean. A few records for core admissions and course pages reveal more than a massive spreadsheet containing every minor component. Ensure the IDs match the actual dataset and distinguish staging from production. If a language version was intentionally withdrawn, record that decision rather than leaving a mysterious blank cell. Good QA is less about adding bureaucratic fields than about knowing which precise object is supposed to appear when a user chooses another language.
Confirm that the language field is trustworthy
A document may contain a language string that was manually set, created by a plugin or inherited during cloning. It is data, not an automatic linguistic detector. An English document incorrectly labeled fr will satisfy a French GROQ filter. A Japanese translation mislabeled ja-JP when the query expects ja may be invisible. These two failures appear opposite to a visitor but have the same root: the routing identifier and document metadata disagree.
Validate the field against the project’s supported locale list at authoring time, where possible. Make the allowed codes explicit rather than free-form user guesses. During QA, compare the code with representative body text, title and regional expectations. If the content is only a placeholder awaiting translation, label it as such instead of marking it ready. The language field should help the application make deterministic decisions, not serve as a decorative badge.
One question is whether the target document contains all fields expected by the schema. Another is whether the target page communicates all essential meaning from the source. A Japanese page can have nonempty title and body fields but omit the deadline paragraph. Conversely, a schema may permit a shared author reference or universal course ID that should not be duplicated. Treat technical completeness and editorial completeness as complementary checks rather than using a nonempty field count as a quality score.
Use a short structural comparison for key content types: title, summary, headings, steps, warnings, links, images, alt text and conversion actions. Then compare high-risk claims such as dates, prices, conditions and requirements for factual equivalence. The goal is not to force identical sentence lengths or paragraph counts across languages. It is to verify that the target document gives readers a comparable, actionable answer while respecting intentional regional differences.
A practical method for nested references
A course article may reference a teacher profile, related lessons, downloadable worksheets and an assessment notice. Even if the article itself is translated, those references may resolve to source-language documents. Sanity will not automatically decide that every arbitrary relationship should switch to a translated sibling in every custom content model. Application queries and authoring rules determine how related objects are resolved. A good audit therefore follows the relationships that directly affect the page rather than assuming one article-level language flag covers everything.
Take one failing related card. Record the referencing document ID, the referenced target ID, the referenced document’s language and the intended destination. Determine whether the relationship is meant to be shared, localized or dynamically mapped through translation metadata. A teacher’s numerical ID may remain common; a worksheet title or article destination may require a target-language sibling. Fix the narrow lookup policy and retest the user’s journey from card to destination.
Portable Text needs more than plain-string comparison
Long-form Sanity articles often use Portable Text, which can contain blocks, marks, links, references and embedded components. When translating a body, the visible words are only part of the structure. A warning block must remain a warning; a citation should still point to the right source; an inline link should not silently send Japanese readers to an irrelevant English page. Structural fidelity matters especially when the page teaches a procedure or presents safety instructions.
Compare the rendered target page with the source at the level of information roles: headings, callouts, lists, examples, warnings and supporting links. Avoid insisting on identical block counts when language-specific examples improve clarity. Instead, verify that the target retains the claims, conditions and navigation necessary for the intended reader job. If the translation pipeline moved or regenerated Portable Text blocks, inspect references and mark types before concluding that the job is complete.
How to test the language switcher honestly
A language switcher should connect corresponding pages, not merely change the interface label or send every visitor to the translated homepage. The correct test starts on a specific lesson, switches to the available sibling, verifies that the topic remains the same, and switches back. Use actual resolved URLs and full reloads. A language control that works only after navigating through one particular page state is not robust enough for copied links and search-engine visitors.
Also test when a sibling is unavailable. Should that language option be hidden, disabled or direct the user to an explanatory fallback? Each can be a valid product decision, but it must be intentional. A link to a nonexistent translation wastes the user’s effort and may create broken search signals. A link to an unrelated document is worse because it falsely implies semantic equivalence. Record availability based on real published sibling records, not on an assumption that every group contains every supported language.
If a translated lesson has a Japanese title but the HTML page exposes an English description, identify whether the metadata is authored in the target document, held in a shared object or inserted by the frontend template. Sanity does not prevent an application from pulling description text from the source language even when the body query is correct. The same applies to Open Graph fields and canonical or alternate URLs generated outside Studio.
Inspect the HTML delivered to an unauthenticated visitor, not only what appears after client rendering. Verify the content-language declaration, the target title and description, and the actual language-alternate URLs. If a translation is unpublished, do not advertise its missing URL as an available alternate. Use search guidance about localized pages to inform those checks; avoid assuming that hreflang repairs a query that fetched the wrong document in the first place.
Failure mode: query uses a hard-coded language
A frontend component may be developed first for English and include language == "en" directly in its GROQ query. Later, the page’s route supports Japanese but the component still fetches English. The main article might be Japanese while a related sidebar remains English. The fix is to thread the approved locale variable through that specific query, validate it against supported codes and test the component under more than one language.
Do not copy the sidebar’s English content into a Japanese-only field as a workaround. That would mask the wrong query and create maintenance debt. Inspect where the locale is set, whether it is passed through function calls, and whether an omitted parameter defaults to English. A test that captures the query variables alongside its response makes future regressions easier to diagnose. It turns a mysterious “sometimes English” report into a precise missing-input defect.
Failure mode: the query finds the wrong first result
A query ending in [0] is a convenient way to select one record, but it is safe only when preceding filters define the intended set. If a slug is duplicated across language documents and the query omits language, the first match can be whichever record the query returns. The website may appear stable for days and then change behavior after a migration or content insertion. The failure is not random translation quality; the selection predicate is insufficient.
Inspect all records matching the current predicate and count them. If more than one plausible document appears, determine the intended identity rule and add an appropriate language, slug, group or stable ID constraint. Do not rely on the current ordering as a substitute for uniqueness. A well-specified query should make the desired record identifiable without depending on incidental storage order. Add a test with two language siblings that share the same slug to prove the fix.
An editor deletes or replaces an old language document while its translation metadata still references the former version. The new Japanese text exists and may publish, but language navigation reads an outdated relationship. Sometimes the old reference is unresolved; sometimes it still points to a live but stale page. Both cases require inspecting the relationship graph rather than rewriting the target paragraphs.
Record whether metadata contains a valid reference for every supported sibling. Compare the referenced IDs with the entries that current page queries actually select. Repair the relation through the documented workflow, then test both document fetching and alternate links. If the issue followed a migration, examine how IDs and reference integrity were preserved. Do not repair one record by scripting a wholesale replacement without first understanding how the plugin maintains its metadata records.
Failure mode: a draft reference leaks into navigation
An English page has a Japanese draft attached to its translation group. A naive switcher lists every referenced language without checking which siblings are publicly available. The Japanese option appears to visitors, but clicking it leads to a blank page or exposes preview behavior that should remain private. The correct solution separates relationship existence from public availability. A translation link should represent a usable published destination, not just an editorial intention.
Review the query that powers navigation and the publication perspective of its client. Make sure a public response cannot rely on privileged preview credentials. When the Japanese version is not ready, present the agreed fallback behavior without inventing a translated URL. After publication, the link can appear through the normal content refresh. This is a small release-governance check with significant consequences for reader trust and accidental draft exposure.
Failure mode: geographic labels are mistaken for language IDs
A school team may name its routes “Japan,” “France” and “Singapore” while storing language codes such as ja, fr and en. That can be harmless presentation if the mapping is explicit, but trouble begins when these labels are passed directly into queries or treated as interchangeable with ISO-style language strings. A page can show a Japanese flag while using the English document because the routing layer could not resolve Japan to ja.
Keep a clear mapping between site-market labels, URL segments and stored language identifiers. For regional variants, decide whether en-SG is a separate content locale or whether one English document serves several markets. Do not invent regional documents that the content model does not support. Test the map with actual pages and related links. The most useful evidence is the exact value that reached the GROQ filter, not the icon displayed in the interface.
Failure mode: a copied translation has the wrong topic identity
Cloning a complete language document is efficient when templates share structure, but it can leave stale references, slugs, SEO descriptions or translation-group membership. A newly written Japanese science lesson might still point to an English mathematics lesson because it began as a copy. The body translation can be fully correct while the surrounding identity remains wrong. This is why a translation review needs to inspect the record’s relationships, not merely approve prose.
Require a light identity check when creating siblings: subject, parent or group reference, target slug, primary call to action, related items and media ownership. Confirm that the target document is genuinely a version of the intended source. If it is an independent article for a different audience, it may not belong to the same translation group at all. A correct classification prevents the language switcher from promising a correspondence that the content does not possess.
A full worked walkthrough: source to Japanese page
Start with an English lesson titled How Fractions Work. Record its source ID and approved Japanese sibling ID. Check that the target has the expected document type, language: "ja", a Japanese title and a complete body. Inspect the translation.metadata relationship so the English and Japanese siblings belong to the same group. Confirm publication using the content perspective appropriate to the public site. These checks establish that the editorial object is ready.
Next run the exact production-style GROQ query with the Japanese route’s parameters. Verify that the returned _id is the Japanese sibling, not the English source. Review its slug and any referenced card titles. Render the public URL without editor permissions, then inspect title, body, links, document language and language switcher. Finally open the Japanese result in a fresh browser session and switch back to English. Each step tests a different boundary; no single screenshot substitutes for the whole journey.
A compact QA matrix for document-level localization
Use columns for source ID, target ID, target language, translation-group reference, target slug, target publication status, query result ID, public URL and reviewer. Add a field for the last substantive source change if the team maintains translations over time. This is enough to distinguish most document-level defects without exporting the entire dataset. Fill one row for each important source–target pair rather than treating all languages as attributes of one article.
Make each cell an observation. “Japanese okay” is not diagnostic. “Production-like GROQ request with language=ja returned _id=lesson-ja-47; public /ja/lessons/fractions rendered the same title” is diagnostic. Keep permission-sensitive query details in appropriate internal records. Review the matrix after migrations, major route changes and language launches, when schema or references may have changed in ways the editorial interface does not immediately reveal.
A release process for translators and developers
Give translators a source document, intended target code, reference context and an explicit list of fields they may edit. Ask them to flag claims that require subject-matter approval rather than changing policies silently. The editor reviews the target document’s meaning and structure. The content owner confirms it belongs to the correct translation group and can be published. The developer verifies the language-filtered query and rendered route. These are distinct sign-offs; one person need not hold every permission.
For a short update, the workflow can remain lightweight: identify changed source claims, update the relevant sibling, verify the group, publish the target version, and run one route check. For major launches, sample multiple content types and nested references. Avoid adding ceremonial checkpoints that do not test anything. Each check should prove an observable fact about document identity, language, publication or reader-visible behavior.
Compare meaning, not sentence length
Sanity’s content model preserves structured fields, but the target language still requires a human judgment about meaning. A Japanese article may use two shorter sentences where English uses one long sentence. That is not an error. The important question is whether instructions, exceptions, dates, costs and claims survive correctly. If the original says that enrollment is limited to three students, a translation must not imply that three is merely an average class size or an optional suggestion.
Review high-risk statements beside the approved source. Use examples from the actual topic rather than generic language tests: an assessment instruction, a prerequisite, a schedule, or a refund condition. Do not let the technical fact “correct Japanese document retrieved” stand in for content review. A successful localization release requires both the correct document and a trustworthy message; the two checks should inform each other while remaining distinguishable.
Faster debugging through small reproductions
When a complex Japanese page fails, resist exporting every document and trying every plugin setting. Reduce the case to one content type, one source document, one target sibling and one route. Capture the exact GROQ query with placeholders for parameters, run it against a safe environment and record the IDs returned. Check whether a metadata relationship resolves both ways. Only after those tests expand to references, cache and rendering.
A small reproduction is especially valuable when multiple teams participate. The writer can confirm intended target content; the Sanity developer can inspect query and schema; the frontend developer can inspect routes. If all three are given the same pair of IDs and a clear expected URL, disagreements become testable. This is how an apparently complicated localization problem becomes a sequence of short, evidence-based decisions.
Transfer exercise: predict the fault layer
Suppose a French lesson is visible by direct URL but absent from the language selector on its English sibling. Which checks matter first? Confirm the French document’s ID and language field, then inspect the translation metadata group and the switcher’s query. If the French page is valid but the reference is absent, adding French text again will not help. If the reference exists but the switcher excludes unpublished records, verify publication status. Distinguish those scenarios before suggesting a fix.
Now reverse the problem: the selector displays French, but the page itself shows English. Confirm the actual target URL and the language value passed into the page query. Check whether the public query selects a French document or falls back to English. Only then compare text. These two exercises show why navigation and page retrieval are separate reader journeys even when both depend on the same translation group.
Summary: speed comes from selecting the correct sibling
Document-level localization in Sanity works when each target document has a trustworthy language identity, belongs to the intended translation group, is published appropriately and is returned by an explicit content query. A readable translation can still fail at any of those boundaries. Diagnose with IDs and language parameters before editing prose. Confirm both the target page and its language-switcher path, then review the delivered meaning and links. That is a repeatable way to translate quickly without replacing correct text or concealing a broken relationship.
Frequently asked questions
What is the difference between document and field localization in Sanity?
Document localization creates separate records for each language, which can be published independently. Field localization stores language values within one document and selects a value from fields or arrays. The appropriate query and editorial workflow differ.
What does the document-internationalization plugin do?
The documented plugin assists with language fields and references linking translated documents. It does not automatically ensure that an application’s route and GROQ query select the intended published sibling.
Why is my Sanity translation visible in Studio but not on the website?
Check whether the target is a draft, which dataset and perspective the public client uses, and whether the production query filters by the target language and correct slug.
In the documented plugin pattern, it is the record that holds relationships among language versions. Its references support discovering siblings but do not replace the actual target content documents.
Can translated documents use different slugs?
Yes, if the routing architecture supports them. Make the policy explicit and test links with the real target slug and language prefix instead of inventing a URL from the source alone.
Does a correct translation group guarantee a good language switcher?
No. The switcher must still filter for usable published siblings and construct correct URLs. A relationship to an unpublished or unrelated document does not provide a safe public destination.
Should untranslated languages show an English fallback page?
That is a product and editorial decision. If fallback is offered, make the language of the displayed content clear and avoid presenting an English page as a completed target-language translation.
Official sources and further reading