@braze/sanity-plugin-ai-translation 0.2.3 → 0.2.5
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 +16 -54
- package/dist/index.d.ts +147 -5
- package/dist/index.js +1052 -1310
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- 🤖 **AI-Powered Translation** - Uses Sanity Agent Actions to translate documents between languages
|
|
8
|
-
-
|
|
8
|
+
- 📦 **Content Releases** - Translations are created in Content Releases for staged publishing
|
|
9
9
|
- 🔗 **Reference Translation** - Optionally translate referenced documents recursively with configurable depth
|
|
10
10
|
- 🎯 **Custom Translation Prompts** - Configure global and locale-specific translation instructions
|
|
11
11
|
- 📚 **Translation Glossary** - Define term-specific translations to ensure consistency
|
|
12
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
13
|
- ⚙️ **Flexible Configuration** - Control concurrent translation jobs, reference depth, and translation behavior
|
|
15
14
|
- 🔍 **Debug Mode** - Comprehensive logging for troubleshooting translation issues
|
|
16
15
|
|
|
@@ -90,7 +89,7 @@ export default defineConfig({
|
|
|
90
89
|
|
|
91
90
|
### OpenAI Integration (Optional)
|
|
92
91
|
|
|
93
|
-
The plugin supports optional OpenAI integration for enhanced translation capabilities, including
|
|
92
|
+
The plugin supports optional OpenAI integration for enhanced translation capabilities, including direct OpenAI translation with no character limits.
|
|
94
93
|
|
|
95
94
|
#### Setup
|
|
96
95
|
|
|
@@ -103,7 +102,7 @@ aiTranslationPlugin({
|
|
|
103
102
|
reasoningEffort: 'medium', // Optional: 'minimal' | 'low' | 'medium' | 'high'
|
|
104
103
|
verbosity: 'medium', // Optional: 'low' | 'medium' | 'high'
|
|
105
104
|
enabled: true, // Optional, defaults to false
|
|
106
|
-
defaultMode: '
|
|
105
|
+
defaultMode: 'openai-only', // Optional, defaults to 'sanity-only'
|
|
107
106
|
}
|
|
108
107
|
})
|
|
109
108
|
```
|
|
@@ -117,7 +116,7 @@ OPENAI_API_KEY=sk-...your-key-here...
|
|
|
117
116
|
|
|
118
117
|
#### Translation Modes
|
|
119
118
|
|
|
120
|
-
When OpenAI is enabled, users can select from
|
|
119
|
+
When OpenAI is enabled, users can select from two translation modes:
|
|
121
120
|
|
|
122
121
|
1. **Sanity Agent Only** (Default)
|
|
123
122
|
- Uses Sanity's built-in translation agent
|
|
@@ -125,21 +124,15 @@ When OpenAI is enabled, users can select from three translation modes:
|
|
|
125
124
|
- No additional API costs
|
|
126
125
|
- 2000 character style guide limit
|
|
127
126
|
|
|
128
|
-
2. **
|
|
129
|
-
- Direct translation via
|
|
127
|
+
2. **OpenAI Only** (Beta)
|
|
128
|
+
- Direct translation via OpenAI
|
|
130
129
|
- 1 million token context window
|
|
131
130
|
- Full style guide capacity
|
|
132
131
|
- Incurs OpenAI API costs
|
|
133
132
|
|
|
134
|
-
|
|
135
|
-
- Sanity translation reviewed and refined by GPT-5
|
|
136
|
-
- Best quality results
|
|
137
|
-
- Approximately 2x processing time
|
|
138
|
-
- Incurs OpenAI API costs
|
|
139
|
-
|
|
140
|
-
#### GPT-5 Features
|
|
133
|
+
#### OpenAI Features
|
|
141
134
|
|
|
142
|
-
|
|
135
|
+
OpenAI models provide:
|
|
143
136
|
- **1M token context window** - Handle very large documents and style guides
|
|
144
137
|
- **Advanced reasoning** - Configurable reasoning effort for quality vs. speed tradeoff
|
|
145
138
|
- **Verbosity control** - Adjust response length to optimize token usage
|
|
@@ -148,7 +141,7 @@ GPT-5 (released August 2025) provides:
|
|
|
148
141
|
#### Cost Considerations
|
|
149
142
|
|
|
150
143
|
OpenAI modes incur API costs based on token usage:
|
|
151
|
-
- **
|
|
144
|
+
- **OpenAI**: ~$0.002 per 1k input tokens, ~$0.010 per 1k output tokens, ~$0.005 per 1k reasoning tokens
|
|
152
145
|
- **Typical article** (2000 words): ~$0.05-0.15 per translation
|
|
153
146
|
- The plugin shows real-time cost estimates and usage summaries
|
|
154
147
|
|
|
@@ -158,8 +151,8 @@ OpenAI modes incur API costs based on token usage:
|
|
|
158
151
|
|--------|------|---------|-------------|
|
|
159
152
|
| `apiKey` | `string` | - | OpenAI API key (required if OpenAI enabled) |
|
|
160
153
|
| `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'` |
|
|
162
|
-
| `verbosity` | `'low' \| 'medium' \| 'high'` | `'medium'` |
|
|
154
|
+
| `reasoningEffort` | `'minimal' \| 'low' \| 'medium' \| 'high'` | `'medium'` | OpenAI reasoning effort (affects speed and quality) |
|
|
155
|
+
| `verbosity` | `'low' \| 'medium' \| 'high'` | `'medium'` | OpenAI response verbosity |
|
|
163
156
|
| `enabled` | `boolean` | `false` | Enable OpenAI features |
|
|
164
157
|
| `defaultMode` | `TranslationMode` | `'sanity-only'` | Default translation mode when dialog opens |
|
|
165
158
|
|
|
@@ -205,19 +198,6 @@ Once configured, a "Translate" action will appear on all documents of types list
|
|
|
205
198
|
- **Max reference depth** - How deep to traverse references (if enabled)
|
|
206
199
|
5. Click "Translate" to start
|
|
207
200
|
|
|
208
|
-
### Translation States
|
|
209
|
-
|
|
210
|
-
The plugin tracks three translation states:
|
|
211
|
-
|
|
212
|
-
- **Fresh** ✅ - Translation is up-to-date with source
|
|
213
|
-
- **Stale** ⚠️ - Source document revision changed (trivial changes)
|
|
214
|
-
- **Drifted** 🔴 - Source document content changed significantly
|
|
215
|
-
|
|
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
|
|
220
|
-
|
|
221
201
|
### Translation Settings
|
|
222
202
|
|
|
223
203
|
Create a `translationSettings` document to customize translation behavior:
|
|
@@ -263,34 +243,16 @@ Create `translationGlossaryTerm` documents for specific term mappings:
|
|
|
263
243
|
}
|
|
264
244
|
```
|
|
265
245
|
|
|
266
|
-
### Give Translation Feedback
|
|
267
|
-
|
|
268
|
-
The plugin includes an AI-powered feedback system that learns from corrections:
|
|
269
|
-
|
|
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
|
|
279
|
-
|
|
280
|
-
The AI analyzes your feedback and automatically updates translation settings to improve future translations.
|
|
281
|
-
|
|
282
246
|
## Translation Workflow
|
|
283
247
|
|
|
284
248
|
### How It Works
|
|
285
249
|
|
|
286
|
-
1. **
|
|
287
|
-
2. **
|
|
288
|
-
3. **
|
|
289
|
-
|
|
290
|
-
- For **stale (translate diffs)**: Diff-based translation of changed fields only
|
|
291
|
-
4. **Translate** - Uses Sanity Agent Actions with configured prompts
|
|
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
|
|
292
254
|
5. **Localize References** - Optionally translates referenced documents
|
|
293
|
-
6. **Update Metadata** - Stores translation history
|
|
255
|
+
6. **Update Metadata** - Stores translation history
|
|
294
256
|
|
|
295
257
|
### Reference Translation
|
|
296
258
|
|
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,30 @@ export declare const aiTranslationPlugin: Plugin_2<PluginConfig>;
|
|
|
38
38
|
*/
|
|
39
39
|
export declare type AnyFieldTransform = FieldTransform<any, any>;
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Common enum field names that are typically excluded from translation
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
export declare const COMMON_ENUM_FIELDS: readonly [
|
|
46
|
+
"status",
|
|
47
|
+
"state",
|
|
48
|
+
"type",
|
|
49
|
+
"category",
|
|
50
|
+
"priority",
|
|
51
|
+
"visibility",
|
|
52
|
+
"role",
|
|
53
|
+
"permission",
|
|
54
|
+
"level",
|
|
55
|
+
"mode",
|
|
56
|
+
"format",
|
|
57
|
+
"variant",
|
|
58
|
+
"size",
|
|
59
|
+
"theme",
|
|
60
|
+
"kind",
|
|
61
|
+
"phase",
|
|
62
|
+
"stage",
|
|
63
|
+
];
|
|
64
|
+
|
|
41
65
|
/**
|
|
42
66
|
* Criteria for matching fields that should be transformed.
|
|
43
67
|
* @public
|
|
@@ -169,6 +193,36 @@ export declare interface FieldTransform<
|
|
|
169
193
|
) => TOriginal;
|
|
170
194
|
}
|
|
171
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Result of filtering excluded fields from a document
|
|
198
|
+
* @internal
|
|
199
|
+
*/
|
|
200
|
+
export declare interface FilteredDocument<T = any> {
|
|
201
|
+
/** Document with excluded fields removed */
|
|
202
|
+
filteredDocument: T;
|
|
203
|
+
/** Excluded field values that were removed */
|
|
204
|
+
excludedValues: Record<string, any>;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Recursively filters out excluded fields from a document
|
|
209
|
+
* @param document - The document to filter
|
|
210
|
+
* @param excludeFields - Array of field patterns to exclude. Supports:
|
|
211
|
+
* - Field names: 'status' (matches any field named 'status' anywhere)
|
|
212
|
+
* - Exact paths: 'meta.category' (matches only 'category' under 'meta')
|
|
213
|
+
* - Array paths: 'body[0].imageType' (matches 'imageType' in first array item)
|
|
214
|
+
* - Wildcard arrays: 'body[*].imageType' (matches 'imageType' in any array item)
|
|
215
|
+
* - Hierarchical: '**.status' (explicitly matches 'status' anywhere - same as just 'status')
|
|
216
|
+
* @param currentPath - Current path in the document (used internally)
|
|
217
|
+
* @returns Filtered document and excluded values
|
|
218
|
+
* @internal
|
|
219
|
+
*/
|
|
220
|
+
export declare function filterExcludedFields<T extends Record<string, any>>(
|
|
221
|
+
document: T,
|
|
222
|
+
excludeFields?: string[],
|
|
223
|
+
currentPath?: string,
|
|
224
|
+
): FilteredDocument<T>;
|
|
225
|
+
|
|
172
226
|
/**
|
|
173
227
|
* Helper type to infer the original type from a FieldTransform.
|
|
174
228
|
* Useful for type checking and creating wrapper functions.
|
|
@@ -233,14 +287,105 @@ export declare interface PluginConfig {
|
|
|
233
287
|
maxReferenceDepth?: number;
|
|
234
288
|
openai?: {
|
|
235
289
|
apiKey: string;
|
|
236
|
-
model?:
|
|
290
|
+
model?:
|
|
291
|
+
| "gpt-5.1"
|
|
292
|
+
| "gpt-5"
|
|
293
|
+
| "gpt-5-mini"
|
|
294
|
+
| "gpt-5-nano"
|
|
295
|
+
| "gpt-5-pro"
|
|
296
|
+
| "gpt-4o"
|
|
297
|
+
| "gpt-4-turbo"
|
|
298
|
+
| "gpt-4";
|
|
237
299
|
reasoningEffort?: "low" | "medium" | "high";
|
|
238
300
|
enabled?: boolean;
|
|
239
301
|
defaultMode?: TranslationMode;
|
|
240
302
|
};
|
|
241
303
|
fieldTransforms?: AnyFieldTransform[];
|
|
304
|
+
/**
|
|
305
|
+
* Fields to exclude from translation. These fields will be preserved as-is in the translated document.
|
|
306
|
+
* Supports field names (e.g., 'status') and nested field paths (e.g., 'meta.category').
|
|
307
|
+
* Useful for enum fields, IDs, technical values, and other non-translatable content.
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```typescript
|
|
311
|
+
* excludeFields: ['status', 'category', 'type', 'meta.priority', 'config.mode']
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
excludeFields?: string[];
|
|
242
315
|
}
|
|
243
316
|
|
|
317
|
+
/**
|
|
318
|
+
* Predefined exclusion lists for common use cases
|
|
319
|
+
* @internal
|
|
320
|
+
*/
|
|
321
|
+
export declare const PREDEFINED_EXCLUSIONS: {
|
|
322
|
+
/** Common enum and status fields */
|
|
323
|
+
readonly enums: readonly [
|
|
324
|
+
"status",
|
|
325
|
+
"state",
|
|
326
|
+
"type",
|
|
327
|
+
"category",
|
|
328
|
+
"priority",
|
|
329
|
+
"visibility",
|
|
330
|
+
"role",
|
|
331
|
+
"permission",
|
|
332
|
+
"level",
|
|
333
|
+
"mode",
|
|
334
|
+
"format",
|
|
335
|
+
"variant",
|
|
336
|
+
"size",
|
|
337
|
+
"theme",
|
|
338
|
+
"kind",
|
|
339
|
+
"phase",
|
|
340
|
+
"stage",
|
|
341
|
+
];
|
|
342
|
+
/** All metadata and system fields (starting with _) */
|
|
343
|
+
readonly metadata: readonly [
|
|
344
|
+
"_id",
|
|
345
|
+
"_type",
|
|
346
|
+
"_rev",
|
|
347
|
+
"_createdAt",
|
|
348
|
+
"_updatedAt",
|
|
349
|
+
];
|
|
350
|
+
/** Common technical and configuration fields */
|
|
351
|
+
readonly technical: readonly [
|
|
352
|
+
"slug",
|
|
353
|
+
"handle",
|
|
354
|
+
"key",
|
|
355
|
+
"code",
|
|
356
|
+
"id",
|
|
357
|
+
"uuid",
|
|
358
|
+
"token",
|
|
359
|
+
"hash",
|
|
360
|
+
"checksum",
|
|
361
|
+
"version",
|
|
362
|
+
"config",
|
|
363
|
+
"settings",
|
|
364
|
+
];
|
|
365
|
+
/** SEO and URL-related fields that often shouldn't be translated */
|
|
366
|
+
readonly seo: readonly [
|
|
367
|
+
"slug",
|
|
368
|
+
"handle",
|
|
369
|
+
"permalink",
|
|
370
|
+
"canonical",
|
|
371
|
+
"redirect",
|
|
372
|
+
"robots",
|
|
373
|
+
"sitemap",
|
|
374
|
+
];
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Restores previously excluded fields to a translated document
|
|
379
|
+
* @param translatedDocument - The translated document
|
|
380
|
+
* @param excludedValues - The excluded field values to restore
|
|
381
|
+
* @returns Document with excluded fields restored
|
|
382
|
+
* @internal
|
|
383
|
+
*/
|
|
384
|
+
export declare function restoreExcludedFields<T extends Record<string, any>>(
|
|
385
|
+
translatedDocument: T,
|
|
386
|
+
excludedValues: Record<string, any>,
|
|
387
|
+
): T;
|
|
388
|
+
|
|
244
389
|
/**
|
|
245
390
|
* Transform for handling Portable Text (rich text) content using XML-like serialization.
|
|
246
391
|
* This leverages the existing serialization utilities to convert complex rich text
|
|
@@ -314,10 +459,7 @@ export declare const translationHistorySchema: {
|
|
|
314
459
|
WidenValidation &
|
|
315
460
|
WidenInitialValue;
|
|
316
461
|
|
|
317
|
-
declare type TranslationMode =
|
|
318
|
-
| "sanity-only"
|
|
319
|
-
| "openai-only"
|
|
320
|
-
| "sanity-with-review";
|
|
462
|
+
declare type TranslationMode = "sanity-only" | "openai-only";
|
|
321
463
|
|
|
322
464
|
/**
|
|
323
465
|
* Represents a VTT caption cue with timing and text content.
|