@sanity/document-internationalization 2.0.0-studio-v3-plugin-v2.7 → 2.0.0-studio-v3-plugin-v2.8
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 +6 -3
- package/lib/index.esm.js +407 -156
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +405 -154
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/BulkPublish/DocumentCheck.tsx +39 -16
- package/src/components/BulkPublish/index.tsx +86 -55
- package/src/components/LanguageManage.tsx +1 -2
- package/src/components/LanguageOption.tsx +78 -28
- package/src/components/LanguagePatch.tsx +16 -8
- package/src/components/MenuButton.tsx +76 -43
- package/src/components/OptimisticallyStrengthen/ReferencePatcher.tsx +49 -0
- package/src/components/OptimisticallyStrengthen/index.tsx +34 -0
- package/src/plugin.tsx +195 -147
- package/src/schema/translation/metadata.ts +1 -1
- package/src/types.ts +9 -7
package/src/plugin.tsx
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import {definePlugin, defineField} from 'sanity'
|
|
3
|
-
import {internationalizedArray} from 'sanity-plugin-internationalized-array'
|
|
4
1
|
import {Stack} from '@sanity/ui'
|
|
2
|
+
import {defineField, definePlugin, isSanityDocument} from 'sanity'
|
|
3
|
+
import {internationalizedArray} from 'sanity-plugin-internationalized-array'
|
|
5
4
|
|
|
6
|
-
import metadata from './schema/translation/metadata'
|
|
7
|
-
import MenuButton from './components/MenuButton'
|
|
8
|
-
import {PluginConfig} from './types'
|
|
9
5
|
import {LanguageBadge} from './badges'
|
|
10
|
-
import {METADATA_SCHEMA_NAME} from './constants'
|
|
11
6
|
import BulkPublish from './components/BulkPublish'
|
|
7
|
+
import MenuButton from './components/MenuButton'
|
|
8
|
+
import OptimisticallyStrengthen from './components/OptimisticallyStrengthen'
|
|
9
|
+
import {API_VERSION, METADATA_SCHEMA_NAME} from './constants'
|
|
10
|
+
import metadata from './schema/translation/metadata'
|
|
11
|
+
import {PluginConfig, TranslationReference} from './types'
|
|
12
12
|
|
|
13
13
|
const DEFAULT_CONFIG = {
|
|
14
14
|
supportedLanguages: [],
|
|
@@ -17,159 +17,207 @@ const DEFAULT_CONFIG = {
|
|
|
17
17
|
bulkPublish: false,
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export const documentInternationalization = definePlugin<PluginConfig>(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
export const documentInternationalization = definePlugin<PluginConfig>(
|
|
21
|
+
(config) => {
|
|
22
|
+
const {supportedLanguages, schemaTypes, languageField, bulkPublish} = {
|
|
23
|
+
...DEFAULT_CONFIG,
|
|
24
|
+
...config,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const renderLanguageFilter = (schemaType: string, documentId?: string) => {
|
|
28
|
+
return (
|
|
29
|
+
<MenuButton
|
|
30
|
+
supportedLanguages={supportedLanguages}
|
|
31
|
+
schemaType={schemaType}
|
|
32
|
+
documentId={documentId ?? ``}
|
|
33
|
+
languageField={languageField}
|
|
34
|
+
/>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
name: '@sanity/document-internationalization',
|
|
40
|
+
|
|
41
|
+
// Adds:
|
|
42
|
+
// - A bulk-publishing UI component to the form
|
|
43
|
+
// - Will only work for projects on a compatible plan
|
|
44
|
+
form: {
|
|
45
|
+
components: {
|
|
46
|
+
input: (props) => {
|
|
47
|
+
if (
|
|
48
|
+
props.id === 'root' &&
|
|
49
|
+
props.schemaType.name === METADATA_SCHEMA_NAME &&
|
|
50
|
+
isSanityDocument(props?.value)
|
|
51
|
+
) {
|
|
52
|
+
const metadataId = props?.value?._id
|
|
53
|
+
const translations =
|
|
54
|
+
(props?.value?.translations as TranslationReference[]) ?? []
|
|
55
|
+
const weakAndTypedTranslations = translations.filter(
|
|
56
|
+
(t) => t?.value?._weak && t.value?._strengthenOnPublish
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Stack space={5}>
|
|
61
|
+
{bulkPublish ? (
|
|
62
|
+
<BulkPublish translations={translations} />
|
|
63
|
+
) : null}
|
|
64
|
+
{weakAndTypedTranslations.length > 0 ? (
|
|
65
|
+
<OptimisticallyStrengthen
|
|
66
|
+
metadataId={metadataId}
|
|
67
|
+
translations={weakAndTypedTranslations}
|
|
68
|
+
/>
|
|
69
|
+
) : null}
|
|
70
|
+
{props.renderDefault(props)}
|
|
71
|
+
</Stack>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return props.renderDefault(props)
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
25
79
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
languageField={languageField}
|
|
33
|
-
/>
|
|
34
|
-
)
|
|
35
|
-
}
|
|
80
|
+
// Adds:
|
|
81
|
+
// - The `Translations` dropdown to the editing form
|
|
82
|
+
// - `Badges` to documents with a language value
|
|
83
|
+
document: {
|
|
84
|
+
unstable_languageFilter: (prev, ctx) => {
|
|
85
|
+
const {schemaType, documentId} = ctx
|
|
36
86
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
components: {
|
|
45
|
-
input: (props) => {
|
|
46
|
-
if (
|
|
47
|
-
bulkPublish &&
|
|
48
|
-
props.id === 'root' &&
|
|
49
|
-
props.schemaType.name === METADATA_SCHEMA_NAME
|
|
50
|
-
) {
|
|
51
|
-
return (
|
|
52
|
-
<Stack space={5}>
|
|
53
|
-
{/* <BulkPublish {...props} /> */}
|
|
54
|
-
{props.renderDefault(props)}
|
|
55
|
-
</Stack>
|
|
56
|
-
)
|
|
87
|
+
return schemaTypes.includes(schemaType)
|
|
88
|
+
? [...prev, () => renderLanguageFilter(schemaType, documentId)]
|
|
89
|
+
: prev
|
|
90
|
+
},
|
|
91
|
+
badges: (prev, {schemaType}) => {
|
|
92
|
+
if (!schemaTypes.includes(schemaType)) {
|
|
93
|
+
return prev
|
|
57
94
|
}
|
|
58
95
|
|
|
59
|
-
return
|
|
96
|
+
return [
|
|
97
|
+
(props) => LanguageBadge(props, supportedLanguages, languageField),
|
|
98
|
+
...prev,
|
|
99
|
+
]
|
|
60
100
|
},
|
|
61
101
|
},
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
// Adds:
|
|
65
|
-
// - The `Translations` dropdown to the editing form
|
|
66
|
-
// - `Badges` to documents with a language value
|
|
67
|
-
document: {
|
|
68
|
-
unstable_languageFilter: (prev, ctx) => {
|
|
69
|
-
const {schemaType, documentId} = ctx
|
|
70
|
-
|
|
71
|
-
return schemaTypes.includes(schemaType)
|
|
72
|
-
? [...prev, () => renderLanguageFilter(schemaType, documentId)]
|
|
73
|
-
: prev
|
|
74
|
-
},
|
|
75
|
-
badges: (prev, {schemaType}) => {
|
|
76
|
-
if (!schemaTypes.includes(schemaType)) {
|
|
77
|
-
return prev
|
|
78
|
-
}
|
|
79
102
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
id: `${schemaType}-parameterized`,
|
|
100
|
-
title: `${schema?.get(schemaType)?.title ?? schemaType}: with Language`,
|
|
101
|
-
schemaType,
|
|
102
|
-
parameters: [{name: `languageId`, title: `Language ID`, type: `string`}],
|
|
103
|
-
value: ({languageId}: {languageId: string}) => ({
|
|
104
|
-
[languageField]: languageId,
|
|
105
|
-
}),
|
|
106
|
-
}))
|
|
107
|
-
|
|
108
|
-
const staticTemplates = schemaTypes.flatMap((schemaType) => {
|
|
109
|
-
return supportedLanguages.map((language) => ({
|
|
110
|
-
id: `${schemaType}-${language.id}`,
|
|
111
|
-
title: `${language.title} ${schema?.get(schemaType)?.title ?? schemaType}`,
|
|
103
|
+
// Adds:
|
|
104
|
+
// - The `Translations metadata` document type to the schema
|
|
105
|
+
schema: {
|
|
106
|
+
// Create the metadata document type
|
|
107
|
+
types: [metadata(schemaTypes)],
|
|
108
|
+
|
|
109
|
+
// For every schema type this plugin is enabled on
|
|
110
|
+
// Create an initial value template to set the language
|
|
111
|
+
templates: (prev, {schema}) => {
|
|
112
|
+
// Templates are not setup for async languages
|
|
113
|
+
if (!Array.isArray(supportedLanguages)) {
|
|
114
|
+
return prev
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const parameterizedTemplates = schemaTypes.map((schemaType) => ({
|
|
118
|
+
id: `${schemaType}-parameterized`,
|
|
119
|
+
title: `${
|
|
120
|
+
schema?.get(schemaType)?.title ?? schemaType
|
|
121
|
+
}: with Language`,
|
|
112
122
|
schemaType,
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
123
|
+
parameters: [
|
|
124
|
+
{name: `languageId`, title: `Language ID`, type: `string`},
|
|
125
|
+
],
|
|
126
|
+
value: ({languageId}: {languageId: string}) => ({
|
|
127
|
+
[languageField]: languageId,
|
|
128
|
+
}),
|
|
116
129
|
}))
|
|
117
|
-
})
|
|
118
130
|
|
|
119
|
-
|
|
131
|
+
const staticTemplates = schemaTypes.flatMap((schemaType) => {
|
|
132
|
+
return supportedLanguages.map((language) => ({
|
|
133
|
+
id: `${schemaType}-${language.id}`,
|
|
134
|
+
title: `${language.title} ${
|
|
135
|
+
schema?.get(schemaType)?.title ?? schemaType
|
|
136
|
+
}`,
|
|
137
|
+
schemaType,
|
|
138
|
+
value: {
|
|
139
|
+
[languageField]: language.id,
|
|
140
|
+
},
|
|
141
|
+
}))
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
return [...prev, ...parameterizedTemplates, ...staticTemplates]
|
|
145
|
+
},
|
|
120
146
|
},
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
// validation: (Rule) => Rule.custom(),
|
|
141
|
-
options: {
|
|
142
|
-
collapsed: false,
|
|
143
|
-
// TODO: Update type once it knows the values of this filter
|
|
144
|
-
// @ts-ignore
|
|
145
|
-
filter: ({parent, document}) => {
|
|
146
|
-
if (!parent) return null
|
|
147
|
-
|
|
148
|
-
// I'm not sure in what instance there's an array of parents
|
|
149
|
-
// But the Type suggests it's possible
|
|
150
|
-
const parentArray = Array.isArray(parent) ? parent : [parent]
|
|
151
|
-
const language = parentArray.find((p) => p._key)
|
|
152
|
-
|
|
153
|
-
if (!language?._key) return null
|
|
154
|
-
|
|
155
|
-
if (document.schemaTypes) {
|
|
156
|
-
return {
|
|
157
|
-
filter: `_type in $schemaTypes && ${languageField} == $language`,
|
|
158
|
-
params: {schemaTypes: document.schemaTypes, language: language._key},
|
|
147
|
+
|
|
148
|
+
// Uses:
|
|
149
|
+
// - `sanity-plugin-internationalized-array` to maintain the translations array
|
|
150
|
+
plugins: [
|
|
151
|
+
// Translation metadata stores its references using this plugin
|
|
152
|
+
// It cuts down on attribute usage and gives UI conveniences to add new translations
|
|
153
|
+
internationalizedArray({
|
|
154
|
+
languages: supportedLanguages,
|
|
155
|
+
fieldTypes: [
|
|
156
|
+
defineField(
|
|
157
|
+
{
|
|
158
|
+
name: 'reference',
|
|
159
|
+
type: 'reference',
|
|
160
|
+
to: schemaTypes.map((type) => ({type})),
|
|
161
|
+
// Reference filters don't actually enforce validation!
|
|
162
|
+
validation: (Rule) =>
|
|
163
|
+
Rule.custom(async (item: TranslationReference, context) => {
|
|
164
|
+
if (!item?.value?._ref || !item?._key) {
|
|
165
|
+
return true
|
|
159
166
|
}
|
|
160
|
-
}
|
|
161
167
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
168
|
+
const client = context.getClient({apiVersion: API_VERSION})
|
|
169
|
+
const valueLanguage = await client.fetch(
|
|
170
|
+
`*[_id in [$ref, $draftRef]][0].${languageField}`,
|
|
171
|
+
{
|
|
172
|
+
ref: item.value._ref,
|
|
173
|
+
draftRef: `drafts.${item.value._ref}`,
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
if (valueLanguage && valueLanguage === item._key) {
|
|
178
|
+
return true
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return `Referenced document does not have the correct language value`
|
|
182
|
+
}),
|
|
183
|
+
options: {
|
|
184
|
+
collapsed: false,
|
|
185
|
+
// TODO: Update type once it knows the values of this filter
|
|
186
|
+
// @ts-expect-error
|
|
187
|
+
filter: ({parent, document}) => {
|
|
188
|
+
if (!parent) return null
|
|
189
|
+
|
|
190
|
+
// I'm not sure in what instance there's an array of parents
|
|
191
|
+
// But the Type suggests it's possible
|
|
192
|
+
const parentArray = Array.isArray(parent)
|
|
193
|
+
? parent
|
|
194
|
+
: [parent]
|
|
195
|
+
const language = parentArray.find((p) => p._key)
|
|
196
|
+
|
|
197
|
+
if (!language?._key) return null
|
|
198
|
+
|
|
199
|
+
if (document.schemaTypes) {
|
|
200
|
+
return {
|
|
201
|
+
filter: `_type in $schemaTypes && ${languageField} == $language`,
|
|
202
|
+
params: {
|
|
203
|
+
schemaTypes: document.schemaTypes,
|
|
204
|
+
language: language._key,
|
|
205
|
+
},
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
filter: `${languageField} == $language`,
|
|
211
|
+
params: {language: language._key},
|
|
212
|
+
}
|
|
213
|
+
},
|
|
166
214
|
},
|
|
167
215
|
},
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
216
|
+
{strict: false}
|
|
217
|
+
),
|
|
218
|
+
],
|
|
219
|
+
}),
|
|
220
|
+
],
|
|
221
|
+
}
|
|
174
222
|
}
|
|
175
|
-
|
|
223
|
+
)
|
|
@@ -18,7 +18,7 @@ export default (schemaTypes: string[]): DocumentDefinition =>
|
|
|
18
18
|
defineField({
|
|
19
19
|
name: 'schemaTypes',
|
|
20
20
|
description:
|
|
21
|
-
'Used to filter the reference fields above so all translations share the same types.',
|
|
21
|
+
'Optional: Used to filter the reference fields above so all translations share the same types.',
|
|
22
22
|
type: 'array',
|
|
23
23
|
// For some reason TS dislikes this line because of the DocumentDefinition return type
|
|
24
24
|
// @ts-expect-error
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
KeyedObject,
|
|
3
|
+
Reference,
|
|
4
|
+
SanityClient,
|
|
5
|
+
SanityDocumentLike,
|
|
6
|
+
} from 'sanity'
|
|
2
7
|
|
|
3
8
|
export type Language = {
|
|
4
9
|
id: Intl.UnicodeBCP47LocaleIdentifier
|
|
@@ -16,12 +21,9 @@ export type PluginConfig = {
|
|
|
16
21
|
bulkPublish?: boolean
|
|
17
22
|
}
|
|
18
23
|
|
|
19
|
-
export type TranslationReference = {
|
|
20
|
-
|
|
21
|
-
value
|
|
22
|
-
_ref: string
|
|
23
|
-
_type: 'reference'
|
|
24
|
-
}
|
|
24
|
+
export type TranslationReference = KeyedObject & {
|
|
25
|
+
_type: 'internationalizedArrayReferenceValue'
|
|
26
|
+
value: Reference
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
export type Metadata = SanityDocumentLike & {
|