@sanity/document-internationalization 4.1.1 → 5.0.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.
Files changed (52) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +44 -36
  3. package/dist/_chunks-es/{resources.mjs → resources.js} +1 -1
  4. package/dist/{_chunks-cjs → _chunks-es}/resources.js.map +1 -1
  5. package/dist/index.d.ts +112 -88
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +1075 -1337
  8. package/dist/index.js.map +1 -1
  9. package/package.json +35 -69
  10. package/dist/_chunks-cjs/resources.js +0 -8
  11. package/dist/_chunks-es/resources.mjs.map +0 -1
  12. package/dist/_legacy/resources.esm.js +0 -9
  13. package/dist/_legacy/resources.esm.js.map +0 -1
  14. package/dist/index.d.mts +0 -108
  15. package/dist/index.esm.js +0 -1625
  16. package/dist/index.esm.js.map +0 -1
  17. package/dist/index.mjs +0 -1625
  18. package/dist/index.mjs.map +0 -1
  19. package/sanity.json +0 -8
  20. package/src/actions/DeleteMetadataAction.tsx +0 -93
  21. package/src/actions/DeleteTranslationAction.tsx +0 -102
  22. package/src/actions/DuplicateWithTranslationsAction.tsx +0 -251
  23. package/src/badges/index.tsx +0 -27
  24. package/src/components/BulkPublish/DocumentCheck.tsx +0 -90
  25. package/src/components/BulkPublish/Info.tsx +0 -28
  26. package/src/components/BulkPublish/InfoIcon.tsx +0 -34
  27. package/src/components/BulkPublish/index.tsx +0 -181
  28. package/src/components/ConstrainedBox.tsx +0 -6
  29. package/src/components/DeleteTranslationDialog/DocumentPreview.tsx +0 -19
  30. package/src/components/DeleteTranslationDialog/index.tsx +0 -111
  31. package/src/components/DeleteTranslationDialog/separateReferences.ts +0 -23
  32. package/src/components/DeleteTranslationFooter.tsx +0 -28
  33. package/src/components/DocumentInternationalizationContext.tsx +0 -47
  34. package/src/components/DocumentInternationalizationMenu.tsx +0 -235
  35. package/src/components/LanguageManage.tsx +0 -108
  36. package/src/components/LanguageOption.tsx +0 -259
  37. package/src/components/LanguagePatch.tsx +0 -67
  38. package/src/components/OptimisticallyStrengthen/ReferencePatcher.tsx +0 -50
  39. package/src/components/OptimisticallyStrengthen/index.tsx +0 -34
  40. package/src/components/Warning.tsx +0 -18
  41. package/src/constants.ts +0 -16
  42. package/src/hooks/useLanguageMetadata.tsx +0 -26
  43. package/src/hooks/useOpenInNewPane.tsx +0 -33
  44. package/src/i18n/index.ts +0 -21
  45. package/src/i18n/resources.ts +0 -7
  46. package/src/index.ts +0 -6
  47. package/src/plugin.tsx +0 -239
  48. package/src/schema/translation/metadata.ts +0 -68
  49. package/src/types.ts +0 -97
  50. package/src/utils/createReference.ts +0 -20
  51. package/src/utils/excludePaths.ts +0 -123
  52. package/v2-incompatible.js +0 -11
package/src/plugin.tsx DELETED
@@ -1,239 +0,0 @@
1
- import {Stack} from '@sanity/ui'
2
- import {defineField, definePlugin, isSanityDocument} from 'sanity'
3
- import {internationalizedArray} from 'sanity-plugin-internationalized-array'
4
-
5
- import {DeleteMetadataAction} from './actions/DeleteMetadataAction'
6
- import {LanguageBadge} from './badges'
7
- import BulkPublish from './components/BulkPublish'
8
- import {DocumentInternationalizationProvider} from './components/DocumentInternationalizationContext'
9
- import {DocumentInternationalizationMenu} from './components/DocumentInternationalizationMenu'
10
- import OptimisticallyStrengthen from './components/OptimisticallyStrengthen'
11
- import {API_VERSION, DEFAULT_CONFIG, METADATA_SCHEMA_NAME} from './constants'
12
- import {documentInternationalizationUsEnglishLocaleBundle} from './i18n'
13
- import metadata from './schema/translation/metadata'
14
- import type {PluginConfig, TranslationReference} from './types'
15
-
16
- export const documentInternationalization = definePlugin<PluginConfig>(
17
- (config) => {
18
- const pluginConfig = {...DEFAULT_CONFIG, ...config}
19
- const {
20
- supportedLanguages,
21
- schemaTypes,
22
- languageField,
23
- bulkPublish,
24
- metadataFields,
25
- } = pluginConfig
26
-
27
- if (schemaTypes.length === 0) {
28
- throw new Error(
29
- 'You must specify at least one schema type on which to enable document internationalization. Update the `schemaTypes` option in the documentInternationalization() configuration.'
30
- )
31
- }
32
-
33
- return {
34
- name: '@sanity/document-internationalization',
35
-
36
- studio: {
37
- components: {
38
- layout: (props) =>
39
- DocumentInternationalizationProvider({...props, pluginConfig}),
40
- },
41
- },
42
-
43
- i18n: {
44
- bundles: [documentInternationalizationUsEnglishLocaleBundle],
45
- },
46
-
47
- // Adds:
48
- // - A bulk-publishing UI component to the form
49
- // - Will only work for projects on a compatible plan
50
- form: {
51
- components: {
52
- input: (props) => {
53
- if (
54
- props.id === 'root' &&
55
- props.schemaType.name === METADATA_SCHEMA_NAME &&
56
- isSanityDocument(props?.value)
57
- ) {
58
- const metadataId = props?.value?._id
59
- const translations =
60
- (props?.value?.translations as TranslationReference[]) ?? []
61
- const weakAndTypedTranslations = translations.filter(
62
- ({value}) => value?._weak && value._strengthenOnPublish
63
- )
64
-
65
- return (
66
- <Stack space={5}>
67
- {bulkPublish ? (
68
- <BulkPublish translations={translations} />
69
- ) : null}
70
- {weakAndTypedTranslations.length > 0 ? (
71
- <OptimisticallyStrengthen
72
- metadataId={metadataId}
73
- translations={weakAndTypedTranslations}
74
- />
75
- ) : null}
76
- {props.renderDefault(props)}
77
- </Stack>
78
- )
79
- }
80
-
81
- return props.renderDefault(props)
82
- },
83
- },
84
- },
85
-
86
- // Adds:
87
- // - The `Translations` dropdown to the editing form
88
- // - `Badges` to documents with a language value
89
- // - The `DeleteMetadataAction` action to the metadata document type
90
- document: {
91
- unstable_languageFilter: (prev, ctx) => {
92
- const {schemaType, documentId} = ctx
93
-
94
- return schemaTypes.includes(schemaType) && documentId
95
- ? [
96
- ...prev,
97
- (props) =>
98
- DocumentInternationalizationMenu({...props, documentId}),
99
- ]
100
- : prev
101
- },
102
- badges: (prev, {schemaType}) => {
103
- if (!schemaTypes.includes(schemaType)) {
104
- return prev
105
- }
106
-
107
- return [(props) => LanguageBadge(props), ...prev]
108
- },
109
- actions: (prev, {schemaType}) => {
110
- if (schemaType === METADATA_SCHEMA_NAME) {
111
- return [...prev, DeleteMetadataAction]
112
- }
113
-
114
- return prev
115
- },
116
- },
117
-
118
- // Adds:
119
- // - The `Translations metadata` document type to the schema
120
- schema: {
121
- // Create the metadata document type
122
- types: [metadata(schemaTypes, metadataFields)],
123
-
124
- // For every schema type this plugin is enabled on
125
- // Create an initial value template to set the language
126
- templates: (prev, {schema}) => {
127
- // Templates are not setup for async languages
128
- if (!Array.isArray(supportedLanguages)) {
129
- return prev
130
- }
131
-
132
- const parameterizedTemplates = schemaTypes.map((schemaType) => ({
133
- id: `${schemaType}-parameterized`,
134
- title: `${
135
- schema?.get(schemaType)?.title ?? schemaType
136
- }: with Language`,
137
- schemaType,
138
- parameters: [
139
- {name: `languageId`, title: `Language ID`, type: `string`},
140
- ],
141
- value: ({languageId}: {languageId: string}) => ({
142
- [languageField]: languageId,
143
- }),
144
- }))
145
-
146
- const staticTemplates = schemaTypes.flatMap((schemaType) => {
147
- return supportedLanguages.map((language) => ({
148
- id: `${schemaType}-${language.id}`,
149
- title: `${language.title} ${
150
- schema?.get(schemaType)?.title ?? schemaType
151
- }`,
152
- schemaType,
153
- value: {
154
- [languageField]: language.id,
155
- },
156
- }))
157
- })
158
-
159
- return [...prev, ...parameterizedTemplates, ...staticTemplates]
160
- },
161
- },
162
-
163
- // Uses:
164
- // - `sanity-plugin-internationalized-array` to maintain the translations array
165
- plugins: [
166
- // Translation metadata stores its references using this plugin
167
- // It cuts down on attribute usage and gives UI conveniences to add new translations
168
- internationalizedArray({
169
- apiVersion: pluginConfig.apiVersion,
170
- languages: supportedLanguages,
171
- fieldTypes: [
172
- defineField(
173
- {
174
- name: 'reference',
175
- type: 'reference',
176
- to: schemaTypes.map((type) => ({type})),
177
- weak: pluginConfig.weakReferences,
178
- // Reference filters don't actually enforce validation!
179
- validation: (Rule) =>
180
- // @ts-expect-error - fix typings
181
- Rule.custom(async (item: TranslationReference, context) => {
182
- if (!item?.value?._ref || !item?._key) {
183
- return true
184
- }
185
-
186
- const client = context.getClient({apiVersion: API_VERSION})
187
- const valueLanguage = await client.fetch(
188
- `*[_id in [$ref, $draftRef]][0].${languageField}`,
189
- {
190
- ref: item.value._ref,
191
- draftRef: `drafts.${item.value._ref}`,
192
- }
193
- )
194
-
195
- if (valueLanguage && valueLanguage === item._key) {
196
- return true
197
- }
198
-
199
- return `Referenced document does not have the correct language value`
200
- }),
201
- options: {
202
- // @ts-expect-error - Update type once it knows the values of this filter
203
- filter: ({parent, document}) => {
204
- if (!parent) return null
205
-
206
- // I'm not sure in what instance there's an array of parents
207
- // But the Type suggests it's possible
208
- const parentArray = Array.isArray(parent)
209
- ? parent
210
- : [parent]
211
- const language = parentArray.find((p) => p._key)
212
-
213
- if (!language?._key) return null
214
-
215
- if (document.schemaTypes) {
216
- return {
217
- filter: `_type in $schemaTypes && ${languageField} == $language`,
218
- params: {
219
- schemaTypes: document.schemaTypes,
220
- language: language._key,
221
- },
222
- }
223
- }
224
-
225
- return {
226
- filter: `${languageField} == $language`,
227
- params: {language: language._key},
228
- }
229
- },
230
- },
231
- },
232
- {strict: false}
233
- ),
234
- ],
235
- }),
236
- ],
237
- }
238
- }
239
- )
@@ -1,68 +0,0 @@
1
- import {TranslateIcon} from '@sanity/icons'
2
- import {
3
- defineField,
4
- defineType,
5
- type DocumentDefinition,
6
- type FieldDefinition,
7
- } from 'sanity'
8
-
9
- import {METADATA_SCHEMA_NAME, TRANSLATIONS_ARRAY_NAME} from '../../constants'
10
-
11
- export default (
12
- schemaTypes: string[],
13
- metadataFields: FieldDefinition[]
14
- ): DocumentDefinition =>
15
- defineType({
16
- type: 'document',
17
- name: METADATA_SCHEMA_NAME,
18
- title: 'Translation metadata',
19
- icon: TranslateIcon,
20
- liveEdit: true,
21
- fields: [
22
- defineField({
23
- name: TRANSLATIONS_ARRAY_NAME,
24
- type: 'internationalizedArrayReference',
25
- }),
26
- defineField({
27
- name: 'schemaTypes',
28
- description:
29
- 'Optional: Used to filter the reference fields above so all translations share the same types.',
30
- type: 'array',
31
- of: [{type: 'string'}],
32
- options: {list: schemaTypes},
33
- readOnly: ({value}) => Boolean(value),
34
- }),
35
- ...metadataFields,
36
- ],
37
- preview: {
38
- select: {
39
- translations: TRANSLATIONS_ARRAY_NAME,
40
- documentSchemaTypes: 'schemaTypes',
41
- },
42
- prepare(selection) {
43
- const {translations = [], documentSchemaTypes = []} = selection
44
- const title =
45
- translations.length === 1
46
- ? `1 Translation`
47
- : `${translations.length} Translations`
48
- const languageKeys = translations.length
49
- ? translations
50
- .map((t: {_key: string}) => t._key.toUpperCase())
51
- .join(', ')
52
- : ``
53
- const subtitle = [
54
- languageKeys ? `(${languageKeys})` : null,
55
- documentSchemaTypes?.length
56
- ? documentSchemaTypes.map((s: string) => s).join(`, `)
57
- : ``,
58
- ]
59
- .filter(Boolean)
60
- .join(` `)
61
-
62
- return {
63
- title,
64
- subtitle,
65
- }
66
- },
67
- },
68
- })
package/src/types.ts DELETED
@@ -1,97 +0,0 @@
1
- /* eslint-disable no-unused-vars */
2
-
3
- import type {
4
- FieldDefinition,
5
- KeyedObject,
6
- ObjectSchemaType,
7
- Reference,
8
- SanityClient,
9
- SanityDocument,
10
- SanityDocumentLike,
11
- } from 'sanity'
12
-
13
- export type Language = {
14
- id: Intl.UnicodeBCP47LocaleIdentifier
15
- title: string
16
- }
17
-
18
- export type SupportedLanguages =
19
- | Language[]
20
- | ((client: SanityClient) => Promise<Language[]>)
21
-
22
- export type PluginCallbackArgs = {
23
- sourceDocument: SanityDocument
24
- newDocument: SanityDocument
25
- sourceLanguageId: string
26
- destinationLanguageId: string
27
- metaDocumentId: string
28
- client: SanityClient
29
- }
30
-
31
- export type PluginConfig = {
32
- supportedLanguages: SupportedLanguages
33
- schemaTypes: string[]
34
- languageField?: string
35
- weakReferences?: boolean
36
- bulkPublish?: boolean
37
- metadataFields?: FieldDefinition[]
38
- apiVersion?: string
39
- allowCreateMetaDoc?: boolean
40
- callback?: ((args: PluginCallbackArgs) => Promise<void>) | null
41
- }
42
-
43
- // Context version of config
44
- // should have processed the
45
- // supportedLanguages function
46
- export type PluginConfigContext = Required<PluginConfig> & {
47
- supportedLanguages: Language[]
48
- }
49
-
50
- export type TranslationReference = KeyedObject & {
51
- _type: 'internationalizedArrayReferenceValue'
52
- value: Reference
53
- }
54
-
55
- export type Metadata = {
56
- _id: string
57
- _createdAt: string
58
- translations: TranslationReference[]
59
- }
60
-
61
- export type MetadataDocument = SanityDocumentLike & {
62
- schemaTypes: string[]
63
- translations: TranslationReference[]
64
- }
65
-
66
- export type DocumentInternationalizationMenuProps = {
67
- schemaType: ObjectSchemaType
68
- documentId: string
69
- }
70
-
71
- // Extend Sanity schema definitions
72
- export interface DocumentInternationalizationSchemaOpts {
73
- documentInternationalization?: {
74
- /** Set to true to disable duplication of this field or type */
75
- exclude?: boolean
76
- }
77
- }
78
-
79
- declare module 'sanity' {
80
- interface ArrayOptions extends DocumentInternationalizationSchemaOpts {}
81
- interface BlockOptions extends DocumentInternationalizationSchemaOpts {}
82
- interface BooleanOptions extends DocumentInternationalizationSchemaOpts {}
83
- interface CrossDatasetReferenceOptions extends DocumentInternationalizationSchemaOpts {}
84
- interface DateOptions extends DocumentInternationalizationSchemaOpts {}
85
- interface DatetimeOptions extends DocumentInternationalizationSchemaOpts {}
86
- interface FileOptions extends DocumentInternationalizationSchemaOpts {}
87
- interface GeopointOptions extends DocumentInternationalizationSchemaOpts {}
88
- interface ImageOptions extends DocumentInternationalizationSchemaOpts {}
89
- interface NumberOptions extends DocumentInternationalizationSchemaOpts {}
90
- interface ObjectOptions extends DocumentInternationalizationSchemaOpts {}
91
- interface ReferenceBaseOptions extends DocumentInternationalizationSchemaOpts {}
92
- interface SlugOptions extends DocumentInternationalizationSchemaOpts {}
93
- interface StringOptions extends DocumentInternationalizationSchemaOpts {}
94
- interface TextOptions extends DocumentInternationalizationSchemaOpts {}
95
- interface UrlOptions extends DocumentInternationalizationSchemaOpts {}
96
- interface EmailOptions extends DocumentInternationalizationSchemaOpts {}
97
- }
@@ -1,20 +0,0 @@
1
- import type {TranslationReference} from '../types'
2
-
3
- export function createReference(
4
- key: string,
5
- ref: string,
6
- type: string,
7
- strengthenOnPublish: boolean = true
8
- ): TranslationReference {
9
- return {
10
- _key: key,
11
- _type: 'internationalizedArrayReferenceValue',
12
- value: {
13
- _type: 'reference',
14
- _ref: ref,
15
- _weak: true,
16
- // If the user has configured weakReferences, we won't want to strengthen them
17
- ...(strengthenOnPublish ? {_strengthenOnPublish: {type}} : {}),
18
- },
19
- }
20
- }
@@ -1,123 +0,0 @@
1
- import {extractWithPath, Mutation} from '@sanity/mutator'
2
- import {
3
- isDocumentSchemaType,
4
- type ObjectSchemaType,
5
- type Path,
6
- pathToString,
7
- type SanityDocument,
8
- type SchemaType,
9
- } from 'sanity'
10
-
11
- export interface DocumentMember {
12
- schemaType: SchemaType
13
- path: Path
14
- name: string
15
- value: unknown
16
- }
17
-
18
- export function removeExcludedPaths(
19
- doc: SanityDocument | null,
20
- schemaType: ObjectSchemaType
21
- ): SanityDocument | null {
22
- // If the supplied doc is null or the schemaType
23
- // isn't a document, return as is.
24
- if (!isDocumentSchemaType(schemaType) || !doc) {
25
- return doc
26
- }
27
-
28
- // The extractPaths function gets all the fields in the doc with
29
- // a value, along with their schemaTypes and paths. We'll end up
30
- // with an array of paths in string form which we want to exclude
31
- const pathsToExclude: string[] = extractPaths(doc, schemaType, [])
32
- // We filter for any fields which should be excluded from the document
33
- // duplicate action, based on the schemaType option being set.
34
- .filter(
35
- (field) =>
36
- field.schemaType?.options?.documentInternationalization?.exclude ===
37
- true
38
- )
39
- // then we return the stringified version of the path
40
- .map((field) => {
41
- return pathToString(field.path)
42
- })
43
-
44
- // Now we can use the Mutation class from @sanity/mutator to patch the document
45
- // to remove all the paths that are for one of the excluded fields. This is just
46
- // done locally, and the documents themselves are not patched in the Content Lake.
47
- const mut = new Mutation({
48
- mutations: [
49
- {
50
- patch: {
51
- id: doc._id,
52
- unset: pathsToExclude,
53
- },
54
- },
55
- ],
56
- })
57
-
58
- return mut.apply(doc) as SanityDocument
59
- }
60
-
61
- function extractPaths(
62
- doc: SanityDocument,
63
- schemaType: ObjectSchemaType,
64
- path: Path
65
- ): DocumentMember[] {
66
- return schemaType.fields.reduce<DocumentMember[]>((acc, field) => {
67
- const fieldPath = [...path, field.name]
68
- const fieldSchema = field.type
69
- const {value} = extractWithPath(pathToString(fieldPath), doc)[0] ?? {}
70
- if (!value) {
71
- return acc
72
- }
73
-
74
- const thisFieldWithPath: DocumentMember = {
75
- path: fieldPath,
76
- name: field.name,
77
- schemaType: fieldSchema,
78
- value,
79
- }
80
-
81
- if (fieldSchema.jsonType === 'object') {
82
- const innerFields = extractPaths(doc, fieldSchema, fieldPath)
83
-
84
- return [...acc, thisFieldWithPath, ...innerFields]
85
- } else if (
86
- fieldSchema.jsonType === 'array' &&
87
- fieldSchema.of.length &&
88
- fieldSchema.of.some((item) => 'fields' in item)
89
- ) {
90
- const {value: arrayValue} =
91
- extractWithPath(pathToString(fieldPath), doc)[0] ?? {}
92
-
93
- let arrayPaths: DocumentMember[] = []
94
- if ((arrayValue as any)?.length) {
95
- for (const item of arrayValue as any[]) {
96
- const itemPath = [...fieldPath, {_key: item._key}]
97
- let itemSchema = fieldSchema.of.find((t) => t.name === item._type)
98
- if (!item._type) {
99
- itemSchema = fieldSchema.of[0]
100
- }
101
- if (item._key && itemSchema) {
102
- const innerFields = extractPaths(
103
- doc,
104
- itemSchema as ObjectSchemaType,
105
- itemPath
106
- )
107
- const arrayMember = {
108
- path: itemPath,
109
- name: item._key,
110
- schemaType: itemSchema,
111
- value: item,
112
- }
113
- arrayPaths = [...arrayPaths, arrayMember, ...innerFields]
114
- }
115
- }
116
- }
117
-
118
- return [...acc, thisFieldWithPath, ...arrayPaths]
119
- }
120
-
121
- return [...acc, thisFieldWithPath]
122
- }, [])
123
- }
@@ -1,11 +0,0 @@
1
- const {showIncompatiblePluginDialog} = require('@sanity/incompatible-plugin')
2
- const {name, version, sanityExchangeUrl} = require('./package.json')
3
-
4
- export default showIncompatiblePluginDialog({
5
- name: name,
6
- versions: {
7
- v3: version,
8
- v2: undefined,
9
- },
10
- sanityExchangeUrl,
11
- })