@sanity/document-internationalization 2.0.3 → 2.1.1
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 +17 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.esm.js +84 -10
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +83 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/DocumentInternationalizationContext.tsx +3 -2
- package/src/components/DocumentInternationalizationMenu.tsx +3 -3
- package/src/components/LanguageOption.tsx +15 -8
- package/src/types.ts +32 -0
- package/src/utils/excludePaths.ts +123 -0
package/README.md
CHANGED
|
@@ -169,6 +169,23 @@ defineField({
|
|
|
169
169
|
})
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
+
### Excluding fields
|
|
173
|
+
|
|
174
|
+
The default behaviour of this plugin when creating a new translation is to duplicate the originating document, which is useful for then translating the fields directly in the new document - perhaps with [Sanity AI Assist](https://github.com/sanity-io/assist). However, sometimes you may want to exclude certain fields from being copied to the new document. You can do this by updating your schema to exclude certain types or fields with `options.documentInternationalization.exclude`:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
defineField({
|
|
178
|
+
name: 'title',
|
|
179
|
+
title: 'Title',
|
|
180
|
+
type: 'string',
|
|
181
|
+
options: {
|
|
182
|
+
documentInternationalization: {
|
|
183
|
+
exclude: true,
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
}),
|
|
187
|
+
```
|
|
188
|
+
|
|
172
189
|
## Querying translations
|
|
173
190
|
|
|
174
191
|
### Querying with GROQ
|
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,13 @@ export declare type DocumentInternationalizationMenuProps = {
|
|
|
20
20
|
documentId: string
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
export declare interface DocumentInternationalizationSchemaOpts {
|
|
24
|
+
documentInternationalization?: {
|
|
25
|
+
/** Set to true to disable duplication of this field or type */
|
|
26
|
+
exclude?: boolean
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
export declare type Language = {
|
|
24
31
|
id: Intl.UnicodeBCP47LocaleIdentifier
|
|
25
32
|
title: string
|
|
@@ -57,3 +64,25 @@ export declare type TranslationReference = KeyedObject & {
|
|
|
57
64
|
export declare function useDocumentInternationalizationContext(): PluginConfigContext
|
|
58
65
|
|
|
59
66
|
export {}
|
|
67
|
+
|
|
68
|
+
declare module 'sanity' {
|
|
69
|
+
interface ArrayOptions extends DocumentInternationalizationSchemaOpts {}
|
|
70
|
+
interface BlockOptions extends DocumentInternationalizationSchemaOpts {}
|
|
71
|
+
interface BooleanOptions extends DocumentInternationalizationSchemaOpts {}
|
|
72
|
+
interface CrossDatasetReferenceOptions
|
|
73
|
+
extends DocumentInternationalizationSchemaOpts {}
|
|
74
|
+
interface DateOptions extends DocumentInternationalizationSchemaOpts {}
|
|
75
|
+
interface DatetimeOptions extends DocumentInternationalizationSchemaOpts {}
|
|
76
|
+
interface FileOptions extends DocumentInternationalizationSchemaOpts {}
|
|
77
|
+
interface GeopointOptions extends DocumentInternationalizationSchemaOpts {}
|
|
78
|
+
interface ImageOptions extends DocumentInternationalizationSchemaOpts {}
|
|
79
|
+
interface NumberOptions extends DocumentInternationalizationSchemaOpts {}
|
|
80
|
+
interface ObjectOptions extends DocumentInternationalizationSchemaOpts {}
|
|
81
|
+
interface ReferenceBaseOptions
|
|
82
|
+
extends DocumentInternationalizationSchemaOpts {}
|
|
83
|
+
interface SlugOptions extends DocumentInternationalizationSchemaOpts {}
|
|
84
|
+
interface StringOptions extends DocumentInternationalizationSchemaOpts {}
|
|
85
|
+
interface TextOptions extends DocumentInternationalizationSchemaOpts {}
|
|
86
|
+
interface UrlOptions extends DocumentInternationalizationSchemaOpts {}
|
|
87
|
+
interface EmailOptions extends DocumentInternationalizationSchemaOpts {}
|
|
88
|
+
}
|
package/dist/index.esm.js
CHANGED
|
@@ -2,11 +2,12 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
2
2
|
import { TrashIcon, CogIcon, SplitVerticalIcon, CheckmarkIcon, AddIcon, EditIcon, TranslateIcon, InfoOutlineIcon } from '@sanity/icons';
|
|
3
3
|
import { Flex, Spinner, Stack, Text, Card, Grid, Button, useToast, Tooltip, Box, Badge, useClickOutside, TextInput, Popover, Inline, Dialog } from '@sanity/ui';
|
|
4
4
|
import { useMemo, useEffect, createContext, useContext, useState, useCallback } from 'react';
|
|
5
|
-
import { useSchema, Preview, useClient, useEditState, useValidationStatus, TextWithTone,
|
|
5
|
+
import { useSchema, Preview, useClient, useWorkspace, isDocumentSchemaType, pathToString, useEditState, useValidationStatus, TextWithTone, PatchEvent, unset, defineType, defineField, definePlugin, isSanityDocument } from 'sanity';
|
|
6
6
|
import { Feedback, useListeningQuery } from 'sanity-plugin-utils';
|
|
7
7
|
import { uuid } from '@sanity/uuid';
|
|
8
8
|
import { usePaneRouter, useDocumentPane } from 'sanity/desk';
|
|
9
9
|
import { RouterContext } from 'sanity/router';
|
|
10
|
+
import { Mutation, extractWithPath } from '@sanity/mutator';
|
|
10
11
|
import styled from 'styled-components';
|
|
11
12
|
import { internationalizedArray } from 'sanity-plugin-internationalized-array';
|
|
12
13
|
function DocumentPreview(props) {
|
|
@@ -218,6 +219,7 @@ function DocumentInternationalizationProvider(props) {
|
|
|
218
219
|
const client = useClient({
|
|
219
220
|
apiVersion: pluginConfig.apiVersion
|
|
220
221
|
});
|
|
222
|
+
const workspace = useWorkspace();
|
|
221
223
|
const supportedLanguages = Array.isArray(pluginConfig.supportedLanguages) ? pluginConfig.supportedLanguages :
|
|
222
224
|
// eslint-disable-next-line require-await
|
|
223
225
|
suspend(async () => {
|
|
@@ -225,7 +227,7 @@ function DocumentInternationalizationProvider(props) {
|
|
|
225
227
|
return pluginConfig.supportedLanguages(client);
|
|
226
228
|
}
|
|
227
229
|
return pluginConfig.supportedLanguages;
|
|
228
|
-
}, []);
|
|
230
|
+
}, [workspace]);
|
|
229
231
|
return /* @__PURE__ */jsx(DocumentInternationalizationContext.Provider, {
|
|
230
232
|
value: {
|
|
231
233
|
...pluginConfig,
|
|
@@ -403,6 +405,77 @@ function createReference(key, ref, type) {
|
|
|
403
405
|
}
|
|
404
406
|
};
|
|
405
407
|
}
|
|
408
|
+
function removeExcludedPaths(doc, schemaType) {
|
|
409
|
+
if (!isDocumentSchemaType(schemaType) || !doc) {
|
|
410
|
+
return doc;
|
|
411
|
+
}
|
|
412
|
+
const pathsToExclude = extractPaths(doc, schemaType, []).filter(field => {
|
|
413
|
+
var _a, _b, _c;
|
|
414
|
+
return ((_c = (_b = (_a = field.schemaType) == null ? void 0 : _a.options) == null ? void 0 : _b.documentInternationalization) == null ? void 0 : _c.exclude) === true;
|
|
415
|
+
}).map(field => {
|
|
416
|
+
return pathToString(field.path);
|
|
417
|
+
});
|
|
418
|
+
const mut = new Mutation({
|
|
419
|
+
mutations: [{
|
|
420
|
+
patch: {
|
|
421
|
+
id: doc._id,
|
|
422
|
+
unset: pathsToExclude
|
|
423
|
+
}
|
|
424
|
+
}]
|
|
425
|
+
});
|
|
426
|
+
return mut.apply(doc);
|
|
427
|
+
}
|
|
428
|
+
function extractPaths(doc, schemaType, path) {
|
|
429
|
+
return schemaType.fields.reduce((acc, field) => {
|
|
430
|
+
var _a, _b;
|
|
431
|
+
const fieldPath = [...path, field.name];
|
|
432
|
+
const fieldSchema = field.type;
|
|
433
|
+
const {
|
|
434
|
+
value
|
|
435
|
+
} = (_a = extractWithPath(pathToString(fieldPath), doc)[0]) != null ? _a : {};
|
|
436
|
+
if (!value) {
|
|
437
|
+
return acc;
|
|
438
|
+
}
|
|
439
|
+
const thisFieldWithPath = {
|
|
440
|
+
path: fieldPath,
|
|
441
|
+
name: field.name,
|
|
442
|
+
schemaType: fieldSchema,
|
|
443
|
+
value
|
|
444
|
+
};
|
|
445
|
+
if (fieldSchema.jsonType === "object") {
|
|
446
|
+
const innerFields = extractPaths(doc, fieldSchema, fieldPath);
|
|
447
|
+
return [...acc, thisFieldWithPath, ...innerFields];
|
|
448
|
+
} else if (fieldSchema.jsonType === "array" && fieldSchema.of.length && fieldSchema.of.some(item => "fields" in item)) {
|
|
449
|
+
const {
|
|
450
|
+
value: arrayValue
|
|
451
|
+
} = (_b = extractWithPath(pathToString(fieldPath), doc)[0]) != null ? _b : {};
|
|
452
|
+
let arrayPaths = [];
|
|
453
|
+
if (arrayValue == null ? void 0 : arrayValue.length) {
|
|
454
|
+
for (const item of arrayValue) {
|
|
455
|
+
const itemPath = [...fieldPath, {
|
|
456
|
+
_key: item._key
|
|
457
|
+
}];
|
|
458
|
+
let itemSchema = fieldSchema.of.find(t => t.name === item._type);
|
|
459
|
+
if (!item._type) {
|
|
460
|
+
itemSchema = fieldSchema.of[0];
|
|
461
|
+
}
|
|
462
|
+
if (item._key && itemSchema) {
|
|
463
|
+
const innerFields = extractPaths(doc, itemSchema, itemPath);
|
|
464
|
+
const arrayMember = {
|
|
465
|
+
path: itemPath,
|
|
466
|
+
name: item._key,
|
|
467
|
+
schemaType: itemSchema,
|
|
468
|
+
value: item
|
|
469
|
+
};
|
|
470
|
+
arrayPaths = [...arrayPaths, arrayMember, ...innerFields];
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return [...acc, thisFieldWithPath, ...arrayPaths];
|
|
475
|
+
}
|
|
476
|
+
return [...acc, thisFieldWithPath];
|
|
477
|
+
}, []);
|
|
478
|
+
}
|
|
406
479
|
function LanguageOption(props) {
|
|
407
480
|
var _a;
|
|
408
481
|
const {
|
|
@@ -426,7 +499,7 @@ function LanguageOption(props) {
|
|
|
426
499
|
apiVersion
|
|
427
500
|
});
|
|
428
501
|
const toast = useToast();
|
|
429
|
-
const open = useOpenInNewPane((_a = translation == null ? void 0 : translation.value) == null ? void 0 : _a._ref, schemaType);
|
|
502
|
+
const open = useOpenInNewPane((_a = translation == null ? void 0 : translation.value) == null ? void 0 : _a._ref, schemaType.name);
|
|
430
503
|
const handleOpen = useCallback(() => open(), [open]);
|
|
431
504
|
const handleCreate = useCallback(async () => {
|
|
432
505
|
if (!source) {
|
|
@@ -440,19 +513,20 @@ function LanguageOption(props) {
|
|
|
440
513
|
}
|
|
441
514
|
const transaction = client.transaction();
|
|
442
515
|
const newTranslationDocumentId = uuid();
|
|
443
|
-
|
|
516
|
+
let newTranslationDocument = {
|
|
444
517
|
...source,
|
|
445
518
|
_id: "drafts.".concat(newTranslationDocumentId),
|
|
446
519
|
// 2. Update language of the translation
|
|
447
520
|
[languageField]: language.id
|
|
448
521
|
};
|
|
522
|
+
newTranslationDocument = removeExcludedPaths(newTranslationDocument, schemaType);
|
|
449
523
|
transaction.create(newTranslationDocument);
|
|
450
|
-
const sourceReference = createReference(sourceLanguageId, documentId, schemaType, !weakReferences);
|
|
451
|
-
const newTranslationReference = createReference(language.id, newTranslationDocumentId, schemaType, !weakReferences);
|
|
524
|
+
const sourceReference = createReference(sourceLanguageId, documentId, schemaType.name, !weakReferences);
|
|
525
|
+
const newTranslationReference = createReference(language.id, newTranslationDocumentId, schemaType.name, !weakReferences);
|
|
452
526
|
const newMetadataDocument = {
|
|
453
527
|
_id: metadataId,
|
|
454
528
|
_type: METADATA_SCHEMA_NAME,
|
|
455
|
-
schemaTypes: [schemaType],
|
|
529
|
+
schemaTypes: [schemaType.name],
|
|
456
530
|
translations: [sourceReference]
|
|
457
531
|
};
|
|
458
532
|
transaction.createIfNotExists(newMetadataDocument);
|
|
@@ -605,7 +679,7 @@ function DocumentInternationalizationMenu(props) {
|
|
|
605
679
|
const {
|
|
606
680
|
documentId
|
|
607
681
|
} = props;
|
|
608
|
-
const schemaType = props.schemaType
|
|
682
|
+
const schemaType = props.schemaType;
|
|
609
683
|
const {
|
|
610
684
|
languageField,
|
|
611
685
|
supportedLanguages
|
|
@@ -640,7 +714,7 @@ function DocumentInternationalizationMenu(props) {
|
|
|
640
714
|
const {
|
|
641
715
|
draft,
|
|
642
716
|
published
|
|
643
|
-
} = useEditState(documentId, schemaType);
|
|
717
|
+
} = useEditState(documentId, schemaType.name);
|
|
644
718
|
const source = draft || published;
|
|
645
719
|
const documentIsInOneMetadataDocument = useMemo(() => {
|
|
646
720
|
return Array.isArray(data) && data.length <= 1;
|
|
@@ -725,7 +799,7 @@ function DocumentInternationalizationMenu(props) {
|
|
|
725
799
|
if (!documentId) {
|
|
726
800
|
return null;
|
|
727
801
|
}
|
|
728
|
-
if (!schemaType) {
|
|
802
|
+
if (!schemaType || !schemaType.name) {
|
|
729
803
|
return null;
|
|
730
804
|
}
|
|
731
805
|
return /* @__PURE__ */jsx(Popover, {
|