# sanity: Plugin Configuration URL: https://generaltranslation.com/en-US/docs/sanity/api/plugin-config.mdx --- title: Plugin Configuration description: API reference for gtPlugin configuration options --- ## Overview The `gtPlugin` function configures General Translation for your Sanity Studio. ```typescript import { gtPlugin } from 'gt-sanity' gtPlugin(config: GTPluginConfig) ``` ## GTPluginConfig string', description: 'Function to generate translated singleton IDs. Default: "${docId}-${locale}"', optional: true, }, ignoreFields: { type: 'IgnoreFields[]', description: 'Fields to exclude from translation. Matched fields are stripped before serialization and restored from the source document after translation.', optional: true, }, dedupeFields: { type: 'DedupeFields[]', description: 'Fields to exclude from translation, then initialize from the source document with the target locale appended when creating a translated document.', optional: true, }, skipFields: { type: 'SkipFields[]', description: 'Fields to remove entirely from translated documents. Unlike ignoreFields, these fields will not appear on the translated document at all.', optional: true, }, translateDocuments: { type: "TranslateDocumentFilter[] | string[]", description: 'Filter which documents can be translated. Accepts an array of filter objects or a shorthand array of document type strings.', optional: true, }, secretsNamespace: { type: 'string', description: 'Namespace for credentials document. Default: "generaltranslation"', optional: true, }, additionalStopTypes: { type: 'string[]', description: 'Additional types to skip during serialization', optional: true, }, additionalSerializers: { type: 'Record', description: 'Custom HTML serializers for block types', optional: true, }, additionalDeserializers: { type: 'Record', description: 'Custom HTML deserializers', optional: true, }, additionalBlockDeserializers: { type: 'BlockDeserializer[]', description: 'Custom block-level deserializers', optional: true, }, customMapping: { type: "Record>", description: 'Custom locale mapping for non-standard locale codes', optional: true, }, showDocumentInternationalization: { type: 'boolean', description: 'When true (default), automatically adds the @sanity/document-internationalization plugin with language badges, translation menu, and per-language templates. Requires translateDocuments. Document types localized in place via internationalized arrays are excluded automatically.', optional: true, }, internationalizedArray: { type: 'GTFieldLevelLocalizationConfig', description: 'Field-level (internationalized array) localization. When enabled, generates internationalizedArray* schema types and input components from sourceLocale and locales.', optional: true, }, fieldLevelLocalization: { type: 'GTFieldLevelLocalizationConfig', description: 'Descriptive alias for internationalizedArray.', optional: true, }, translationLevel: { type: "'document' | 'internationalizedArray' | 'mixed'", description: 'How matched documents are translated. "document" (default) creates per-locale documents; "internationalizedArray" localizes fields in place; "mixed" uses the array strategy for fieldLevelDocuments and document-level for everything else.', optional: true, }, fieldLevelDocuments: { type: "TranslateDocumentFilter[] | string[]", description: 'In "mixed" mode, the document types that use the internationalized-array strategy.', optional: true, }, }} /> ## IgnoreFields Fields that are not translated or sent to the API, but are copied over from the source document to the translation. Use this for fields like categories, tags, or internal metadata that should have the same value across all languages. ```typescript type IgnoreFields = { documentId?: string; fields?: Array<{ property: string; type?: string; }>; }; ``` ### Example ```typescript gtPlugin({ sourceLocale: 'en', locales: ['es'], ignoreFields: [ // Copy category as-is to all translated documents { fields: [{ property: '$.category' }], }, // Copy these fields as-is only for articles { documentId: 'article', fields: [{ property: '$.tags' }, { property: '$.author' }], }, ], }); ``` ## DedupeFields Fields that are not translated or sent to the API, but are copied from the source document with the target locale appended when a translated document is first created. Use this for fields that should start source-derived but unique per translated document, such as Sanity slugs. ```typescript type DedupeFields = { documentId?: string; fields?: Array<{ property: string; type?: string; }>; }; ``` ### Example ```typescript gtPlugin({ sourceLocale: 'en', locales: ['es', 'fr'], dedupeFields: [ // "about" becomes "about-es" and "about-fr" { fields: [{ property: '$.slug', type: 'slug' }], }, ], }); ``` For Sanity slug fields, the plugin updates the slug object's `current` value. For example, `{ _type: 'slug', current: 'about' }` becomes `{ _type: 'slug', current: 'about-es' }` when the Spanish document is created. If an editor later changes the translated slug, future translation imports preserve that edited value. ## SkipFields Fields that are removed entirely from translated documents. Unlike `ignoreFields`, these fields will not appear on translations at all. Use this for fields like SEO canonical URLs, source-only metadata, or slugs that editors should set manually per language. ```typescript type SkipFields = { documentId?: string; fields?: Array<{ property: string; type?: string; }>; }; ``` ### Example ```typescript gtPlugin({ sourceLocale: 'en', locales: ['es'], skipFields: [ // Editors will set slugs manually per language { fields: [{ property: '$.slug', type: 'slug' }], }, // Remove source-only debug data from homepage translations { documentId: 'homepage', fields: [{ property: '$.debugInfo' }], }, ], }); ``` ## TranslateDocumentFilter Filter which documents are available for translation: ```typescript type TranslateDocumentFilter = { documentId?: string; // Specific document ID type?: string; // Document type }; ``` ### Example ```typescript gtPlugin({ sourceLocale: 'en', locales: ['es'], translateDocuments: [ { type: 'article' }, { type: 'page' }, { documentId: 'homepage' }, ], }); ``` ## GTFieldLevelLocalizationConfig Field-level localization options, passed as `internationalizedArray` (or its alias `fieldLevelLocalization`). Locale identity always comes from the plugin's `sourceLocale` and `locales`. ```typescript type GTFieldLevelLocalizationConfig = { // Generate internationalizedArray* schema types and input components. // Default: false enabled?: boolean; // Which field types to generate. Built-in shortcuts: 'string', 'text', // 'block' (Portable Text). Object form supplies a custom value field. // Default: ['string', 'text'] fieldTypes?: FieldLevelFieldType[]; // Per-locale display labels shown in the Studio input. languageTitles?: Record; // Compute a display label for a locale (overrides languageTitles). getLanguageTitle?: (locale: string) => string; // Prefix for generated type names. Default: 'internationalizedArray' typePrefix?: string; // When typePrefix is customized, also generate internationalizedArray* // aliases for interop with existing data. Default: true includeCompatibilityTypes?: boolean; // Override or detach the Studio components attached to generated types. // Each slot accepts a component, or false to use Sanity's default rendering. components?: { input?: ComponentType | false; item?: ComponentType | false; field?: ComponentType | false; }; }; type FieldLevelFieldType = | 'string' | 'text' | 'block' | { name: string; // suffix for the generated type name, e.g. 'seo' → internationalizedArraySeo type: string; // Sanity type of the generated value field title?: string; of?: unknown[]; fields?: unknown[]; options?: Record; }; ``` ### Example ```typescript gtPlugin({ sourceLocale: 'en', locales: ['es', 'fr'], translateDocuments: [{ type: 'post' }], internationalizedArray: { enabled: true, fieldTypes: ['string', 'text', 'block'], languageTitles: { es: 'Español', fr: 'Français' }, }, translationLevel: 'internationalizedArray', }); ``` Then use the generated types in your schemas: ```typescript defineField({ name: 'title', type: 'internationalizedArrayString', }); ``` The stored data matches `sanity-plugin-internationalized-array`: each field is an array of `{ _key, _type, language, value }` items, so existing internationalized-array content works without migration. ## Serializer Custom function to convert a Sanity block to HTML: ```typescript type Serializer = (props: { value: any; isInline?: boolean; children?: string; }) => string; ``` ### Example ```typescript import { attachGTData, gtPlugin } from 'gt-sanity'; gtPlugin({ sourceLocale: 'en', locales: ['es'], additionalSerializers: { link: ({ value, children }) => attachGTData(`${children}`, value, 'markDef'), }, }); ``` ## Default stop types These types are preserved but not sent for translation: ```typescript const defaultStopTypes = [ 'reference', 'crossDatasetReference', 'date', 'datetime', 'file', 'geopoint', 'image', 'number', 'slug', 'url', ]; ``` Add more with `additionalStopTypes`: ```typescript gtPlugin({ sourceLocale: 'en', locales: ['es'], additionalStopTypes: ['codeBlock', 'mathFormula'], }); ``` ## Complete example ```typescript title="sanity.config.ts" import { defineConfig } from 'sanity'; import { attachGTData, gtPlugin } from 'gt-sanity'; export default defineConfig({ plugins: [ gtPlugin({ // Required sourceLocale: 'en', locales: ['es', 'fr', 'de', 'ja'], // Document handling languageField: 'language', singletons: ['siteSettings', 'navigation'], singletonMapping: (id, locale) => `${id}_${locale}`, // Filtering translateDocuments: [{ type: 'article' }, { type: 'page' }], ignoreFields: [{ fields: [{ property: '$.publishedAt' }] }], dedupeFields: [{ fields: [{ property: '$.slug', type: 'slug' }] }], skipFields: [{ fields: [{ property: '$.internalNotes' }] }], // Serialization - Do not use this unless you know what you are doing! additionalSerializers: { // Additional serializers for marks (custom annotations) marks: { link: ({ value, children }) => attachGTData(`${children}`, value, 'markDef'), inlineMath: ({ value, children }) => attachGTData(`${children}`, value, 'markDef'), }, }, }), ], }); ``` ## Next steps - [Configuration Guide](/docs/sanity/guides/configuration) - Configuration patterns - [Serialization Guide](/docs/sanity/guides/serialization) - Custom serialization