Sanity Desk - How to Change the Localization Version of the Document?

5 replies
Last updated: Jul 14, 2022
Hello Everyone,
I have a question related to Sanity desk.

We are showing our home page on the initial page. However, when we try to change the localization version of the document, we get blank page, because URL is changed with the translated document's
_id
How can we prevent this behavior?


https://share.getcloudapp.com/OAu8lGXm
Here the code.


export default () =>
	S.list()
		.title("Content")
		.items([
			S.listItem()
				.title("Home Page")
				.icon(GoHome)
				.child(
					S.document()
						.schemaType("page")
						.documentId("frontpage")
						.views([
							S.view.form(),
							S.view
								.component(Iframe)
								.options({ url: (doc) => resolveProductionUrl(doc) })
								.title("Preview"),
						])
				),
			page,
			press,
			blog,
			customer,
			company,
			navigation,
			dictionary,
		]); 
AI Update

I can see the issue you're facing! When using the @sanity/document-internationalization plugin (or similar i18n plugins), translated documents get their own _id with a language suffix (like frontpage__i18n_en, frontpage__i18n_no, etc.), but your desk structure is hardcoded to look for documentId("frontpage"). When you switch languages, the URL changes to the translated document's ID, resulting in a blank page because your structure doesn't account for these ID variations.

Here are a few solutions:

Solution 1: Use a filter instead of hardcoded documentId

Instead of specifying a fixed documentId, use a filter to match the base document and its translations:

S.listItem()
  .title("Home Page")
  .icon(GoHome)
  .child(
    S.documentList()
      .title("Home Page")
      .filter('_id in ["frontpage", "frontpage__i18n_*"] && _type == "page"')
      .child(documentId =>
        S.document()
          .documentId(documentId)
          .schemaType("page")
          .views([
            S.view.form(),
            S.view
              .component(Iframe)
              .options({ url: (doc) => resolveProductionUrl(doc) })
              .title("Preview"),
          ])
      )
  )

Solution 2: Extract the base ID in your preview function

If you want to keep the singleton structure, modify your resolveProductionUrl function to handle the i18n suffix. Most i18n plugins follow a pattern where the base ID is before the __i18n suffix:

function resolveProductionUrl(doc) {
  // Extract base ID by removing __i18n suffix
  const baseId = doc._id.split('__i18n')[0];
  
  // Use baseId or doc._id depending on your preview needs
  // and extract language from doc.__i18n_lang or similar field
  const language = doc.__i18n?.lang || 'en';
  
  return `https://yoursite.com/${language}/${baseId}`;
}

Solution 3: Use the plugin's helper functions

The @sanity/document-internationalization plugin typically provides helper functions like getBaseIdFromId(). Check your plugin's documentation for these utilities:

import { getBaseIdFromId } from '@sanity/document-internationalization'

S.view
  .component(Iframe)
  .options({ 
    url: (doc) => {
      const baseId = getBaseIdFromId(doc._id);
      return resolveProductionUrl({ ...doc, _id: baseId });
    }
  })
  .title("Preview")

The root cause is that your structure needs to be aware that "frontpage" isn't just one document anymore—it's a family of documents with language variations. The first solution (using a filter) is generally the most robust as it lets Sanity's desk handle the document switching naturally.

For more context on localization patterns in Sanity, check out the localization documentation which covers both document-level and field-level approaches.

This is happening because your Studio is looking to display a document whose
_id
is 'frontpage', but since you're using the document-level translations you're switching to a completely different document with a different
_id
when you change the language.
That's correct, but is there a mechanism to prevent this, i.e. to have some function on translation button click or on URL change?
No, unfortunately. The point of a singleton is to show a single document, so that's not going to work with out of the box functionality.
Thank you for support!
Good to now about this limitation

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?