@braze/sanity-plugin-ai-translation 0.2.55 → 0.2.57

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 CHANGED
@@ -1,296 +1,499 @@
1
1
  # @braze/sanity-plugin-ai-translation
2
2
 
3
- > A Sanity Studio v3 plugin that provides AI-powered translation capabilities for internationalized content using Sanity Agent Actions.
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
- ## Features
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
- - 🤖 **AI-Powered Translation** - Uses Sanity Agent Actions to translate documents between languages
8
- - 📦 **Content Releases** - Translations are created in Content Releases for staged publishing
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
- ## Installation
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
- ## Prerequisites
87
+ You’ll also need the prerequisites if you haven’t installed them yet:
23
88
 
24
- This plugin requires:
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
- 1. **Sanity Studio v4** - Version 4.9.0 or later
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
- ## Configuration
98
+ ### 1) Configure document internationalization
32
99
 
33
- ### Basic Setup
100
+ This plugin is designed to work with `@sanity/document-internationalization`. Configure it first.
34
101
 
35
- Add the plugin to your `sanity.config.ts` file:
102
+ You’ll typically define your supported languages as:
36
103
 
37
104
  ```typescript
38
- import { defineConfig } from 'sanity'
39
- import { documentInternationalization } from '@sanity/document-internationalization'
40
- import { aiTranslationPlugin } from '@braze/sanity-plugin-ai-translation'
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: 'en', title: 'English' },
44
- { id: 'es', title: 'Spanish' },
45
- { id: 'fr', title: 'French' },
46
- { id: 'de', title: 'German' },
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
- // ... other config
138
+ // ...your config...
51
139
  plugins: [
52
- // Document internationalization must be configured first
53
140
  documentInternationalization({
54
141
  supportedLanguages: SUPPORTED_LANGUAGES,
55
- schemaTypes: ['post', 'page', 'product'],
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
- // Required: Document types that can be translated
64
- translatableSchemaTypes: ['post', 'page', 'product'],
158
+ **Notes**
65
159
 
66
- // Required: Field name containing the language identifier
67
- languageFieldName: 'language',
160
+ - `schemaId` is usually `'_.schemas.default'` for most projects.
161
+ - `languageFieldName` must match the field your documents use (often `language`).
68
162
 
69
- // Required: Schema ID for Agent Actions (usually '_.schemas.default')
70
- schemaId: '_.schemas.default',
163
+ ### 3) Add translation history metadata
71
164
 
72
- // Optional: Maximum concurrent translation jobs (default: 5)
73
- maxConcurrentTranslationJobs: 5,
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
- ### Configuration Options
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
- | Option | Type | Required | Description |
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
- ### OpenAI Integration (Optional)
198
+ ## Optional: OpenAI mode
91
199
 
92
- The plugin supports optional OpenAI integration for enhanced translation capabilities, including direct OpenAI translation with no character limits.
200
+ OpenAI mode is optional. If enabled, users can choose **OpenAI** as the translation provider inside the translation dialog.
93
201
 
94
- #### Setup
202
+ Example configuration:
95
203
 
96
204
  ```typescript
97
205
  aiTranslationPlugin({
98
- // ... other required config
206
+ supportedLanguages: SUPPORTED_LANGUAGES,
207
+ translatableSchemaTypes: ["post", "page"],
208
+ languageFieldName: "language",
209
+ schemaId: "_.schemas.default",
210
+
99
211
  openai: {
100
- apiKey: process.env.OPENAI_API_KEY!, // Required
101
- model: 'gpt-5', // Optional, defaults to 'gpt-5'
102
- reasoningEffort: 'medium', // Optional: 'minimal' | 'low' | 'medium' | 'high'
103
- verbosity: 'medium', // Optional: 'low' | 'medium' | 'high'
104
- enabled: true, // Optional, defaults to false
105
- defaultMode: 'openai-only', // Optional, defaults to 'sanity-only'
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
- **⚠️ Security Note:** Never commit API keys to version control. Always use environment variables:
222
+ **Security**
111
223
 
112
- ```bash
113
- # .env.local
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
- #### Translation Modes
227
+ **Why use OpenAI mode?**
118
228
 
119
- When OpenAI is enabled, users can select from two translation modes:
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
- 1. **Sanity Agent Only** (Default)
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
- 2. **OpenAI Only** (Beta)
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
- #### OpenAI Features
237
+ ---
134
238
 
135
- OpenAI models provide:
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
- #### Cost Considerations
241
+ ### Translate a document
142
242
 
143
- OpenAI modes incur API costs based on token usage:
144
- - **OpenAI**: ~$0.002 per 1k input tokens, ~$0.010 per 1k output tokens, ~$0.005 per 1k reasoning tokens
145
- - **Typical article** (2000 words): ~$0.05-0.15 per translation
146
- - The plugin shows real-time cost estimates and usage summaries
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
- #### OpenAI Configuration Options
249
+ While translation runs, you’ll see job statuses for each target language (and for any referenced documents, if enabled).
149
250
 
150
- | Option | Type | Default | Description |
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
- ### Schema Setup
253
+ Translations are always created inside a **Content Release**.
160
254
 
161
- The plugin requires you to add the `translationHistory` schema to your document internationalization configuration:
255
+ In the dialog you can typically:
162
256
 
163
- ```typescript
164
- import { documentInternationalization } from '@sanity/document-internationalization'
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
- // In your sanity.config.ts
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
- ### Deploy Schema
262
+ - staged review
263
+ - coordinated publishing of multiple translations at once
177
264
 
178
- After configuration, deploy your schema so Agent Actions can access it:
265
+ ### Translation options
179
266
 
180
- ```bash
181
- cd your-sanity-project
182
- npx sanity deploy
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
- ## Usage
301
+ ---
186
302
 
187
- ### Translation Action
303
+ ## Content configuration (settings + glossary)
188
304
 
189
- Once configured, a "Translate" action will appear on all documents of types listed in `translatableSchemaTypes`.
305
+ The plugin introduces two document types for configuration:
190
306
 
191
- 1. Open a document in Sanity Studio
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
- ### Translation Settings
309
+ Create a document with `_id == "translation-settings"` to configure:
202
310
 
203
- Create a `translationSettings` document to customize translation behavior:
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
- locale: 'es',
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
- ### Translation Glossary
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
- Create `translationGlossaryTerm` documents for specific term mappings:
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
- { locale: 'en', value: 'dashboard' },
239
- { locale: 'es', value: 'panel de control' },
240
- { locale: 'fr', value: 'tableau de bord' },
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
- ## Translation Workflow
354
+ Glossary terms are used to build locale-specific translation instructions.
355
+
356
+ ---
247
357
 
248
- ### How It Works
358
+ ## Advanced configuration
249
359
 
250
- 1. **Select Release** - Choose to create a new Content Release or add to an existing one
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
- ### Reference Translation
362
+ Use `excludeFields` to prevent certain fields from being translated (slugs, enums, flags, etc.).
258
363
 
259
- When "Translate references" is enabled:
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
- // Example: Post with author reference
263
- {
264
- _type: 'post',
265
- title: 'My Post',
266
- author: { _ref: 'author-en' } // Original English author
267
- }
373
+ aiTranslationPlugin({
374
+ // ...
375
+ excludeFields: ["slug", "status", "seo.canonicalUrl", "body[*].variant"],
376
+ });
377
+ ```
268
378
 
269
- // After translation with references enabled:
270
- {
271
- _type: 'post',
272
- language: 'es',
273
- title: 'Mi Publicación',
274
- author: { _ref: 'author-es' } // Now points to Spanish author
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
- The plugin:
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
- ## Publishing
430
+ ### Concurrency and depth
285
431
 
286
- This package is configured for internal publishing to the Braze npm registry.
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
- ```bash
289
- # Login to registry
290
- npm login --scope=@braze --registry=https://registry.npmjs.org/
435
+ ---
291
436
 
292
- # Build and publish
293
- cd package
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
- npm publish
488
+
489
+ cd package
490
+ pnpm test
491
+ pnpm typecheck
492
+ pnpm lint
296
493
  ```
494
+
495
+ ---
496
+
497
+ ## License
498
+
499
+ MIT