gt-sanity 0.0.6 → 1.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 (88) hide show
  1. package/LICENSE.md +1 -1
  2. package/dist/index.d.mts +95 -73
  3. package/dist/index.d.ts +95 -73
  4. package/dist/index.js +6233 -1162
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +6292 -1193
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +9 -4
  9. package/src/adapter/core.ts +41 -4
  10. package/src/adapter/getLocales.ts +2 -2
  11. package/src/components/TranslationsProvider.tsx +942 -0
  12. package/src/components/page/BatchProgress.tsx +27 -0
  13. package/src/components/page/ImportAllDialog.tsx +51 -0
  14. package/src/components/page/ImportMissingDialog.tsx +55 -0
  15. package/src/components/page/TranslateAllDialog.tsx +55 -0
  16. package/src/components/page/TranslationsTable.tsx +81 -0
  17. package/src/components/page/TranslationsTool.tsx +299 -837
  18. package/src/components/shared/BaseTranslationWrapper.tsx +82 -0
  19. package/src/components/shared/LocaleCheckbox.tsx +47 -0
  20. package/src/components/shared/SingleDocumentView.tsx +108 -0
  21. package/src/components/tab/TranslationView.tsx +379 -0
  22. package/src/components/tab/TranslationsTab.tsx +25 -0
  23. package/src/configuration/baseDocumentLevelConfig/documentLevelPatch.ts +6 -9
  24. package/src/configuration/baseDocumentLevelConfig/helpers/createI18nDocAndPatchMetadata.ts +5 -24
  25. package/src/configuration/baseDocumentLevelConfig/helpers/patchI18nDoc.ts +3 -23
  26. package/src/configuration/baseDocumentLevelConfig/index.ts +16 -68
  27. package/src/configuration/baseFieldLevelConfig.ts +15 -50
  28. package/src/index.ts +29 -43
  29. package/src/sanity-api/findDocuments.ts +44 -0
  30. package/src/sanity-api/publishDocuments.ts +49 -0
  31. package/src/sanity-api/resolveRefs.ts +146 -0
  32. package/src/serialization/BaseDocumentMerger.ts +138 -0
  33. package/src/serialization/BaseSerializationConfig.ts +220 -0
  34. package/src/serialization/__tests__/BaseDocumentDeserializer/__snapshots__/documentLevelDeserialization.test.ts.snap +189 -0
  35. package/src/serialization/__tests__/BaseDocumentDeserializer/__snapshots__/fieldLevelDeserialization.test.ts.snap +107 -0
  36. package/src/serialization/__tests__/BaseDocumentDeserializer/baseDeserialization.test.ts +397 -0
  37. package/src/serialization/__tests__/BaseDocumentDeserializer/documentLevelDeserialization.test.ts +107 -0
  38. package/src/serialization/__tests__/BaseDocumentDeserializer/fieldLevelDeserialization.test.ts +107 -0
  39. package/src/serialization/__tests__/BaseDocumentMerger/__snapshots__/documentLevelMerge.test.ts.snap +193 -0
  40. package/src/serialization/__tests__/BaseDocumentMerger/__snapshots__/fieldLevelMerge.test.ts.snap +97 -0
  41. package/src/serialization/__tests__/BaseDocumentMerger/baseMerge.test.ts +36 -0
  42. package/src/serialization/__tests__/BaseDocumentMerger/documentLevelMerge.test.ts +96 -0
  43. package/src/serialization/__tests__/BaseDocumentMerger/fieldLevelMerge.test.ts +142 -0
  44. package/src/serialization/__tests__/BaseDocumentMerger/utils.ts +52 -0
  45. package/src/serialization/__tests__/BaseDocumentSerializer/__snapshots__/documentInlineMarks.test.ts.snap +39 -0
  46. package/src/serialization/__tests__/BaseDocumentSerializer/__snapshots__/documentLevelSerialization.test.ts.snap +8 -0
  47. package/src/serialization/__tests__/BaseDocumentSerializer/__snapshots__/fieldLevelSerialization.test.ts.snap +8 -0
  48. package/src/serialization/__tests__/BaseDocumentSerializer/baseSerialization.test.ts +345 -0
  49. package/src/serialization/__tests__/BaseDocumentSerializer/documentInlineMarks.test.ts +53 -0
  50. package/src/serialization/__tests__/BaseDocumentSerializer/documentLevelSerialization.test.ts +120 -0
  51. package/src/serialization/__tests__/BaseDocumentSerializer/fieldLevelSerialization.test.ts +153 -0
  52. package/src/serialization/__tests__/BaseDocumentSerializer/utils.ts +27 -0
  53. package/src/serialization/__tests__/README +2 -0
  54. package/src/serialization/__tests__/__fixtures__/annotationAndInlineBlocks.json +140 -0
  55. package/src/serialization/__tests__/__fixtures__/customStyles.json +62 -0
  56. package/src/serialization/__tests__/__fixtures__/documentInlineMarks.json +70 -0
  57. package/src/serialization/__tests__/__fixtures__/documentLevelArticle.json +185 -0
  58. package/src/serialization/__tests__/__fixtures__/fieldLevelArticle.json +107 -0
  59. package/src/serialization/__tests__/__fixtures__/inlineDocumentLevelArticle.json +134 -0
  60. package/src/serialization/__tests__/__fixtures__/inlineSchema.ts +270 -0
  61. package/src/serialization/__tests__/__fixtures__/messy-html.html +26 -0
  62. package/src/serialization/__tests__/__fixtures__/nestedLanguageFields.json +54 -0
  63. package/src/serialization/__tests__/__fixtures__/schema.ts +310 -0
  64. package/src/serialization/__tests__/global.setup.ts +40 -0
  65. package/src/serialization/__tests__/helpers.ts +132 -0
  66. package/src/serialization/data.ts +82 -0
  67. package/src/serialization/deserialize/BaseDocumentDeserializer.ts +171 -0
  68. package/src/serialization/deserialize/helpers.ts +42 -0
  69. package/src/serialization/helpers.ts +18 -0
  70. package/src/serialization/index.ts +11 -0
  71. package/src/serialization/serialize/fieldFilters.ts +124 -0
  72. package/src/serialization/serialize/index.ts +284 -0
  73. package/src/serialization/types.ts +41 -0
  74. package/src/translation/importDocument.ts +4 -5
  75. package/src/translation/uploadFiles.ts +1 -1
  76. package/src/types.ts +3 -19
  77. package/src/utils/batchProcessor.ts +111 -0
  78. package/src/utils/importUtils.ts +95 -0
  79. package/src/utils/serialize.ts +25 -5
  80. package/src/utils/shared.ts +1 -1
  81. package/src/adapter/index.ts +0 -13
  82. package/src/components/NewTask.tsx +0 -251
  83. package/src/components/TaskView.tsx +0 -257
  84. package/src/components/TranslationContext.tsx +0 -24
  85. package/src/components/TranslationView.tsx +0 -114
  86. package/src/components/TranslationsTab.tsx +0 -181
  87. /package/src/components/{LanguageStatus.tsx → shared/LanguageStatus.tsx} +0 -0
  88. /package/src/components/{ProgressBar.tsx → shared/ProgressBar.tsx} +0 -0
@@ -1,257 +0,0 @@
1
- // adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.
2
-
3
- import { useCallback, useContext, useState, useEffect } from 'react';
4
- import { Box, Button, Flex, Text, Stack, useToast, Switch } from '@sanity/ui';
5
- import {
6
- ArrowTopRightIcon,
7
- DownloadIcon,
8
- CheckmarkCircleIcon,
9
- } from '@sanity/icons';
10
-
11
- import { TranslationContext } from './TranslationContext';
12
- import { TranslationLocale, TranslationTask } from '../types';
13
- import { LanguageStatus } from './LanguageStatus';
14
-
15
- type JobProps = {
16
- task: TranslationTask;
17
- locales: TranslationLocale[];
18
- refreshTask: () => Promise<void>;
19
- };
20
-
21
- const getLocale = (
22
- localeId: string,
23
- locales: TranslationLocale[]
24
- ): TranslationLocale | undefined =>
25
- locales.find((l) => l.localeId === localeId);
26
-
27
- export const TaskView = ({ task, locales, refreshTask }: JobProps) => {
28
- const context = useContext(TranslationContext);
29
- const toast = useToast();
30
-
31
- const [isRefreshing, setIsRefreshing] = useState(false);
32
- const [autoRefresh, setAutoRefresh] = useState(true);
33
- const [isBusy, setIsBusy] = useState(false);
34
- const [autoImport, setAutoImport] = useState(true);
35
- const [importedFiles, setImportedFiles] = useState<Set<string>>(new Set());
36
-
37
- const importFile = useCallback(
38
- async (localeId: string) => {
39
- if (!context) {
40
- toast.push({
41
- title:
42
- 'Missing context, unable to import translation. Try refreshing or clicking away from this tab and back.',
43
- status: 'error',
44
- closable: true,
45
- });
46
- return;
47
- }
48
-
49
- const locale = getLocale(localeId, locales);
50
- const localeTitle = locale?.description || localeId;
51
-
52
- try {
53
- const translation = await context.adapter.getTranslation(
54
- task.document,
55
- localeId,
56
- context.secrets
57
- );
58
-
59
- const sanityId = context.localeIdAdapter
60
- ? await context.localeIdAdapter(localeId)
61
- : localeId;
62
-
63
- await context.importTranslation(sanityId, translation);
64
-
65
- setImportedFiles((prev) => new Set([...prev, localeId]));
66
-
67
- toast.push({
68
- title: `Imported ${localeTitle} translation`,
69
- status: 'success',
70
- closable: true,
71
- });
72
- } catch (err) {
73
- let errorMsg;
74
- if (err instanceof Error) {
75
- errorMsg = err.message;
76
- } else {
77
- errorMsg = err ? String(err) : null;
78
- }
79
-
80
- toast.push({
81
- title: `Error getting ${localeTitle} translation`,
82
- description: errorMsg,
83
- status: 'error',
84
- closable: true,
85
- });
86
- }
87
- },
88
- [locales, context, task.document, toast]
89
- );
90
-
91
- const checkAndImportCompletedFiles = useCallback(async () => {
92
- if (!autoImport || isBusy) return;
93
-
94
- const completedFiles = task.locales.filter(
95
- (locale) =>
96
- (locale.progress || 0) >= 100 && !importedFiles.has(locale.localeId)
97
- );
98
-
99
- if (completedFiles.length === 0) return;
100
-
101
- setIsBusy(true);
102
- try {
103
- for (const locale of completedFiles) {
104
- await importFile(locale.localeId);
105
- }
106
- } finally {
107
- setIsBusy(false);
108
- }
109
- }, [autoImport, isBusy, task.locales, importedFiles, importFile]);
110
-
111
- const handleRefreshClick = useCallback(async () => {
112
- if (isRefreshing) return;
113
- setIsRefreshing(true);
114
- await refreshTask();
115
- await checkAndImportCompletedFiles();
116
- setIsRefreshing(false);
117
- }, [refreshTask, setIsRefreshing, checkAndImportCompletedFiles]);
118
-
119
- const handleImportAll = useCallback(async () => {
120
- if (isBusy) return;
121
- setIsBusy(true);
122
-
123
- try {
124
- const filesToImport = task.locales.filter(
125
- (locale) => !importedFiles.has(locale.localeId)
126
- );
127
- for (const locale of filesToImport) {
128
- await importFile(locale.localeId);
129
- }
130
- } finally {
131
- setIsBusy(false);
132
- }
133
- }, [task.locales, importFile, isBusy, importedFiles]);
134
-
135
- useEffect(() => {
136
- if (!autoRefresh || importedFiles.size === task.locales.length) return;
137
-
138
- const interval = setInterval(async () => {
139
- await handleRefreshClick();
140
- }, 5000);
141
-
142
- return () => clearInterval(interval);
143
- }, [
144
- handleRefreshClick,
145
- autoRefresh,
146
- importedFiles.size,
147
- task.locales.length,
148
- ]);
149
-
150
- useEffect(() => {
151
- checkAndImportCompletedFiles();
152
- }, [checkAndImportCompletedFiles, task.locales]);
153
-
154
- useEffect(() => {
155
- setImportedFiles((prev) => {
156
- const newSet = new Set<string>();
157
- for (const localeId of prev) {
158
- if (task.locales.some((locale) => locale.localeId === localeId)) {
159
- newSet.add(localeId);
160
- }
161
- }
162
- return newSet;
163
- });
164
- }, [task.locales]);
165
-
166
- return (
167
- <Stack space={4}>
168
- <Flex align='center' justify='space-between'>
169
- <Text as='h2' weight='semibold' size={2}>
170
- Translation Progress
171
- </Text>
172
-
173
- <Flex gap={3} align='center'>
174
- <Flex gap={2} align='center'>
175
- <Text size={1}>Auto-refresh</Text>
176
- <Switch
177
- checked={autoRefresh}
178
- onChange={() => setAutoRefresh(!autoRefresh)}
179
- />
180
- </Flex>
181
- {task.linkToVendorTask && (
182
- <Button
183
- as='a'
184
- text='View Job'
185
- iconRight={ArrowTopRightIcon}
186
- href={task.linkToVendorTask}
187
- target='_blank'
188
- rel='noreferrer noopener'
189
- fontSize={1}
190
- padding={2}
191
- mode='bleed'
192
- />
193
- )}
194
- <Button
195
- fontSize={1}
196
- padding={2}
197
- text='Refresh Status'
198
- onClick={handleRefreshClick}
199
- disabled={isRefreshing}
200
- />
201
- </Flex>
202
- </Flex>
203
-
204
- <Box>
205
- {task.locales.map((localeTask) => {
206
- const reportPercent = localeTask.progress || 0;
207
- const locale = getLocale(localeTask.localeId, locales);
208
- return (
209
- <LanguageStatus
210
- key={[task.document.documentId, localeTask.localeId].join('.')}
211
- importFile={async () => {
212
- await importFile(localeTask.localeId);
213
- }}
214
- title={locale?.description || localeTask.localeId}
215
- progress={reportPercent}
216
- isImported={importedFiles.has(localeTask.localeId)}
217
- />
218
- );
219
- })}
220
- </Box>
221
- <Stack space={3}>
222
- <Flex gap={3} align='center' justify='space-between'>
223
- <Flex gap={2} align='center'>
224
- <Button
225
- mode='ghost'
226
- onClick={handleImportAll}
227
- text={isBusy ? 'Importing...' : 'Import All'}
228
- icon={isBusy ? null : DownloadIcon}
229
- disabled={isBusy || importedFiles.size === task.locales.length}
230
- />
231
- {importedFiles.size === task.locales.length &&
232
- task.locales.length > 0 && (
233
- <Flex gap={2} align='center' style={{ color: 'green' }}>
234
- <CheckmarkCircleIcon />
235
- <Text size={1}>All translations imported</Text>
236
- </Flex>
237
- )}
238
- {importedFiles.size > 0 &&
239
- importedFiles.size < task.locales.length && (
240
- <Text size={1} style={{ color: '#666' }}>
241
- {importedFiles.size}/{task.locales.length} imported
242
- </Text>
243
- )}
244
- </Flex>
245
- <Flex gap={2} align='center' style={{ whiteSpace: 'nowrap' }}>
246
- <Text size={1}>Auto-import when complete</Text>
247
- <Switch
248
- checked={autoImport}
249
- onChange={() => setAutoImport(!autoImport)}
250
- disabled={isBusy}
251
- />
252
- </Flex>
253
- </Flex>
254
- </Stack>
255
- </Stack>
256
- );
257
- };
@@ -1,24 +0,0 @@
1
- // adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.
2
-
3
- import React from 'react';
4
- import { SanityDocument } from 'sanity';
5
- import { GTSerializedDocument } from '../types';
6
- import { Adapter, GTFile, Secrets, WorkflowIdentifiers } from '../types';
7
-
8
- export type ContextProps = {
9
- documentInfo: GTFile;
10
- document: SanityDocument;
11
- languageField: string;
12
- adapter: Adapter;
13
- importTranslation: (languageId: string, document: string) => Promise<void>;
14
- exportForTranslation: (documentInfo: GTFile) => Promise<GTSerializedDocument>;
15
- secrets: Secrets;
16
- workflowOptions?: WorkflowIdentifiers[];
17
- localeIdAdapter?: (id: string) => string | Promise<string>;
18
- callbackUrl?: string;
19
- mergeWithTargetLocale?: boolean;
20
- };
21
-
22
- export const TranslationContext = React.createContext<ContextProps | null>(
23
- null
24
- );
@@ -1,114 +0,0 @@
1
- // adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.
2
-
3
- /**
4
- * Add cleanup function to cancel async tasks
5
- */
6
-
7
- import { useCallback, useContext, useEffect, useState, useMemo } from 'react';
8
- import { Stack, useToast, Text, Card } from '@sanity/ui';
9
- import { TranslationContext } from './TranslationContext';
10
- import { gtConfig } from '../adapter/core';
11
-
12
- import { NewTask } from './NewTask';
13
- import { TaskView } from './TaskView';
14
- import { TranslationTask, TranslationLocale } from '../types';
15
-
16
- export const TranslationView = () => {
17
- const [locales, setLocales] = useState<TranslationLocale[]>([]);
18
- const [task, setTask] = useState<TranslationTask | null>(null);
19
-
20
- const context = useContext(TranslationContext);
21
- const toast = useToast();
22
-
23
- // Extract the current document's language from the language field
24
- const currentDocumentLanguage = useMemo(() => {
25
- if (!context?.document || !context?.languageField) return null;
26
-
27
- // Get the language from the document's language field
28
- const documentLanguage = context.document[context.languageField];
29
-
30
- // If no language field is set, assume it's the source language
31
- return documentLanguage || gtConfig.getSourceLocale();
32
- }, [context?.document, context?.languageField]);
33
-
34
- // Only show translation components if we're on a source language document
35
- const shouldShowTranslationComponents = useMemo(() => {
36
- if (!currentDocumentLanguage) return false;
37
- return currentDocumentLanguage === gtConfig.getSourceLocale();
38
- }, [currentDocumentLanguage]);
39
-
40
- useEffect(() => {
41
- async function fetchData() {
42
- if (!context) {
43
- toast.push({
44
- title: 'Unable to load translation data: missing context',
45
- status: 'error',
46
- closable: true,
47
- });
48
- return;
49
- }
50
-
51
- const locales = await context.adapter.getLocales(context.secrets);
52
- setLocales(locales);
53
- try {
54
- const task = await context?.adapter.getTranslationTask(
55
- context.documentInfo,
56
- context.secrets
57
- );
58
- setTask(task);
59
- } catch (err) {
60
- let errorMsg;
61
- if (err instanceof Error) {
62
- errorMsg = err.message;
63
- } else {
64
- errorMsg = err ? String(err) : null;
65
- }
66
-
67
- // Hacky bypass for when a document is not yet translated and has never been uploaded
68
- if (errorMsg?.toLowerCase().includes('no source file found')) {
69
- return;
70
- }
71
-
72
- toast.push({
73
- title: `Error creating translation job`,
74
- description: errorMsg,
75
- status: 'error',
76
- closable: true,
77
- });
78
- }
79
- }
80
-
81
- fetchData();
82
- }, [context, toast]);
83
-
84
- const refreshTask = useCallback(async () => {
85
- const task = await context?.adapter.getTranslationTask(
86
- context.documentInfo,
87
- context.secrets
88
- );
89
- if (task) {
90
- setTask(task);
91
- }
92
- }, [context, setTask]);
93
-
94
- // Show message if we're not on a source language document
95
- if (!shouldShowTranslationComponents) {
96
- return (
97
- <Card padding={4} tone='neutral' border>
98
- <Text size={1} muted>
99
- Translation tools are only available for{' '}
100
- <code>{gtConfig.getSourceLocale()}</code> documents.
101
- </Text>
102
- </Card>
103
- );
104
- }
105
-
106
- return (
107
- <Stack space={6}>
108
- <NewTask locales={locales} refreshTask={refreshTask} />
109
- {task && (
110
- <TaskView task={task} locales={locales} refreshTask={refreshTask} />
111
- )}
112
- </Stack>
113
- );
114
- };
@@ -1,181 +0,0 @@
1
- // adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.
2
-
3
- import { useMemo } from 'react';
4
- import { SanityDocument, useSchema } from 'sanity';
5
- import { randomKey } from '@sanity/util/content';
6
- import {
7
- ThemeProvider,
8
- ToastProvider,
9
- Stack,
10
- Text,
11
- Layer,
12
- Box,
13
- Card,
14
- Flex,
15
- Spinner,
16
- } from '@sanity/ui';
17
-
18
- import { TranslationContext } from './TranslationContext';
19
- import { TranslationView } from './TranslationView';
20
- import { useClient } from '../hooks/useClient';
21
- import { useSecrets } from '../hooks/useSecrets';
22
- import { GTFile, Secrets, TranslationsTabConfigOptions } from '../types';
23
-
24
- type TranslationTabProps = {
25
- document: {
26
- displayed: SanityDocument;
27
- };
28
- options: TranslationsTabConfigOptions;
29
- };
30
-
31
- const TranslationTab = (props: TranslationTabProps) => {
32
- const { displayed } = props.document;
33
- const client = useClient();
34
- const schema = useSchema();
35
-
36
- const documentId =
37
- displayed && displayed._id
38
- ? (displayed._id.split('drafts.').pop() as string)
39
- : '';
40
-
41
- const revisionId = displayed && displayed._rev ? displayed._rev : undefined;
42
-
43
- const { errors, importTranslation, exportForTranslation } = useMemo(() => {
44
- const { serializationOptions, languageField, mergeWithTargetLocale } =
45
- props.options;
46
- const ctx = {
47
- client,
48
- schema,
49
- };
50
-
51
- const allErrors = [];
52
-
53
- const importTranslationFunc = props.options.importTranslation;
54
- if (!importTranslationFunc) {
55
- allErrors.push({
56
- key: randomKey(12),
57
- text: (
58
- <>
59
- You need to provide an <code>importTranslation</code> function. See
60
- documentation.
61
- </>
62
- ),
63
- });
64
- }
65
-
66
- const contextImportTranslation = (localeId: string, doc: string) => {
67
- return importTranslationFunc(
68
- { documentId, versionId: revisionId },
69
- localeId,
70
- doc,
71
- ctx,
72
- serializationOptions,
73
- languageField,
74
- mergeWithTargetLocale
75
- );
76
- };
77
-
78
- const exportTranslationFunc = props.options.exportForTranslation;
79
- if (!exportTranslationFunc) {
80
- allErrors.push({
81
- key: randomKey(12),
82
- text: (
83
- <>
84
- You need to provide an <code>exportForTranslation</code> function.
85
- See documentation.
86
- </>
87
- ),
88
- });
89
- }
90
-
91
- const contextExportForTranslation = (docInfo: GTFile) => {
92
- return exportTranslationFunc(
93
- docInfo,
94
- ctx,
95
- serializationOptions,
96
- languageField
97
- );
98
- };
99
-
100
- return {
101
- errors: allErrors,
102
- importTranslation: contextImportTranslation,
103
- exportForTranslation: contextExportForTranslation,
104
- };
105
- }, [props.options, documentId, revisionId, client, schema]);
106
-
107
- const { loading, secrets } = useSecrets<Secrets>(
108
- `${props.options.secretsNamespace || 'translationService'}.secrets`
109
- );
110
-
111
- const hasErrors = errors.length > 0;
112
-
113
- if (loading || !secrets) {
114
- return (
115
- <ThemeProvider>
116
- <Flex padding={5} align='center' justify='center'>
117
- <Spinner />
118
- </Flex>
119
- </ThemeProvider>
120
- );
121
- } else if (!secrets) {
122
- return (
123
- <ThemeProvider>
124
- <Box padding={4}>
125
- <Card tone='caution' padding={[2, 3, 4, 4]} shadow={1} radius={2}>
126
- <Text>
127
- Can't find secrets for your translation service. Did you load them
128
- into this dataset?
129
- </Text>
130
- </Card>
131
- </Box>
132
- </ThemeProvider>
133
- );
134
- }
135
- return (
136
- <ThemeProvider>
137
- <Box padding={4}>
138
- <Layer>
139
- <ToastProvider paddingY={7}>
140
- {hasErrors && (
141
- <Stack space={3}>
142
- {errors.map((error) => (
143
- <Card
144
- key={error.key}
145
- tone='caution'
146
- padding={[2, 3, 4, 4]}
147
- shadow={1}
148
- radius={2}
149
- >
150
- <Text>{error.text}</Text>
151
- </Card>
152
- ))}
153
- </Stack>
154
- )}
155
- {!hasErrors && (
156
- <TranslationContext.Provider
157
- value={{
158
- documentInfo: { documentId, versionId: revisionId },
159
- document: displayed,
160
- languageField: props.options.languageField || 'language',
161
- secrets,
162
- importTranslation,
163
- exportForTranslation,
164
- adapter: props.options.adapter,
165
- workflowOptions: props.options.workflowOptions,
166
- localeIdAdapter: props.options.localeIdAdapter,
167
- callbackUrl: props.options.callbackUrl,
168
- mergeWithTargetLocale: props.options.mergeWithTargetLocale,
169
- }}
170
- >
171
- <TranslationView />
172
- </TranslationContext.Provider>
173
- )}
174
- </ToastProvider>
175
- </Layer>
176
- </Box>
177
- </ThemeProvider>
178
- );
179
- };
180
-
181
- export default TranslationTab;