Structure Builder breaking sanity-plugin-intl-input translate features

13 replies
Last updated: Feb 18, 2022
I am using sanity-plugin-intl-input and I need to use structure builder to organize my documents to be more user friendly. My issue is that whenever I attempt to follow the structure builder documentation , the translate features in the studio no longer show. The sanity-plugin-intl-input structure instructions do not seem to line up with any examples I can find. How can I add basic structure builder features to organize documents translated with sanity-plugin-intl-input ?
If transitioning to the new
document-internationalization will help, I can do that, but I did not see anything in there that addresses my specific issue.
AI Update

The key issue you're encountering is that when you customize the Structure Builder, you need to work with the getFilteredDocumentTypeListItems() function rather than replacing it entirely. This function is what makes the internationalization plugin recognize translated documents as a single entity.

Based on a community answer from the Sanity team, here's how to organize your translated documents with custom structure:

The Solution

The trick is to get the filtered items first, then manipulate that array to organize them into groups. Here's a working example:

import S from '@sanity/desk-tool/structure-builder'
import * as Structure from '@sanity/document-internationalization/lib/structure'

export default () => {
  // Get the filtered document type list items from document-internationalization
  const items = Structure.getFilteredDocumentTypeListItems()

  // Group the items into different categories
  const groupedItems = items.reduce(
    (reduced, item) => {
      // Check whether the item should be included in your custom group
      if (item.id === 'page' || item.id === 'post') {
        return {
          ...reduced,
          mainPages: [...reduced.mainPages, item],
        }
      }

      // Otherwise, add it to the general group
      return {
        ...reduced,
        other: [...reduced.other, item],
      }
    },
    {
      mainPages: [],
      other: [],
    }
  )

  return S.list()
    .id('root')
    .title('Content')
    .items([
      // Create a nested list for your main pages
      S.listItem()
        .title('Website Pages')
        .child(
          S.list()
            .id('mainPages')
            .title('Website Pages')
            .items(groupedItems.mainPages)
        ),
      S.divider(),
      // Include the rest of the documents
      ...groupedItems.other,
    ])
}

How It Works

  1. getFilteredDocumentTypeListItems() returns an array of list items that already have the translation logic baked in
  2. You can then use JavaScript array methods like reduce(), filter(), or map() to reorganize these items
  3. The key is checking item.id to identify which document types should go where
  4. You can create nested lists using S.listItem().child(S.list().items([...]))

Studio v3 Update

If you're using Studio v3, the import paths have changed slightly:

import {structureTool} from 'sanity/structure'
import * as Structure from '@sanity/document-internationalization/lib/structure'

export const structure = (S) => {
  const items = Structure.getFilteredDocumentTypeListItems()
  // ... same logic as above
}

// In sanity.config.ts
export default defineConfig({
  plugins: [
    structureTool({structure}),
    documentInternationalization({
      // your i18n config
    })
  ]
})

Should You Migrate to document-internationalization?

Yes, migrating to @sanity/document-internationalization is recommended because:

  • It's actively maintained by Sanity
  • It has better documentation and community support
  • The structure customization pattern is the same as what you're trying to achieve
  • It works well with Studio v3's Structure Tool

The migration shouldn't be too difficult since both plugins use similar concepts, and the structure customization approach described above works with both.

Show original thread
13 replies
Maybe this can help you? Using the new plugin.
Thank you for replying. That code does not seem to do anything to allow me to use a translated document with structure builder.
Hi User. Migrating to
document-internationalization
is probably a good idea if it's not too much trouble for you. It's being actively maintained by Sanity and Liam.

document-internationalization
does have manual implementation instructions that cover using your own custom desk structure . Does this help at all?
document-internationalization has the same instructions that the previous version had
The problem seems to be in this

export default () => {
  const items = Structure.getFilteredDocumentTypeListItems()
  return S.list().id('__root__').title('Content').items(items)
}
This function, Structure.getFilteredDocumentTypeListItems(), is what flattens all of the translated versions into one document in the studio. If I use anything besides Structure.getFilteredDocumentTypeListItems() in the .items() function, it no longer sees the translated documents as one document. This is an issue as the
structure-builder instructions indicate to use the .items() to customize how documents appear in the studio. How can I have the result caused by using Structure.getFilteredDocumentTypeListItems() with a custom structure?
Is there any chance of getting a reply about this?
Hi User. I'm sorry for not getting back to you on this one sooner. I'll add the Document Internationalization plugin to my test Studio and see what I'm able to do!
Have you had any luck with this?
I've taken a closer look, and although the
getFilteredDocumentTypeListItems
function is fairly closed off, I think it might be possible to map the items returned in order to customise them. Would you be able to explain the changes you'd like to make?
My goal is to identify certain schemas or documents that make up the high-level pages of our website and have those in one folder. We are letting a client have a login to edit content and I want to make the content easier to find. All schemas must support translation, and we like the features of document-internationalization . I am new to structure builder, but I think all I need to do is identify the documents that make up our website pages using the documentList() function.
Is there any more information you need to understand the issue I am encountering?
Hi User. I'm really sorry, we've been quite busy and I hadn't had a chance to take a close look at your document structure question. I think I've achieved something similar to what you need. I've commented the code, but please let me know if you have any questions.
Does this screenshot show a structure that reflects your needs? I have taken the
page
document type (which supports translation), and added it to a new list named "Group A". You could group multiple document types into different groups using this technique.

import S from '@sanity/desk-tool/structure-builder'
import * as Structure from '@sanity/document-internationalization/lib/structure'

export default () => {
  // Get the filtered document type list items from `document-internationalization`.
  const items = Structure.getFilteredDocumentTypeListItems()

  // Group the items into a `main` group and a `groupA` group. The `groupA` group
  // will be nested in a new list item named "Group A".
  const groupedItems = items.reduce(
    (reduced, item) => {
      // Check whether the item should be included in `groupA`.
      if (item.id === 'page') {
        return {
          ...reduced,
          groupA: [...reduced.groupA, item],
        }
      }

      // If the item should not be included in `groupA`, add it to the `main`
      // group.
      return {
        ...reduced,
        main: [...reduced.main, item],
      }
    },
    {
      main: [],
      groupA: [],
    },
  )

  return S.list()
    .id('main')
    .title('Content')
    .items([
      // Include the `main` group.
      ...groupedItems.main,
      S.divider(),
      // Include the `groupA` group in a nested list.
      S.listItem()
        .title('Group A')
        .child(
          S.list().id('groupA').title('Group A').items(groupedItems.groupA),
        ),
    ])
}
I believe that is exactly what I am looking for. I will give it a shot. Thank you.
Fab! Let us know how it goes! 🙂

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?