@easyling/sanity-connector 1.4.0 → 2.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.
Files changed (69) hide show
  1. package/README.md +560 -90
  2. package/dist/index.js +2 -1
  3. package/dist/index.js.map +1 -0
  4. package/package.json +38 -54
  5. package/LICENSE +0 -21
  6. package/dist/.tsbuildinfo +0 -1
  7. package/dist-types/actions/bulkTranslate.d.ts +0 -6
  8. package/dist-types/actions/manageDNTFields.d.ts +0 -11
  9. package/dist-types/actions/translateDocument.d.ts +0 -6
  10. package/dist-types/components/RadioWithDefault.d.ts +0 -16
  11. package/dist-types/components/auth/AuthNavbar.d.ts +0 -17
  12. package/dist-types/components/auth/AuthStatus.d.ts +0 -26
  13. package/dist-types/components/auth/AuthStatusWrapper.d.ts +0 -14
  14. package/dist-types/components/auth/MigrationPrompt.d.ts +0 -19
  15. package/dist-types/components/auth/MigrationPromptWrapper.d.ts +0 -13
  16. package/dist-types/components/auth/OAuthCallback.d.ts +0 -19
  17. package/dist-types/components/auth/index.d.ts +0 -14
  18. package/dist-types/components/config/LocaleConfigTool.d.ts +0 -16
  19. package/dist-types/components/config/LocaleConfigToolWrapper.d.ts +0 -12
  20. package/dist-types/components/config/OAuthConfig.d.ts +0 -25
  21. package/dist-types/components/config/OAuthConfigWrapper.d.ts +0 -12
  22. package/dist-types/components/config/PasswordInput.d.ts +0 -13
  23. package/dist-types/components/config/index.d.ts +0 -8
  24. package/dist-types/components/config/localeConfigToolDefinition.d.ts +0 -12
  25. package/dist-types/components/config/oauthConfigToolDefinition.d.ts +0 -12
  26. package/dist-types/components/dialogs/ConfirmationDialog.d.ts +0 -20
  27. package/dist-types/components/dialogs/ErrorDialog.d.ts +0 -20
  28. package/dist-types/components/dialogs/LocaleSelectionDialog.d.ts +0 -62
  29. package/dist-types/components/dialogs/SuccessDialog.d.ts +0 -18
  30. package/dist-types/components/dialogs/index.d.ts +0 -11
  31. package/dist-types/components/dnt/DNTFieldBadge.d.ts +0 -15
  32. package/dist-types/components/dnt/DNTFieldComponent.d.ts +0 -16
  33. package/dist-types/components/dnt/DNTFieldInput.d.ts +0 -13
  34. package/dist-types/components/dnt/DebugDNTBadge.d.ts +0 -19
  35. package/dist-types/components/dnt/index.d.ts +0 -7
  36. package/dist-types/config/index.d.ts +0 -5
  37. package/dist-types/config/pluginConfig.d.ts +0 -162
  38. package/dist-types/index.d.ts +0 -11
  39. package/dist-types/plugin.d.ts +0 -12
  40. package/dist-types/services/authStateManager.d.ts +0 -93
  41. package/dist-types/services/collisionDetectionService.d.ts +0 -85
  42. package/dist-types/services/contentExtractor.d.ts +0 -161
  43. package/dist-types/services/dialogService.d.ts +0 -95
  44. package/dist-types/services/dntServiceManager.d.ts +0 -43
  45. package/dist-types/services/dntStorageAdapter.d.ts +0 -72
  46. package/dist-types/services/documentCreationService.d.ts +0 -262
  47. package/dist-types/services/localeService.d.ts +0 -159
  48. package/dist-types/services/localeStorageAdapter.d.ts +0 -41
  49. package/dist-types/services/oauthConfigStorage.d.ts +0 -45
  50. package/dist-types/services/oauthService.d.ts +0 -47
  51. package/dist-types/services/oauthServiceManager.d.ts +0 -195
  52. package/dist-types/services/tokenStorage.d.ts +0 -53
  53. package/dist-types/services/translationService.d.ts +0 -385
  54. package/dist-types/services/unifiedConfigStorage.d.ts +0 -158
  55. package/dist-types/test-utils.d.ts +0 -8
  56. package/dist-types/types/dialog.d.ts +0 -118
  57. package/dist-types/types/dnt.d.ts +0 -83
  58. package/dist-types/types/index.d.ts +0 -11
  59. package/dist-types/types/locale.d.ts +0 -115
  60. package/dist-types/types/oauth.d.ts +0 -89
  61. package/dist-types/types/pluginConfig.d.ts +0 -64
  62. package/dist-types/types/translation.d.ts +0 -121
  63. package/dist-types/utils/dntDefaults.d.ts +0 -101
  64. package/dist-types/utils/htmlFormatter.d.ts +0 -65
  65. package/dist-types/utils/index.d.ts +0 -16
  66. package/dist-types/utils/logger.d.ts +0 -104
  67. package/dist-types/utils/oauthErrorFeedback.d.ts +0 -75
  68. package/dist-types/utils/oauthLogger.d.ts +0 -175
  69. package/dist-types/utils/validator.d.ts +0 -66
package/README.md CHANGED
@@ -1,154 +1,624 @@
1
- # Sanity Translation Plugin
1
+ # @easyling/sanity-connector
2
2
 
3
- A Sanity Studio plugin that enables seamless document translation workflows. It extracts content as HTML, manages translation requests to external services, and handles the re-import of translated content while preserving Portable Text structures.
3
+ Sanity Studio v3 plugin for document translation with Easyling. Provides UI-based translation functionality with support for single document translation, bulk operations, and granular control over translatable content.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Single Document Translation**: Translate individual documents directly from the document form.
8
- - **Bulk Translation**: Batch process multiple documents via a dedicated tool.
9
- - **Smart Content Extraction**: Converts Sanity Portable Text to HTML for translation and back again.
10
- - **Translation Collision Handling**: Intelligent detection and resolution when re-translating to the same locale.
11
- - **Replace Mode**: Overwrite existing translated documents with new translations.
12
- - **Create Mode**: Create new documents while managing existing ones (draft or delete).
13
- - **Translation Invariance**: granular control over what gets translated via "Do Not Translate" (DNT) flags.
14
- - **Inline Badges**: Toggle translation status for individual fields directly in the editor.
15
- - **Field Management**: dedicated action to manage DNT status across the whole document.
16
- - **Authentication Support**: Secure OAuth integration with translation services, with a legacy mode for local testing.
17
- - **Auto-Configuration**: Intelligent defaults for new installations to get you started quickly.
18
- - **Progress Tracking**: Real-time feedback for long-running bulk operations.
7
+ - **Single Document Translation**: Translate individual documents directly from the document form
8
+ - **Bulk Translation Tool**: Batch process multiple documents via a dedicated tool
9
+ - **Smart Content Extraction**: Converts Sanity Portable Text to HTML for translation and back again
10
+ - **Translation Collision Handling**: Intelligent detection and resolution when re-translating to the same locale
11
+ - **Do Not Translate (DNT) Control**: Granular field-level control over what gets translated
12
+ - Inline badges for toggling translation status
13
+ - Dedicated field management action
14
+ - Smart defaults based on field types and names
15
+ - **OAuth Integration**: Secure authentication with translation services
16
+ - **Real-time Progress Tracking**: Visual feedback for long-running operations
17
+ - **Debug Mode**: Detailed field information for troubleshooting
19
18
 
20
19
  ## Installation
21
20
 
22
- Install the plugin in your Sanity Studio project:
23
-
24
21
  ```bash
25
- npm install sanity-translation-plugin
22
+ npm install @easyling/sanity-connector
26
23
  ```
27
24
 
28
- Add the plugin to your `sanity.config.ts` file:
25
+ ### Peer Dependencies
26
+
27
+ The plugin requires the following peer dependencies:
28
+
29
+ - `sanity` ^3.0.0
30
+ - `react` ^18.0.0
31
+ - `react-dom` ^18.0.0
32
+
33
+ These are typically already installed in your Sanity Studio project.
34
+
35
+ ## Setup
36
+
37
+ ### Basic Configuration
38
+
39
+ Add the plugin to your `sanity.config.ts` or `sanity.config.js`:
29
40
 
30
41
  ```typescript
31
42
  import { defineConfig } from 'sanity'
32
- import translationPlugin from 'sanity-translation-plugin'
43
+ import translationPlugin from '@easyling/sanity-connector'
33
44
 
34
45
  export default defineConfig({
35
- // ... your other config
46
+ // ... other config
36
47
  plugins: [
37
- // ... other plugins
38
48
  translationPlugin()
39
49
  ]
40
50
  })
41
51
  ```
42
52
 
43
- ## Configuration
53
+ That's it! The plugin will automatically:
54
+ - Register document actions (Translate, Manage DNT Fields)
55
+ - Add the Bulk Translate tool to your Studio
56
+ - Create configuration document types
57
+ - Initialize services on Studio load
58
+
59
+ ### Initial Configuration
60
+
61
+ After installing the plugin, you'll need to configure:
62
+
63
+ 1. **OAuth Credentials** (required for translation)
64
+ 2. **Target Locales** (languages to translate to)
65
+ 3. **Translation API Endpoint** (optional, defaults to Easyling)
66
+
67
+ Configuration is stored in your Sanity dataset as an `EL_PluginConfiguration` document. You can configure through:
68
+
69
+ - The Studio UI (recommended)
70
+ - Direct document editing
71
+ - The UnifiedConfigStorage API
72
+
73
+ ## Configuration Options
74
+
75
+ ### OAuth Configuration
76
+
77
+ Configure authentication with your translation service:
78
+
79
+ 1. Navigate to your Studio
80
+ 2. Create or edit the `EL_PluginConfiguration` document
81
+ 3. Fill in the OAuth section:
82
+ - **Project ID**: Your translation project identifier
83
+ - **Access Token**: Long-lived access token (hidden for security)
84
+
85
+ ```typescript
86
+ // Example: Programmatic configuration
87
+ import { UnifiedConfigStorage } from '@easyling/sanity-connector'
88
+ import { createClient } from 'sanity'
89
+
90
+ const client = createClient({
91
+ projectId: 'your-project-id',
92
+ dataset: 'production',
93
+ apiVersion: '2024-01-01',
94
+ token: 'your-token'
95
+ })
96
+
97
+ const configStorage = new UnifiedConfigStorage(client)
98
+
99
+ await configStorage.update({
100
+ projectId: 'your-easyling-project-id',
101
+ accessToken: 'your-access-token'
102
+ })
103
+ ```
104
+
105
+ ### Locale Configuration
106
+
107
+ Define which languages you want to translate to:
108
+
109
+ ```typescript
110
+ await configStorage.update({
111
+ locales: [
112
+ {
113
+ code: 'en',
114
+ title: 'English',
115
+ enabled: true,
116
+ isDefault: true
117
+ },
118
+ {
119
+ code: 'ja',
120
+ title: 'Japanese',
121
+ enabled: true,
122
+ isDefault: false
123
+ },
124
+ {
125
+ code: 'de',
126
+ title: 'German',
127
+ enabled: true,
128
+ isDefault: false
129
+ }
130
+ ]
131
+ })
132
+ ```
133
+
134
+ **Locale Fields:**
135
+ - `code`: Language code (e.g., 'en', 'ja-JP')
136
+ - `title`: Display name for the language
137
+ - `enabled`: Whether this locale is active for translation
138
+ - `isDefault`: Whether this is the source language (only one should be true)
139
+
140
+ ### Translation API Configuration
141
+
142
+ Customize the translation service endpoint and format:
143
+
144
+ ```typescript
145
+ await configStorage.update({
146
+ translationApiEndpoint: 'https://api.easyling.com/translate',
147
+ requestContentType: 'application/x-protobuf', // or 'application/json'
148
+ responseAcceptHeader: 'application/x-protobuf' // or 'application/json'
149
+ })
150
+ ```
151
+
152
+ **Default values:**
153
+ - Endpoint: Easyling translation API
154
+ - Content Type: `application/x-protobuf`
155
+ - Accept Header: `application/x-protobuf`
156
+
157
+ ### Document Creation Options
158
+
159
+ Control how translated documents are created:
160
+
161
+ ```typescript
162
+ await configStorage.update({
163
+ defaultDocumentCreationMode: 'draft', // or 'published'
164
+ collisionResolutionMode: 'skip', // or 'replace', 'merge'
165
+ existingDocumentHandling: 'keep' // or 'archive', 'delete'
166
+ })
167
+ ```
168
+
169
+ **Creation Modes:**
170
+ - `draft`: Create translated documents as drafts (recommended)
171
+ - `published`: Create translated documents as published
44
172
 
45
- ### Authentication & Connection
173
+ **Collision Resolution:**
174
+ - `skip`: Don't create if translation already exists
175
+ - `replace`: Overwrite existing translation
176
+ - `merge`: Merge with existing translation (preserves untranslated fields)
46
177
 
47
- The plugin supports two modes of operation:
178
+ **Existing Document Handling:**
179
+ - `keep`: Keep existing document as-is
180
+ - `archive`: Move existing document to drafts
181
+ - `delete`: Delete existing document
48
182
 
49
- 1. **OAuth Mode (Recommended for Production)**:
50
- - Uses secure token-based authentication.
51
- - Configurable via the **OAuth Configuration** tool within Sanity Studio.
52
- - Supports project-specific access control.
183
+ ### DNT (Do Not Translate) Configuration
53
184
 
54
- 2. **Legacy/Development Mode**:
55
- - Default behavior out of the box.
56
- - Points to `http://app.easyling.com` by default.
57
- - Useful for local development and testing without setting up full auth.
185
+ Configure which fields should not be translated by default:
58
186
 
59
- To configure the plugin for production use, navigate to the **Easyling Translation Plugin Configuration** document type in your Sanity Studio after installation, and create a new configuration. Enter your project code and access token (both are available in the Easyling platform), and publish your configuration.
187
+ ```typescript
188
+ await configStorage.setDNTField('article', 'author.name', true)
189
+ await configStorage.setDNTField('article', 'publishDate', true)
190
+ ```
60
191
 
61
- Next, navigate to the **Locales** tab of the configuration, and add the locales you wish to handle. These are the ones you will be able to translate your content into.
192
+ The plugin automatically applies smart defaults for common non-translatable fields:
193
+ - Author names
194
+ - Dates and timestamps
195
+ - IDs and references
196
+ - Technical metadata
62
197
 
63
- At this point, you're ready to begin processing content, but if you want, you can add translation-invariant fields for your content types, by toggling the badges on the individual fields.
198
+ You can override these defaults on a per-field basis using the inline DNT badges or the Manage DNT Fields action.
64
199
 
65
- ### Defaults
200
+ ### Debug Mode
66
201
 
67
- The plugin comes with "Auto-Default" behavior. When you install it for the first time, it will automatically select sensible defaults (like "Draft" mode for new translated documents) so you can start using it immediately without manual configuration.
202
+ Enable debug mode to see detailed field information:
203
+
204
+ ```typescript
205
+ await configStorage.update({
206
+ debugMode: true
207
+ })
208
+ ```
209
+
210
+ When enabled, all fields will show debug badges with:
211
+ - Field path
212
+ - Field type
213
+ - DNT status (default and stored)
214
+ - Group/fieldset information
68
215
 
69
216
  ## Usage
70
217
 
71
218
  ### Single Document Translation
72
219
 
73
- 1. Open a document in Sanity Studio.
74
- 2. Click the **Translate** icon in the document toolbar.
75
- 3. Review the document details in the confirmation dialog.
76
- 4. Click **Translate**.
77
- 5. The plugin will process the translation and inform you when complete.
220
+ 1. Open any document in your Studio
221
+ 2. Click the **Translate** button in the document toolbar
222
+ 3. Select target languages
223
+ 4. Configure translation options (creation mode, collision handling)
224
+ 5. Click **Translate**
225
+
226
+ The plugin will:
227
+ - Extract translatable content from the document
228
+ - Send translation request to the configured API
229
+ - Create new documents for each target language
230
+ - Show progress and results
78
231
 
79
232
  ### Bulk Translation
80
233
 
81
- 1. Open the **Bulk Translate** tool from the Sanity Studio tools menu.
82
- 2. Select the document types you wish to translate.
83
- 3. Filter and select specific documents from the list.
84
- 4. Click the **Translate** button to process the batch.
85
- 5. A summary report will be displayed upon completion.
234
+ 1. Open the **Bulk Translate** tool from the Studio tools menu
235
+ 2. Select document type to translate
236
+ 3. Choose documents (or select all)
237
+ 4. Select target languages
238
+ 5. Configure translation options
239
+ 6. Click **Start Translation**
240
+
241
+ The tool provides:
242
+ - Real-time progress tracking
243
+ - Success/failure counts
244
+ - Detailed results for each document
245
+ - Rollback capability if needed
86
246
 
87
- ### Managing Translatable Fields
247
+ ### Managing DNT Fields
88
248
 
89
- Sometimes you need to keep specific fields (like product codes, technical IDs, or proper names) from being translated.
249
+ #### Inline Badges
90
250
 
91
- **Method 1: Inline Badges**
92
- In the document editor, you will see small badges below translatable fields:
93
- - **Green "Will Translate"**: The field will be included in the translation request.
94
- - **Red "Do Not Translate"**: The field will be skipped.
95
- Click the badge to toggle the status.
251
+ For translatable fields (string, text, array), you'll see a DNT badge:
252
+ - **Green badge**: Field will be translated
253
+ - **Red badge**: Field will NOT be translated
254
+ - Click the badge to toggle the DNT status
96
255
 
97
- **Method 2: Field Management Action**
98
- For a high-level view:
99
- 1. Click the document menu (three dots) in the top right.
100
- 2. Select **Manage Translation Fields**.
101
- 3. View and toggle the translation status for all fields in the document.
256
+ #### Manage DNT Fields Action
102
257
 
103
- ### Translation Collision Handling
258
+ 1. Open any document
259
+ 2. Click **Manage DNT Fields** in the document toolbar
260
+ 3. View all fields with their DNT status
261
+ 4. Toggle individual fields or apply bulk changes
262
+ 5. Save changes
104
263
 
105
- When translating a document to a locale that already has an existing translation, the plugin detects this "collision" and offers resolution options.
264
+ The action shows:
265
+ - Field path and type
266
+ - Current DNT status
267
+ - Smart default recommendations
268
+ - Ability to reset to defaults
106
269
 
107
- **Collision Detection**
108
- A collision is detected when a translated document already exists for the same source document and target locale. The plugin identifies existing translations by:
109
- 1. **Parent Reference**: Documents linked via `parentDocument._ref` to the source document.
110
- 2. **Slug + Locale**: Documents with matching slug and locale (as a fallback).
270
+ ## Migration from Previous Version
111
271
 
112
- **Resolution Modes**
272
+ If you're upgrading from the single-package version (pre-monorepo), follow these steps:
113
273
 
114
- When a collision is detected, you can choose how to handle it:
274
+ ### 1. Update Package Name
115
275
 
116
- - **Replace existing translated document**: Overwrites the existing translation with the new content. The document ID remains the same.
117
- - **Create new translated document**: Creates a new document with a unique ID. You can also specify what happens to the existing document:
118
- - **Set existing document to draft**: Converts the existing published translation to a draft.
119
- - **Delete existing document**: Permanently removes the existing translation.
276
+ The plugin package name remains the same, but the internal structure has changed:
120
277
 
121
- **Configuration**
278
+ ```bash
279
+ # Uninstall old version
280
+ npm uninstall @easyling/sanity-connector
122
281
 
123
- Default collision resolution settings can be configured in the **Easyling Translation Plugin Configuration** document:
282
+ # Install new version
283
+ npm install @easyling/sanity-connector
284
+ ```
124
285
 
125
- 1. Navigate to the plugin configuration document in Sanity Studio.
126
- 2. Find the **Translation** settings group.
127
- 3. Set the **Default Collision Resolution Mode** (Replace or Create).
128
- 4. If using Create mode, set the **Existing Document Handling** preference (Draft or Delete).
286
+ ### 2. Update Imports
129
287
 
130
- These defaults can be overridden on a per-translation basis in the locale selection dialog.
288
+ Most imports remain the same, but some have moved to the shared library:
289
+
290
+ **Before:**
291
+ ```typescript
292
+ import { UnifiedConfigStorage } from '@easyling/sanity-connector'
293
+ ```
294
+
295
+ **After:**
296
+ ```typescript
297
+ // Still works - re-exported from plugin
298
+ import { UnifiedConfigStorage } from '@easyling/sanity-connector'
299
+
300
+ // Or import directly from shared library
301
+ import { UnifiedConfigStorage } from '@easyling/sanity-connector-shared'
302
+ ```
303
+
304
+ ### 3. Configuration Migration
305
+
306
+ The plugin automatically migrates legacy configuration documents:
307
+
308
+ - **Legacy OAuth Config** (`EL_oauth-config`) → Merged into `EL_PluginConfiguration`
309
+ - **Legacy Locale Config** (`EL_locale-config`) → Merged into `EL_PluginConfiguration`
310
+
311
+ Migration happens automatically on first load. Legacy documents are hidden from the UI but preserved for rollback if needed.
312
+
313
+ ### 4. Verify Configuration
314
+
315
+ After migration, verify your configuration:
316
+
317
+ 1. Open the `EL_PluginConfiguration` document in your Studio
318
+ 2. Check that OAuth credentials are present
319
+ 3. Verify locale settings
320
+ 4. Test a translation to ensure everything works
321
+
322
+ ### 5. Update Custom Code (if applicable)
323
+
324
+ If you have custom code using the plugin's APIs:
325
+
326
+ **Service Imports:**
327
+ ```typescript
328
+ // Before
329
+ import { ContentExtractor } from '@easyling/sanity-connector/services'
330
+
331
+ // After - import from shared library
332
+ import { ContentExtractor } from '@easyling/sanity-connector-shared'
333
+ ```
334
+
335
+ **Type Imports:**
336
+ ```typescript
337
+ // Before
338
+ import type { TranslationRequest } from '@easyling/sanity-connector/types'
339
+
340
+ // After - still works, or use shared library
341
+ import type { TranslationRequest } from '@easyling/sanity-connector'
342
+ // or
343
+ import type { TranslationRequest } from '@easyling/sanity-connector-shared'
344
+ ```
345
+
346
+ ### Breaking Changes
347
+
348
+ The monorepo restructuring introduces minimal breaking changes:
349
+
350
+ 1. **Internal file structure**: If you were importing from internal paths (not recommended), update to use public exports
351
+ 2. **Service initialization**: Some services now require explicit client initialization
352
+ 3. **Configuration storage**: Legacy config documents are deprecated (but still supported)
353
+
354
+ ### Rollback
355
+
356
+ If you need to rollback to the previous version:
357
+
358
+ ```bash
359
+ npm install @easyling/sanity-connector@1.3.0
360
+ ```
361
+
362
+ Your configuration will remain intact as the document structure hasn't changed.
363
+
364
+ ## Advanced Usage
365
+
366
+ ### Custom Translation Workflow
367
+
368
+ You can build custom translation workflows using the exported services:
369
+
370
+ ```typescript
371
+ import {
372
+ ContentExtractor,
373
+ TranslationService,
374
+ DocumentCreationService,
375
+ UnifiedConfigStorage
376
+ } from '@easyling/sanity-connector-shared'
377
+ import { useClient } from 'sanity'
378
+
379
+ function MyCustomTranslationComponent() {
380
+ const client = useClient()
381
+
382
+ const handleCustomTranslation = async (document) => {
383
+ // Initialize services
384
+ const configStorage = new UnifiedConfigStorage(client)
385
+ const extractor = new ContentExtractor(client)
386
+ const translationService = new TranslationService(client)
387
+ const docCreationService = new DocumentCreationService(client)
388
+
389
+ // Load configuration
390
+ const config = await configStorage.load()
391
+ translationService.setEndpoint(config.translationApiEndpoint)
392
+ translationService.setAuthToken(config.accessToken, config.projectId)
393
+
394
+ // Extract content
395
+ const structured = await extractor.extractStructuredContent(
396
+ document,
397
+ configStorage
398
+ )
399
+
400
+ // Translate
401
+ const response = await translationService.translateDocument(
402
+ structured,
403
+ document._type,
404
+ 'en',
405
+ undefined,
406
+ ['ja', 'de']
407
+ )
408
+
409
+ // Create translated documents
410
+ for (const translatedDoc of response.translatedDocuments) {
411
+ await docCreationService.createDocumentFromTranslation(
412
+ document,
413
+ { ...response, translatedDocuments: [translatedDoc] },
414
+ {
415
+ targetLanguage: translatedDoc.locale,
416
+ creationMode: 'draft'
417
+ }
418
+ )
419
+ }
420
+ }
421
+
422
+ return <button onClick={() => handleCustomTranslation(doc)}>Translate</button>
423
+ }
424
+ ```
425
+
426
+ ### Custom DNT Logic
427
+
428
+ Implement custom DNT logic for your schema:
429
+
430
+ ```typescript
431
+ import { DNTServiceManager } from '@easyling/sanity-connector'
432
+ import { useClient } from 'sanity'
433
+
434
+ function MyComponent() {
435
+ const client = useClient()
436
+ const dntService = DNTServiceManager.getInstance(client)
437
+
438
+ const checkDNTStatus = async (documentType, fieldPath) => {
439
+ const isDNT = await dntService.getDNTFieldStatus(documentType, fieldPath)
440
+ console.log(`Field ${fieldPath} is ${isDNT ? 'NOT' : ''} translatable`)
441
+ }
442
+
443
+ const setDNTStatus = async (documentType, fieldPath, isDNT) => {
444
+ await dntService.setDNTField(documentType, fieldPath, isDNT)
445
+ }
446
+
447
+ return <div>Custom DNT UI</div>
448
+ }
449
+ ```
450
+
451
+ ### Accessing Configuration
452
+
453
+ Access plugin configuration in your custom components:
454
+
455
+ ```typescript
456
+ import { UnifiedConfigStorage } from '@easyling/sanity-connector'
457
+ import { useClient } from 'sanity'
458
+ import { useEffect, useState } from 'react'
459
+
460
+ function MyConfigComponent() {
461
+ const client = useClient()
462
+ const [config, setConfig] = useState(null)
463
+
464
+ useEffect(() => {
465
+ const loadConfig = async () => {
466
+ const configStorage = new UnifiedConfigStorage(client)
467
+ const cfg = await configStorage.load()
468
+ setConfig(cfg)
469
+ }
470
+ loadConfig()
471
+ }, [client])
472
+
473
+ return (
474
+ <div>
475
+ <h2>Current Configuration</h2>
476
+ <pre>{JSON.stringify(config, null, 2)}</pre>
477
+ </div>
478
+ )
479
+ }
480
+ ```
131
481
 
132
482
  ## Troubleshooting
133
483
 
134
- **Plugin not appearing in Studio**
135
- - Verify `npm install sanity-translation-plugin` completed successfully.
136
- - Ensure `translationPlugin()` is in the `plugins` array in `sanity.config.ts`.
137
- - Restart the Sanity Studio development server.
484
+ ### Translation Fails with Authentication Error
485
+
486
+ **Problem**: Translation requests fail with 401 or 403 errors
487
+
488
+ **Solution**:
489
+ 1. Verify OAuth credentials in `EL_PluginConfiguration`
490
+ 2. Check that Project ID and Access Token are correct
491
+ 3. Ensure access token hasn't expired
492
+ 4. Contact your translation service provider for new credentials
493
+
494
+ ### DNT Badges Not Showing
495
+
496
+ **Problem**: DNT badges don't appear on fields
497
+
498
+ **Solution**:
499
+ 1. Check that the field type is translatable (string, text, array)
500
+ 2. Verify the field isn't blacklisted (locale, _id, _type, etc.)
501
+ 3. Enable debug mode to see all fields
502
+ 4. Check browser console for errors
503
+
504
+ ### Translated Documents Not Created
138
505
 
139
- **Translation action not visible**
140
- - The action only appears on documents that have translatable fields defined in their schema.
506
+ **Problem**: Translation succeeds but no documents are created
141
507
 
142
- **Authentication Issues**
143
- - If using OAuth, check the **OAuth Configuration** tool to ensure your tokens are valid.
144
- - If using local testing, ensure your mock translation service is running on the expected port.
508
+ **Solution**:
509
+ 1. Check collision resolution mode - may be set to 'skip'
510
+ 2. Verify you have write permissions in the dataset
511
+ 3. Check browser console for document creation errors
512
+ 4. Ensure target locale codes match your schema
513
+
514
+ ### Bulk Translation Stalls
515
+
516
+ **Problem**: Bulk translation stops or hangs
517
+
518
+ **Solution**:
519
+ 1. Check network connection
520
+ 2. Verify translation API is responding
521
+ 3. Try translating a single document to isolate the issue
522
+ 4. Check browser console for errors
523
+ 5. Reduce batch size if translating many documents
524
+
525
+ ### Configuration Not Persisting
526
+
527
+ **Problem**: Configuration changes don't save
528
+
529
+ **Solution**:
530
+ 1. Verify you have write permissions in the dataset
531
+ 2. Check that `EL_PluginConfiguration` document exists
532
+ 3. Look for validation errors in the Studio
533
+ 4. Check browser console for save errors
534
+
535
+ ### Migration Issues
536
+
537
+ **Problem**: Legacy configuration not migrated
538
+
539
+ **Solution**:
540
+ 1. Check that legacy documents exist (`EL_oauth-config`, `EL_locale-config`)
541
+ 2. Manually create `EL_PluginConfiguration` document
542
+ 3. Copy values from legacy documents
543
+ 4. Contact support if automatic migration fails
544
+
545
+ ## API Reference
546
+
547
+ ### Exported Components
548
+
549
+ - `DNTFieldBadge`: Standalone DNT badge component
550
+ - `withDNTBadge`: HOC for adding DNT badge to custom fields
551
+ - `DNTFieldInput`: Complete field input with DNT badge
552
+
553
+ ### Exported Services
554
+
555
+ - `UnifiedConfigStorage`: Configuration management
556
+ - `DNTServiceManager`: DNT field management
557
+ - `DNTStorageAdapter`: DNT storage interface
558
+ - `LegacyDNTStorageAdapter`: Legacy DNT storage support
559
+
560
+ ### Exported Types
561
+
562
+ ```typescript
563
+ import type {
564
+ LocaleDefinition,
565
+ LocaleConfig,
566
+ TranslationRequestPayload,
567
+ TranslationResponse,
568
+ TranslatableField,
569
+ DNTFieldPreference,
570
+ DNTPreferences,
571
+ DNTTypeConfig,
572
+ DNTStorage,
573
+ UnifiedPluginConfig
574
+ } from '@easyling/sanity-connector'
575
+ ```
576
+
577
+ See the [shared library documentation](../shared/README.md) for complete API reference.
578
+
579
+ ## Development
580
+
581
+ ### Building
582
+
583
+ ```bash
584
+ npm run build # Production build
585
+ npm run dev # Development build with watch
586
+ npm run clean # Remove build artifacts
587
+ ```
588
+
589
+ ### Testing
590
+
591
+ ```bash
592
+ npm test # Run all tests
593
+ npm run test:watch # Run tests in watch mode
594
+ npm run test:coverage # Generate coverage report
595
+ ```
596
+
597
+ ### Code Quality
598
+
599
+ ```bash
600
+ npm run lint # Check for linting issues
601
+ npm run lint:fix # Auto-fix linting issues
602
+ npm run typecheck # Type check without emitting
603
+ ```
145
604
 
146
605
  ## Support
147
606
 
148
- Our support team can be reached at support@easyling.com.
607
+ For questions, issues, or feature requests:
149
608
 
150
- **Note:** In order to investigate compatibility or interoperability issues, we may need access to your Sanity data lake and Studio codebase. We are happy to work with you to establish secure access for debugging purposes.
609
+ - **Email**: support@easyling.com
610
+ - **Issues**: [GitHub Issues](https://github.com/easyling/el-sanity-connector/issues)
611
+ - **Documentation**: [Main README](../README.md) | [Shared Library](../shared/README.md)
151
612
 
152
613
  ## License
153
614
 
154
- MIT License - see [LICENSE](LICENSE) file for details.
615
+ MIT
616
+
617
+ ## Related Packages
618
+
619
+ - [@easyling/sanity-connector-shared](../shared/README.md) - Core translation logic
620
+ - [@easyling/sanity-function-auto-translate](../function/README.md) - Automatic translation on publish
621
+
622
+ ## Changelog
623
+
624
+ See [CHANGELOG.md](CHANGELOG.md) for version history and migration notes.