How to filter a reference field in Sanity schema for localization.

2 replies
Last updated: Apr 17, 2024
To add language to the schema and do localization, I'm using documentInternationalization from '@sanity/document-internationalization'.Where I utilized another schema in my parent schema, I wanted to filter, but I couldn't find out how.


defineField({  name: 'product',

type: 'array',

of: [{type: 'reference', to: [{type: 'dogTreat'}, {type: 'catTreat'}]}],

options: {

filter: ({ document }) => {

let currentLanguage = document.language;


return {
`filter:
_type == "catTreat" && slug.current == '${currentLanguage}' 
,`
params: {

type:'catTreat'},

}

}

},

group: 'products',

}),

If the current page is in en-US, I would want to see the en-US version of the product in the dropdown menu. I have provided language to both schemas, but I'm unable to filter it. Could anyone possibly assist?
AI Update

I can help you with filtering references based on the language from @sanity/document-internationalization! The issue in your code is a few syntax errors and you need to use the correct field name that the plugin creates.

When you use @sanity/document-internationalization, it adds a special field called __i18n_lang to your documents to track their language. Here's the corrected filter:

defineField({
  name: 'product',
  type: 'array',
  of: [{type: 'reference', to: [{type: 'dogTreat'}, {type: 'catTreat'}]}],
  options: {
    filter: ({ document }) => {
      const currentLanguage = document.__i18n_lang; // Use __i18n_lang field
      return {
        filter: '_type == $type && __i18n_lang == $language', // Fixed syntax
        params: {
          type: 'catTreat',
          language: currentLanguage
        }
      };
    }
  },
  group: 'products',
})

Key changes I made:

  1. Use __i18n_lang field: The document-internationalization plugin stores the language code in a field called __i18n_lang, not language
  2. Fixed GROQ syntax: Your filter string had template literals mixed with GROQ syntax incorrectly - use parameterized queries instead
  3. Use $language parameter: Pass the language as a param to avoid injection issues

If you want to filter for multiple types, adjust it like this:

filter: ({ document }) => {
  const currentLanguage = document.__i18n_lang;
  return {
    filter: '_type in $types && __i18n_lang == $language',
    params: {
      types: ['catTreat', 'dogTreat'],
      language: currentLanguage
    }
  };
}

This will ensure that when you're editing the en-US version of a document, you'll only see en-US versions of the referenced products in the dropdown. The __i18n_lang field is automatically managed by the plugin alongside __i18n_base and __i18n_refs fields that maintain relationships between translated documents.

It looks to be a problem with your filter.
A few things to note:

1.
Options are in the wrong place | Currently your options are being applied to the array. They should be nested inside your reference type, otherwise it has no function.2.
Multiple _type restrictions | In general, I would only recommend filtering the type in one location. In your array reference, you're allowing the user to select both dogTreat, and catTreat. In your filter, you're then restricting that specifically to catTreat. I would remove the _type from the filter and only do this in the reference type if possible.3.
Incorrectly passing params to the filter | You're correctly fetching the document's language with
let currentLanguage = document.language
, but you're then incorrectly passing that to the filter. You shouldn't use string interpolation to pass variables, but rather the params object (like you've used for the 'type' property. The way you reference that variables then also changes to something like this:
return {filter: 'slug.current == $language', params: {language: currentLanguage}}
.4.
Filtering the wrong value | I've also just set up reference filtering depending on the document language, and you do this by then filtering the language property of the document, not slug.current. Your field should look something like this:


defineField({
			title: 'Products',
			name: 'product',
			type: 'array',
			of: [
				defineArrayMember({
					type: 'reference',
					to: { type: 'catTreat' },
					options: {
						filter: ({ document }) => {
							const { language } = document
		
							if (language) {
								return {
									filter: 'language == $language',
									params: {
										language: language,
									},
								}
							}
		
							return {}
						},
					},
				}),
			],
			group: 'products',
		})
user F
Brother thank you very much. it worked fine I'm just a bit new to sanity but thank you I'll learn from this.

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?