# General Translation Integrations: 配置 Sanity
URL: https://generaltranslation.com/zh/docs/integrations/sanity/guides/configuring-sanity.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: 如何配置 General Translation 的 gt-sanity 插件，以设置 locales、文档筛选器、字段级本地化、凭据和单例文档。

使用 `gtPlugin` 函数配置 General Translation 在 Sanity Studio 中的运行方式。

本指南介绍最常见的选项。完整列表请参阅[插件配置参考](/docs/integrations/sanity/reference/plugin-configuration)。

## 添加 插件 [#add-plugin]

将 `gtPlugin` 添加到你的 Studio 配置中。此步骤在[快速入门](/docs/integrations/sanity/quickstart)中也有介绍。

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

export default defineConfig({
  plugins: [
    gtPlugin({
      sourceLocale: 'en',
      locales: ['es', 'zh', 'ja'],
      translateDocuments: [{ type: 'article' }, { type: 'page' }],
    }),
  ],
});
```

## 按区域设置浏览翻译 [#browse-locales]

Sanity 通常会将翻译后的文档与其源文档一同列出。使用 `gtStructureItems` 按区域设置将每种可翻译文档类型分组到各自的窗格中，同时保留其他结构项。

```ts title="sanity.config.ts"
import { defineConfig } from 'sanity';
import { structureTool } from 'sanity/structure';
import { gtPlugin, gtStructureItems } from 'gt-sanity';

export default defineConfig({
  plugins: [
    gtPlugin({
      sourceLocale: 'en',
      locales: ['es', 'zh', 'ja'],
      translateDocuments: [{ type: 'article' }, { type: 'page' }],
    }),
    structureTool({
      structure: (S, context) =>
        S.list()
          .title('Content')
          .items([
            ...gtStructureItems(S, context),
            S.divider(),
            ...S.documentTypeListItems(),
          ]),
    }),
  ],
});
```

源区域设置窗格会包含没有 language field 的文档，因此在插件引入前创建的内容仍会显示。使用国际化数组进行原地本地化的类型会被跳过，因为其翻译仍保留在源文档中。

如果 Studio 只需按区域设置分组的类型，请将完整的 `gtStructure()` 解析器传递给 `structureTool`：

```ts
import { gtStructure } from 'gt-sanity';

structureTool({ structure: gtStructure() });
```

向任一 helper 传入 `types`，即可覆盖要分组的文档类型。使用 `sourceTitle` 重命名源语言窗格，或使用 `localeTitle` 自定义目标窗格标题。 (请参阅[结构 helper 参考](/docs/integrations/sanity/reference/plugin-configuration#structure-helpers)) 。

## 设置 source 和目标区域设置 [#set-locales]

源语言使用 `sourceLocale`，目标语言使用 `locales`。

```ts
gtPlugin({
  sourceLocale: 'en',
  locales: ['es', 'zh', 'ja'],
});
```

如果你已经有 `gt.config.json`，可以在插件配置中将其展开。`defaultLocale` 也可以作为 `sourceLocale` 的别名。

```ts title="sanity.config.ts"
import gtConfig from './gt.config.json';

gtPlugin({
  ...gtConfig,
});
```

源区域设置会按以下顺序解析：`sourceLocale`，然后是 `defaultLocale`，最后是库的默认值。如果同时设置了 `sourceLocale` 和 `defaultLocale`，则 `sourceLocale` 优先。插件会从 `locales` 中移除源区域设置和重复条目，因此共享的 `gt.config.json` 可以安全地包含默认区域设置。

## 添加 language field [#language-field]

文档级翻译内容以独立文档的形式存储。该插件使用 language field 来记录每个文档的区域设置。默认情况下，该字段名为 `language`。字段级本地化不使用此字段。

```ts title="schema/article.ts"
import { defineField, defineType } from 'sanity';

export const articleType = defineType({
  name: 'article',
  title: 'Article',
  type: 'document',
  fields: [
    defineField({
      name: 'language',
      type: 'string',
      readOnly: true,
      hidden: true,
    }),
  ],
});
```

如果要使用不同的字段名，请设置 `languageField`，并在你的 schema 中使用相同的名称。

```ts
gtPlugin({
  sourceLocale: 'en',
  locales: ['es', 'zh', 'ja'],
  languageField: 'locale',
});
```

## 选择要翻译的文档 [#choose-documents]

使用 `translateDocuments` 来筛选可翻译的文档。它支持文档类型过滤器、文档 ID 过滤器，或简写类型字符串。

```ts
// 按文档类型
gtPlugin({
  sourceLocale: 'en',
  locales: ['es', 'zh', 'ja'],
  translateDocuments: [{ type: 'page' }, { type: 'post' }],
});
```

```ts
// 按指定文档 ID
gtPlugin({
  sourceLocale: 'en',
  locales: ['es', 'zh', 'ja'],
  translateDocuments: [{ documentId: 'homepage' }, { documentId: 'about-page' }],
});
```

```ts
// 简写类型字符串
gtPlugin({
  sourceLocale: 'en',
  locales: ['es'],
  translateDocuments: ['article', 'page'],
});
```

字符串 entries 会被视为 `{ type: '<string>' }`。`showDocumentInternationalization` 会根据 `type` entries 决定哪些 schema 类型显示语言徽章并应用 templates，因此必须配置文档类型过滤器才能启用这些功能。

## 配置字段级本地化 [#field-level]

默认情况下，`gt-sanity` 按文档级别翻译，为每个区域设置创建一份文档。字段级本地化会将各个区域设置的值都存储在同一份文档中，采用 internationalized array 的形式 (`[{ _key, _type, language, value }]` —— 其结构与 [`sanity-plugin-internationalized-array`](https://github.com/sanity-io/sanity-plugin-internationalized-array) 相同，因此现有数据无需迁移) 。

使用 `internationalizedArray` (或其别名 `fieldLevelLocalization`) 启用 schema 生成，然后将 `translationLevel` 设置为 `'internationalizedArray'`。

```ts
gtPlugin({
  sourceLocale: 'en',
  locales: ['es', 'zh', 'ja'],
  translateDocuments: [{ type: 'post' }],
  internationalizedArray: { enabled: true },
  translationLevel: 'internationalizedArray',
});
```

字段级本地化由作为参考实现的 Sanity 插件 [`sanity-plugin-internationalized-array`](https://github.com/sanity-io/sanity-plugin-internationalized-array) 提供支持。`gtPlugin` 会根据 `sourceLocale` 和 `locales` 对其进行配置，而原生插件会注册 `internationalizedArray*` schema 类型和 Studio 编辑 UI——按语言添加按钮、语言标签和字段操作的行为都与独立插件完全一致。请在你的 schema 中使用这些已注册的类型。

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

默认情况下，该插件会注册 `string` 和 `text` 类型。使用 `fieldTypes` 可添加 `block` (Portable Text) 类型或自定义对象定义。

```ts
internationalizedArray: {
  enabled: true,
  fieldTypes: ['string', 'text', 'block', { name: 'seo', type: 'seoFields' }],
},
```

如果你已经在自己的 Studio 中注册了 `sanity-plugin-internationalized-array`，请保留你当前的 setup，并将 `internationalizedArray` 保持为未设置状态，这样 schema 类型就只会注册一次。无论是哪一个插件实例注册了这些类型，翻译都会读取和写入已存储的 `{ _key, _type, language, value }` 数据，因此 GT 只需要设置 `translationLevel` (以及 `translateDocuments`) 即可。

```ts
import { internationalizedArray } from 'gt-sanity';

plugins: [
  internationalizedArray({
    languages: [
      { id: 'en', title: 'English' },
      { id: 'es', title: 'Spanish' },
    ],
    fieldTypes: ['string'],
  }),
  gtPlugin({
    sourceLocale: 'en',
    locales: ['es'],
    translateDocuments: [{ type: 'post' }],
    translationLevel: 'internationalizedArray',
  }),
],
```

如果要混合使用这两种策略，请将 `translationLevel` 设为 `'mixed'`，并在 `fieldLevelDocuments` 中列出按字段级别翻译的文档类型。

```ts
gtPlugin({
  sourceLocale: 'en',
  locales: ['es', 'zh', 'ja'],
  translateDocuments: [{ type: 'post' }, { type: 'siteSettings' }],
  internationalizedArray: { enabled: true },
  translationLevel: 'mixed',
  fieldLevelDocuments: [{ type: 'siteSettings' }],
});
```

以原地方式本地化的文档类型会自动从 `@sanity/document-internationalization` 中排除，因此不会显示语言徽章，也不会为每个区域设置生成单独的文档模板。导入时，插件只会更新源文档中的目标区域设置，并保留其他所有语言。

(请参阅 [插件配置参考](/docs/integrations/sanity/reference/plugin-configuration#field-level) 了解所有字段级选项) 。

## 排除不参与翻译的字段 [#exclude-fields]

在 schema 中标记某个字段，即可使其内容不参与翻译。在字段定义中设置 `options.gt.exclude`。

```ts title="schema/article.ts"
defineField({
  name: 'internalNotes',
  type: 'string',
  options: { gt: { exclude: true } },
});
```

被排除的字段绝不会被发送去翻译，因此翻译后的文档会保留 source value 不变。排除规则适用于任意层级的嵌套。

该 插件 也会遵循标准 Sanity localization 插件 的排除选项，因此如果你的 schema 已经使用了它们，就无需再添加第二个标记：

* `options.documentInternationalization.exclude`，来自 `@sanity/document-internationalization`
* `options.aiAssist.exclude`，来自 `@sanity/assist`
* 旧版 `localize: false` 字段属性

如果要排除某个自定义类型的所有出现位置，请直接在该类型定义本身上设置此选项。

```ts title="schema/objects/legalDisclaimer.ts"
export const legalDisclaimer = defineType({
  name: 'legalDisclaimer',
  type: 'object',
  // 在所有使用此类型的地方将其排除
  options: { gt: { exclude: true } },
  fields: [
    defineField({ name: 'jurisdiction', type: 'string' }),
    defineField({ name: 'text', type: 'text' }),
  ],
});
```

对于按 ID 匹配文档或按区域设置转换值的规则 (例如 slug 去重) ，请改用插件级别的 [`ignoreFields`, `skipFields`, and `dedupeFields`](/docs/integrations/sanity/reference/plugin-configuration#field-matchers) 选项。

## 配置单例文档 [#singletons]

对于每个站点只存在一份的文档 (例如站点设置或导航) ，请使用 `singletons`。`singletonMapping` 用于控制如何根据源 ID 和区域设置生成已翻译单例文档的文档 ID。

```ts
gtPlugin({
  sourceLocale: 'en',
  locales: ['es', 'zh', 'ja'],
  singletons: ['siteSettings', 'navigation', 'footer'],
  singletonMapping: (sourceDocumentId, locale) => `${sourceDocumentId}-${locale}`,
});
```

如果省略 `singletonMapping`，默认会把 `sourceDocumentId` 和 `locale` 映射到 `` `${sourceDocumentId}-${locale}` `` (例如 `siteSettings-es`) 。

## 存储凭据 [#store-credentials]

该 插件 会从一个私有 Sanity 文档中读取你的 API 密钥和项目 ID；该文档的 `_id` 必须与 `secretsNamespace` 一致 (默认值为 `generaltranslation.secrets`) 。请使用一次性脚本创建该文档。

```js title="populateSecrets.js"
import { getCliClient } from 'sanity/cli';

const client = getCliClient({ apiVersion: '2025-09-15' });

client.createOrReplace({
  _id: 'generaltranslation.secrets',
  _type: 'generaltranslationSettings',
  secret: process.env.GT_API_KEY,
  project: process.env.GT_PROJECT_ID,
});
```

```bash
GT_API_KEY=your-api-key GT_PROJECT_ID=your-project-id npx sanity exec populateSecrets.js --with-user-token
```

`secret` 字段用作 API 密钥，`project` 字段用作项目 ID。要从其他文档读取凭据，请将 `secretsNamespace` 设置为该文档的 `_id`。

你也可以将 `apiKey` 和 `projectId` 直接传给 `gtPlugin`，但更推荐使用 secrets 文档，这样凭据就不会被纳入源代码版本控制。当两者同时存在时，运行时会优先使用 secrets 文档。

私有文档这一约定可防止未经身份验证的公开查询；但它不能取代对已通过身份验证的 Studio 用户设置 Sanity 权限。请使用 [Sanity 基于角色的访问控制](https://www.sanity.io/docs/access-control) 限制数据集访问，并在创建文档后删除该一次性脚本。

## 添加可选的 Translations 选项卡 [#translations-tab]

系统会自动添加 **Translate** 文档操作。若还想在文档编辑器中显示 Translations 选项卡，请将 `TranslationsTab` 与 `structureTool` 一起添加。

```ts title="sanity.config.ts"
import { defineConfig } from 'sanity';
import { structureTool } from 'sanity/structure';
import { gtPlugin, TranslationsTab } from 'gt-sanity';

export default defineConfig({
  plugins: [
    structureTool({
      defaultDocumentNode: (S) =>
        S.document().views([
          S.view.form(),
          S.view.component(TranslationsTab).title('General Translation'),
        ]),
    }),
    gtPlugin({
      sourceLocale: 'en',
      locales: ['es', 'zh', 'ja'],
    }),
  ],
});
```

## Next steps

- /docs/integrations/sanity/guides/translating-content
- /docs/integrations/sanity/guides/managing-translations
- /docs/integrations/sanity/guides/querying-translations

## Sitemap

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