# General Translation Changelog: gt-sanity 2.1.0: Field-level localization
URL: https://generaltranslation.com/en-US/blog/gt-sanity_v2_1_0.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: 
Authors: Brian Lou
Published: 2026-07-14

## Overview

`gt-sanity` v2.1 adds **field-level localization**: instead of creating a separate document per locale, you can now store every language's value inside the same document using internationalized arrays. The plugin generates the schema types for you, ships an inline per-locale editing UI, and routes translation through the same GT workflow you already use — translated values are merged back into the source document in place.

The data shape matches [`sanity-plugin-internationalized-array`](https://github.com/sanity-io/sanity-plugin-internationalized-array) (`[{ _key, _type, language, value }]`), so existing internationalized-array content works with zero migration.

---

## What's new

### Field-level (internationalized array) localization

Document-level translation remains the default: each locale gets its own document, linked via `@sanity/document-internationalization`. That model fits documents where everything varies by language.

The new field-level model keeps a single document and localizes individual fields in place:

```typescript
{
  _id: 'post-123',
  _type: 'post',
  title: [
    { _key: 'x1', _type: 'internationalizedArrayStringValue', language: 'en', value: 'Hello' },
    { _key: 'x2', _type: 'internationalizedArrayStringValue', language: 'es', value: 'Hola' },
  ],
}
```

Enable it with the new `internationalizedArray` option (or its descriptive alias, `fieldLevelLocalization`):

```typescript title="sanity.config.ts"
import { defineConfig } from 'sanity';
import { gtPlugin } from 'gt-sanity';

export default defineConfig({
  plugins: [
    gtPlugin({
      sourceLocale: 'en',
      locales: ['es', 'fr', 'ja'],
      translateDocuments: [{ type: 'post' }],
      internationalizedArray: { enabled: true },
      translationLevel: 'internationalizedArray',
    }),
  ],
});
```

### Generated schema types

When enabled, the plugin generates `internationalizedArray*` schema types (e.g. `internationalizedArrayString`, `internationalizedArrayText`) from the same `sourceLocale` / `locales` you already pass to `gtPlugin` — locale identity is defined once. Use them in your schemas like any other type:

```typescript
defineField({
  name: 'title',
  type: 'internationalizedArrayString',
});
```

`fieldTypes` controls which types are generated. It defaults to `['string', 'text']`, accepts `'block'` for Portable Text, and accepts custom object definitions for arbitrary value shapes:

```typescript
internationalizedArray: {
  enabled: true,
  fieldTypes: [
    'string',
    'text',
    'block',
    { name: 'seo', type: 'seoFields' }, // generates internationalizedArraySeo
  ],
},
```

You can also customize the generated type names with `typePrefix` (compatibility aliases under the standard `internationalizedArray*` names are kept by default) and the locale labels shown in the Studio with `languageTitles` or `getLanguageTitle`.

### Inline per-locale editing UI

Generated types come with a purpose-built Studio input: each language renders as a labeled inline editor (no collapsed object rows or edit dialogs), with per-locale add buttons and remove buttons. The source language can't be removed.

If you'd rather bring your own UI, the `components` option lets you override the `input`, `item`, and `field` slots — or pass `false` to fall back to Sanity's default rendering. Translation is unaffected either way, since it operates on the stored data rather than the components.

### `translationLevel` and mixed mode

Schema generation and translation routing are independent: enabling `internationalizedArray` only adds editable field types. The new `translationLevel` option controls how matched documents are translated:

- `'document'` (default) — whole-document translation with per-locale documents, unchanged from v2.0.
- `'internationalizedArray'` — all matched documents are localized in place via internationalized arrays.
- `'mixed'` — the document types listed in `fieldLevelDocuments` use the array strategy; everything else stays document-level.

```typescript
gtPlugin({
  sourceLocale: 'en',
  locales: ['es', 'fr'],
  translateDocuments: [{ type: 'post' }, { type: 'siteSettings' }],
  internationalizedArray: { enabled: true },
  translationLevel: 'mixed',
  fieldLevelDocuments: [{ type: 'siteSettings' }], // localized in place
});
```

Document types localized in place are automatically excluded from `@sanity/document-internationalization`, so they don't get language badges or per-locale document templates.

### Importing in place

Field-level documents go through the same GT workflow you already use. On import, translated values are merged back into the same document: only the target locale is updated, and all other languages — including edits made while translation was running — are left untouched.

Translation statuses in the Studio also now stay accurate after in-place imports and page refreshes, instead of showing completed translations as "not started".

---

## Links

- [Quickstart](/docs/integrations/sanity/quickstart)
- [Configuration guide](/docs/integrations/sanity/guides/configuring-sanity)
- [API reference](/docs/integrations/sanity/reference/plugin-configuration)

## Sitemap

See the full [sitemap](https://generaltranslation.com/sitemap.md) for all pages.
