@braze/sanity-plugin-ai-translation 0.2.7 → 0.2.22

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,499 +1,334 @@
1
1
  # @braze/sanity-plugin-ai-translation
2
2
 
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
- ---
3
+ > A Sanity Studio v3 plugin that provides AI-powered translation capabilities for internationalized content using Sanity Agent Actions.
60
4
 
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)
5
+ ## Features
71
6
 
72
- Also required for Agent Actions:
7
+ - 🤖 **AI-Powered Translation** - Uses Sanity Agent Actions to translate documents between languages
8
+ - 🔄 **Smart Translation Strategies** - Automatically detects translation freshness (fresh/stale/drifted) and applies appropriate strategy
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
+ - 💬 **Feedback System** - AI-powered feedback analysis that automatically improves translation settings
14
+ - ⚙️ **Flexible Configuration** - Control concurrent translation jobs, reference depth, and translation behavior
15
+ - 🔍 **Debug Mode** - Comprehensive logging for troubleshooting translation issues
73
16
 
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.
76
-
77
- ---
78
-
79
- ## Install
80
-
81
- Use your Studio package manager (examples use `pnpm`):
17
+ ## Installation
82
18
 
83
19
  ```sh
84
20
  pnpm add @braze/sanity-plugin-ai-translation
85
21
  ```
86
22
 
87
- You’ll also need the prerequisites if you haven’t installed them yet:
88
-
89
- ```sh
90
- pnpm add @sanity/document-internationalization sanity-plugin-internationalized-array
91
- pnpm add @sanity/client@^7.1.0
92
- ```
93
-
94
- ---
95
-
96
- ## Configure (Studio)
97
-
98
- ### 1) Configure document internationalization
99
-
100
- This plugin is designed to work with `@sanity/document-internationalization`. Configure it first.
101
-
102
- You’ll typically define your supported languages as:
23
+ ## Prerequisites
103
24
 
104
- ```typescript
105
- const SUPPORTED_LANGUAGES = [
106
- { id: "en-us", title: "English" },
107
- { id: "es", title: "Spanish" },
108
- { id: "fr", title: "French" },
109
- ];
110
- ```
25
+ This plugin requires:
111
26
 
112
- Then enable internationalization for the schema types you want to translate:
27
+ 1. **Sanity Studio v4** - Version 4.9.0 or later
28
+ 2. **@sanity/client** - Version 7.1.0 or later (for Agent Actions)
29
+ 3. **@sanity/document-internationalization** - Plugin must be installed and configured
30
+ 4. **sanity-plugin-internationalized-array** - Version 3.1.5 or later
113
31
 
114
- ```typescript
115
- documentInternationalization({
116
- supportedLanguages: SUPPORTED_LANGUAGES,
117
- schemaTypes: ["post", "page"],
118
- languageField: "language", // your language field name (example)
119
- });
120
- ```
32
+ ## Configuration
121
33
 
122
- ### 2) Add the AI translation plugin
34
+ ### Basic Setup
123
35
 
124
- Add `aiTranslationPlugin()` after `documentInternationalization()`:
36
+ Add the plugin to your `sanity.config.ts` file:
125
37
 
126
38
  ```typescript
127
- import { defineConfig } from "sanity";
128
- import { documentInternationalization } from "@sanity/document-internationalization";
129
- import { aiTranslationPlugin } from "@braze/sanity-plugin-ai-translation";
39
+ import { defineConfig } from 'sanity'
40
+ import { documentInternationalization } from '@sanity/document-internationalization'
41
+ import { aiTranslationPlugin } from '@braze/sanity-plugin-ai-translation'
130
42
 
131
43
  const SUPPORTED_LANGUAGES = [
132
- { id: "en", title: "English" },
133
- { id: "es", title: "Spanish" },
134
- { id: "fr", title: "French" },
135
- ];
44
+ { id: 'en', title: 'English' },
45
+ { id: 'es', title: 'Spanish' },
46
+ { id: 'fr', title: 'French' },
47
+ { id: 'de', title: 'German' },
48
+ ]
136
49
 
137
50
  export default defineConfig({
138
- // ...your config...
51
+ // ... other config
139
52
  plugins: [
53
+ // Document internationalization must be configured first
140
54
  documentInternationalization({
141
55
  supportedLanguages: SUPPORTED_LANGUAGES,
142
- schemaTypes: ["post", "page"],
143
- languageField: "language",
56
+ schemaTypes: ['post', 'page', 'product'],
144
57
  }),
145
58
 
59
+ // Then add the AI translation plugin
146
60
  aiTranslationPlugin({
61
+ // Required: Array of supported languages
147
62
  supportedLanguages: SUPPORTED_LANGUAGES,
148
- translatableSchemaTypes: ["post", "page"],
149
- languageFieldName: "language",
150
- schemaId: "_.schemas.default",
151
- maxConcurrentTranslationJobs: 5,
152
- maxReferenceDepth: 3,
153
- }),
154
- ],
155
- });
156
- ```
157
-
158
- **Notes**
159
-
160
- - `schemaId` is usually `'_.schemas.default'` for most projects.
161
- - `languageFieldName` must match the field your documents use (often `language`).
162
-
163
- ### 3) Add translation history metadata
164
63
 
165
- This plugin can store translation history via a metadata schema you attach to `documentInternationalization`.
64
+ // Required: Document types that can be translated
65
+ translatableSchemaTypes: ['post', 'page', 'product'],
166
66
 
167
- Add `translationHistorySchema`:
67
+ // Required: Field name containing the language identifier
68
+ languageFieldName: 'language',
168
69
 
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.
70
+ // Required: Schema ID for Agent Actions (usually '_.schemas.default')
71
+ schemaId: '_.schemas.default',
183
72
 
184
- From your Studio project directory:
185
-
186
- ```sh
187
- npx sanity deploy
73
+ // Optional: Maximum concurrent translation jobs (default: 5)
74
+ maxConcurrentTranslationJobs: 5,
75
+ }),
76
+ ],
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
+ ### Configuration Options
195
81
 
196
- ---
82
+ | Option | Type | Required | Description |
83
+ |--------|------|----------|-------------|
84
+ | `supportedLanguages` | `Array<{id: string, title: string}>` | **Yes** | List of supported languages for translation |
85
+ | `translatableSchemaTypes` | `string[]` | **Yes** | Document types that should have translation actions |
86
+ | `languageFieldName` | `string` | **Yes** | Field name containing the language identifier in documents |
87
+ | `schemaId` | `string` | **Yes** | Schema ID for Sanity Agent Actions (typically `'_.schemas.default'`) |
88
+ | `maxConcurrentTranslationJobs` | `number` | No | Maximum number of concurrent translations (default: 5) |
89
+ | `openai` | `OpenAIConfig` | No | Optional OpenAI integration configuration (see below) |
197
90
 
198
- ## Optional: OpenAI mode
91
+ ### OpenAI Integration (Optional)
199
92
 
200
- OpenAI mode is optional. If enabled, users can choose **OpenAI** as the translation provider inside the translation dialog.
93
+ The plugin supports optional OpenAI integration for enhanced translation capabilities, including review of Sanity translations and direct GPT-5 translation with no character limits.
201
94
 
202
- Example configuration:
95
+ #### Setup
203
96
 
204
97
  ```typescript
205
98
  aiTranslationPlugin({
206
- supportedLanguages: SUPPORTED_LANGUAGES,
207
- translatableSchemaTypes: ["post", "page"],
208
- languageFieldName: "language",
209
- schemaId: "_.schemas.default",
210
-
99
+ // ... other required config
211
100
  openai: {
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
- });
101
+ apiKey: process.env.OPENAI_API_KEY!, // Required
102
+ model: 'gpt-5', // Optional, defaults to 'gpt-5'
103
+ reasoningEffort: 'medium', // Optional: 'minimal' | 'low' | 'medium' | 'high'
104
+ verbosity: 'medium', // Optional: 'low' | 'medium' | 'high'
105
+ enabled: true, // Optional, defaults to false
106
+ defaultMode: 'sanity-with-review', // Optional, defaults to 'sanity-only'
107
+ }
108
+ })
220
109
  ```
221
110
 
222
- **Security**
223
-
224
- - Do not hardcode API keys.
225
- - Use environment variables (e.g. `.env` / `.env.local`) and your deployment platform’s secret manager.
226
-
227
- **Why use OpenAI mode?**
228
-
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
232
-
233
- **Costs**
234
-
235
- - OpenAI calls incur API costs based on token usage.
236
-
237
- ---
111
+ **⚠️ Security Note:** Never commit API keys to version control. Always use environment variables:
238
112
 
239
- ## User guide (for editors)
113
+ ```bash
114
+ # .env.local
115
+ OPENAI_API_KEY=sk-...your-key-here...
116
+ ```
240
117
 
241
- ### Translate a document
118
+ #### Translation Modes
242
119
 
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.
120
+ When OpenAI is enabled, users can select from three translation modes:
248
121
 
249
- While translation runs, you’ll see job statuses for each target language (and for any referenced documents, if enabled).
122
+ 1. **Sanity Agent Only** (Default)
123
+ - Uses Sanity's built-in translation agent
124
+ - Fast and reliable
125
+ - No additional API costs
126
+ - 2000 character style guide limit
250
127
 
251
- ### Choose a Content Release
128
+ 2. **GPT-5 Only** (Beta)
129
+ - Direct translation via GPT-5
130
+ - 1 million token context window
131
+ - Full style guide capacity
132
+ - Incurs OpenAI API costs
252
133
 
253
- Translations are always created inside a **Content Release**.
134
+ 3. **Sanity + GPT-5 Review** (Highest Quality)
135
+ - Sanity translation reviewed and refined by GPT-5
136
+ - Best quality results
137
+ - Approximately 2x processing time
138
+ - Incurs OpenAI API costs
254
139
 
255
- In the dialog you can typically:
140
+ #### GPT-5 Features
256
141
 
257
- - create a new release, or
258
- - add the translations to an existing active release
142
+ GPT-5 (released August 2025) provides:
143
+ - **1M token context window** - Handle very large documents and style guides
144
+ - **Advanced reasoning** - Configurable reasoning effort for quality vs. speed tradeoff
145
+ - **Verbosity control** - Adjust response length to optimize token usage
146
+ - **Structure preservation** - Deterministic serialization ensures all document metadata and structure is preserved
259
147
 
260
- Use releases when you want:
148
+ #### Cost Considerations
261
149
 
262
- - staged review
263
- - coordinated publishing of multiple translations at once
150
+ OpenAI modes incur API costs based on token usage:
151
+ - **GPT-5**: ~$0.002 per 1k input tokens, ~$0.010 per 1k output tokens, ~$0.005 per 1k reasoning tokens
152
+ - **Typical article** (2000 words): ~$0.05-0.15 per translation
153
+ - The plugin shows real-time cost estimates and usage summaries
264
154
 
265
- ### Translation options
155
+ #### OpenAI Configuration Options
266
156
 
267
- The exact UI labels may vary, but the workflow supports:
157
+ | Option | Type | Default | Description |
158
+ |--------|------|---------|-------------|
159
+ | `apiKey` | `string` | - | OpenAI API key (required if OpenAI enabled) |
160
+ | `model` | `'gpt-5' \| 'gpt-4o' \| 'gpt-4-turbo' \| 'gpt-4'` | `'gpt-5'` | Model to use for translation/review |
161
+ | `reasoningEffort` | `'minimal' \| 'low' \| 'medium' \| 'high'` | `'medium'` | GPT-5 reasoning effort (affects speed and quality) |
162
+ | `verbosity` | `'low' \| 'medium' \| 'high'` | `'medium'` | GPT-5 response verbosity |
163
+ | `enabled` | `boolean` | `false` | Enable OpenAI features |
164
+ | `defaultMode` | `TranslationMode` | `'sanity-only'` | Default translation mode when dialog opens |
268
165
 
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).
166
+ ### Schema Setup
277
167
 
278
- ### Translate referenced documents
168
+ The plugin requires you to add the `translationHistory` schema to your document internationalization configuration:
279
169
 
280
- If you enable reference translation:
170
+ ```typescript
171
+ import { documentInternationalization } from '@sanity/document-internationalization'
172
+ import { translationHistorySchema } from '@braze/sanity-plugin-ai-translation'
281
173
 
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.
174
+ // In your sanity.config.ts
175
+ documentInternationalization({
176
+ supportedLanguages: SUPPORTED_LANGUAGES,
177
+ schemaTypes: ['post', 'page'],
178
+ // Add translation history to metadata
179
+ metadataFields: [translationHistorySchema],
180
+ })
181
+ ```
285
182
 
286
- This is useful for content like:
183
+ ### Deploy Schema
287
184
 
288
- - posts referencing authors
289
- - pages referencing shared sections
290
- - documents referencing related content
185
+ After configuration, deploy your schema so Agent Actions can access it:
291
186
 
292
- ### What gets created
187
+ ```bash
188
+ cd your-sanity-project
189
+ npx sanity deploy
190
+ ```
293
191
 
294
- For each selected target language, the plugin creates a **versioned document** inside the selected Content Release.
192
+ ## Usage
295
193
 
296
- You can then:
194
+ ### Translation Action
297
195
 
298
- - review and edit translated versions
299
- - publish the release when ready
196
+ Once configured, a "Translate" action will appear on all documents of types listed in `translatableSchemaTypes`.
300
197
 
301
- ---
198
+ 1. Open a document in Sanity Studio
199
+ 2. Click the "Translate" action in the document menu
200
+ 3. Select target languages
201
+ 4. Configure translation options:
202
+ - **Overwrite fresh translations** - Re-translate even if translation is up-to-date
203
+ - **Translate only diffs** - For stale translations, only translate changed fields
204
+ - **Translate references** - Include referenced documents in translation
205
+ - **Max reference depth** - How deep to traverse references (if enabled)
206
+ 5. Click "Translate" to start
302
207
 
303
- ## Content configuration (settings + glossary)
208
+ ### Translation States
304
209
 
305
- The plugin introduces two document types for configuration:
210
+ The plugin tracks three translation states:
306
211
 
307
- ### `translationSettings`
212
+ - **Fresh** ✅ - Translation is up-to-date with source
213
+ - **Stale** ⚠️ - Source document revision changed (trivial changes)
214
+ - **Drifted** 🔴 - Source document content changed significantly
308
215
 
309
- Create a document with `_id == "translation-settings"` to configure:
216
+ Based on state:
217
+ - **Fresh** translations are skipped (unless "Overwrite fresh" is enabled)
218
+ - **Stale** translations can use diff-based translation (if "Translate only diffs" is enabled)
219
+ - **Drifted** translations are fully re-translated
310
220
 
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)
221
+ ### Translation Settings
314
222
 
315
- Example shape:
223
+ Create a `translationSettings` document to customize translation behavior:
316
224
 
317
225
  ```typescript
318
226
  {
319
227
  _type: 'translationSettings',
320
228
  _id: 'translation-settings',
229
+
230
+ // Global prompt applied to all translations
321
231
  globalPrompt: 'Maintain a professional tone. Preserve formatting and links.',
232
+
233
+ // Locale-specific prompts
322
234
  localePrompts: [
323
- {_key: 'es', value: 'Use formal Spanish (usted).'},
324
- {_key: 'fr', value: 'Use formal French.'},
235
+ {
236
+ locale: 'es',
237
+ prompt: 'Use formal Spanish (usted). Avoid Latin American regionalisms.'
238
+ },
239
+ {
240
+ locale: 'fr',
241
+ prompt: 'Use formal French. Maintain gender agreement for all terms.'
242
+ }
325
243
  ],
244
+
245
+ // Terms that should never be translated
326
246
  protectedPhrases: ['Braze', 'iOS', 'Android', 'SDK']
327
247
  }
328
248
  ```
329
249
 
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).
250
+ ### Translation Glossary
334
251
 
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:
252
+ Create `translationGlossaryTerm` documents for specific term mappings:
342
253
 
343
254
  ```typescript
344
255
  {
345
256
  _type: 'translationGlossaryTerm',
346
257
  translations: [
347
- {_key: 'en', value: 'dashboard'},
348
- {_key: 'es', value: 'panel de control'},
349
- {_key: 'fr', value: 'tableau de bord'},
258
+ { locale: 'en', value: 'dashboard' },
259
+ { locale: 'es', value: 'panel de control' },
260
+ { locale: 'fr', value: 'tableau de bord' },
261
+ { locale: 'de', value: 'Dashboard' }
350
262
  ]
351
263
  }
352
264
  ```
353
265
 
354
- Glossary terms are used to build locale-specific translation instructions.
355
-
356
- ---
357
-
358
- ## Advanced configuration
359
-
360
- ### Exclude fields from translation
361
-
362
- Use `excludeFields` to prevent certain fields from being translated (slugs, enums, flags, etc.).
363
-
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:
371
-
372
- ```typescript
373
- aiTranslationPlugin({
374
- // ...
375
- excludeFields: ["slug", "status", "seo.canonicalUrl", "body[*].variant"],
376
- });
377
- ```
378
-
379
- Important behavior:
266
+ ### Give Translation Feedback
380
267
 
381
- - The plugin will **not** allow the `languageFieldName` to be excluded. If you include it, it will be removed to prevent translation errors.
268
+ The plugin includes an AI-powered feedback system that learns from corrections:
382
269
 
383
- ### Field transforms
270
+ 1. Open a translated document
271
+ 2. Click "Give Translation Feedback" action
272
+ 3. Provide feedback and/or enable "Include edits" to analyze changes
273
+ 4. Review AI-generated suggestions:
274
+ - Global prompt updates
275
+ - Locale-specific prompt updates
276
+ - Protected phrases to add
277
+ - Glossary terms to add
278
+ 5. Approve suggestions to apply
384
279
 
385
- Some fields (like Portable Text or caption formats) benefit from transformation before translation.
280
+ The AI analyzes your feedback and automatically updates translation settings to improve future translations.
386
281
 
387
- Transforms run in this sequence:
282
+ ## Translation Workflow
388
283
 
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
284
+ ### How It Works
395
285
 
396
- Built-in transforms include:
286
+ 1. **Fetch Metadata** - Retrieves translation history and existing translations
287
+ 2. **Determine Strategy** - Checks freshness state (fresh/stale/drifted)
288
+ 3. **Prepare Translation**:
289
+ - For **drifted** or **fresh (overwrite)**: Full document translation
290
+ - For **stale (translate diffs)**: Diff-based translation of changed fields only
291
+ 4. **Translate** - Uses Sanity Agent Actions with configured prompts
292
+ 5. **Localize References** - Optionally translates referenced documents
293
+ 6. **Update Metadata** - Stores translation history with snapshots
397
294
 
398
- - `richTextTransform` for Portable Text
399
- - `vttCaptionTransform` for VTT captions
400
- - `wistiaCaptionTransform` for Wistia captions (if used by your schema)
295
+ ### Reference Translation
401
296
 
402
- Example setup:
297
+ When "Translate references" is enabled:
403
298
 
404
299
  ```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
- });
426
- ```
427
-
428
- **Order matters:** first match wins.
429
-
430
- ### Concurrency and depth
431
-
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).
434
-
435
- ---
436
-
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:
300
+ // Example: Post with author reference
301
+ {
302
+ _type: 'post',
303
+ title: 'My Post',
304
+ author: { _ref: 'author-en' } // Original English author
305
+ }
448
306
 
449
- ```js
450
- localStorage.removeItem("sanity-ai-translation:debug");
307
+ // After translation with references enabled:
308
+ {
309
+ _type: 'post',
310
+ language: 'es',
311
+ title: 'Mi Publicación',
312
+ author: { _ref: 'author-es' } // Now points to Spanish author
313
+ }
451
314
  ```
452
315
 
453
- ### Common issues
316
+ The plugin:
317
+ - Recursively traverses references up to configured depth
318
+ - Translates referenced documents if they don't exist
319
+ - Updates references to point to localized versions
320
+ - Uses semaphore to control concurrent jobs
454
321
 
455
- **Agent Actions fail immediately**
322
+ ## Publishing
456
323
 
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'`)
324
+ This package is configured for internal publishing to the Braze npm registry.
461
325
 
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
487
- pnpm build
326
+ ```bash
327
+ # Login to registry
328
+ npm login --scope=@braze --registry=https://registry.npmjs.org/
488
329
 
330
+ # Build and publish
489
331
  cd package
490
- pnpm test
491
- pnpm typecheck
492
- pnpm lint
332
+ pnpm build
333
+ npm publish
493
334
  ```
494
-
495
- ---
496
-
497
- ## License
498
-
499
- MIT