@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
@@ -1,259 +0,0 @@
1
- import {AddIcon, CheckmarkIcon, SplitVerticalIcon} from '@sanity/icons'
2
- import {
3
- Badge,
4
- Box,
5
- Button,
6
- Flex,
7
- Spinner,
8
- Text,
9
- Tooltip,
10
- useToast,
11
- } from '@sanity/ui'
12
- import {uuid} from '@sanity/uuid'
13
- import {useCallback, useEffect, useState} from 'react'
14
- import {type ObjectSchemaType, type SanityDocument, useClient} from 'sanity'
15
-
16
- import {METADATA_SCHEMA_NAME} from '../constants'
17
- import {useOpenInNewPane} from '../hooks/useOpenInNewPane'
18
- import type {
19
- Language,
20
- Metadata,
21
- MetadataDocument,
22
- TranslationReference,
23
- } from '../types'
24
- import {createReference} from '../utils/createReference'
25
- import {removeExcludedPaths} from '../utils/excludePaths'
26
- import {useDocumentInternationalizationContext} from './DocumentInternationalizationContext'
27
-
28
- type LanguageOptionProps = {
29
- language: Language
30
- schemaType: ObjectSchemaType
31
- documentId: string
32
- disabled: boolean
33
- current: boolean
34
- source: SanityDocument | null
35
- metadataId: string | null
36
- metadata?: Metadata | null
37
- sourceLanguageId?: string
38
- }
39
-
40
- export default function LanguageOption(props: LanguageOptionProps) {
41
- const {
42
- language,
43
- schemaType,
44
- documentId,
45
- current,
46
- source,
47
- sourceLanguageId,
48
- metadata,
49
- metadataId,
50
- } = props
51
- /* When the user has clicked the Create button, the button should be disabled
52
- * to prevent double-clicks from firing onCreate twice. This creates duplicate
53
- * translation metadata entries, which editors will not be able to delete */
54
- const [userHasClicked, setUserHasClicked] = useState(false)
55
- const disabled =
56
- props.disabled ||
57
- userHasClicked ||
58
- current ||
59
- !source ||
60
- !sourceLanguageId ||
61
- !metadataId
62
- const translation: TranslationReference | undefined = metadata?.translations
63
- .length
64
- ? metadata.translations.find((t) => t._key === language.id)
65
- : undefined
66
- const {apiVersion, languageField, weakReferences, callback} =
67
- useDocumentInternationalizationContext()
68
- const client = useClient({apiVersion})
69
- const toast = useToast()
70
-
71
- const open = useOpenInNewPane(translation?.value?._ref, schemaType.name)
72
- const handleOpen = useCallback(() => open(), [open])
73
-
74
- /* Once a translation has been created, reset the userHasClicked state to false
75
- * so they can click on it to navigate to the translation. If a translation already
76
- * existed when this component was mounted, this will have no effect. */
77
- const hasTranslation = Boolean(translation)
78
- useEffect(() => {
79
- setUserHasClicked(false)
80
- }, [hasTranslation])
81
-
82
- const handleCreate = useCallback(async () => {
83
- if (!source) {
84
- throw new Error(`Cannot create translation without source document`)
85
- }
86
-
87
- if (!sourceLanguageId) {
88
- throw new Error(`Cannot create translation without source language ID`)
89
- }
90
-
91
- if (!metadataId) {
92
- throw new Error(`Cannot create translation without a metadata ID`)
93
- }
94
- /* Disable the create button while this request is pending */
95
- setUserHasClicked(true)
96
-
97
- const transaction = client.transaction()
98
-
99
- // 1. Duplicate source document
100
- const newTranslationDocumentId = uuid()
101
- let newTranslationDocument = {
102
- ...source,
103
- _id: `drafts.${newTranslationDocumentId}`,
104
- // 2. Update language of the translation
105
- [languageField]: language.id,
106
- }
107
-
108
- // Remove fields / paths we don't want to duplicate
109
- newTranslationDocument = removeExcludedPaths(
110
- newTranslationDocument,
111
- schemaType
112
- ) as SanityDocument
113
-
114
- transaction.create(newTranslationDocument)
115
-
116
- // 3. Maybe create the metadata document
117
- const sourceReference = createReference(
118
- sourceLanguageId,
119
- documentId,
120
- schemaType.name,
121
- !weakReferences
122
- )
123
- const newTranslationReference = createReference(
124
- language.id,
125
- newTranslationDocumentId,
126
- schemaType.name,
127
- !weakReferences
128
- )
129
- const newMetadataDocument: MetadataDocument = {
130
- _id: metadataId,
131
- _type: METADATA_SCHEMA_NAME,
132
- schemaTypes: [schemaType.name],
133
- translations: [sourceReference],
134
- }
135
-
136
- transaction.createIfNotExists(newMetadataDocument)
137
-
138
- // 4. Patch translation to metadata document
139
- // Note: If the document was only just created in the operation above
140
- // This patch operation will have no effect
141
- const metadataPatch = client
142
- .patch(metadataId)
143
- .setIfMissing({translations: [sourceReference]})
144
- .insert(`after`, `translations[-1]`, [newTranslationReference])
145
-
146
- transaction.patch(metadataPatch)
147
-
148
- // 5. Commit!
149
- transaction
150
- .commit()
151
- .then(() => {
152
- const metadataExisted = Boolean(metadata?._createdAt)
153
-
154
- callback?.({
155
- client,
156
- sourceLanguageId,
157
- sourceDocument: source,
158
- newDocument: newTranslationDocument,
159
- destinationLanguageId: language.id,
160
- metaDocumentId: metadataId,
161
- }).catch((err) => {
162
- toast.push({
163
- status: 'error',
164
- title: `Callback`,
165
- description: `Error while running callback - ${err}.`,
166
- })
167
- })
168
-
169
- return toast.push({
170
- status: 'success',
171
- title: `Created "${language.title}" translation`,
172
- description: metadataExisted
173
- ? `Updated Translations Metadata`
174
- : `Created Translations Metadata`,
175
- })
176
- })
177
- .catch((err) => {
178
- console.error(err)
179
-
180
- /* Re-enable the create button if there was an error */
181
- setUserHasClicked(false)
182
-
183
- return toast.push({
184
- status: 'error',
185
- title: `Error creating translation`,
186
- description: err.message,
187
- })
188
- })
189
- }, [
190
- client,
191
- documentId,
192
- language.id,
193
- language.title,
194
- languageField,
195
- metadata?._createdAt,
196
- metadataId,
197
- schemaType,
198
- source,
199
- sourceLanguageId,
200
- toast,
201
- weakReferences,
202
- callback,
203
- ])
204
-
205
- let message
206
-
207
- if (current) {
208
- message = `Current document`
209
- } else if (translation) {
210
- message = `Open ${language.title} translation`
211
- } else if (!translation) {
212
- message = `Create new ${language.title} translation`
213
- }
214
-
215
- return (
216
- <Tooltip
217
- animate
218
- content={
219
- <Box padding={2}>
220
- <Text muted size={1}>
221
- {message}
222
- </Text>
223
- </Box>
224
- }
225
- fallbackPlacements={['right', 'left']}
226
- placement="top"
227
- portal
228
- >
229
- <Button
230
- onClick={translation ? handleOpen : handleCreate}
231
- mode={current && disabled ? `default` : `bleed`}
232
- disabled={disabled}
233
- >
234
- <Flex gap={3} align="center">
235
- {disabled && !current ? (
236
- <Spinner />
237
- ) : (
238
- <Text size={2}>
239
- {/* eslint-disable-next-line no-nested-ternary */}
240
- {translation ? (
241
- <SplitVerticalIcon />
242
- ) : current ? (
243
- <CheckmarkIcon />
244
- ) : (
245
- <AddIcon />
246
- )}
247
- </Text>
248
- )}
249
- <Box flex={1}>
250
- <Text>{language.title}</Text>
251
- </Box>
252
- <Badge tone={disabled || current ? `default` : `primary`}>
253
- {language.id}
254
- </Badge>
255
- </Flex>
256
- </Button>
257
- </Tooltip>
258
- )
259
- }
@@ -1,67 +0,0 @@
1
- import {EditIcon} from '@sanity/icons'
2
- import {Badge, Box, Button, Flex, Text, useToast} from '@sanity/ui'
3
- import {useCallback} from 'react'
4
- import {type SanityDocument, useClient} from 'sanity'
5
-
6
- import type {Language} from '../types'
7
- import {useDocumentInternationalizationContext} from './DocumentInternationalizationContext'
8
-
9
- type LanguagePatchProps = {
10
- language: Language
11
- source: SanityDocument | null
12
- disabled: boolean
13
- }
14
-
15
- export default function LanguagePatch(props: LanguagePatchProps) {
16
- const {language, source} = props
17
- const {apiVersion, languageField} = useDocumentInternationalizationContext()
18
- const disabled = props.disabled || !source
19
- const client = useClient({apiVersion})
20
- const toast = useToast()
21
-
22
- const handleClick = useCallback(() => {
23
- if (!source) {
24
- throw new Error(`Cannot patch missing document`)
25
- }
26
-
27
- const currentId = source._id
28
-
29
- client
30
- .patch(currentId)
31
- .set({[languageField]: language.id})
32
- .commit()
33
- .then(() => {
34
- toast.push({
35
- title: `Set document language to ${language.title}`,
36
- status: `success`,
37
- })
38
- })
39
- .catch((err) => {
40
- console.error(err)
41
-
42
- return toast.push({
43
- title: `Failed to set document language to ${language.title}`,
44
- status: `error`,
45
- })
46
- })
47
- }, [source, client, languageField, language, toast])
48
-
49
- return (
50
- <Button
51
- mode="bleed"
52
- onClick={handleClick}
53
- disabled={disabled}
54
- justify="flex-start"
55
- >
56
- <Flex gap={3} align="center">
57
- <Text size={2}>
58
- <EditIcon />
59
- </Text>
60
- <Box flex={1}>
61
- <Text>{language.title}</Text>
62
- </Box>
63
- <Badge>{language.id}</Badge>
64
- </Flex>
65
- </Button>
66
- )
67
- }
@@ -1,50 +0,0 @@
1
- import {useEffect} from 'react'
2
- import {PatchEvent, unset, useClient, useEditState} from 'sanity'
3
- import {useDocumentPane} from 'sanity/structure'
4
-
5
- import {API_VERSION} from '../../constants'
6
- import type {TranslationReference} from '../../types'
7
-
8
- type ReferencePatcherProps = {
9
- translation: TranslationReference
10
- documentType: string
11
- metadataId: string
12
- }
13
-
14
- // For every reference, check if it is published, and if so, strengthen the reference
15
- export default function ReferencePatcher(props: ReferencePatcherProps) {
16
- const {translation, documentType, metadataId} = props
17
- const editState = useEditState(translation.value._ref, documentType)
18
- const client = useClient({apiVersion: API_VERSION})
19
- const {onChange} = useDocumentPane()
20
-
21
- useEffect(() => {
22
- if (
23
- // We have a reference
24
- translation.value._ref &&
25
- // It's still weak and not-yet-strengthened
26
- translation.value._weak &&
27
- // We also want to keep this check because maybe the user *configured* weak refs
28
- translation.value._strengthenOnPublish &&
29
- // The referenced document has just been published
30
- !editState.draft &&
31
- editState.published &&
32
- editState.ready
33
- ) {
34
- const referencePathBase = [
35
- 'translations',
36
- {_key: translation._key},
37
- 'value',
38
- ]
39
-
40
- onChange(
41
- new PatchEvent([
42
- unset([...referencePathBase, '_weak']),
43
- unset([...referencePathBase, '_strengthenOnPublish']),
44
- ])
45
- )
46
- }
47
- }, [translation, editState, metadataId, client, onChange])
48
-
49
- return null
50
- }
@@ -1,34 +0,0 @@
1
- import type {TranslationReference} from '../../types'
2
- import ReferencePatcher from './ReferencePatcher'
3
-
4
- type OptimisticallyStrengthenProps = {
5
- translations: TranslationReference[]
6
- metadataId: string
7
- }
8
-
9
- // There's no good reason to leave published references as weak
10
- // So this component will run on every render and strengthen them
11
- export default function OptimisticallyStrengthen(
12
- props: OptimisticallyStrengthenProps
13
- ) {
14
- const {translations = [], metadataId} = props
15
-
16
- if (!translations.length) {
17
- return null
18
- }
19
-
20
- return (
21
- <>
22
- {translations.map((translation) =>
23
- translation.value._strengthenOnPublish?.type ? (
24
- <ReferencePatcher
25
- key={translation._key}
26
- translation={translation}
27
- documentType={translation.value._strengthenOnPublish.type}
28
- metadataId={metadataId}
29
- />
30
- ) : null
31
- )}
32
- </>
33
- )
34
- }
@@ -1,18 +0,0 @@
1
- import {Card, Flex, Text} from '@sanity/ui'
2
- import type {PropsWithChildren} from 'react'
3
-
4
- import ConstrainedBox from './ConstrainedBox'
5
-
6
- export default function Warning({children}: PropsWithChildren) {
7
- return (
8
- <Card tone="caution" padding={3}>
9
- <Flex justify="center">
10
- <ConstrainedBox>
11
- <Text size={1} align="center">
12
- {children}
13
- </Text>
14
- </ConstrainedBox>
15
- </Flex>
16
- </Card>
17
- )
18
- }
package/src/constants.ts DELETED
@@ -1,16 +0,0 @@
1
- import type {PluginConfigContext} from './types'
2
-
3
- export const METADATA_SCHEMA_NAME = `translation.metadata`
4
- export const TRANSLATIONS_ARRAY_NAME = `translations`
5
- export const API_VERSION = `2025-02-19`
6
- export const DEFAULT_CONFIG: PluginConfigContext = {
7
- supportedLanguages: [],
8
- schemaTypes: [],
9
- languageField: `language`,
10
- weakReferences: false,
11
- bulkPublish: false,
12
- metadataFields: [],
13
- apiVersion: API_VERSION,
14
- allowCreateMetaDoc: false,
15
- callback: null,
16
- }
@@ -1,26 +0,0 @@
1
- import {useListeningQuery} from 'sanity-plugin-utils'
2
-
3
- import {METADATA_SCHEMA_NAME} from '../constants'
4
- import type {Metadata} from '../types'
5
-
6
- // Using references() seemed less reliable for updating the listener
7
- // results than querying raw values in the array
8
- // AFAIK: references is _faster_ when querying with GROQ
9
- // const query = `*[_type == $translationSchema && references($id)]`
10
- const query = `*[_type == $translationSchema && $id in translations[].value._ref]{
11
- _id,
12
- _createdAt,
13
- translations
14
- }`
15
-
16
- export function useTranslationMetadata(id: string): {
17
- data: Metadata[] | null
18
- loading: boolean
19
- error: boolean | unknown | ProgressEvent
20
- } {
21
- const {data, loading, error} = useListeningQuery<Metadata[]>(query, {
22
- params: {id, translationSchema: METADATA_SCHEMA_NAME},
23
- })
24
-
25
- return {data: data as Metadata[] | null, loading, error}
26
- }
@@ -1,33 +0,0 @@
1
- import {useCallback, useContext} from 'react'
2
- import {RouterContext} from 'sanity/router'
3
- import {usePaneRouter} from 'sanity/structure'
4
-
5
- export function useOpenInNewPane(id?: string | null, type?: string) {
6
- const routerContext = useContext(RouterContext)
7
- const {routerPanesState, groupIndex} = usePaneRouter()
8
-
9
- const openInNewPane = useCallback(() => {
10
- if (!routerContext || !id || !type) {
11
- return
12
- }
13
-
14
- // No panes open, function might be called outside Structure
15
- if (!routerPanesState.length) {
16
- routerContext.navigateIntent('edit', {id, type})
17
- return
18
- }
19
-
20
- const panes = [...routerPanesState]
21
- panes.splice(groupIndex + 1, 0, [
22
- {
23
- id: id,
24
- params: {type},
25
- },
26
- ])
27
-
28
- const href = routerContext.resolvePathFromState({panes})
29
- routerContext.navigateUrl({path: href})
30
- }, [id, type, routerContext, routerPanesState, groupIndex])
31
-
32
- return openInNewPane
33
- }
package/src/i18n/index.ts DELETED
@@ -1,21 +0,0 @@
1
- import {defineLocaleResourceBundle} from 'sanity'
2
-
3
- /**
4
- * The locale namespace for the document internationalization plugin.
5
- *
6
- * @public
7
- */
8
- export const documenti18nLocaleNamespace =
9
- 'document-internationalization' as const
10
-
11
- /**
12
- * The default locale bundle for the document internationalization plugin, which is US English.
13
- *
14
- * @internal
15
- */
16
- export const documentInternationalizationUsEnglishLocaleBundle =
17
- defineLocaleResourceBundle({
18
- locale: 'en-US',
19
- namespace: documenti18nLocaleNamespace,
20
- resources: () => import('./resources'),
21
- })
@@ -1,7 +0,0 @@
1
- export default {
2
- 'action.duplicate.label': 'Duplicate with translations',
3
- 'action.duplicate.disabled.missing-metadata':
4
- 'The document cannot be duplicated because the metadata document is missing',
5
- 'action.duplicate.disabled.multiple-metadata':
6
- 'The document cannot be duplicated because there are multiple metadata documents',
7
- }
package/src/index.ts DELETED
@@ -1,6 +0,0 @@
1
- export {DeleteTranslationAction} from './actions/DeleteTranslationAction'
2
- export {DuplicateWithTranslationsAction} from './actions/DuplicateWithTranslationsAction'
3
- export {useDocumentInternationalizationContext} from './components/DocumentInternationalizationContext'
4
- export {DocumentInternationalizationMenu} from './components/DocumentInternationalizationMenu'
5
- export {documentInternationalization} from './plugin'
6
- export * from './types'