A Sanity plugin to manage i18n at field level
npm install sanity-plugin-i18n-fieldsAn alternative way to manage localization at field level in your Sanity Studio.

- โก๏ธ Features
- ๐ Installation
- ๐งโ๐ป Usage
- โ๏ธ Plugin Configuration
- ๐ง Field Configuration
- ๐๏ธ Data Model
- ๐จ Validation
- ๐คฉ Examples Examples Examples
- ๐ Future features
- ๐ License
- ๐งช Develop & test
- Sanity v3 plugin.
- Field-level localization for the following Sanity types: string, text, and number.
- Optional UI (slider or dropdown).
- Locale visibility by user roles.
- Locale read-only by user roles.
- Object Validation.
- Customization available also at field level.
- Customizable types prefix.
``sh`
npm install sanity-plugin-i18n-fields
Add it as a plugin in sanity.config.ts (or .js):
`ts
import {defineConfig} from 'sanity'
import {I18nFields} from 'sanity-plugin-i18n-fields'
export default defineConfig({
//...
plugins: [I18nFields({
// your configuration here
})],
})
`i18n.string
The plugin will provide three new types: , i18n.text, and i18n.number. All three types will be objects with a dynamic number of fields based on the localizations provided during configuration.
ts
{
prefix?: string // You can configure the prefix of the types created by the plugin. If you are already using them or prefer a different name for any reason, you can change it. The default is 'i18n'.
// The 'ui' option allows you to customize the appearance of the plugin's UI. By default, it is set to 'slider'.
ui?: {
type?: 'slider' | 'dropdown' // The UI of the plugin, Default is 'slider'
position?: 'top' | 'bottom' // You can specify the position of the 'slider' above or below the input field, with the default being 'bottom'.
selected?: 'border' | 'background' // For the 'slider' type, you can configure the UI of the selected locale, and the default setting is 'border'.
},
// The 'locales' option is the core of the configuration, enabling you to set up all available locales for your project.
locales: [
{
code: string // the code of the locale
label: ReactNode | ComponentType // the label of the locale
title: string // the title of the locale
default?: boolean // This is the flag to identify the default locale. If set to true, the locale is placed in the first position.
visibleFor?: string[] // You can define a list of roles for which this locale is visible. By using the '!' operator, you can make it not visible.
editableFor?: string[] // You can define a list of roles for which this locale is editable. The '!' operator allows you to specify the opposite condition.
},
// other locales
]
}
`
Sample configuration:
`ts
import {defineConfig} from 'sanity'
import {I18nFields} from 'sanity-plugin-i18n-fields'export default defineConfig({
//...
plugins: [I18nFields({
ui: {
position: 'bottom'
},
locales: [
{code: 'en', label: '๐ฌ๐ง', title: 'English', default: true},
{code: 'en_us', label: '๐บ๐ธ๐ฌ๐ง', title: 'American English'},
{code: 'it', label: '๐ฎ๐น', title: 'Italian', visibleFor: ['it_editor']}, // country visible only for administrator and it_editor roles
{code: 'es', label: '๐ช๐ธ', title: 'Spanish'},
]
})],
})
`
๐ง Field Configuration
Other than global configuration, you can customize your configuration at field level. For example, for a specific field, you can have a dropdown layout or hide a particular locale.
`ts
import {ConditionalProperty, NumberOptions, StringOptions} from 'sanity'export default defineType({
type: 'document',
name: 'myDocument',
title: 'My Document',
fields: [
defineField({
type: 'i18n.string' | 'i18n.text' | 'i18n.number',
// ...
options: {
ui?: {
type?: 'slider' | 'dropdown'
position?: 'top' | 'bottom'
selected?: 'border' | 'background'
},
locales?: [
{
code: string // the code of the locale. MUST be the same as the one used in the global configuration.
readOnly?: ConditionalProperty
hidden?: ConditionalProperty
options?: StringOptions | { rows?:number } | NumberOptions
visibleFor?: string[] // same as global configuration
editableFor?: string[] // same as global configuration
},
// other locales
]
}
})
]
})
`
๐๏ธ Data model
`ts
// sample with 'en', 'en_us', 'it' and 'es' locales {
_type: 'i18n.string',
en: string,
en_us: string,
it: string,
es: string,
}
{
_type: 'i18n.text',
en: string,
en_us: string,
it: string,
es: string,
}
{
_type: 'i18n.number',
en: number,
en_us: number,
it: number,
es: number,
}
``


- Basic Configuration
- Global user roles visibility
- String field
- Text field
- Number field
- Slider top position
- Slider with background option
- Dropdown UI
- Multiple UI on different fields
- Hide specific locale for a single field
- Locale not editable for a specific field
- Conditionally set a locale visible or not editable
- List of values
- Custom rows for i18n.text
- Global validation
- Children validation
- Alternative locale label
- Alternative locale label 2
- Customized prefix
> While writing this documentation, I realized that with the 'prefix' option, you can define the plugin multiple times with different prefixes.
>
> Codes and Labels are customizable, and this plugin could be used for other use cases, not only for internationalization.
>
> So, perhaps the name 'I18N Fields' is already outdated? ๐
Should I find a different name? Any suggestions? ๐
MIT ยฉ William Iommi
This plugin uses @sanity/plugin-kit
with default configuration for build & watch scripts.
See Testing a plugin in Sanity Studio
on how to run this plugin with hotreload in the studio.
Run "CI & Release" workflow.
Make sure to select the main branch and check "Release new version".
Semantic release will only release on configured branches, so it is safe to run release on any branch.