@braze/sanity-plugin-ai-translation 0.2.56 → 0.2.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +394 -191
- package/dist/index.js +44 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,296 +1,499 @@
|
|
|
1
1
|
# @braze/sanity-plugin-ai-translation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A Sanity Studio plugin that adds an AI-powered **Translate** document action for internationalized content.
|
|
4
|
+
|
|
5
|
+
- **Default provider:** Sanity Agent Actions (`client.agent.action.translate()`)
|
|
6
|
+
- **Optional provider:** OpenAI GPT-5 (direct API) for large documents / long style guides
|
|
7
|
+
- **Output:** Translations are created as **versioned documents inside Content Releases** (staged publishing)
|
|
8
|
+
- **Extras:** translate referenced documents, glossary terms, protected phrases, debug logging, field exclusion, and field transforms (Portable Text + captions)
|
|
9
|
+
|
|
10
|
+
**For editors:** see the standalone user guide at `docs/user-guide.md`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Table of contents
|
|
15
|
+
|
|
16
|
+
- [What this plugin does](#what-this-plugin-does)
|
|
17
|
+
- [Prerequisites](#prerequisites)
|
|
18
|
+
- [Install](#install)
|
|
19
|
+
- [Configure (Studio)](#configure-studio)
|
|
20
|
+
- [1) Configure document internationalization](#1-configure-document-internationalization)
|
|
21
|
+
- [2) Add the AI translation plugin](#2-add-the-ai-translation-plugin)
|
|
22
|
+
- [3) Add translation history metadata](#3-add-translation-history-metadata)
|
|
23
|
+
- [4) Deploy schema for Agent Actions](#4-deploy-schema-for-agent-actions)
|
|
24
|
+
- [Optional: OpenAI mode](#optional-openai-mode)
|
|
25
|
+
- [User guide (for editors)](#user-guide-for-editors)
|
|
26
|
+
- [Translate a document](#translate-a-document)
|
|
27
|
+
- [Choose a Content Release](#choose-a-content-release)
|
|
28
|
+
- [Translation options](#translation-options)
|
|
29
|
+
- [Translate referenced documents](#translate-referenced-documents)
|
|
30
|
+
- [What gets created](#what-gets-created)
|
|
31
|
+
- [Content configuration (settings + glossary)](#content-configuration-settings--glossary)
|
|
32
|
+
- [`translationSettings`](#translationsettings)
|
|
33
|
+
- [`translationGlossaryTerm`](#translationglossaryterm)
|
|
34
|
+
- [Advanced configuration](#advanced-configuration)
|
|
35
|
+
- [Exclude fields from translation](#exclude-fields-from-translation)
|
|
36
|
+
- [Field transforms](#field-transforms)
|
|
37
|
+
- [Concurrency and depth](#concurrency-and-depth)
|
|
38
|
+
- [Debugging & troubleshooting](#debugging--troubleshooting)
|
|
39
|
+
- [Development (this repo)](#development-this-repo)
|
|
40
|
+
- [License](#license)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## What this plugin does
|
|
45
|
+
|
|
46
|
+
When you open a document in Sanity Studio (for a configured schema type), the plugin adds a **Translate** action. You can:
|
|
47
|
+
|
|
48
|
+
1. Select one or more **target languages**
|
|
49
|
+
2. Choose whether to:
|
|
50
|
+
- overwrite existing translations
|
|
51
|
+
- translate only diffs (when applicable)
|
|
52
|
+
- translate referenced documents (with depth control)
|
|
53
|
+
3. Run translation using:
|
|
54
|
+
- **Sanity Agent Actions** (default), or
|
|
55
|
+
- **OpenAI** (optional)
|
|
56
|
+
|
|
57
|
+
Translations are written as **version documents** in a **Content Release**, so you can review and publish them on your schedule.
|
|
58
|
+
|
|
59
|
+
---
|
|
4
60
|
|
|
5
|
-
##
|
|
61
|
+
## Prerequisites
|
|
62
|
+
|
|
63
|
+
Your Studio must already support internationalized documents.
|
|
64
|
+
|
|
65
|
+
Required:
|
|
66
|
+
|
|
67
|
+
- **Sanity Studio v4** (plugin is built for Sanity Studio v4)
|
|
68
|
+
- `@sanity/document-internationalization` configured
|
|
69
|
+
- `sanity-plugin-internationalized-array` installed and configured (used for glossary term translations)
|
|
70
|
+
- `@sanity/client` **7.1.0+** (required for Agent Actions)
|
|
71
|
+
|
|
72
|
+
Also required for Agent Actions:
|
|
6
73
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
- 🔗 **Reference Translation** - Optionally translate referenced documents recursively with configurable depth
|
|
10
|
-
- 🎯 **Custom Translation Prompts** - Configure global and locale-specific translation instructions
|
|
11
|
-
- 📚 **Translation Glossary** - Define term-specific translations to ensure consistency
|
|
12
|
-
- 🛡️ **Protected Phrases** - Specify terms that should never be translated (e.g., brand names, product names)
|
|
13
|
-
- ⚙️ **Flexible Configuration** - Control concurrent translation jobs, reference depth, and translation behavior
|
|
14
|
-
- 🔍 **Debug Mode** - Comprehensive logging for troubleshooting translation issues
|
|
74
|
+
- Your schema must be deployed to Sanity so Agent Actions can access it (see [Deploy schema](#4-deploy-schema-for-agent-actions))
|
|
75
|
+
- **Important API version requirement:** the client must use `apiVersion: 'vX'` (not date-based versions). Date-based versions can cause Agent Actions to fail.
|
|
15
76
|
|
|
16
|
-
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Install
|
|
80
|
+
|
|
81
|
+
Use your Studio package manager (examples use `pnpm`):
|
|
17
82
|
|
|
18
83
|
```sh
|
|
19
84
|
pnpm add @braze/sanity-plugin-ai-translation
|
|
20
85
|
```
|
|
21
86
|
|
|
22
|
-
|
|
87
|
+
You’ll also need the prerequisites if you haven’t installed them yet:
|
|
23
88
|
|
|
24
|
-
|
|
89
|
+
```sh
|
|
90
|
+
pnpm add @sanity/document-internationalization sanity-plugin-internationalized-array
|
|
91
|
+
pnpm add @sanity/client@^7.1.0
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
25
95
|
|
|
26
|
-
|
|
27
|
-
2. **@sanity/client** - Version 7.1.0 or later (for Agent Actions)
|
|
28
|
-
3. **@sanity/document-internationalization** - Plugin must be installed and configured
|
|
29
|
-
4. **sanity-plugin-internationalized-array** - Version 3.1.5 or later
|
|
96
|
+
## Configure (Studio)
|
|
30
97
|
|
|
31
|
-
|
|
98
|
+
### 1) Configure document internationalization
|
|
32
99
|
|
|
33
|
-
|
|
100
|
+
This plugin is designed to work with `@sanity/document-internationalization`. Configure it first.
|
|
34
101
|
|
|
35
|
-
|
|
102
|
+
You’ll typically define your supported languages as:
|
|
36
103
|
|
|
37
104
|
```typescript
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
105
|
+
const SUPPORTED_LANGUAGES = [
|
|
106
|
+
{ id: "en-us", title: "English" },
|
|
107
|
+
{ id: "es", title: "Spanish" },
|
|
108
|
+
{ id: "fr", title: "French" },
|
|
109
|
+
];
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Then enable internationalization for the schema types you want to translate:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
documentInternationalization({
|
|
116
|
+
supportedLanguages: SUPPORTED_LANGUAGES,
|
|
117
|
+
schemaTypes: ["post", "page"],
|
|
118
|
+
languageField: "language", // your language field name (example)
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 2) Add the AI translation plugin
|
|
123
|
+
|
|
124
|
+
Add `aiTranslationPlugin()` after `documentInternationalization()`:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { defineConfig } from "sanity";
|
|
128
|
+
import { documentInternationalization } from "@sanity/document-internationalization";
|
|
129
|
+
import { aiTranslationPlugin } from "@braze/sanity-plugin-ai-translation";
|
|
41
130
|
|
|
42
131
|
const SUPPORTED_LANGUAGES = [
|
|
43
|
-
{ id:
|
|
44
|
-
{ id:
|
|
45
|
-
{ id:
|
|
46
|
-
|
|
47
|
-
]
|
|
132
|
+
{ id: "en", title: "English" },
|
|
133
|
+
{ id: "es", title: "Spanish" },
|
|
134
|
+
{ id: "fr", title: "French" },
|
|
135
|
+
];
|
|
48
136
|
|
|
49
137
|
export default defineConfig({
|
|
50
|
-
// ...
|
|
138
|
+
// ...your config...
|
|
51
139
|
plugins: [
|
|
52
|
-
// Document internationalization must be configured first
|
|
53
140
|
documentInternationalization({
|
|
54
141
|
supportedLanguages: SUPPORTED_LANGUAGES,
|
|
55
|
-
schemaTypes: [
|
|
142
|
+
schemaTypes: ["post", "page"],
|
|
143
|
+
languageField: "language",
|
|
56
144
|
}),
|
|
57
145
|
|
|
58
|
-
// Then add the AI translation plugin
|
|
59
146
|
aiTranslationPlugin({
|
|
60
|
-
// Required: Array of supported languages
|
|
61
147
|
supportedLanguages: SUPPORTED_LANGUAGES,
|
|
148
|
+
translatableSchemaTypes: ["post", "page"],
|
|
149
|
+
languageFieldName: "language",
|
|
150
|
+
schemaId: "_.schemas.default",
|
|
151
|
+
maxConcurrentTranslationJobs: 5,
|
|
152
|
+
maxReferenceDepth: 3,
|
|
153
|
+
}),
|
|
154
|
+
],
|
|
155
|
+
});
|
|
156
|
+
```
|
|
62
157
|
|
|
63
|
-
|
|
64
|
-
translatableSchemaTypes: ['post', 'page', 'product'],
|
|
158
|
+
**Notes**
|
|
65
159
|
|
|
66
|
-
|
|
67
|
-
|
|
160
|
+
- `schemaId` is usually `'_.schemas.default'` for most projects.
|
|
161
|
+
- `languageFieldName` must match the field your documents use (often `language`).
|
|
68
162
|
|
|
69
|
-
|
|
70
|
-
schemaId: '_.schemas.default',
|
|
163
|
+
### 3) Add translation history metadata
|
|
71
164
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
165
|
+
This plugin can store translation history via a metadata schema you attach to `documentInternationalization`.
|
|
166
|
+
|
|
167
|
+
Add `translationHistorySchema`:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { translationHistorySchema } from "@braze/sanity-plugin-ai-translation";
|
|
171
|
+
|
|
172
|
+
documentInternationalization({
|
|
173
|
+
supportedLanguages: SUPPORTED_LANGUAGES,
|
|
174
|
+
schemaTypes: ["post", "page"],
|
|
175
|
+
languageField: "language",
|
|
176
|
+
metadataFields: [translationHistorySchema],
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 4) Deploy schema for Agent Actions
|
|
181
|
+
|
|
182
|
+
Agent Actions need access to your deployed schema.
|
|
183
|
+
|
|
184
|
+
From your Studio project directory:
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
npx sanity deploy
|
|
77
188
|
```
|
|
78
189
|
|
|
79
|
-
|
|
190
|
+
If Agent Actions fail with schema-related errors, re-check:
|
|
191
|
+
|
|
192
|
+
- schema deployment
|
|
193
|
+
- `schemaId`
|
|
194
|
+
- client `apiVersion` is set to `'vX'` (not date-based)
|
|
80
195
|
|
|
81
|
-
|
|
82
|
-
|--------|------|----------|-------------|
|
|
83
|
-
| `supportedLanguages` | `Array<{id: string, title: string}>` | **Yes** | List of supported languages for translation |
|
|
84
|
-
| `translatableSchemaTypes` | `string[]` | **Yes** | Document types that should have translation actions |
|
|
85
|
-
| `languageFieldName` | `string` | **Yes** | Field name containing the language identifier in documents |
|
|
86
|
-
| `schemaId` | `string` | **Yes** | Schema ID for Sanity Agent Actions (typically `'_.schemas.default'`) |
|
|
87
|
-
| `maxConcurrentTranslationJobs` | `number` | No | Maximum number of concurrent translations (default: 5) |
|
|
88
|
-
| `openai` | `OpenAIConfig` | No | Optional OpenAI integration configuration (see below) |
|
|
196
|
+
---
|
|
89
197
|
|
|
90
|
-
|
|
198
|
+
## Optional: OpenAI mode
|
|
91
199
|
|
|
92
|
-
|
|
200
|
+
OpenAI mode is optional. If enabled, users can choose **OpenAI** as the translation provider inside the translation dialog.
|
|
93
201
|
|
|
94
|
-
|
|
202
|
+
Example configuration:
|
|
95
203
|
|
|
96
204
|
```typescript
|
|
97
205
|
aiTranslationPlugin({
|
|
98
|
-
|
|
206
|
+
supportedLanguages: SUPPORTED_LANGUAGES,
|
|
207
|
+
translatableSchemaTypes: ["post", "page"],
|
|
208
|
+
languageFieldName: "language",
|
|
209
|
+
schemaId: "_.schemas.default",
|
|
210
|
+
|
|
99
211
|
openai: {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
defaultMode:
|
|
106
|
-
}
|
|
107
|
-
})
|
|
212
|
+
enabled: true,
|
|
213
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
214
|
+
model: "gpt-5",
|
|
215
|
+
reasoningEffort: "medium", // 'minimal' | 'low' | 'medium' | 'high'
|
|
216
|
+
verbosity: "medium", // 'low' | 'medium' | 'high' (if supported by model)
|
|
217
|
+
defaultMode: "openai-only", // 'sanity-only' | 'openai-only'
|
|
218
|
+
},
|
|
219
|
+
});
|
|
108
220
|
```
|
|
109
221
|
|
|
110
|
-
|
|
222
|
+
**Security**
|
|
111
223
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
OPENAI_API_KEY=sk-...your-key-here...
|
|
115
|
-
```
|
|
224
|
+
- Do not hardcode API keys.
|
|
225
|
+
- Use environment variables (e.g. `.env` / `.env.local`) and your deployment platform’s secret manager.
|
|
116
226
|
|
|
117
|
-
|
|
227
|
+
**Why use OpenAI mode?**
|
|
118
228
|
|
|
119
|
-
|
|
229
|
+
- Larger effective context window for long documents and long style guides
|
|
230
|
+
- Deterministic serialization/deserialization to preserve structure
|
|
231
|
+
- Strict structure validation to prevent data corruption
|
|
120
232
|
|
|
121
|
-
|
|
122
|
-
- Uses Sanity's built-in translation agent
|
|
123
|
-
- Fast and reliable
|
|
124
|
-
- No additional API costs
|
|
125
|
-
- 2000 character style guide limit
|
|
233
|
+
**Costs**
|
|
126
234
|
|
|
127
|
-
|
|
128
|
-
- Direct translation via OpenAI
|
|
129
|
-
- 1 million token context window
|
|
130
|
-
- Full style guide capacity
|
|
131
|
-
- Incurs OpenAI API costs
|
|
235
|
+
- OpenAI calls incur API costs based on token usage.
|
|
132
236
|
|
|
133
|
-
|
|
237
|
+
---
|
|
134
238
|
|
|
135
|
-
|
|
136
|
-
- **1M token context window** - Handle very large documents and style guides
|
|
137
|
-
- **Advanced reasoning** - Configurable reasoning effort for quality vs. speed tradeoff
|
|
138
|
-
- **Verbosity control** - Adjust response length to optimize token usage
|
|
139
|
-
- **Structure preservation** - Deterministic serialization ensures all document metadata and structure is preserved
|
|
239
|
+
## User guide (for editors)
|
|
140
240
|
|
|
141
|
-
|
|
241
|
+
### Translate a document
|
|
142
242
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
243
|
+
1. Open a document in Studio whose type is included in `translatableSchemaTypes`.
|
|
244
|
+
2. Open the document actions menu and click **Translate**.
|
|
245
|
+
3. Select one or more target languages.
|
|
246
|
+
4. Configure translation options (see below).
|
|
247
|
+
5. Click **Translate** to start.
|
|
147
248
|
|
|
148
|
-
|
|
249
|
+
While translation runs, you’ll see job statuses for each target language (and for any referenced documents, if enabled).
|
|
149
250
|
|
|
150
|
-
|
|
151
|
-
|--------|------|---------|-------------|
|
|
152
|
-
| `apiKey` | `string` | - | OpenAI API key (required if OpenAI enabled) |
|
|
153
|
-
| `model` | `'gpt-5' \| 'gpt-4o' \| 'gpt-4-turbo' \| 'gpt-4'` | `'gpt-5'` | Model to use for translation/review |
|
|
154
|
-
| `reasoningEffort` | `'minimal' \| 'low' \| 'medium' \| 'high'` | `'medium'` | OpenAI reasoning effort (affects speed and quality) |
|
|
155
|
-
| `verbosity` | `'low' \| 'medium' \| 'high'` | `'medium'` | OpenAI response verbosity |
|
|
156
|
-
| `enabled` | `boolean` | `false` | Enable OpenAI features |
|
|
157
|
-
| `defaultMode` | `TranslationMode` | `'sanity-only'` | Default translation mode when dialog opens |
|
|
251
|
+
### Choose a Content Release
|
|
158
252
|
|
|
159
|
-
|
|
253
|
+
Translations are always created inside a **Content Release**.
|
|
160
254
|
|
|
161
|
-
|
|
255
|
+
In the dialog you can typically:
|
|
162
256
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
import { translationHistorySchema } from '@braze/sanity-plugin-ai-translation'
|
|
257
|
+
- create a new release, or
|
|
258
|
+
- add the translations to an existing active release
|
|
166
259
|
|
|
167
|
-
|
|
168
|
-
documentInternationalization({
|
|
169
|
-
supportedLanguages: SUPPORTED_LANGUAGES,
|
|
170
|
-
schemaTypes: ['post', 'page'],
|
|
171
|
-
// Add translation history to metadata
|
|
172
|
-
metadataFields: [translationHistorySchema],
|
|
173
|
-
})
|
|
174
|
-
```
|
|
260
|
+
Use releases when you want:
|
|
175
261
|
|
|
176
|
-
|
|
262
|
+
- staged review
|
|
263
|
+
- coordinated publishing of multiple translations at once
|
|
177
264
|
|
|
178
|
-
|
|
265
|
+
### Translation options
|
|
179
266
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
267
|
+
The exact UI labels may vary, but the workflow supports:
|
|
268
|
+
|
|
269
|
+
- **Overwrite fresh translations**
|
|
270
|
+
- Forces re-translation even if the existing translation is considered up-to-date.
|
|
271
|
+
- **Translate only diffs**
|
|
272
|
+
- For stale translations, translate only the changed fields where supported.
|
|
273
|
+
- **Translate references**
|
|
274
|
+
- Also translate referenced documents and update references to point at the localized versions.
|
|
275
|
+
- **Max reference depth**
|
|
276
|
+
- How far to traverse reference graphs (depth `0` means no traversal).
|
|
277
|
+
|
|
278
|
+
### Translate referenced documents
|
|
279
|
+
|
|
280
|
+
If you enable reference translation:
|
|
281
|
+
|
|
282
|
+
- The plugin traverses references (up to the configured depth).
|
|
283
|
+
- It translates referenced documents that are eligible (type is included in `translatableSchemaTypes`).
|
|
284
|
+
- It updates references in the translated document to point to localized versions.
|
|
285
|
+
|
|
286
|
+
This is useful for content like:
|
|
287
|
+
|
|
288
|
+
- posts referencing authors
|
|
289
|
+
- pages referencing shared sections
|
|
290
|
+
- documents referencing related content
|
|
291
|
+
|
|
292
|
+
### What gets created
|
|
293
|
+
|
|
294
|
+
For each selected target language, the plugin creates a **versioned document** inside the selected Content Release.
|
|
295
|
+
|
|
296
|
+
You can then:
|
|
297
|
+
|
|
298
|
+
- review and edit translated versions
|
|
299
|
+
- publish the release when ready
|
|
184
300
|
|
|
185
|
-
|
|
301
|
+
---
|
|
186
302
|
|
|
187
|
-
|
|
303
|
+
## Content configuration (settings + glossary)
|
|
188
304
|
|
|
189
|
-
|
|
305
|
+
The plugin introduces two document types for configuration:
|
|
190
306
|
|
|
191
|
-
|
|
192
|
-
2. Click the "Translate" action in the document menu
|
|
193
|
-
3. Select target languages
|
|
194
|
-
4. Configure translation options:
|
|
195
|
-
- **Overwrite fresh translations** - Re-translate even if translation is up-to-date
|
|
196
|
-
- **Translate only diffs** - For stale translations, only translate changed fields
|
|
197
|
-
- **Translate references** - Include referenced documents in translation
|
|
198
|
-
- **Max reference depth** - How deep to traverse references (if enabled)
|
|
199
|
-
5. Click "Translate" to start
|
|
307
|
+
### `translationSettings`
|
|
200
308
|
|
|
201
|
-
|
|
309
|
+
Create a document with `_id == "translation-settings"` to configure:
|
|
202
310
|
|
|
203
|
-
|
|
311
|
+
- **Global prompt** (applies to all translations)
|
|
312
|
+
- **Locale prompts** (per-target-language instructions)
|
|
313
|
+
- **Protected phrases** (never translate these terms; e.g. brand names)
|
|
314
|
+
|
|
315
|
+
Example shape:
|
|
204
316
|
|
|
205
317
|
```typescript
|
|
206
318
|
{
|
|
207
319
|
_type: 'translationSettings',
|
|
208
320
|
_id: 'translation-settings',
|
|
209
|
-
|
|
210
|
-
// Global prompt applied to all translations
|
|
211
321
|
globalPrompt: 'Maintain a professional tone. Preserve formatting and links.',
|
|
212
|
-
|
|
213
|
-
// Locale-specific prompts
|
|
214
322
|
localePrompts: [
|
|
215
|
-
{
|
|
216
|
-
|
|
217
|
-
prompt: 'Use formal Spanish (usted). Avoid Latin American regionalisms.'
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
locale: 'fr',
|
|
221
|
-
prompt: 'Use formal French. Maintain gender agreement for all terms.'
|
|
222
|
-
}
|
|
323
|
+
{_key: 'es', value: 'Use formal Spanish (usted).'},
|
|
324
|
+
{_key: 'fr', value: 'Use formal French.'},
|
|
223
325
|
],
|
|
224
|
-
|
|
225
|
-
// Terms that should never be translated
|
|
226
326
|
protectedPhrases: ['Braze', 'iOS', 'Android', 'SDK']
|
|
227
327
|
}
|
|
228
328
|
```
|
|
229
329
|
|
|
230
|
-
|
|
330
|
+
Notes:
|
|
331
|
+
|
|
332
|
+
- `localePrompts` uses `_key` for the locale id (must match your `supportedLanguages[].id`).
|
|
333
|
+
- Protected phrases may be filtered to only those that appear in the source document (to keep prompts smaller).
|
|
231
334
|
|
|
232
|
-
|
|
335
|
+
### `translationGlossaryTerm`
|
|
336
|
+
|
|
337
|
+
Create glossary term documents to enforce consistent translations of key terms.
|
|
338
|
+
|
|
339
|
+
This schema uses `internationalizedArrayString` so you can provide one value per locale.
|
|
340
|
+
|
|
341
|
+
Conceptual example:
|
|
233
342
|
|
|
234
343
|
```typescript
|
|
235
344
|
{
|
|
236
345
|
_type: 'translationGlossaryTerm',
|
|
237
346
|
translations: [
|
|
238
|
-
{
|
|
239
|
-
{
|
|
240
|
-
{
|
|
241
|
-
{ locale: 'de', value: 'Dashboard' }
|
|
347
|
+
{_key: 'en', value: 'dashboard'},
|
|
348
|
+
{_key: 'es', value: 'panel de control'},
|
|
349
|
+
{_key: 'fr', value: 'tableau de bord'},
|
|
242
350
|
]
|
|
243
351
|
}
|
|
244
352
|
```
|
|
245
353
|
|
|
246
|
-
|
|
354
|
+
Glossary terms are used to build locale-specific translation instructions.
|
|
355
|
+
|
|
356
|
+
---
|
|
247
357
|
|
|
248
|
-
|
|
358
|
+
## Advanced configuration
|
|
249
359
|
|
|
250
|
-
|
|
251
|
-
2. **Prepare Translation** - Assemble translation prompts and prepare source document
|
|
252
|
-
3. **Translate** - Uses Sanity Agent Actions (or OpenAI) with configured prompts
|
|
253
|
-
4. **Create Versions** - Translations are created as versioned documents in the release
|
|
254
|
-
5. **Localize References** - Optionally translates referenced documents
|
|
255
|
-
6. **Update Metadata** - Stores translation history
|
|
360
|
+
### Exclude fields from translation
|
|
256
361
|
|
|
257
|
-
|
|
362
|
+
Use `excludeFields` to prevent certain fields from being translated (slugs, enums, flags, etc.).
|
|
258
363
|
|
|
259
|
-
|
|
364
|
+
Supports:
|
|
365
|
+
|
|
366
|
+
- field name matches anywhere (e.g. `'status'`)
|
|
367
|
+
- exact paths (e.g. `'seo.title'`)
|
|
368
|
+
- array paths / wildcards (e.g. `'body[*].imageType'`)
|
|
369
|
+
|
|
370
|
+
Example:
|
|
260
371
|
|
|
261
372
|
```typescript
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
373
|
+
aiTranslationPlugin({
|
|
374
|
+
// ...
|
|
375
|
+
excludeFields: ["slug", "status", "seo.canonicalUrl", "body[*].variant"],
|
|
376
|
+
});
|
|
377
|
+
```
|
|
268
378
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
379
|
+
Important behavior:
|
|
380
|
+
|
|
381
|
+
- The plugin will **not** allow the `languageFieldName` to be excluded. If you include it, it will be removed to prevent translation errors.
|
|
382
|
+
|
|
383
|
+
### Field transforms
|
|
384
|
+
|
|
385
|
+
Some fields (like Portable Text or caption formats) benefit from transformation before translation.
|
|
386
|
+
|
|
387
|
+
Transforms run in this sequence:
|
|
388
|
+
|
|
389
|
+
1. Filter excluded fields
|
|
390
|
+
2. Apply transforms (to produce a translatable representation)
|
|
391
|
+
3. Translate (Sanity Agent or OpenAI)
|
|
392
|
+
4. Restore transforms (back into original structure)
|
|
393
|
+
5. Restore excluded fields (except language)
|
|
394
|
+
6. Create version document in the release
|
|
395
|
+
|
|
396
|
+
Built-in transforms include:
|
|
397
|
+
|
|
398
|
+
- `richTextTransform` for Portable Text
|
|
399
|
+
- `vttCaptionTransform` for VTT captions
|
|
400
|
+
- `wistiaCaptionTransform` for Wistia captions (if used by your schema)
|
|
401
|
+
|
|
402
|
+
Example setup:
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
import {
|
|
406
|
+
aiTranslationPlugin,
|
|
407
|
+
richTextTransform,
|
|
408
|
+
vttCaptionTransform,
|
|
409
|
+
wistiaCaptionTransform,
|
|
410
|
+
} from "@braze/sanity-plugin-ai-translation";
|
|
411
|
+
|
|
412
|
+
aiTranslationPlugin({
|
|
413
|
+
// ...
|
|
414
|
+
fieldTransforms: [
|
|
415
|
+
{
|
|
416
|
+
...vttCaptionTransform,
|
|
417
|
+
matcher: { schemaType: "video", fieldName: "captions" },
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
...wistiaCaptionTransform,
|
|
421
|
+
matcher: { schemaType: "videoDoc", fieldName: "wistiaCaptions" },
|
|
422
|
+
},
|
|
423
|
+
richTextTransform,
|
|
424
|
+
],
|
|
425
|
+
});
|
|
276
426
|
```
|
|
277
427
|
|
|
278
|
-
|
|
279
|
-
- Recursively traverses references up to configured depth
|
|
280
|
-
- Translates referenced documents if they don't exist
|
|
281
|
-
- Updates references to point to localized versions
|
|
282
|
-
- Uses semaphore to control concurrent jobs
|
|
428
|
+
**Order matters:** first match wins.
|
|
283
429
|
|
|
284
|
-
|
|
430
|
+
### Concurrency and depth
|
|
285
431
|
|
|
286
|
-
|
|
432
|
+
- `maxConcurrentTranslationJobs` controls how many translations run at the same time (default behavior is conservative).
|
|
433
|
+
- `maxReferenceDepth` controls how deeply references are traversed (set to `0` to disable traversal).
|
|
287
434
|
|
|
288
|
-
|
|
289
|
-
# Login to registry
|
|
290
|
-
npm login --scope=@braze --registry=https://registry.npmjs.org/
|
|
435
|
+
---
|
|
291
436
|
|
|
292
|
-
|
|
293
|
-
|
|
437
|
+
## Debugging & troubleshooting
|
|
438
|
+
|
|
439
|
+
### Enable debug logging
|
|
440
|
+
|
|
441
|
+
This plugin uses a centralized debug logger. To enable debug output in your browser:
|
|
442
|
+
|
|
443
|
+
```js
|
|
444
|
+
localStorage.setItem("sanity-ai-translation:debug", "true");
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
To disable:
|
|
448
|
+
|
|
449
|
+
```js
|
|
450
|
+
localStorage.removeItem("sanity-ai-translation:debug");
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Common issues
|
|
454
|
+
|
|
455
|
+
**Agent Actions fail immediately**
|
|
456
|
+
|
|
457
|
+
- Confirm `@sanity/client` is **7.1.0+**
|
|
458
|
+
- Confirm your client API version is `apiVersion: 'vX'` (not date-based)
|
|
459
|
+
- Confirm schema is deployed: `npx sanity deploy`
|
|
460
|
+
- Confirm `schemaId` matches your deployed schema (commonly `'_.schemas.default'`)
|
|
461
|
+
|
|
462
|
+
**Translation completes but content didn’t change**
|
|
463
|
+
|
|
464
|
+
- Ensure the document type is included in `translatableSchemaTypes`
|
|
465
|
+
- Check whether excluded fields or transforms are preventing updates
|
|
466
|
+
- If using OpenAI mode, structure validation can reject translations that modify non-text fields
|
|
467
|
+
|
|
468
|
+
**Reference translation is slow**
|
|
469
|
+
|
|
470
|
+
- Reduce `maxReferenceDepth`
|
|
471
|
+
- Reduce `maxConcurrentTranslationJobs`
|
|
472
|
+
- Ensure you’re not translating large reference graphs unnecessarily
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## Development (this repo)
|
|
477
|
+
|
|
478
|
+
This repository is a pnpm monorepo with:
|
|
479
|
+
|
|
480
|
+
- `package/` — the plugin package
|
|
481
|
+
- `demo-nextjs/` — demo Next.js app with embedded Studio
|
|
482
|
+
|
|
483
|
+
Common commands:
|
|
484
|
+
|
|
485
|
+
```sh
|
|
486
|
+
pnpm dev
|
|
294
487
|
pnpm build
|
|
295
|
-
|
|
488
|
+
|
|
489
|
+
cd package
|
|
490
|
+
pnpm test
|
|
491
|
+
pnpm typecheck
|
|
492
|
+
pnpm lint
|
|
296
493
|
```
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
## License
|
|
498
|
+
|
|
499
|
+
MIT
|