# General Translation Integrations: Sanity 插件 配置 URL: https://generaltranslation.com/zh/docs/integrations/sanity/reference/plugin-configuration.mdx --- title: Sanity 插件 配置 description: 为 Sanity Studio 配置 General Translation 的 gt-sanity 插件。gtPlugin 的 API 参考。 --- 使用 `gtPlugin` 函数在 Sanity Studio 中配置 General Translation。传入一个选项对象。 ```ts title="sanity.config.ts" import { gtPlugin } from 'gt-sanity'; gtPlugin({ sourceLocale: 'en', locales: ['es', 'fr'], translateDocuments: [{ type: 'article' }], }); ``` ## 选项 [#options] | 选项 | 说明 | 类型 | 可选 | 默认值 | | ----------------------------------------------------------------- | --------------------------------------------- | --------------------------------------------------------------------- | -- | ------------------------------------- | | [`sourceLocale`](#source-locale) | 源语言代码,例如 `en`。 | `string` | 是 | `defaultLocale`,然后使用库默认值 | | [`defaultLocale`](#default-locale) | `sourceLocale` 的别名,便于展开 `gt.config.json`。 | `string` | 是 | — | | [`locales`](#locales) | 目标区域设置代码。 | `string[]` | 否 | — | | [`customMapping`](#custom-mapping) | 自定义区域设置代码映射和属性覆盖。 | [`CustomMapping`](/docs/platform/core/reference/types/custom-mapping) | 是 | — | | [`apiKey`](#api-key) | General Translation API 密钥。 | `string` | 是 | Secrets 文档 | | [`projectId`](#project-id) | General Translation 项目 ID。 | `string` | 是 | Secrets 文档 | | [`secretsNamespace`](#secrets-namespace) | 私有凭据文档的 `_id`。 | `string` | 是 | `generaltranslation.secrets` | | [`languageField`](#language-field) | 用于存储区域设置的文档字段。 | `string` | 是 | `language` | | [`translateDocuments`](#translate-documents) | 过滤可翻译的文档。 | `TranslateDocumentFilter[] \| string[]` | 是 | `[]` | | [`singletons`](#singletons) | 视为单例的文档 ID。 | `string[]` | 是 | `[]` | | [`singletonMapping`](#singleton-mapping) | 将源 ID 和区域设置映射到翻译后的单例 ID。 | `(sourceDocumentId: string, locale: string) => string` | 是 | `` `${sourceDocumentId}-${locale}` `` | | [`showDocumentInternationalization`](#show-doc-i18n) | 自动添加 `@sanity/document-internationalization`。 | `boolean` | 是 | `true` | | [`internationalizedArray`](#internationalized-array) | 使用国际化数组配置字段级本地化。 | `GTFieldLevelLocalizationConfig` | 是 | — | | [`fieldLevelLocalization`](#field-level-localization) | `internationalizedArray` 的别名。 | `GTFieldLevelLocalizationConfig` | 是 | — | | [`translationLevel`](#translation-level) | 选择文档级、字段级或混合翻译。 | `'document' \| 'internationalizedArray' \| 'mixed'` | 是 | `'document'` | | [`fieldLevelDocuments`](#field-level-documents) | 在混合模式下使用字段级本地化的文档类型。 | `TranslateDocumentFilter[] \| string[]` | 是 | `[]` | | [`ignoreFields`](#ignore-fields) | 从源内容复制但不翻译的字段。 | `FieldMatcher[]` | 是 | `[]` | | [`dedupeFields`](#dedupe-fields) | 从源内容复制,并在每个区域设置中保持唯一的字段。 | `FieldMatcher[]` | 是 | `[]` | | [`skipFields`](#skip-fields) | 从翻译后的文档中移除的字段。 | `FieldMatcher[]` | 是 | `[]` | | [`additionalStopTypes`](#additional-stop-types) | 额外保留且不翻译的 schema 类型。 | `string[]` | 是 | `[]` | | [`additionalSerializers`](#additional-serializers) | 用于 marks 和 block 类型的自定义 HTML 序列化器。 | `Partial` | 是 | `{}` | | [`additionalDeserializers`](#additional-deserializers) | 自定义 HTML 反序列化器。 | `CustomDeserializers` | 是 | `{}` | | [`additionalBlockDeserializers`](#additional-block-deserializers) | 自定义 Portable Text block 反序列化规则。 | `unknown[]` | 是 | `[]` | ## 区域设置选项 [#locale-options] ### `sourceLocale` [#source-locale] **类型** `string` · **可选** · **默认值** `defaultLocale`,否则使用库默认值 源语言代码,例如 `en`。插件按以下顺序解析源区域设置:先是 `sourceLocale`,然后是 `defaultLocale`,最后是 `generaltranslation` 库的默认值。 ### `defaultLocale` [#default-locale] **Type** `string` · **可选** `sourceLocale` 的别名,因此你可以直接将 `gt.config.json` 展开传入 插件。如果两者都已设置,则以 `sourceLocale` 为准。 ```ts import gtConfig from './gt.config.json'; gtPlugin({ ...gtConfig }); ``` ### `locales` [#locales] **Type** `string[]` · **Required** 要翻译到的目标区域设置代码,例如 `['es', 'fr', 'ja']`。 ### `customMapping` [#custom-mapping] **类型** `CustomMapping` · **可选** 用于将区域设置代码自定义映射到名称,或覆盖区域设置属性。会传递给 `generaltranslation` 库。参见 [CustomMapping](/docs/platform/core/reference/types/custom-mapping)。 ## 凭据 [#credentials] 默认情况下,该 插件 会从 Sanity 的私有文档中读取凭据。请参阅[存储凭据](/docs/integrations/sanity/guides/configuring-sanity#store-credentials)。 ### `apiKey` [#api-key] **类型** `string` · **可选** · **默认值** 从 secrets 文档读取 你的 General Translation API 密钥。如果已设置,启动时会将其传递给库。如果存在 secrets 文档,则其 `secret` 字段会在运行时优先生效。建议优先使用 secrets 文档,以免将密钥纳入版本控制。 ### `projectId` [#project-id] **类型** `string` · **可选** · **默认值** 从 secrets 文档读取 你的 General Translation 项目 ID。如果存在 secrets 文档,则其中的 `project` 字段会在运行时优先生效。 ### `secretsNamespace` [#secrets-namespace] **类型** `string` · **可选** · **默认值** `generaltranslation.secrets` 用于存放凭证的私有 Sanity 文档的 `_id`。该 插件 会通过 `_id` 获取此文档,并将其 `secret` 字段作为 API 密钥,`project` 字段作为 project ID 读取。给 `_id` 加上前导 `.` 后,该文档即使位于公共数据集中也会保持私有。 ```js title="populateSecrets.js" import { getCliClient } from 'sanity/cli'; const client = getCliClient({ apiVersion: '2026-04-06' }); client.createOrReplace({ _id: 'generaltranslation.secrets', _type: 'generaltranslation.secrets', secret: process.env.GT_API_KEY, project: process.env.GT_PROJECT_ID, }); ``` ## 文档相关选项 [#document-options] ### `languageField` [#language-field] **类型** `string` · **可选** · **默认值** `language` 用于存储每个文档区域设置的字段。请在每种可翻译的文档类型中添加一个同名字段,并在查询时使用它来获取特定区域设置的文档。 ### `translateDocuments` [#translate-documents] **类型** `TranslateDocumentFilter[] | string[]` · **可选** · **默认值** `[]` 用于筛选哪些文档可以翻译。接受筛选对象或简写类型字符串。每个字符串条目 `'article'` 都会标准化为 `{ type: 'article' }`,不包含 `documentId` 或 `type` 的条目会被丢弃。 ```ts gtPlugin({ sourceLocale: 'en', locales: ['es'], translateDocuments: [ { type: 'article' }, { documentId: 'homepage' }, 'page', // { type: 'page' } 的简写 ], }); ``` `TranslateDocumentFilter` 的结构如下: ```ts type TranslateDocumentFilter = { documentId?: string; // 通过 _id 匹配特定文档 type?: string; // 匹配指定 schema 类型的所有文档 }; ``` `type` 条目还会决定 [`showDocumentInternationalization`](#show-doc-i18n) 启用哪些 schema 类型。 ### `singletons` [#singletons] **类型** `string[]` · **可选** · **默认值** `[]` 被视为单例文档的文档 ID,例如站点设置或导航。它们的翻译后文档 ID 由 [`singletonMapping`](#singleton-mapping) 推导。 ### `singletonMapping` [#singleton-mapping] **类型** `(sourceDocumentId: string, locale: string) => string` · **可选** · **默认值** `` `${sourceDocumentId}-${locale}` `` 将单例的源文档 ID 和区域设置映射为翻译后单例的文档 ID。默认映射规则是确定的,因此 `siteSettings` 在西班牙语中会变为 `siteSettings-es`。 ```ts gtPlugin({ sourceLocale: 'en', locales: ['es'], singletons: ['siteSettings'], singletonMapping: (sourceDocumentId, locale) => `${sourceDocumentId}_${locale}`, }); ``` ### `showDocumentInternationalization` [#show-doc-i18n] **类型** `boolean` · **可选** · **默认值** `true` 当为 `true` 时,插件 会添加 `@sanity/document-internationalization` 插件,并提供语言徽章、翻译菜单以及按语言划分的文档模板。它会将 [`translateDocuments`](#translate-documents) 中的 `type` entries 作为 schema 类型,将 `[sourceLocale, ...locales]` 作为受支持的语言,因此仅在 `translateDocuments` 包含文档类型时才会生效。使用 internationalized array 原地本地化的文档类型会被自动排除。将其设为 `false` 即可自行管理国际化。 ## 字段级本地化 [#field-level] 字段级本地化会将每个区域设置的值以国际化数组的形式存储在同一个文档中。存储的数据项采用与 `sanity-plugin-internationalized-array` 相同的 `{ _key, _type, language, value }` 结构,因此现有的 internationalized-array 内容无需迁移。 ### `internationalizedArray` [#internationalized-array] **类型** `GTFieldLevelLocalizationConfig` · **可选** 配置字段级本地化所用的 schema 类型和 Studio 输入组件。区域设置的标识始终由 `sourceLocale` 和 `locales` 决定。 ```ts type GTFieldLevelLocalizationConfig = { enabled?: boolean; // 默认值:false fieldTypes?: FieldLevelFieldType[]; // 默认值:['string', 'text'] languageTitles?: Record; getLanguageTitle?: (locale: string) => string; typePrefix?: string; // 默认值:'internationalizedArray' includeCompatibilityTypes?: boolean; // 默认值:true components?: { input?: ComponentType | false; item?: ComponentType | false; field?: ComponentType | false; }; }; type FieldLevelFieldType = | 'string' | 'text' | 'block' | { name: string; type: string; title?: string; of?: unknown[]; fields?: unknown[]; options?: Record; }; ``` 内置的 `fieldTypes` 快捷写法有 `string`、`text` 和 `block` (Portable Text) 。对象条目会定义一个自定义生成的类型。当两者都设置时,`getLanguageTitle` 会覆盖 `languageTitles`。每个 `components` 槽位都可以传入一个 Studio 组件,或设为 `false` 以使用 Sanity 的默认渲染。 ### `fieldLevelLocalization` [#field-level-localization] **类型** `GTFieldLevelLocalizationConfig` · **可选** 是 [`internationalizedArray`](#internationalized-array) 的说明性别名。 ### `translationLevel` [#translation-level] **类型** `'document' | 'internationalizedArray' | 'mixed'` · **可选** · **默认值** `'document'` 控制匹配文档的翻译方式: * `'document'` 为每个区域设置创建一份文档 * `'internationalizedArray'` 对已配置字段进行原地本地化 * `'mixed'` 对 [`fieldLevelDocuments`](#field-level-documents) 采用字段级本地化,对其他所有内容采用文档级本地化 ### `fieldLevelDocuments` [#field-level-documents] **类型** `TranslateDocumentFilter[] | string[]` · **可选** · **默认** `[]` 指定在 `translationLevel` 为 `'mixed'` 时使用国际化数组的文档类型。它接受与 [`translateDocuments`](#translate-documents) 相同的过滤器形式和简写字符串形式。 ```ts gtPlugin({ sourceLocale: 'en', locales: ['es', 'fr'], translateDocuments: [{ type: 'post' }, { type: 'siteSettings' }], internationalizedArray: { enabled: true, fieldTypes: ['string', 'text', 'block'], languageTitles: { es: 'Español', fr: 'Français' }, }, translationLevel: 'mixed', fieldLevelDocuments: [{ type: 'siteSettings' }], }); ``` 然后在 schema 中使用生成的类型: ```ts defineField({ name: 'title', type: 'internationalizedArrayString', }); ``` ## 字段匹配器 [#field-matchers] `ignoreFields`、`dedupeFields` 和 `skipFields` 均接受一个由 `FieldMatcher` 对象组成的数组。匹配器通过 JSONPath `property` 表达式匹配字段,并且还可通过 `documentId` 将范围可选地限制到单个 source document。 ```ts type FieldMatcher = { documentId?: string | null; // 通过 _id 限定到特定源文档 fields?: { property: string; // JSONPath 表达式,例如 $.slug type?: string; // 可选的 schema 类型提示,例如 slug }[]; }; ``` ### `ignoreFields` [#ignore-fields] **类型** `FieldMatcher[]` · **可选** · **默认值** `[]` 这些字段会直接从源文档复制到翻译后的文档,不会发送到翻译 API。适用于在不同区域设置中应保持完全一致的值,例如类别或标签。 ```ts gtPlugin({ sourceLocale: 'en', locales: ['es'], ignoreFields: [ // 对所有文档原样复制 category 字段 { fields: [{ property: '$.category' }] }, // 仅对一个文档原样复制 tags 字段 { documentId: 'homepage', fields: [{ property: '$.tags' }] }, ], }); ``` ### `dedupeFields` [#dedupe-fields] **类型** `FieldMatcher[]` · **可选** · **默认值** `[]` 首次创建翻译后的文档时,会从源值复制这些字段,并通过附加区域设置使其保持唯一。常用于 slug。 ```ts gtPlugin({ sourceLocale: 'en', locales: ['es', 'fr'], // "about" 变为 "about-es" 和 "about-fr" dedupeFields: [{ fields: [{ property: '$.slug', type: 'slug' }] }], }); ``` 对于 slug 字段,插件 会更新 slug 对象的 `current` 值。如果之后有人修改了翻译后的 slug,后续导入会保留这个修改后的值。 ### `skipFields` [#skip-fields] **类型** `FieldMatcher[]` · **可选** · **默认值** `[]` 会从翻译后的文档中完全移除的字段。 ```ts gtPlugin({ sourceLocale: 'en', locales: ['es'], skipFields: [ { fields: [{ property: '$.slug', type: 'slug' }] }, { documentId: 'homepage', fields: [{ property: '$.debugInfo' }] }, ], }); ``` ## 序列化 [#serialization] 该插件会先将文档序列化为 HTML 以便翻译,再将结果反序列化回 Sanity 字段。大多数项目都不需要这些选项。 ### `additionalStopTypes` [#additional-stop-types] **类型** `string[]` · **可选** · **默认值** `[]` 添加到[默认 停止类型](#stop-types)中的额外 schema 类型,这些类型会被保留而不进行翻译。 ```ts gtPlugin({ sourceLocale: 'en', locales: ['es'], additionalStopTypes: ['codeBlock', 'mux.video', 'mux.videoAsset'], }); ``` ### `additionalSerializers` [#additional-serializers] **类型** `Partial` · **可选** · **默认值** `{}` 与默认序列化器合并使用的自定义序列化器,遵循 `@portabletext/to-html` 的组件结构 (如 `types`、`marks`、`block`、`list`、`listItem` 等) 。最常见的用法是序列化自定义 `marks`。 对于自定义 `marks`,请用 `attachGTData` 包裹输出,以确保该标记的数据在翻译后仍能保留。 ```ts title="sanity.config.ts" import { attachGTData, gtPlugin } from 'gt-sanity'; gtPlugin({ sourceLocale: 'en', locales: ['es'], additionalSerializers: { marks: { link: ({ value, children }) => attachGTData(`${children}`, value, 'markDef'), inlineMath: ({ value, children }) => attachGTData(`${children}`, value, 'markDef'), }, }, }); ``` `attachGTData(html, data, 'markDef')` 会将 `data` 进行 base64 编码后写入 `html` 第一个元素的 `data-gt-internal` 属性中,并返回更新后的 HTML。导入时,plugin 会读取该属性以重新构建 mark 定义。 ```ts function attachGTData( html: string, data: Record, type: 'markDef' ): string; ``` ### `additionalDeserializers` [#additional-deserializers] **类型** `CustomDeserializers` · **可选** · **默认值** `{}` 按类型区分的自定义反序列化器,用于将已翻译的 HTML 元素转换回 Sanity 对象。 ```ts type CustomDeserializers = { types?: Record< string, (element: HTMLElement) => Record | unknown[] >; } & Record; ``` ### `additionalBlockDeserializers` [#additional-block-deserializers] **类型** `unknown[]` · **可选** · **默认值** `[]` 额外的 Portable Text 块反序列化规则,会追加到插件的内置规则后面。每条规则都是一个带有 `deserialize(node, next)` 方法的对象,其结构与 `@portabletext/block-tools` 的规则格式一致。 ## 默认停止类型 [#stop-types] 这些 schema 类型会被保留,且绝不会发送去翻译。你可以使用 [`additionalStopTypes`](#additional-stop-types) 添加更多类型。 ```ts const defaultStopTypes = [ 'reference', 'date', 'datetime', 'file', 'geopoint', 'image', 'number', 'crop', 'hotspot', 'boolean', 'url', 'color', 'code', ]; ``` slug 字段默认*不会*被跳过,因此除非你使用 [`dedupeFields`](#dedupe-fields) 或 [`skipFields`](#skip-fields),否则 slug 的 `current` 字符串会被翻译。 ## 导出的辅助工具 [#helpers] `gt-sanity` 还导出了一些用于高级序列化和自定义文档节点的基础组件。大多数项目都不需要它们。 * `TranslationsTab` — `structureTool` 的文档标签页组件。参见[配置 Sanity](/docs/integrations/sanity/guides/configuring-sanity#translations-tab)。 * `attachGTData` / `detachGTData` — 用于附加和读取自定义序列化器使用的编码标记数据。 * `BaseDocumentSerializer`, `BaseDocumentDeserializer`, `BaseDocumentMerger` — 默认的序列化、反序列化和合并实现。 * `defaultStopTypes`, `customSerializers` — 默认的 停止类型 和序列化器集合。 * `documentInternationalization` 及其类型 (`DocumentInternationalizationConfig`, `Language`, `Metadata`, `TranslationReference`) — 从 `@sanity/document-internationalization` 重新导出。 ## 完整示例 [#complete-example] ```ts title="sanity.config.ts" import { defineConfig } from 'sanity'; import { attachGTData, gtPlugin } from 'gt-sanity'; export default defineConfig({ plugins: [ gtPlugin({ // 必填 sourceLocale: 'en', locales: ['es', 'fr', 'de', 'ja'], // 文档与字段 languageField: 'language', translateDocuments: [{ type: 'article' }, { type: 'page' }], singletons: ['siteSettings', 'navigation'], singletonMapping: (id, locale) => `${id}_${locale}`, // 字段行为 ignoreFields: [{ fields: [{ property: '$.category' }] }], dedupeFields: [{ fields: [{ property: '$.slug', type: 'slug' }] }], skipFields: [{ fields: [{ property: '$.internalNotes' }] }], // 序列化 — 仅在默认配置无法处理你的 schema 时使用 additionalSerializers: { marks: { link: ({ value, children }) => attachGTData(`${children}`, value, 'markDef'), }, }, }), ], }); ```