@easyling/sanity-auto-translate 0.0.0
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 +748 -0
- package/dist/config.d.ts +55 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/index.d.ts +109 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +73 -0
- package/dist/logger.d.ts.map +1 -0
- package/package.json +71 -0
- package/sanity.function.json +9 -0
package/README.md
ADDED
|
@@ -0,0 +1,748 @@
|
|
|
1
|
+
# Sanity Function: Auto-Translate on Publish
|
|
2
|
+
|
|
3
|
+
Serverless function that automatically translates Sanity documents when published. Hooks into the `document.publish` lifecycle event to create translated versions without blocking the publish operation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Automatic Translation**: Translates documents on publish without manual intervention
|
|
8
|
+
- **Configurable Document Types**: Control which document types are auto-translated
|
|
9
|
+
- **Multi-Locale Support**: Translate to multiple target languages simultaneously
|
|
10
|
+
- **Shared Configuration**: Uses the same configuration as the Studio plugin (no environment variables needed)
|
|
11
|
+
- **Non-Blocking**: Never blocks document publishing - errors are logged and gracefully handled
|
|
12
|
+
- **Deadline Monitoring**: Tracks execution time and terminates gracefully before timeout
|
|
13
|
+
- **Size Limit Protection**: Skips documents exceeding size limits to prevent timeouts
|
|
14
|
+
- **Comprehensive Logging**: Structured JSON logs for monitoring and debugging
|
|
15
|
+
- **Metrics Tracking**: Tracks success/failure rates per locale and error types
|
|
16
|
+
|
|
17
|
+
## How It Works
|
|
18
|
+
|
|
19
|
+
1. **Trigger**: Function is invoked when any document is published in Sanity
|
|
20
|
+
2. **Filter**: Checks if document type is in `autoTranslateDocumentTypes` configuration
|
|
21
|
+
3. **Extract**: Uses `ContentExtractor` from shared library to extract translatable content
|
|
22
|
+
4. **Translate**: Sends translation request to configured API using `TranslationService`
|
|
23
|
+
5. **Create**: Creates translated documents as drafts using `DocumentCreationService`
|
|
24
|
+
6. **Log**: Records all operations with structured logging for monitoring
|
|
25
|
+
|
|
26
|
+
The function uses the same core services as the Studio plugin, ensuring identical translation behavior across both contexts.
|
|
27
|
+
|
|
28
|
+
## Deployment
|
|
29
|
+
|
|
30
|
+
### Prerequisites
|
|
31
|
+
|
|
32
|
+
- Sanity CLI installed: `npm install -g @sanity/cli`
|
|
33
|
+
- Sanity project with dataset
|
|
34
|
+
- Write access to the Sanity project
|
|
35
|
+
|
|
36
|
+
### Deploy the Function
|
|
37
|
+
|
|
38
|
+
1. Navigate to the function directory:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
cd function
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
2. Build the function:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm run build
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
3. Deploy using Sanity CLI:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
sanity function deploy
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The CLI will:
|
|
57
|
+
- Upload the function code to Sanity's infrastructure
|
|
58
|
+
- Register the `document.publish` trigger
|
|
59
|
+
- Set the 120-second execution timeout
|
|
60
|
+
- Activate the function for your project
|
|
61
|
+
|
|
62
|
+
### Verify Deployment
|
|
63
|
+
|
|
64
|
+
Check function status:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
sanity function list
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
View function logs:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
sanity function logs translate-on-publish
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Configuration
|
|
77
|
+
|
|
78
|
+
The function reads all configuration from your Sanity dataset using the `EL_PluginConfiguration` document. This is the same configuration used by the Studio plugin, providing a single source of truth.
|
|
79
|
+
|
|
80
|
+
### Configuration Document
|
|
81
|
+
|
|
82
|
+
- **Document ID**: `sanity-translation-plugin.config`
|
|
83
|
+
- **Document Type**: `EL_PluginConfiguration`
|
|
84
|
+
|
|
85
|
+
### Required Configuration Fields
|
|
86
|
+
|
|
87
|
+
#### OAuth Credentials
|
|
88
|
+
|
|
89
|
+
The function requires OAuth credentials to authenticate with the translation service:
|
|
90
|
+
|
|
91
|
+
- `projectId`: Your translation project identifier
|
|
92
|
+
- `accessToken`: Long-lived access token for API authentication
|
|
93
|
+
|
|
94
|
+
Configure through the Studio plugin UI or directly in the configuration document.
|
|
95
|
+
|
|
96
|
+
#### Target Locales
|
|
97
|
+
|
|
98
|
+
Define which languages to translate to:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
{
|
|
102
|
+
locales: [
|
|
103
|
+
{
|
|
104
|
+
code: 'en',
|
|
105
|
+
title: 'English',
|
|
106
|
+
enabled: true,
|
|
107
|
+
isDefault: true // Source language
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
code: 'ja',
|
|
111
|
+
title: 'Japanese',
|
|
112
|
+
enabled: true,
|
|
113
|
+
isDefault: false
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
code: 'de',
|
|
117
|
+
title: 'German',
|
|
118
|
+
enabled: true,
|
|
119
|
+
isDefault: false
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Only locales with `enabled: true` will be used as translation targets. The locale with `isDefault: true` is used as the source language.
|
|
126
|
+
|
|
127
|
+
#### Auto-Translate Document Types
|
|
128
|
+
|
|
129
|
+
Specify which document types should be automatically translated:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
{
|
|
133
|
+
autoTranslateDocumentTypes: ['article', 'blogPost', 'page']
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Important**: Only document types in this array will trigger automatic translation. This prevents unwanted translations of configuration documents, user profiles, etc.
|
|
138
|
+
|
|
139
|
+
### Optional Configuration Fields
|
|
140
|
+
|
|
141
|
+
#### Translation API Endpoint
|
|
142
|
+
|
|
143
|
+
Customize the translation service endpoint:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
{
|
|
147
|
+
translationApiEndpoint: 'https://api.easyling.com/translate'
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Default**: Easyling translation API endpoint
|
|
152
|
+
|
|
153
|
+
#### Content Type Settings
|
|
154
|
+
|
|
155
|
+
Configure request/response format:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
{
|
|
159
|
+
requestContentType: 'application/x-protobuf', // or 'application/json'
|
|
160
|
+
responseAcceptHeader: 'application/x-protobuf' // or 'application/json'
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Default**: `application/json` for both
|
|
165
|
+
|
|
166
|
+
#### Document Creation Mode
|
|
167
|
+
|
|
168
|
+
Control how translated documents are created:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
{
|
|
172
|
+
defaultDocumentCreationMode: 'draft' // or 'published'
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Default**: `draft` (recommended to allow review before publishing)
|
|
177
|
+
|
|
178
|
+
### Configuration Example
|
|
179
|
+
|
|
180
|
+
Complete configuration document:
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"_id": "sanity-translation-plugin.config",
|
|
185
|
+
"_type": "EL_PluginConfiguration",
|
|
186
|
+
"projectId": "your-easyling-project-id",
|
|
187
|
+
"accessToken": "your-access-token",
|
|
188
|
+
"translationApiEndpoint": "https://app.easyling.com/_el/ext/direct/sanity",
|
|
189
|
+
"requestContentType": "application/json",
|
|
190
|
+
"responseAcceptHeader": "application/json",
|
|
191
|
+
"defaultDocumentCreationMode": "draft",
|
|
192
|
+
"autoTranslateDocumentTypes": ["article", "blogPost", "page"],
|
|
193
|
+
"locales": [
|
|
194
|
+
{
|
|
195
|
+
"code": "en",
|
|
196
|
+
"title": "English",
|
|
197
|
+
"enabled": true,
|
|
198
|
+
"isDefault": true
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"code": "ja",
|
|
202
|
+
"title": "Japanese",
|
|
203
|
+
"enabled": true,
|
|
204
|
+
"isDefault": false
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"code": "de",
|
|
208
|
+
"title": "German",
|
|
209
|
+
"enabled": true,
|
|
210
|
+
"isDefault": false
|
|
211
|
+
}
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Blueprint Configuration
|
|
217
|
+
|
|
218
|
+
The function is configured via `sanity.function.json`:
|
|
219
|
+
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"name": "translate-on-publish",
|
|
223
|
+
"description": "Automatically translate documents when published",
|
|
224
|
+
"runtime": "nodejs20",
|
|
225
|
+
"trigger": {
|
|
226
|
+
"type": "document.publish"
|
|
227
|
+
},
|
|
228
|
+
"timeout": 120
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Blueprint Fields
|
|
233
|
+
|
|
234
|
+
- **name**: Function identifier (used in CLI commands and logs)
|
|
235
|
+
- **description**: Human-readable description
|
|
236
|
+
- **runtime**: Node.js version (nodejs20)
|
|
237
|
+
- **trigger.type**: Lifecycle event (`document.publish`)
|
|
238
|
+
- **timeout**: Maximum execution time in seconds (120)
|
|
239
|
+
|
|
240
|
+
### No Environment Variables Required
|
|
241
|
+
|
|
242
|
+
Unlike typical serverless functions, this function does not require environment variables. All configuration is read from the Sanity dataset, which provides several benefits:
|
|
243
|
+
|
|
244
|
+
- **Single Source of Truth**: Configuration is shared with Studio plugin
|
|
245
|
+
- **Easy Updates**: Change configuration through Studio UI without redeploying
|
|
246
|
+
- **No Secrets Management**: Credentials stored securely in Sanity dataset
|
|
247
|
+
- **Immediate Effect**: Configuration changes take effect on next function invocation
|
|
248
|
+
|
|
249
|
+
## Monitoring and Logging
|
|
250
|
+
|
|
251
|
+
### Structured Logs
|
|
252
|
+
|
|
253
|
+
The function emits structured JSON logs for easy parsing:
|
|
254
|
+
|
|
255
|
+
```json
|
|
256
|
+
{
|
|
257
|
+
"timestamp": "2024-01-15T10:30:45.123Z",
|
|
258
|
+
"level": "info",
|
|
259
|
+
"message": "Translation workflow completed",
|
|
260
|
+
"context": {
|
|
261
|
+
"documentId": "article-123",
|
|
262
|
+
"documentType": "article",
|
|
263
|
+
"operation": "translateOnPublish",
|
|
264
|
+
"successCount": 2,
|
|
265
|
+
"failureCount": 0,
|
|
266
|
+
"elapsedMs": 3456
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Log Levels
|
|
272
|
+
|
|
273
|
+
- **info**: Normal operation events (function start, translation complete, etc.)
|
|
274
|
+
- **warn**: Non-critical issues (approaching deadline, document skipped, etc.)
|
|
275
|
+
- **error**: Failures that don't block publish (translation failed, document creation failed, etc.)
|
|
276
|
+
|
|
277
|
+
### Key Log Events
|
|
278
|
+
|
|
279
|
+
#### Function Invocation
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
{
|
|
283
|
+
"level": "info",
|
|
284
|
+
"message": "Function invoked",
|
|
285
|
+
"context": {
|
|
286
|
+
"documentId": "article-123",
|
|
287
|
+
"documentType": "article",
|
|
288
|
+
"startTime": 1705315845123
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
#### Configuration Loaded
|
|
294
|
+
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"level": "info",
|
|
298
|
+
"message": "Configuration validated",
|
|
299
|
+
"context": {
|
|
300
|
+
"targetLocales": ["ja", "de"],
|
|
301
|
+
"autoTranslateDocumentTypes": ["article", "blogPost"]
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
#### Document Skipped
|
|
307
|
+
|
|
308
|
+
```json
|
|
309
|
+
{
|
|
310
|
+
"level": "info",
|
|
311
|
+
"message": "Document type not configured for auto-translation",
|
|
312
|
+
"context": {
|
|
313
|
+
"documentType": "user",
|
|
314
|
+
"configuredTypes": ["article", "blogPost"]
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### Translation Completed
|
|
320
|
+
|
|
321
|
+
```json
|
|
322
|
+
{
|
|
323
|
+
"level": "info",
|
|
324
|
+
"message": "Translation workflow completed",
|
|
325
|
+
"context": {
|
|
326
|
+
"totalResults": 2,
|
|
327
|
+
"successCount": 2,
|
|
328
|
+
"failureCount": 0,
|
|
329
|
+
"elapsedMs": 3456,
|
|
330
|
+
"metrics": {
|
|
331
|
+
"successfulTranslations": 2,
|
|
332
|
+
"failedTranslations": 0,
|
|
333
|
+
"localeMetrics": {
|
|
334
|
+
"ja": { "successCount": 1, "failureCount": 0 },
|
|
335
|
+
"de": { "successCount": 1, "failureCount": 0 }
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
#### Error Occurred
|
|
343
|
+
|
|
344
|
+
```json
|
|
345
|
+
{
|
|
346
|
+
"level": "error",
|
|
347
|
+
"message": "Translation service call failed",
|
|
348
|
+
"context": {
|
|
349
|
+
"documentId": "article-123",
|
|
350
|
+
"documentType": "article",
|
|
351
|
+
"targetLocales": ["ja", "de"],
|
|
352
|
+
"error": "Network timeout",
|
|
353
|
+
"stack": "Error: Network timeout\n at ..."
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Viewing Logs
|
|
359
|
+
|
|
360
|
+
View real-time logs:
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
sanity function logs translate-on-publish --follow
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
View recent logs:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
sanity function logs translate-on-publish --limit 100
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Filter by log level:
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
sanity function logs translate-on-publish --level error
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Metrics Tracking
|
|
379
|
+
|
|
380
|
+
The function tracks comprehensive metrics for monitoring:
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
{
|
|
384
|
+
totalInvocations: 1,
|
|
385
|
+
successfulTranslations: 2,
|
|
386
|
+
failedTranslations: 0,
|
|
387
|
+
skippedTranslations: 0,
|
|
388
|
+
localeMetrics: {
|
|
389
|
+
"ja": { successCount: 1, failureCount: 0 },
|
|
390
|
+
"de": { successCount: 1, failureCount: 0 }
|
|
391
|
+
},
|
|
392
|
+
errorsByStage: {
|
|
393
|
+
configurationLoad: 0,
|
|
394
|
+
configurationValidation: 0,
|
|
395
|
+
contentExtraction: 0,
|
|
396
|
+
translationService: 0,
|
|
397
|
+
documentCreation: 0,
|
|
398
|
+
timeout: 0,
|
|
399
|
+
sizeLimit: 0,
|
|
400
|
+
other: 0
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Use these metrics to:
|
|
406
|
+
- Track translation success rates per locale
|
|
407
|
+
- Identify problematic document types
|
|
408
|
+
- Monitor timeout and size limit issues
|
|
409
|
+
- Detect configuration problems
|
|
410
|
+
|
|
411
|
+
## Troubleshooting
|
|
412
|
+
|
|
413
|
+
### Function Not Triggering
|
|
414
|
+
|
|
415
|
+
**Problem**: Documents are published but function doesn't run
|
|
416
|
+
|
|
417
|
+
**Solutions**:
|
|
418
|
+
|
|
419
|
+
1. Verify function is deployed:
|
|
420
|
+
```bash
|
|
421
|
+
sanity function list
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
2. Check function status is "active"
|
|
425
|
+
|
|
426
|
+
3. Verify document type is in `autoTranslateDocumentTypes`:
|
|
427
|
+
```bash
|
|
428
|
+
sanity function logs translate-on-publish --limit 10
|
|
429
|
+
```
|
|
430
|
+
Look for "Document type not configured for auto-translation" messages
|
|
431
|
+
|
|
432
|
+
4. Check configuration document exists:
|
|
433
|
+
- Open Studio
|
|
434
|
+
- Navigate to `EL_PluginConfiguration` document
|
|
435
|
+
- Verify `autoTranslateDocumentTypes` array is populated
|
|
436
|
+
|
|
437
|
+
### Translation Fails with Authentication Error
|
|
438
|
+
|
|
439
|
+
**Problem**: Function logs show 401 or 403 errors
|
|
440
|
+
|
|
441
|
+
**Solutions**:
|
|
442
|
+
|
|
443
|
+
1. Verify OAuth credentials in configuration:
|
|
444
|
+
- Check `projectId` is correct
|
|
445
|
+
- Check `accessToken` is valid and not expired
|
|
446
|
+
|
|
447
|
+
2. Test credentials with Studio plugin:
|
|
448
|
+
- Try manual translation in Studio
|
|
449
|
+
- If Studio works, function should work too
|
|
450
|
+
|
|
451
|
+
3. Check translation API endpoint:
|
|
452
|
+
- Verify `translationApiEndpoint` is correct
|
|
453
|
+
- Ensure endpoint is accessible from Sanity's infrastructure
|
|
454
|
+
|
|
455
|
+
4. Contact translation service provider:
|
|
456
|
+
- Request new access token
|
|
457
|
+
- Verify project ID is active
|
|
458
|
+
|
|
459
|
+
### Documents Not Created
|
|
460
|
+
|
|
461
|
+
**Problem**: Translation succeeds but no documents appear
|
|
462
|
+
|
|
463
|
+
**Solutions**:
|
|
464
|
+
|
|
465
|
+
1. Check function logs for document creation errors:
|
|
466
|
+
```bash
|
|
467
|
+
sanity function logs translate-on-publish --level error
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
2. Verify creation mode:
|
|
471
|
+
- If `defaultDocumentCreationMode` is "draft", check Drafts view
|
|
472
|
+
- If "published", check published documents
|
|
473
|
+
|
|
474
|
+
3. Check for collision resolution:
|
|
475
|
+
- Function may skip creation if document already exists
|
|
476
|
+
- Look for "Collision detected" in logs
|
|
477
|
+
|
|
478
|
+
4. Verify Sanity client permissions:
|
|
479
|
+
- Function needs write access to dataset
|
|
480
|
+
- Check project permissions in Sanity dashboard
|
|
481
|
+
|
|
482
|
+
### Function Timeout
|
|
483
|
+
|
|
484
|
+
**Problem**: Function times out before completing
|
|
485
|
+
|
|
486
|
+
**Solutions**:
|
|
487
|
+
|
|
488
|
+
1. Check document size:
|
|
489
|
+
- Function skips documents over 10MB
|
|
490
|
+
- Look for "Document exceeds size limit" in logs
|
|
491
|
+
|
|
492
|
+
2. Reduce target locales:
|
|
493
|
+
- Translating to many locales increases execution time
|
|
494
|
+
- Consider translating to fewer locales per publish
|
|
495
|
+
|
|
496
|
+
3. Check translation API response time:
|
|
497
|
+
- Slow API responses can cause timeouts
|
|
498
|
+
- Monitor "elapsedMs" in logs
|
|
499
|
+
|
|
500
|
+
4. Review deadline warnings:
|
|
501
|
+
- Function logs warnings at 100 seconds
|
|
502
|
+
- If consistently hitting warnings, optimize document size or locale count
|
|
503
|
+
|
|
504
|
+
### Configuration Not Loading
|
|
505
|
+
|
|
506
|
+
**Problem**: Function logs show "Configuration not found"
|
|
507
|
+
|
|
508
|
+
**Solutions**:
|
|
509
|
+
|
|
510
|
+
1. Verify configuration document exists:
|
|
511
|
+
```bash
|
|
512
|
+
sanity documents get sanity-translation-plugin.config
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
2. Check document type:
|
|
516
|
+
- Must be `EL_PluginConfiguration`
|
|
517
|
+
- Must have document ID `sanity-translation-plugin.config`
|
|
518
|
+
|
|
519
|
+
3. Create configuration through Studio plugin:
|
|
520
|
+
- Install and configure Studio plugin first
|
|
521
|
+
- Plugin will create configuration document
|
|
522
|
+
|
|
523
|
+
4. Manually create configuration document:
|
|
524
|
+
```bash
|
|
525
|
+
sanity documents create --replace <<EOF
|
|
526
|
+
{
|
|
527
|
+
"_id": "sanity-translation-plugin.config",
|
|
528
|
+
"_type": "EL_PluginConfiguration",
|
|
529
|
+
"projectId": "your-project-id",
|
|
530
|
+
"accessToken": "your-token",
|
|
531
|
+
"autoTranslateDocumentTypes": ["article"],
|
|
532
|
+
"locales": [
|
|
533
|
+
{"code": "en", "title": "English", "enabled": true, "isDefault": true},
|
|
534
|
+
{"code": "ja", "title": "Japanese", "enabled": true, "isDefault": false}
|
|
535
|
+
]
|
|
536
|
+
}
|
|
537
|
+
EOF
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Partial Translations
|
|
541
|
+
|
|
542
|
+
**Problem**: Some locales succeed, others fail
|
|
543
|
+
|
|
544
|
+
**Solutions**:
|
|
545
|
+
|
|
546
|
+
1. Check locale-specific metrics in logs:
|
|
547
|
+
```json
|
|
548
|
+
{
|
|
549
|
+
"localeMetrics": {
|
|
550
|
+
"ja": { "successCount": 1, "failureCount": 0 },
|
|
551
|
+
"de": { "successCount": 0, "failureCount": 1 }
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
2. Review error messages for failed locales:
|
|
557
|
+
- Look for locale-specific errors in logs
|
|
558
|
+
- May indicate API issues for specific languages
|
|
559
|
+
|
|
560
|
+
3. Verify locale codes:
|
|
561
|
+
- Ensure locale codes match translation service expectations
|
|
562
|
+
- Check for typos in locale configuration
|
|
563
|
+
|
|
564
|
+
4. Test individual locales:
|
|
565
|
+
- Temporarily disable problematic locales
|
|
566
|
+
- Test with Studio plugin to isolate issue
|
|
567
|
+
|
|
568
|
+
### High Error Rate
|
|
569
|
+
|
|
570
|
+
**Problem**: Many translations failing
|
|
571
|
+
|
|
572
|
+
**Solutions**:
|
|
573
|
+
|
|
574
|
+
1. Review error breakdown by stage:
|
|
575
|
+
```json
|
|
576
|
+
{
|
|
577
|
+
"errorsByStage": {
|
|
578
|
+
"contentExtraction": 5,
|
|
579
|
+
"translationService": 12,
|
|
580
|
+
"documentCreation": 3
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
2. Address most common error stage:
|
|
586
|
+
- **contentExtraction**: Document structure issues, invalid portable text
|
|
587
|
+
- **translationService**: API issues, authentication, network problems
|
|
588
|
+
- **documentCreation**: Permission issues, validation errors, collisions
|
|
589
|
+
|
|
590
|
+
3. Check for systematic issues:
|
|
591
|
+
- Specific document type causing problems
|
|
592
|
+
- Specific locale consistently failing
|
|
593
|
+
- Time-based patterns (API rate limits, downtime)
|
|
594
|
+
|
|
595
|
+
4. Enable debug mode in Studio plugin:
|
|
596
|
+
- Set `debugMode: true` in configuration
|
|
597
|
+
- Review detailed field information
|
|
598
|
+
- Identify problematic fields or content
|
|
599
|
+
|
|
600
|
+
## Performance Considerations
|
|
601
|
+
|
|
602
|
+
### Execution Time
|
|
603
|
+
|
|
604
|
+
- **Typical**: 3-5 seconds per document with 2-3 target locales
|
|
605
|
+
- **Maximum**: 120 seconds (hard timeout)
|
|
606
|
+
- **Warning Threshold**: 100 seconds (function logs warning)
|
|
607
|
+
- **Termination Threshold**: 110 seconds (function terminates gracefully)
|
|
608
|
+
|
|
609
|
+
### Document Size Limits
|
|
610
|
+
|
|
611
|
+
- **Maximum**: 10MB per document
|
|
612
|
+
- Documents exceeding limit are skipped with warning log
|
|
613
|
+
- Consider splitting large documents into smaller pieces
|
|
614
|
+
|
|
615
|
+
### Concurrent Translations
|
|
616
|
+
|
|
617
|
+
The function processes target locales sequentially to:
|
|
618
|
+
- Avoid overwhelming translation API
|
|
619
|
+
- Provide better error isolation
|
|
620
|
+
- Enable partial success (some locales succeed even if others fail)
|
|
621
|
+
|
|
622
|
+
### Optimization Tips
|
|
623
|
+
|
|
624
|
+
1. **Limit Target Locales**: Fewer locales = faster execution
|
|
625
|
+
2. **Use Draft Mode**: Creating drafts is faster than published documents
|
|
626
|
+
3. **Optimize Document Structure**: Simpler structures extract faster
|
|
627
|
+
4. **Monitor Execution Time**: Review "elapsedMs" in logs to identify slow documents
|
|
628
|
+
5. **Batch Similar Documents**: Publish related documents together for better caching
|
|
629
|
+
|
|
630
|
+
## Shared Configuration with Studio Plugin
|
|
631
|
+
|
|
632
|
+
The function and Studio plugin share the same configuration document, providing several benefits:
|
|
633
|
+
|
|
634
|
+
### Single Source of Truth
|
|
635
|
+
|
|
636
|
+
- No duplicate configuration to maintain
|
|
637
|
+
- Changes apply to both function and plugin
|
|
638
|
+
- Consistent behavior across manual and automatic translation
|
|
639
|
+
|
|
640
|
+
### Easy Management
|
|
641
|
+
|
|
642
|
+
- Configure through Studio UI (user-friendly)
|
|
643
|
+
- Or edit configuration document directly (programmatic)
|
|
644
|
+
- No need to redeploy function after configuration changes
|
|
645
|
+
|
|
646
|
+
### Configuration Fields Used by Function
|
|
647
|
+
|
|
648
|
+
The function reads these fields from `EL_PluginConfiguration`:
|
|
649
|
+
|
|
650
|
+
- `projectId`: OAuth project identifier
|
|
651
|
+
- `accessToken`: OAuth access token
|
|
652
|
+
- `translationApiEndpoint`: Translation API URL
|
|
653
|
+
- `requestContentType`: Request format (JSON or protobuf)
|
|
654
|
+
- `responseAcceptHeader`: Response format (JSON or protobuf)
|
|
655
|
+
- `defaultDocumentCreationMode`: Draft or published
|
|
656
|
+
- `autoTranslateDocumentTypes`: Document types to auto-translate
|
|
657
|
+
- `locales`: Locale definitions with enabled flags
|
|
658
|
+
- `defaultLocale`: Source language code
|
|
659
|
+
|
|
660
|
+
### Configuration Fields Ignored by Function
|
|
661
|
+
|
|
662
|
+
These fields are used only by the Studio plugin:
|
|
663
|
+
|
|
664
|
+
- `collisionResolutionMode`: UI-specific collision handling
|
|
665
|
+
- `existingDocumentHandling`: UI-specific document handling
|
|
666
|
+
- `dntFieldConfigurations`: DNT preferences (function uses defaults)
|
|
667
|
+
- `debugMode`: UI-specific debug display
|
|
668
|
+
|
|
669
|
+
## Development
|
|
670
|
+
|
|
671
|
+
### Local Testing
|
|
672
|
+
|
|
673
|
+
Test the function locally before deploying:
|
|
674
|
+
|
|
675
|
+
```bash
|
|
676
|
+
# Build the function
|
|
677
|
+
npm run build
|
|
678
|
+
|
|
679
|
+
# Run tests
|
|
680
|
+
npm test
|
|
681
|
+
|
|
682
|
+
# Run specific test file
|
|
683
|
+
npm test -- config.test.ts
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
### Function Structure
|
|
687
|
+
|
|
688
|
+
```
|
|
689
|
+
function/
|
|
690
|
+
├── src/
|
|
691
|
+
│ ├── index.ts # Main function entry point
|
|
692
|
+
│ ├── config.ts # Configuration loading and validation
|
|
693
|
+
│ ├── logger.ts # Structured logging
|
|
694
|
+
│ └── __tests__/ # Unit and integration tests
|
|
695
|
+
├── sanity.function.json # Blueprint configuration
|
|
696
|
+
├── package.json # Dependencies and scripts
|
|
697
|
+
└── tsconfig.json # TypeScript configuration
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
### Key Files
|
|
701
|
+
|
|
702
|
+
- **index.ts**: Main function logic, handles publish events
|
|
703
|
+
- **config.ts**: Loads configuration from Sanity dataset
|
|
704
|
+
- **logger.ts**: Structured logging with context
|
|
705
|
+
- **sanity.function.json**: Deployment configuration
|
|
706
|
+
|
|
707
|
+
### Testing
|
|
708
|
+
|
|
709
|
+
```bash
|
|
710
|
+
# Run all tests
|
|
711
|
+
npm test
|
|
712
|
+
|
|
713
|
+
# Run with coverage
|
|
714
|
+
npm run test:coverage
|
|
715
|
+
|
|
716
|
+
# Run in watch mode
|
|
717
|
+
npm run test:watch
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
### Building
|
|
721
|
+
|
|
722
|
+
```bash
|
|
723
|
+
# Production build
|
|
724
|
+
npm run build
|
|
725
|
+
|
|
726
|
+
# Clean build artifacts
|
|
727
|
+
npm run clean
|
|
728
|
+
|
|
729
|
+
# Type check
|
|
730
|
+
npm run typecheck
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
## Related Packages
|
|
734
|
+
|
|
735
|
+
- [@easyling/sanity-connector](../plugin/README.md) - Studio plugin for manual translation
|
|
736
|
+
- [@easyling/sanity-connector-shared](../shared/README.md) - Shared translation logic
|
|
737
|
+
|
|
738
|
+
## Support
|
|
739
|
+
|
|
740
|
+
For questions, issues, or feature requests:
|
|
741
|
+
|
|
742
|
+
- **Email**: support@easyling.com
|
|
743
|
+
- **Issues**: [GitHub Issues](https://github.com/easyling/el-sanity-connector/issues)
|
|
744
|
+
- **Documentation**: [Main README](../README.md) | [Plugin README](../plugin/README.md) | [Shared Library](../shared/README.md)
|
|
745
|
+
|
|
746
|
+
## License
|
|
747
|
+
|
|
748
|
+
MIT
|