Skip to content

Sanity plugin for TranslationOS

Notifications You must be signed in to change notification settings

translated/sanity-plugin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

Repository files navigation

TranslationOS plugin for Sanity Studio v3

A plugin for Sanity Studio v3 that integrates with the TranslationOS API to translate Sanity documents.

This plugin requires either the Sanity document internationalization plugin or the Sanity field-level internationalization plugin.

Features

The TranslationOS plugin for Sanity offers two independent translation modes:

  • Single document translation: Sends a single document to the TranslationOS API for translation. Supports both document-level and field-level localization.
  • Bulk document translation: Sends multiple documents to the TranslationOS API for translation. Supports document-level localization only.

Single document translation is available within the Structure tool. Bulk document translation is available as a top-level tool.

Installation

Add the plugin to your Sanity Studio project as a dependency by running:

npm install sanity-plugin-tos

Configuration

Add the plugin to your sanity.config.ts (or .js).

Below is an example configuration using both modes, sharing languages and document types with the internationalization plugins, and defining supported field types.

We recommended using TranslationOS-supported language codes, but we can unofficially support other language codes by configuring a custom mapping.

import {defineConfig} from 'sanity'
import {StructureBuilder} from "sanity/structure";
import {tosPlugin} from 'sanity-plugin-tos'
import {internationalizedArray} from 'sanity-plugin-internationalized-array'

// Languages shared across plugins
const languages = [
    {id: 'en-US', title: 'English (US)'},
    {id: 'fr-FR', title: 'French (France)'},
    {id: 'de-DE', title: 'German (Germany)'},
    {id: 'es-ES', title: 'Spanish (Spain)'},
];

// Document types handled by each mode
const documentLevelTypes = ['post', 'author']
const fieldLevelTypes = ['blog']

// Common TranslationOS configuration
const tosCommonConfig = {
    supportedLanguages: languages,
    customBlockTypes: ['myblock'],
}

export default defineConfig({
    // [...]
    plugins: [
        // [...]
        documentInternationalization({
            supportedLanguages: languages,
            schemaTypes: documentLevelTypes,
            weakReferences: true,
        }),
        structureTool({
            defaultDocumentNode: (S: StructureBuilder, {schemaType}: DefaultDocumentNodeContext) => {
                if ([...documentLevelTypes, ...fieldLevelTypes].includes(schemaType)) {
                    return S.document().views([
                        S.view.form(),
                        // Structure tool plugin view for single document translation
                        tosPlugin(S, {
                            ...tosCommonConfig,
                            // Document types supported in document-level translation mode
                            documentLocalizationSchemaTypes: documentLevelTypes,
                            // Document types supported in field-level translation mode
                            fieldLocalizationSchemaTypes: fieldLevelTypes,
                        })
                    ])
                }
            }
        }),
        internationalizedArray({
            languages,
            fieldTypes: ['string', 'text', 'block'],
        }),
    ],

    // Top-level tool for bulk document translation in document-level translation mode
    tools: [
        translationOS({
            ...tosCommonConfig,
            schemaTypes: documentLevelTypes,
        })
    ],
})

Plugin options

tosPlugin (single document translation view)

Returns a ComponentViewBuilder to be added to the editor views for specific document types.

Recommended: only enable for schema types configured in your internationalization plugin.

Options:

  • supportedLanguages – array of {id, title} language objects
  • documentLocalizationSchemaTypes – document types for document-level translation
  • fieldLocalizationSchemaTypes – document types for field-level translation
  • customBlockTypes – additional block type names to treat like Sanity's block

Note: A schema type can't be included in both the documentLocalizationSchemaTypes and the fieldLocalizationSchemaTypes options, otherwise the plugin will display a configuration error and won't work properly.

translationOS (bulk document translation tool)

Returns a tool to be added to the top-level tools array in your Sanity configuration.

Recommended: only enable for schema types configured in the document internationalization plugin.

Options:

  • env – TranslationOS API environment (staging, sandbox or production)
  • apiKey – TranslationOS API key for the above environment
  • supportedLanguages – array of {id, title} language objects
  • customBlockTypes – additional block type names to treat like Sanity's block
  • schemaTypes – document types to manage with bulk translation

Authentication

Initial setup

The plugin requires a TranslationOS API key to function. This API key will be stored securely in your Sanity dataset. When you first use the plugin, by clicking on the TranslationOS editor tab, you will be prompted to enter your API key and select the environment (sandbox or production).

NOTE: the authentication setup can be performed only by a Studio user with admin privileges.

TOS authentication configuration

Non-admin users will see a warning message requesting them to contact their Sanity administrator.

TOS authentication warning

Reset

If you need to change your API key or environment, you can reset the plugin configuration by clicking on the Reset credentials menu item in the settings menu. The settings menu is accessible by clicking on the cog button near the version badge in the top-right corner of the TranslationOS editor tab.

NOTE: after resetting the authentication configuration, the plugin will display the setup screen again for admin users and the warning message for non-admin users.

TOS authentication reset

Known limitations

For field translation mode:

  • Supports common types: string, text, block
  • Supports nested object fields
  • Does not traverse array fields to locate nested translatable fields

Field-level options in schema

You can add tosProperties to any field to control translation behavior.

defineField({
  name: 'fullname',
  type: 'string',
  title: 'Full Name',
  options: {
    tosProperties: {
      exclude: true, // exclude from translation
    }
  }
})

Adding tosProperties.exclude: true to an object field excludes all nested fields.

Default behavior in document-level mode

By default, the plugin translates:

  • All fields of type string, text, slug, block
  • Nested fields within array or object values (recursively)
  • Excludes Sanity metadata (_id, _rev, _type, createdAt, etc.)
  • Excludes fields with tosProperties.exclude: true

Rich text (block content) support

Sanity's block type represents rich text as an array of objects. The plugin converts these to HTML before sending to TranslationOS, preserving structure and context. Supported features include:

  • Bold, italic, underline, strikethrough, code spans
  • Headings, blockquotes
  • Bullet and numbered lists
  • Image references
  • Links with metadata (metadata preserved, not translated)

Custom block types

If you define custom block names in your schema, list them in customBlockTypes so the plugin can process them correctly.

Let's say you have the following rich text type definition:

export default defineType({
  name: 'myrichtext',
  title: 'My Rich Text Content',
  type: 'array',
  of: [
    defineArrayMember({
      name: 'myblock', // <--- custom block type name
      title: 'My Block',
      type: 'block',
      styles: [
        {title: 'Normal', value: 'normal'},
        {title: 'H1', value: 'h1'},
      ],
      marks: {
        decorators: [
          {title: 'Code', value: 'code'}
        ],
      },
    }),
  ],
})

Fields of type myrichtext would have the following JSON structure:

{
  "_createdAt": "2025-01-16T13:48:35Z",
  "_id": "drafts.cc28b1ec-8340-41ae-a820-3cd3e4f6038c",
  "_rev": "b464c3da-548a-4402-a2a0-be29fb61120e",
  "_type": "post",
  "_updatedAt": "2025-01-17T13:44:05Z",
  "body": [
    {
      "_key": "aba42a503204",
      "_type": "myblock", // <--- custom block type name
      "children": [
        {
          "_key": "e8799f8c0f9e",
          "_type": "span",
          "marks": [],
          "text": "The Post Body"
        }
      ],
      "markDefs": [],
      "style": "h2"
    }
  ]
}

You must configure the plugin to correctly handle fields of type myrichtext with myblock elements as follows:

tosPlugin(S, {
  // [...]
  customBlockTypes: ['myblock'],
})

Link handling

The plugin supports links with arbitrary metadata inside rich text. Metadata is preserved but not translated.

Example:

export default defineType({
  name: 'blockContent',
  title: 'Block Content',
  type: 'array',
  of: [
    defineArrayMember({
      title: 'Block',
      type: 'block',
      // [...]
      marks: {
        decorators: [
          // [...]
        ],
        annotations: [
          {
            name: 'link',
            title: 'Complex Link',
            type: 'object',
            fields: [
              {
                name: 'title',
                title: 'Title',
                type: 'string',
              },
              {
                name: 'external',
                title: 'External Link',
                type: 'url',
              },
              {
                name: 'author',
                title: 'Author',
                type: 'reference',
                to: [{type: 'author'}]
              },
              {
                name: 'newTab',
                title: 'Open in new tab',
                type: 'boolean',
                initialValue: false,
                description: 'Set to true to open the link in a new tab.',
              },
            ],
          },
        ],
      },
    }),
  ],
})

Migration from older versions to version 5.x

If you are migrating from version 4.x or below to version 5.x of the sanity-plugin-tos, please note the following. In version 5.x, the plugin changes how it manages the TOS API key. Once you update to v5, the process mentioned in the Authentication section above will have to be followed. The plugin also requires you to slightly change your previous configuration. Please follow the steps below:

  • Remove the apiKey and env options from your TOS plugin configuration in sanity.config.ts or sanity.config.js, both from the tosPlugin or the translationOS tool.
  • Start your Sanity Studio, the TOS configuration page should pop up automatically.
  • Fill in the required fields (TOS API key, environment) and save the configuration.

The authentication information will be saved in your Sanity Studio dataset as a document of type translationOSSettings, and the plugin will use this configuration from then on.

About

Sanity plugin for TranslationOS

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •