gt-sanity 2.0.21 → 2.1.0
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/dist/index.cjs +1220 -763
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +113 -1
- package/dist/index.d.ts +113 -1
- package/dist/index.js +1211 -754
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/adapter/core.ts +27 -2
- package/src/adapter/types.ts +9 -0
- package/src/components/TranslationsProvider.tsx +92 -6
- package/src/components/page/TranslationsTable.tsx +5 -3
- package/src/components/shared/SingleDocumentView.tsx +5 -3
- package/src/components/tab/TranslationView.tsx +24 -14
- package/src/configuration/baseDocumentLevelConfig/documentLevelPatch.ts +1 -1
- package/src/configuration/baseFieldLevelConfig.ts +1 -1
- package/src/configuration/internationalizedArrayConfig/internationalizedArrayPatch.ts +59 -0
- package/src/index.ts +114 -58
- package/src/schema/InternationalizedArrayInput.tsx +278 -0
- package/src/schema/__tests__/createInternationalizedArrayTypes.test.ts +169 -0
- package/src/schema/createInternationalizedArrayTypes.ts +209 -0
- package/src/schema/types.ts +84 -0
- package/src/serialization/__tests__/BaseDocumentDeserializer/baseDeserialization.test.ts +3 -3
- package/src/serialization/__tests__/BaseDocumentMerger/baseMerge.test.ts +1 -1
- package/src/serialization/__tests__/BaseDocumentMerger/documentLevelMerge.test.ts +1 -1
- package/src/serialization/__tests__/BaseDocumentMerger/fieldLevelMerge.test.ts +1 -1
- package/src/serialization/__tests__/BaseDocumentSerializer/baseSerialization.test.ts +2 -2
- package/src/serialization/__tests__/BaseDocumentSerializer/documentInlineMarks.test.ts +4 -2
- package/src/serialization/__tests__/global.setup.ts +6 -0
- package/src/serialization/__tests__/helpers.ts +2 -1
- package/src/serialization/internationalizedArray/__tests__/internationalizedArray.test.ts +265 -0
- package/src/serialization/internationalizedArray/__tests__/serializeRoundTrip.test.ts +83 -0
- package/src/serialization/internationalizedArray/collapse.ts +52 -0
- package/src/serialization/internationalizedArray/detect.ts +81 -0
- package/src/serialization/internationalizedArray/merge.ts +149 -0
- package/src/serialization/types.ts +5 -1
- package/src/translation/__tests__/strategy.test.ts +47 -0
- package/src/translation/importDocument.ts +9 -5
- package/src/translation/strategy.ts +92 -0
- package/src/translation/uploadFiles.ts +1 -1
- package/src/types.ts +1 -1
- package/src/utils/__tests__/batchProcessor.test.ts +61 -2
- package/src/utils/batchProcessor.ts +11 -6
- package/src/utils/serialize.ts +24 -7
- package/src/serialization/index.ts +0 -16
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: !0 });
|
|
3
|
-
var
|
|
3
|
+
var generaltranslation = require("generaltranslation"), internal = require("generaltranslation/internal"), sanity = require("sanity"), router = require("sanity/router"), jsxRuntime = require("react/jsx-runtime"), o = require("react"), icons = require("@sanity/icons"), ui = require("@sanity/ui"), theme$1 = require("@sanity/ui/theme"), mutator = require("@sanity/mutator"), jsonpathPlus = require("jsonpath-plus"), JSONPointer = require("jsonpointer"), blockTools = require("@portabletext/block-tools"), schema = require("@sanity/schema"), toHtml = require("@portabletext/to-html"), merge = require("lodash.merge"), documentInternationalization = require("@sanity/document-internationalization");
|
|
4
4
|
function _interopDefaultCompat(e) {
|
|
5
5
|
return e && typeof e == "object" && "default" in e ? e : { default: e };
|
|
6
6
|
}
|
|
7
|
-
var o__default = /* @__PURE__ */ _interopDefaultCompat(o),
|
|
7
|
+
var o__default = /* @__PURE__ */ _interopDefaultCompat(o), JSONPointer__default = /* @__PURE__ */ _interopDefaultCompat(JSONPointer), merge__default = /* @__PURE__ */ _interopDefaultCompat(merge);
|
|
8
8
|
const useClient = () => sanity.useClient({ apiVersion: "2025-09-15" });
|
|
9
9
|
function useSecrets(id) {
|
|
10
10
|
const [loading, setLoading] = o.useState(!0), [secrets, setSecrets] = o.useState(null), client = useClient();
|
|
@@ -42,9 +42,12 @@ class GTConfig {
|
|
|
42
42
|
additionalSerializers;
|
|
43
43
|
additionalDeserializers;
|
|
44
44
|
additionalBlockDeserializers;
|
|
45
|
+
translationLevel;
|
|
46
|
+
fieldLevelDocuments;
|
|
47
|
+
fieldLevelTypePrefix;
|
|
45
48
|
static instance;
|
|
46
|
-
constructor(secretsNamespace, languageField, sourceLocale, locales, singletons, singletonMapping, ignoreFields, dedupeFields, skipFields, translateDocuments, additionalStopTypes = [], additionalSerializers = {}, additionalDeserializers = { types: {} }, additionalBlockDeserializers = []) {
|
|
47
|
-
this.secretsNamespace = secretsNamespace, this.languageField = languageField, this.sourceLocale = sourceLocale, this.locales = locales, this.singletons = singletons, this.singletonMapping = singletonMapping, this.ignoreFields = ignoreFields, this.dedupeFields = dedupeFields, this.skipFields = skipFields, this.translateDocuments = translateDocuments, this.additionalStopTypes = additionalStopTypes, this.additionalSerializers = additionalSerializers, this.additionalDeserializers = additionalDeserializers, this.additionalBlockDeserializers = additionalBlockDeserializers;
|
|
49
|
+
constructor(secretsNamespace, languageField, sourceLocale, locales, singletons, singletonMapping, ignoreFields, dedupeFields, skipFields, translateDocuments, additionalStopTypes = [], additionalSerializers = {}, additionalDeserializers = { types: {} }, additionalBlockDeserializers = [], translationLevel = "document", fieldLevelDocuments = [], fieldLevelTypePrefix = "internationalizedArray") {
|
|
50
|
+
this.secretsNamespace = secretsNamespace, this.languageField = languageField, this.sourceLocale = sourceLocale, this.locales = locales, this.singletons = singletons, this.singletonMapping = singletonMapping, this.ignoreFields = ignoreFields, this.dedupeFields = dedupeFields, this.skipFields = skipFields, this.translateDocuments = translateDocuments, this.additionalStopTypes = additionalStopTypes, this.additionalSerializers = additionalSerializers, this.additionalDeserializers = additionalDeserializers, this.additionalBlockDeserializers = additionalBlockDeserializers, this.translationLevel = translationLevel, this.fieldLevelDocuments = fieldLevelDocuments, this.fieldLevelTypePrefix = fieldLevelTypePrefix;
|
|
48
51
|
}
|
|
49
52
|
static getInstance() {
|
|
50
53
|
return this.instance || (this.instance = new GTConfig(
|
|
@@ -64,8 +67,8 @@ class GTConfig {
|
|
|
64
67
|
[]
|
|
65
68
|
)), this.instance;
|
|
66
69
|
}
|
|
67
|
-
init(secretsNamespace, languageField, sourceLocale, locales, singletons, singletonMapping, ignoreFields, dedupeFields, skipFields, translateDocuments, additionalStopTypes = [], additionalSerializers = {}, additionalDeserializers = { types: {} }, additionalBlockDeserializers = []) {
|
|
68
|
-
this.secretsNamespace = secretsNamespace, this.languageField = languageField, this.sourceLocale = sourceLocale, this.locales = locales, this.singletons = singletons, this.singletonMapping = singletonMapping, this.ignoreFields = ignoreFields, this.dedupeFields = dedupeFields, this.skipFields = skipFields, this.translateDocuments = translateDocuments, this.additionalStopTypes = additionalStopTypes, this.additionalSerializers = additionalSerializers, this.additionalDeserializers = additionalDeserializers, this.additionalBlockDeserializers = additionalBlockDeserializers;
|
|
70
|
+
init(secretsNamespace, languageField, sourceLocale, locales, singletons, singletonMapping, ignoreFields, dedupeFields, skipFields, translateDocuments, additionalStopTypes = [], additionalSerializers = {}, additionalDeserializers = { types: {} }, additionalBlockDeserializers = [], translationLevel = "document", fieldLevelDocuments = [], fieldLevelTypePrefix = "internationalizedArray") {
|
|
71
|
+
this.secretsNamespace = secretsNamespace, this.languageField = languageField, this.sourceLocale = sourceLocale, this.locales = locales, this.singletons = singletons, this.singletonMapping = singletonMapping, this.ignoreFields = ignoreFields, this.dedupeFields = dedupeFields, this.skipFields = skipFields, this.translateDocuments = translateDocuments, this.additionalStopTypes = additionalStopTypes, this.additionalSerializers = additionalSerializers, this.additionalDeserializers = additionalDeserializers, this.additionalBlockDeserializers = additionalBlockDeserializers, this.translationLevel = translationLevel, this.fieldLevelDocuments = fieldLevelDocuments, this.fieldLevelTypePrefix = fieldLevelTypePrefix;
|
|
69
72
|
}
|
|
70
73
|
getSecretsNamespace() {
|
|
71
74
|
return this.secretsNamespace;
|
|
@@ -109,6 +112,15 @@ class GTConfig {
|
|
|
109
112
|
getAdditionalBlockDeserializers() {
|
|
110
113
|
return this.additionalBlockDeserializers;
|
|
111
114
|
}
|
|
115
|
+
getTranslationLevel() {
|
|
116
|
+
return this.translationLevel;
|
|
117
|
+
}
|
|
118
|
+
getFieldLevelDocuments() {
|
|
119
|
+
return this.fieldLevelDocuments;
|
|
120
|
+
}
|
|
121
|
+
getFieldLevelTypePrefix() {
|
|
122
|
+
return this.fieldLevelTypePrefix;
|
|
123
|
+
}
|
|
112
124
|
}
|
|
113
125
|
const pluginConfig = GTConfig.getInstance(), theme = theme$1.buildTheme(), BaseTranslationWrapper = ({
|
|
114
126
|
children,
|
|
@@ -122,21 +134,21 @@ const pluginConfig = GTConfig.getInstance(), theme = theme$1.buildTheme(), BaseT
|
|
|
122
134
|
!loadingSecrets && secrets && children
|
|
123
135
|
] });
|
|
124
136
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.ThemeProvider, { theme, children: /* @__PURE__ */ jsxRuntime.jsx(ui.ToastProvider, { paddingY: 7, children: showContainer ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding, children: content }) : content }) });
|
|
125
|
-
}, isRecord$
|
|
137
|
+
}, isRecord$5 = (value) => typeof value == "object" && value !== null && !Array.isArray(value), reconcileArray = (origArray, translatedArray) => {
|
|
126
138
|
if (translatedArray && translatedArray.some((el) => typeof el == "string"))
|
|
127
139
|
return translatedArray;
|
|
128
140
|
const combined = JSON.parse(JSON.stringify(origArray));
|
|
129
141
|
return translatedArray.forEach((translatedItem) => {
|
|
130
|
-
if (!isRecord$
|
|
142
|
+
if (!isRecord$5(translatedItem) || !translatedItem._key)
|
|
131
143
|
return;
|
|
132
144
|
const foundBlockIdx = origArray.findIndex(
|
|
133
|
-
(origBlock) => isRecord$
|
|
145
|
+
(origBlock) => isRecord$5(origBlock) && origBlock._key === translatedItem._key
|
|
134
146
|
);
|
|
135
147
|
foundBlockIdx < 0 ? console.warn(
|
|
136
148
|
`This block no longer exists on the original document. Was it removed? ${JSON.stringify(
|
|
137
149
|
translatedItem
|
|
138
150
|
)}`
|
|
139
|
-
) : isRecord$
|
|
151
|
+
) : isRecord$5(origArray[foundBlockIdx]) && (origArray[foundBlockIdx]._type === "block" || origArray[foundBlockIdx]._type === "span") ? combined[foundBlockIdx] = translatedItem : isRecord$5(origArray[foundBlockIdx]) && (combined[foundBlockIdx] = reconcileObject(
|
|
140
152
|
origArray[foundBlockIdx],
|
|
141
153
|
translatedItem
|
|
142
154
|
));
|
|
@@ -149,8 +161,8 @@ const pluginConfig = GTConfig.getInstance(), theme = theme$1.buildTheme(), BaseT
|
|
|
149
161
|
!value || key[0] === "_" || (typeof value == "string" ? updatedObj[key] = value : Array.isArray(value) ? updatedObj[key] = reconcileArray(
|
|
150
162
|
Array.isArray(origObject[key]) ? origObject[key] : [],
|
|
151
163
|
value
|
|
152
|
-
) : isRecord$
|
|
153
|
-
isRecord$
|
|
164
|
+
) : isRecord$5(value) && (updatedObj[key] = reconcileObject(
|
|
165
|
+
isRecord$5(origObject[key]) ? origObject[key] : {},
|
|
154
166
|
value
|
|
155
167
|
)));
|
|
156
168
|
}), updatedObj;
|
|
@@ -171,7 +183,7 @@ const pluginConfig = GTConfig.getInstance(), theme = theme$1.buildTheme(), BaseT
|
|
|
171
183
|
origVal ?? [],
|
|
172
184
|
translatedVal
|
|
173
185
|
) : typeof translatedVal == "object" && Object.keys(translatedVal).length && (valToPatch = reconcileObject(
|
|
174
|
-
isRecord$
|
|
186
|
+
isRecord$5(origVal) ? origVal : {},
|
|
175
187
|
translatedVal
|
|
176
188
|
));
|
|
177
189
|
const destinationPath = [
|
|
@@ -190,215 +202,701 @@ const pluginConfig = GTConfig.getInstance(), theme = theme$1.buildTheme(), BaseT
|
|
|
190
202
|
documentLevelMerge,
|
|
191
203
|
reconcileArray,
|
|
192
204
|
reconcileObject
|
|
193
|
-
}, defaultSchema = schema.Schema.compile({
|
|
194
|
-
name: "default",
|
|
195
|
-
types: [
|
|
196
|
-
{
|
|
197
|
-
type: "object",
|
|
198
|
-
name: "default",
|
|
199
|
-
fields: [
|
|
200
|
-
{
|
|
201
|
-
name: "block",
|
|
202
|
-
type: "array",
|
|
203
|
-
of: [{ type: "block" }]
|
|
204
|
-
}
|
|
205
|
-
]
|
|
206
|
-
}
|
|
207
|
-
]
|
|
208
|
-
}), blockContentType = defaultSchema.get("default").fields.find((field) => field.name === "block").type, preprocess = (html) => {
|
|
209
|
-
const intermediateBlocks = blockTools.htmlToBlocks(
|
|
210
|
-
`<p>${html}</p>`,
|
|
211
|
-
blockContentType
|
|
212
|
-
);
|
|
213
|
-
if (!intermediateBlocks.length)
|
|
214
|
-
throw new Error(`Error parsing string '${html}'`);
|
|
215
|
-
return intermediateBlocks[0].children[0].text;
|
|
216
205
|
};
|
|
217
|
-
function
|
|
218
|
-
|
|
219
|
-
if (!firstElement)
|
|
220
|
-
return html;
|
|
221
|
-
const encodedData = encode(JSON.stringify({ [type]: data }));
|
|
222
|
-
return firstElement.setAttribute("data-gt-internal", encodedData), firstElement.outerHTML;
|
|
206
|
+
function getPublishedId(documentId) {
|
|
207
|
+
return documentId.startsWith("drafts.") ? documentId.slice(7) : documentId;
|
|
223
208
|
}
|
|
224
|
-
function
|
|
225
|
-
|
|
226
|
-
if (!firstElement)
|
|
227
|
-
return { html };
|
|
228
|
-
const encodedData = firstElement.getAttribute("data-gt-internal");
|
|
229
|
-
let extractedData;
|
|
230
|
-
if (encodedData)
|
|
231
|
-
try {
|
|
232
|
-
const decodedData = decode(encodedData);
|
|
233
|
-
extractedData = JSON.parse(decodedData), firstElement.removeAttribute("data-gt-internal");
|
|
234
|
-
} catch (error) {
|
|
235
|
-
console.warn("Failed to decode GT internal data:", error);
|
|
236
|
-
}
|
|
237
|
-
return {
|
|
238
|
-
html: firstElement.outerHTML,
|
|
239
|
-
data: extractedData
|
|
240
|
-
};
|
|
209
|
+
function getDocumentPublishedId(document2) {
|
|
210
|
+
return getPublishedId(document2._id);
|
|
241
211
|
}
|
|
242
|
-
function
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
212
|
+
function dedupeDocumentsPreferDraft(documents) {
|
|
213
|
+
const byPublishedId = /* @__PURE__ */ new Map();
|
|
214
|
+
for (const document2 of documents) {
|
|
215
|
+
const publishedId = getDocumentPublishedId(document2);
|
|
216
|
+
(!byPublishedId.get(publishedId) || document2._id.startsWith("drafts.")) && byPublishedId.set(publishedId, document2);
|
|
217
|
+
}
|
|
218
|
+
return Array.from(byPublishedId.values());
|
|
248
219
|
}
|
|
249
|
-
function
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
bytes[i] = binary.charCodeAt(i);
|
|
253
|
-
return new TextDecoder().decode(bytes);
|
|
220
|
+
function createTranslationStatusKey(branchId, documentId, versionId, localeId) {
|
|
221
|
+
const publishedId = getPublishedId(documentId);
|
|
222
|
+
return branchId ? `${branchId}:${publishedId}:${versionId}:${localeId}` : `${publishedId}:${versionId}:${localeId}`;
|
|
254
223
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
"
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
list: defaultLists,
|
|
293
|
-
listItem: defaultListItem,
|
|
294
|
-
unknownBlockStyle: unknownBlockFunc
|
|
295
|
-
}, customDeserializers = { types: {} }, customBlockDeserializers = [
|
|
296
|
-
// handle marks with data-gt-internal
|
|
297
|
-
{
|
|
298
|
-
deserialize(node2, next2) {
|
|
299
|
-
if (node2.nodeType !== 1)
|
|
300
|
-
return;
|
|
301
|
-
const el = node2;
|
|
302
|
-
if (!el.hasChildNodes() || !el.getAttribute("data-gt-internal"))
|
|
303
|
-
return;
|
|
304
|
-
const { html, data } = detachGTData(el.outerHTML), block = blockTools.htmlToBlocks(html, blockContentType)[0], children = next2(el.childNodes);
|
|
305
|
-
let markDefs = [];
|
|
306
|
-
return "markDefs" in block && (markDefs = block.markDefs ?? []), data?.markDef && markDefs.push(data.markDef), Array.isArray(children) && children.forEach((child) => {
|
|
307
|
-
if (!isRecord$3(child))
|
|
308
|
-
return;
|
|
309
|
-
const marks = Array.isArray(child.marks) ? child.marks : [];
|
|
310
|
-
child.marks = data?.markDef?._key ? [...marks, data.markDef._key] : marks;
|
|
311
|
-
}), {
|
|
312
|
-
...block,
|
|
313
|
-
markDefs,
|
|
314
|
-
children
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
},
|
|
318
|
-
//handle undeclared styles
|
|
319
|
-
{
|
|
320
|
-
deserialize(node2, next2) {
|
|
321
|
-
if (node2.nodeType !== 1)
|
|
322
|
-
return;
|
|
323
|
-
const el = node2;
|
|
324
|
-
if (!el.hasChildNodes() || el.getAttribute("data-type") !== "unknown-block-style")
|
|
325
|
-
return;
|
|
326
|
-
const style = el.getAttribute("data-style") ?? "";
|
|
327
|
-
return {
|
|
328
|
-
...blockTools.htmlToBlocks(el.outerHTML, blockContentType)[0],
|
|
329
|
-
style,
|
|
330
|
-
children: next2(el.childNodes)
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
//handle list items
|
|
335
|
-
{
|
|
336
|
-
deserialize(node2, next2) {
|
|
337
|
-
if (node2.nodeType !== 1)
|
|
338
|
-
return;
|
|
339
|
-
const el = node2;
|
|
340
|
-
if (!el.hasChildNodes() || el.tagName.toLowerCase() !== "li")
|
|
341
|
-
return;
|
|
342
|
-
const tagsToStyle = {
|
|
343
|
-
ul: "bullet",
|
|
344
|
-
ol: "number"
|
|
345
|
-
}, parent = el.parentNode;
|
|
346
|
-
if (!parent || !parent.tagName)
|
|
347
|
-
return;
|
|
348
|
-
const listItem = tagsToStyle[parent.tagName.toLowerCase()];
|
|
349
|
-
if (!listItem)
|
|
350
|
-
return;
|
|
351
|
-
const level = el.getAttribute("data-level") && parseInt(el.getAttribute("data-level") || "0", 10), _key = el.id;
|
|
352
|
-
let block = blockTools.htmlToBlocks(parent.outerHTML, blockContentType)[0];
|
|
353
|
-
const customStyle = el.children?.[0]?.getAttribute("data-style");
|
|
354
|
-
if (new RegExp(/<("[^"]*"|'[^']*'|[^'">])*>/).test(el.innerHTML)) {
|
|
355
|
-
const newBlock = blockTools.htmlToBlocks(el.innerHTML, blockContentType)[0];
|
|
356
|
-
if (newBlock && (block = {
|
|
357
|
-
...block,
|
|
358
|
-
...newBlock,
|
|
359
|
-
// @ts-ignore
|
|
360
|
-
style: customStyle ?? newBlock.style
|
|
361
|
-
}, customStyle))
|
|
362
|
-
return block;
|
|
224
|
+
function createStableTranslationKey(branchId, documentId, localeId) {
|
|
225
|
+
const publishedId = getPublishedId(documentId);
|
|
226
|
+
return branchId ? `${branchId}:${publishedId}:${localeId}` : `${publishedId}:${localeId}`;
|
|
227
|
+
}
|
|
228
|
+
const findLatestDraft = (documentId, client) => {
|
|
229
|
+
const publishedId = getPublishedId(documentId), query = "*[_id == $id || _id == $draftId]", params = { id: publishedId, draftId: `drafts.${publishedId}` };
|
|
230
|
+
return client.fetch(query, params).then(
|
|
231
|
+
(docs) => docs.find((doc) => doc._id.startsWith("drafts.")) ?? docs[0]
|
|
232
|
+
);
|
|
233
|
+
}, findDocumentAtRevision = async (documentId, rev, client) => {
|
|
234
|
+
const baseUrl = `/data/history/${client.config().dataset}/documents/${documentId}?revision=${rev}`, url = client.getUrl(baseUrl);
|
|
235
|
+
return await fetch(url, { credentials: "include" }).then((req) => req.json()).then((req) => req.documents && req.documents.length ? req.documents[0] : null);
|
|
236
|
+
};
|
|
237
|
+
function forEachMatchingField(documentId, document2, fields, callback) {
|
|
238
|
+
const applicable = fields.filter(
|
|
239
|
+
(field) => field.documentId === documentId || field.documentId === void 0 || field.documentId === null
|
|
240
|
+
);
|
|
241
|
+
for (const entry of applicable)
|
|
242
|
+
if (entry.fields)
|
|
243
|
+
for (const field of entry.fields) {
|
|
244
|
+
const { property, type } = field;
|
|
245
|
+
try {
|
|
246
|
+
const results = jsonpathPlus.JSONPath({
|
|
247
|
+
json: document2,
|
|
248
|
+
path: property,
|
|
249
|
+
resultType: "all",
|
|
250
|
+
flatten: !0,
|
|
251
|
+
wrap: !0
|
|
252
|
+
});
|
|
253
|
+
results && results.length > 0 && results.forEach(
|
|
254
|
+
(result) => {
|
|
255
|
+
type !== void 0 ? typeof result.value == "object" && result.value !== null && !Array.isArray(result.value) && result.value._type === type && callback(result) : callback(result);
|
|
256
|
+
}
|
|
257
|
+
);
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.warn(`Invalid JSONPath: ${property}`, error);
|
|
260
|
+
}
|
|
363
261
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
262
|
+
}
|
|
263
|
+
function deleteMatchingFields(documentId, document2, fields) {
|
|
264
|
+
const arrayRemovals = [];
|
|
265
|
+
forEachMatchingField(documentId, document2, fields, (result) => {
|
|
266
|
+
Array.isArray(result.parent) ? arrayRemovals.push({
|
|
267
|
+
parent: result.parent,
|
|
268
|
+
index: Number(result.parentProperty)
|
|
269
|
+
}) : delete result.parent[result.parentProperty];
|
|
270
|
+
}), arrayRemovals.sort((a, b) => b.index - a.index);
|
|
271
|
+
for (const { parent, index } of arrayRemovals)
|
|
272
|
+
parent.splice(index, 1);
|
|
273
|
+
}
|
|
274
|
+
function applyDocuments(documentId, sourceDocument, targetDocument, ignore, skip = [], dedupe = [], localeId) {
|
|
275
|
+
const mergedDocument = JSON.parse(JSON.stringify(sourceDocument)), clonedTarget = JSON.parse(JSON.stringify(targetDocument));
|
|
276
|
+
for (const [key, value] of Object.entries(clonedTarget))
|
|
277
|
+
mergedDocument[key] = value;
|
|
278
|
+
return forEachMatchingField(documentId, sourceDocument, ignore, (result) => {
|
|
279
|
+
JSONPointer__default.default.set(mergedDocument, result.pointer, result.value);
|
|
280
|
+
}), forEachMatchingField(documentId, sourceDocument, dedupe, (result) => {
|
|
281
|
+
JSONPointer__default.default.set(
|
|
282
|
+
mergedDocument,
|
|
283
|
+
result.pointer,
|
|
284
|
+
dedupeFieldValue(result.value, localeId)
|
|
285
|
+
);
|
|
286
|
+
}), deleteMatchingFields(documentId, mergedDocument, skip), mergedDocument;
|
|
287
|
+
}
|
|
288
|
+
function dedupeFieldValue(value, localeId) {
|
|
289
|
+
if (!localeId) return value;
|
|
290
|
+
if (typeof value == "string")
|
|
291
|
+
return appendLocaleSuffix(value, localeId);
|
|
292
|
+
if (value && typeof value == "object" && !Array.isArray(value) && typeof value.current == "string") {
|
|
293
|
+
const slug = value;
|
|
294
|
+
return {
|
|
295
|
+
...slug,
|
|
296
|
+
current: appendLocaleSuffix(slug.current, localeId)
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
return value;
|
|
300
|
+
}
|
|
301
|
+
function appendLocaleSuffix(value, localeId) {
|
|
302
|
+
if (!value) return value;
|
|
303
|
+
const suffix = createLocaleSuffix(localeId);
|
|
304
|
+
return !suffix || value.endsWith(suffix) ? value : `${value}${suffix}`;
|
|
305
|
+
}
|
|
306
|
+
function createLocaleSuffix(localeId) {
|
|
307
|
+
const normalized = localeId.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
308
|
+
return normalized ? `-${normalized}` : "";
|
|
309
|
+
}
|
|
310
|
+
function randomKey() {
|
|
311
|
+
return Math.random().toString(36).slice(2, 10);
|
|
312
|
+
}
|
|
313
|
+
async function createI18nDocAndPatchMetadata(sourceDocument, translatedDoc, localeId, client, translationMetadata, sourceDocumentId, languageField = "language") {
|
|
314
|
+
const publishedSourceDocumentId = getPublishedId(sourceDocumentId);
|
|
315
|
+
translatedDoc[languageField] = localeId;
|
|
316
|
+
const existingLocaleKey = translationMetadata.translations.find(
|
|
317
|
+
(translation) => translation.language === localeId
|
|
318
|
+
), operation = existingLocaleKey ? "replace" : "after", location = existingLocaleKey ? `translations[language == "${localeId}"]` : "translations[-1]", { _updatedAt, _createdAt, ...rest } = translatedDoc, appliedDocument = applyDocuments(
|
|
319
|
+
publishedSourceDocumentId,
|
|
320
|
+
sourceDocument,
|
|
321
|
+
rest,
|
|
322
|
+
pluginConfig.getIgnoreFields(),
|
|
323
|
+
pluginConfig.getSkipFields(),
|
|
324
|
+
pluginConfig.getDedupeFields(),
|
|
325
|
+
localeId
|
|
326
|
+
), isSingleton = pluginConfig.getSingletons().includes(publishedSourceDocumentId);
|
|
327
|
+
let createDocumentPromise;
|
|
328
|
+
if (isSingleton) {
|
|
329
|
+
const translatedDocId = pluginConfig.getSingletonMapping()(
|
|
330
|
+
publishedSourceDocumentId,
|
|
331
|
+
localeId
|
|
332
|
+
);
|
|
333
|
+
createDocumentPromise = client.create({
|
|
334
|
+
...appliedDocument,
|
|
335
|
+
_type: rest._type,
|
|
336
|
+
_id: `drafts.${translatedDocId}`
|
|
337
|
+
});
|
|
338
|
+
} else
|
|
339
|
+
createDocumentPromise = client.create({
|
|
340
|
+
...appliedDocument,
|
|
341
|
+
_type: rest._type,
|
|
342
|
+
_id: "drafts."
|
|
343
|
+
});
|
|
344
|
+
const doc = await createDocumentPromise, _ref = getPublishedId(doc._id);
|
|
345
|
+
await client.transaction().patch(
|
|
346
|
+
translationMetadata._id,
|
|
347
|
+
(p) => p.insert(operation, location, [
|
|
348
|
+
{
|
|
349
|
+
_key: randomKey(),
|
|
350
|
+
language: localeId,
|
|
351
|
+
_type: "internationalizedArrayReferenceValue",
|
|
352
|
+
value: {
|
|
353
|
+
_type: "reference",
|
|
354
|
+
_ref,
|
|
355
|
+
_weak: !0,
|
|
356
|
+
_strengthenOnPublish: {
|
|
357
|
+
type: doc._type
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
])
|
|
362
|
+
).commit();
|
|
363
|
+
}
|
|
364
|
+
const getOrCreateTranslationMetadata = async (documentId, baseDocument, client, baseLanguage) => {
|
|
365
|
+
const publishedId = getPublishedId(documentId), existingMetadata = await client.fetch(
|
|
366
|
+
`*[
|
|
367
|
+
_type == 'translation.metadata' &&
|
|
368
|
+
translations[language == $baseLanguage][0].value._ref == $id
|
|
369
|
+
][0]`,
|
|
370
|
+
{ baseLanguage, id: publishedId }
|
|
371
|
+
);
|
|
372
|
+
if (existingMetadata)
|
|
373
|
+
return existingMetadata;
|
|
374
|
+
const baseLangEntry = {
|
|
375
|
+
_key: randomKey(),
|
|
376
|
+
language: baseLanguage,
|
|
377
|
+
_type: "internationalizedArrayReferenceValue",
|
|
378
|
+
value: {
|
|
379
|
+
_type: "reference",
|
|
380
|
+
_ref: getPublishedId(baseDocument._id)
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
baseDocument._id.startsWith("drafts.") && (baseLangEntry.value = {
|
|
384
|
+
...baseLangEntry.value,
|
|
385
|
+
_weak: !0,
|
|
386
|
+
//this should reflect doc i18n config when this
|
|
387
|
+
//plugin is able to take that as a config option
|
|
388
|
+
_strengthenOnPublish: {
|
|
389
|
+
type: baseDocument._type
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
try {
|
|
393
|
+
return await client.createIfNotExists({
|
|
394
|
+
_id: `translation.metadata.${publishedId}`,
|
|
395
|
+
_type: "translation.metadata",
|
|
396
|
+
translations: [baseLangEntry]
|
|
397
|
+
});
|
|
398
|
+
} catch (error) {
|
|
399
|
+
const metadata = await client.fetch(
|
|
400
|
+
`*[
|
|
401
|
+
_type == 'translation.metadata' &&
|
|
402
|
+
translations[language == $baseLanguage][0].value._ref == $id
|
|
403
|
+
][0]`,
|
|
404
|
+
{ baseLanguage, id: publishedId }
|
|
405
|
+
);
|
|
406
|
+
if (metadata)
|
|
407
|
+
return metadata;
|
|
408
|
+
throw error;
|
|
409
|
+
}
|
|
410
|
+
}, SYSTEM_FIELDS = ["_id", "_rev", "_updatedAt", "language"], isSystemField = (field) => SYSTEM_FIELDS.includes(field);
|
|
411
|
+
async function patchI18nDoc(sourceDocumentId, i18nDocId, sourceDocument, mergedDocument, translatedFields, client, existingDocument) {
|
|
412
|
+
const cleanedMerge = {};
|
|
413
|
+
Object.entries(mergedDocument).forEach(([key, value]) => {
|
|
414
|
+
key in translatedFields && //don't overwrite any existing system values on the i18n doc
|
|
415
|
+
!isSystemField(key) && (cleanedMerge[key] = value);
|
|
416
|
+
});
|
|
417
|
+
const cleanedSourceDocument = {};
|
|
418
|
+
Object.entries(sourceDocument).forEach(([key, value]) => {
|
|
419
|
+
isSystemField(key) || (cleanedSourceDocument[key] = value);
|
|
420
|
+
});
|
|
421
|
+
const appliedDocument = applyDocuments(
|
|
422
|
+
sourceDocumentId,
|
|
423
|
+
cleanedSourceDocument,
|
|
424
|
+
cleanedMerge,
|
|
425
|
+
pluginConfig.getIgnoreFields(),
|
|
426
|
+
pluginConfig.getSkipFields()
|
|
427
|
+
), dedupeFields = pluginConfig.getDedupeFields();
|
|
428
|
+
deleteMatchingFields(sourceDocumentId, appliedDocument, dedupeFields), existingDocument && forEachMatchingField(
|
|
429
|
+
sourceDocumentId,
|
|
430
|
+
existingDocument,
|
|
431
|
+
dedupeFields,
|
|
432
|
+
(result) => {
|
|
433
|
+
JSONPointer__default.default.set(appliedDocument, result.pointer, result.value);
|
|
434
|
+
}
|
|
435
|
+
), await client.patch(i18nDocId, { set: appliedDocument }).commit();
|
|
436
|
+
}
|
|
437
|
+
const documentLevelPatch = async (docInfo, translatedFields, localeId, client, languageField = "language", mergeWithTargetLocale = !1) => {
|
|
438
|
+
const baseLanguage = pluginConfig.getSourceLocale();
|
|
439
|
+
let baseDoc = null, i18nDoc = null;
|
|
440
|
+
docInfo.documentId && docInfo.versionId && (baseDoc = await findDocumentAtRevision(
|
|
441
|
+
docInfo.documentId,
|
|
442
|
+
docInfo.versionId,
|
|
443
|
+
client
|
|
444
|
+
)), baseDoc || (baseDoc = await findLatestDraft(docInfo.documentId, client));
|
|
445
|
+
const i18nDocId = (await getOrCreateTranslationMetadata(
|
|
446
|
+
docInfo.documentId,
|
|
447
|
+
baseDoc,
|
|
448
|
+
client,
|
|
449
|
+
baseLanguage
|
|
450
|
+
)).translations.find(
|
|
451
|
+
(translation) => translation.language === localeId
|
|
452
|
+
)?.value?._ref;
|
|
453
|
+
i18nDocId && (i18nDoc = await findLatestDraft(i18nDocId, client)), mergeWithTargetLocale && i18nDoc ? baseDoc = i18nDoc : docInfo.documentId && docInfo.versionId && (baseDoc = await findDocumentAtRevision(
|
|
454
|
+
docInfo.documentId,
|
|
455
|
+
docInfo.versionId,
|
|
456
|
+
client
|
|
457
|
+
)), baseDoc || (baseDoc = await findLatestDraft(docInfo.documentId, client));
|
|
458
|
+
const merged = BaseDocumentMerger.documentLevelMerge(
|
|
459
|
+
translatedFields,
|
|
460
|
+
baseDoc
|
|
461
|
+
);
|
|
462
|
+
if (i18nDoc)
|
|
463
|
+
await patchI18nDoc(
|
|
464
|
+
docInfo.documentId,
|
|
465
|
+
i18nDoc._id,
|
|
466
|
+
baseDoc,
|
|
467
|
+
merged,
|
|
468
|
+
translatedFields,
|
|
469
|
+
client,
|
|
470
|
+
i18nDoc
|
|
471
|
+
);
|
|
472
|
+
else {
|
|
473
|
+
const freshTranslationMetadata = await getOrCreateTranslationMetadata(
|
|
474
|
+
docInfo.documentId,
|
|
475
|
+
baseDoc,
|
|
476
|
+
client,
|
|
477
|
+
baseLanguage
|
|
478
|
+
), freshI18nDocId = freshTranslationMetadata.translations.find(
|
|
479
|
+
(translation) => translation.language === localeId
|
|
480
|
+
)?.value?._ref;
|
|
481
|
+
if (freshI18nDocId) {
|
|
482
|
+
const freshI18nDoc = await findLatestDraft(freshI18nDocId, client);
|
|
483
|
+
await patchI18nDoc(
|
|
484
|
+
docInfo.documentId,
|
|
485
|
+
freshI18nDoc._id,
|
|
486
|
+
baseDoc,
|
|
487
|
+
merged,
|
|
488
|
+
translatedFields,
|
|
489
|
+
client,
|
|
490
|
+
freshI18nDoc
|
|
491
|
+
);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
await createI18nDocAndPatchMetadata(
|
|
495
|
+
baseDoc,
|
|
496
|
+
merged,
|
|
497
|
+
localeId,
|
|
498
|
+
client,
|
|
499
|
+
freshTranslationMetadata,
|
|
500
|
+
docInfo.documentId,
|
|
501
|
+
languageField
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
}, DEFAULT_TYPE_PREFIX$1 = "internationalizedArray";
|
|
505
|
+
function hasRecognizedTypePrefix(type) {
|
|
506
|
+
return type.startsWith(DEFAULT_TYPE_PREFIX$1) || type.startsWith(pluginConfig.getFieldLevelTypePrefix());
|
|
507
|
+
}
|
|
508
|
+
const isRecord$4 = (value) => typeof value == "object" && value !== null && !Array.isArray(value);
|
|
509
|
+
function isInternationalizedArrayItem(item) {
|
|
510
|
+
return isRecord$4(item) && typeof item._type == "string" && hasRecognizedTypePrefix(item._type) && item._type.endsWith("Value") && typeof item.language == "string" && "value" in item;
|
|
511
|
+
}
|
|
512
|
+
function isInternationalizedArrayField(value) {
|
|
513
|
+
return Array.isArray(value) && value.length > 0 && value.every(isInternationalizedArrayItem);
|
|
514
|
+
}
|
|
515
|
+
function findLocaleItem(field, locale) {
|
|
516
|
+
return field.find((item) => item.language === locale);
|
|
517
|
+
}
|
|
518
|
+
function upsertLocaleItem(baseArray, translatedValue, targetLocale, sourceLocale) {
|
|
519
|
+
const itemType = (findLocaleItem(baseArray, sourceLocale) ?? baseArray[0])._type, updated = baseArray.map(
|
|
520
|
+
(item) => item.language === targetLocale ? { ...item, value: translatedValue } : { ...item }
|
|
521
|
+
);
|
|
522
|
+
return findLocaleItem(updated, targetLocale) || updated.push({
|
|
523
|
+
_key: randomKey(),
|
|
524
|
+
_type: itemType,
|
|
525
|
+
language: targetLocale,
|
|
526
|
+
value: translatedValue
|
|
527
|
+
}), updated;
|
|
528
|
+
}
|
|
529
|
+
function mergeValue(baseValue, translatedValue, targetLocale, sourceLocale) {
|
|
530
|
+
if (isInternationalizedArrayField(baseValue))
|
|
531
|
+
return upsertLocaleItem(
|
|
532
|
+
baseValue,
|
|
533
|
+
translatedValue,
|
|
534
|
+
targetLocale,
|
|
535
|
+
sourceLocale
|
|
536
|
+
);
|
|
537
|
+
if (Array.isArray(baseValue) && Array.isArray(translatedValue)) {
|
|
538
|
+
let changed = !1;
|
|
539
|
+
const merged = baseValue.map((item) => {
|
|
540
|
+
if (!isRecord$4(item) || typeof item._key != "string")
|
|
541
|
+
return item;
|
|
542
|
+
const translatedItem = translatedValue.find(
|
|
543
|
+
(candidate) => isRecord$4(candidate) && candidate._key === item._key
|
|
544
|
+
);
|
|
545
|
+
if (!translatedItem)
|
|
546
|
+
return item;
|
|
547
|
+
const mergedItem = mergeValue(
|
|
548
|
+
item,
|
|
549
|
+
translatedItem,
|
|
550
|
+
targetLocale,
|
|
551
|
+
sourceLocale
|
|
552
|
+
);
|
|
553
|
+
return mergedItem !== void 0 ? (changed = !0, mergedItem) : item;
|
|
554
|
+
});
|
|
555
|
+
return changed ? merged : void 0;
|
|
556
|
+
}
|
|
557
|
+
if (isRecord$4(baseValue) && isRecord$4(translatedValue)) {
|
|
558
|
+
let changed = !1;
|
|
559
|
+
const merged = { ...baseValue };
|
|
560
|
+
for (const key of Object.keys(translatedValue)) {
|
|
561
|
+
if (key.startsWith("_") || !(key in baseValue))
|
|
562
|
+
continue;
|
|
563
|
+
const mergedChild = mergeValue(
|
|
564
|
+
baseValue[key],
|
|
565
|
+
translatedValue[key],
|
|
566
|
+
targetLocale,
|
|
567
|
+
sourceLocale
|
|
568
|
+
);
|
|
569
|
+
mergedChild !== void 0 && (merged[key] = mergedChild, changed = !0);
|
|
570
|
+
}
|
|
571
|
+
return changed ? merged : void 0;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
function mergeInternationalizedArrays(baseDoc, translatedFields, targetLocale, sourceLocale) {
|
|
575
|
+
const changes = {};
|
|
576
|
+
for (const key of Object.keys(translatedFields)) {
|
|
577
|
+
if (key.startsWith("_") || !(key in baseDoc))
|
|
578
|
+
continue;
|
|
579
|
+
const merged = mergeValue(
|
|
580
|
+
baseDoc[key],
|
|
581
|
+
translatedFields[key],
|
|
582
|
+
targetLocale,
|
|
583
|
+
sourceLocale
|
|
584
|
+
);
|
|
585
|
+
merged !== void 0 && (changes[key] = merged);
|
|
586
|
+
}
|
|
587
|
+
return changes;
|
|
588
|
+
}
|
|
589
|
+
const internationalizedArrayPatch = async (docInfo, translatedFields, localeId, client) => {
|
|
590
|
+
const sourceLocale = pluginConfig.getSourceLocale(), baseDoc = await findLatestDraft(docInfo.documentId, client);
|
|
591
|
+
if (!baseDoc)
|
|
592
|
+
return;
|
|
593
|
+
const changes = mergeInternationalizedArrays(
|
|
594
|
+
baseDoc,
|
|
595
|
+
translatedFields,
|
|
596
|
+
localeId,
|
|
597
|
+
sourceLocale
|
|
598
|
+
);
|
|
599
|
+
if (Object.keys(changes).length === 0)
|
|
600
|
+
return;
|
|
601
|
+
if (baseDoc._id.startsWith("drafts.")) {
|
|
602
|
+
await client.patch(baseDoc._id).set(changes).commit();
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
const draftId = `drafts.${getPublishedId(baseDoc._id)}`;
|
|
606
|
+
await client.transaction().createIfNotExists({ ...baseDoc, _id: draftId }).patch(draftId, (patch) => patch.set(changes)).commit();
|
|
607
|
+
}, defaultSchema = schema.Schema.compile({
|
|
608
|
+
name: "default",
|
|
609
|
+
types: [
|
|
610
|
+
{
|
|
611
|
+
type: "object",
|
|
612
|
+
name: "default",
|
|
613
|
+
fields: [
|
|
614
|
+
{
|
|
615
|
+
name: "block",
|
|
616
|
+
type: "array",
|
|
617
|
+
of: [{ type: "block" }]
|
|
618
|
+
}
|
|
619
|
+
]
|
|
620
|
+
}
|
|
621
|
+
]
|
|
622
|
+
}), blockContentType = defaultSchema.get("default").fields.find((field) => field.name === "block").type, preprocess = (html) => {
|
|
623
|
+
const intermediateBlocks = blockTools.htmlToBlocks(
|
|
624
|
+
`<p>${html}</p>`,
|
|
625
|
+
blockContentType
|
|
626
|
+
);
|
|
627
|
+
if (!intermediateBlocks.length)
|
|
628
|
+
throw new Error(`Error parsing string '${html}'`);
|
|
629
|
+
return intermediateBlocks[0].children[0].text;
|
|
630
|
+
};
|
|
631
|
+
function attachGTData(html, data, type) {
|
|
632
|
+
const firstElement = new DOMParser().parseFromString(html, "text/html").body.firstElementChild;
|
|
633
|
+
if (!firstElement)
|
|
634
|
+
return html;
|
|
635
|
+
const encodedData = encode(JSON.stringify({ [type]: data }));
|
|
636
|
+
return firstElement.setAttribute("data-gt-internal", encodedData), firstElement.outerHTML;
|
|
637
|
+
}
|
|
638
|
+
function detachGTData(html) {
|
|
639
|
+
const firstElement = new DOMParser().parseFromString(html, "text/html").body.firstElementChild;
|
|
640
|
+
if (!firstElement)
|
|
641
|
+
return { html };
|
|
642
|
+
const encodedData = firstElement.getAttribute("data-gt-internal");
|
|
643
|
+
let extractedData;
|
|
644
|
+
if (encodedData)
|
|
645
|
+
try {
|
|
646
|
+
const decodedData = decode(encodedData);
|
|
647
|
+
extractedData = JSON.parse(decodedData), firstElement.removeAttribute("data-gt-internal");
|
|
648
|
+
} catch (error) {
|
|
649
|
+
console.warn("Failed to decode GT internal data:", error);
|
|
650
|
+
}
|
|
651
|
+
return {
|
|
652
|
+
html: firstElement.outerHTML,
|
|
653
|
+
data: extractedData
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
function encode(data) {
|
|
657
|
+
const bytes = new TextEncoder().encode(data);
|
|
658
|
+
let binary = "";
|
|
659
|
+
for (let i = 0; i < bytes.length; i++)
|
|
660
|
+
binary += String.fromCharCode(bytes[i]);
|
|
661
|
+
return btoa(binary);
|
|
662
|
+
}
|
|
663
|
+
function decode(base64) {
|
|
664
|
+
const binary = atob(base64), bytes = new Uint8Array(binary.length);
|
|
665
|
+
for (let i = 0; i < binary.length; i++)
|
|
666
|
+
bytes[i] = binary.charCodeAt(i);
|
|
667
|
+
return new TextDecoder().decode(bytes);
|
|
668
|
+
}
|
|
669
|
+
const isRecord$3 = (value) => typeof value == "object" && value !== null && !Array.isArray(value), defaultStopTypes = [
|
|
670
|
+
"reference",
|
|
671
|
+
"date",
|
|
672
|
+
"datetime",
|
|
673
|
+
"file",
|
|
674
|
+
"geopoint",
|
|
675
|
+
"image",
|
|
676
|
+
"number",
|
|
677
|
+
"crop",
|
|
678
|
+
"hotspot",
|
|
679
|
+
"boolean",
|
|
680
|
+
"url",
|
|
681
|
+
"color",
|
|
682
|
+
"code"
|
|
683
|
+
], defaultMarks = {}, defaultPortableTextBlockStyles = {
|
|
684
|
+
normal: ({ value, children }) => `<p id="${value._key}">${children}</p>`,
|
|
685
|
+
blockquote: ({ value, children }) => `<blockquote id="${value._key}">${children}</blockquote>`,
|
|
686
|
+
h1: ({ value, children }) => `<h1 id="${value._key}">${children}</h1>`,
|
|
687
|
+
h2: ({ value, children }) => `<h2 id="${value._key}">${children}</h2>`,
|
|
688
|
+
h3: ({ value, children }) => `<h3 id="${value._key}">${children}</h3>`,
|
|
689
|
+
h4: ({ value, children }) => `<h4 id="${value._key}">${children}</h4>`,
|
|
690
|
+
h5: ({ value, children }) => `<h5 id="${value._key}">${children}</h5>`,
|
|
691
|
+
h6: ({ value, children }) => `<h6 id="${value._key}">${children}</h6>`
|
|
692
|
+
}, defaultLists = {
|
|
693
|
+
number: ({ value, children }) => `<ol id="${value._key.replace("-parent", "")}">${children}</ol>`,
|
|
694
|
+
bullet: ({ value, children }) => `<ul id="${value._key.replace("-parent", "")}">${children}</ul>`
|
|
695
|
+
}, defaultListItem = ({
|
|
696
|
+
value,
|
|
697
|
+
children
|
|
698
|
+
}) => {
|
|
699
|
+
const { _key, level } = value;
|
|
700
|
+
return `<li id="${(_key || "").replace("-parent", "")}" data-level="${level}">${children}</li>`;
|
|
701
|
+
}, unknownBlockFunc = ({ value, children }) => `<p id="${value._key}" data-type="unknown-block-style" data-style="${value.style}">${children}</p>`, customSerializers = {
|
|
702
|
+
unknownType: ({ value }) => `<div class="${value._type}"></div>`,
|
|
703
|
+
types: {},
|
|
704
|
+
marks: defaultMarks,
|
|
705
|
+
block: defaultPortableTextBlockStyles,
|
|
706
|
+
list: defaultLists,
|
|
707
|
+
listItem: defaultListItem,
|
|
708
|
+
unknownBlockStyle: unknownBlockFunc
|
|
709
|
+
}, customDeserializers = { types: {} }, customBlockDeserializers = [
|
|
710
|
+
// handle marks with data-gt-internal
|
|
711
|
+
{
|
|
712
|
+
deserialize(node2, next2) {
|
|
713
|
+
if (node2.nodeType !== 1)
|
|
714
|
+
return;
|
|
715
|
+
const el = node2;
|
|
716
|
+
if (!el.hasChildNodes() || !el.getAttribute("data-gt-internal"))
|
|
717
|
+
return;
|
|
718
|
+
const { html, data } = detachGTData(el.outerHTML), block = blockTools.htmlToBlocks(html, blockContentType)[0], children = next2(el.childNodes);
|
|
719
|
+
let markDefs = [];
|
|
720
|
+
return "markDefs" in block && (markDefs = block.markDefs ?? []), data?.markDef && markDefs.push(data.markDef), Array.isArray(children) && children.forEach((child) => {
|
|
721
|
+
if (!isRecord$3(child))
|
|
722
|
+
return;
|
|
723
|
+
const marks = Array.isArray(child.marks) ? child.marks : [];
|
|
724
|
+
child.marks = data?.markDef?._key ? [...marks, data.markDef._key] : marks;
|
|
725
|
+
}), {
|
|
726
|
+
...block,
|
|
727
|
+
markDefs,
|
|
728
|
+
children
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
},
|
|
732
|
+
//handle undeclared styles
|
|
733
|
+
{
|
|
734
|
+
deserialize(node2, next2) {
|
|
735
|
+
if (node2.nodeType !== 1)
|
|
736
|
+
return;
|
|
737
|
+
const el = node2;
|
|
738
|
+
if (!el.hasChildNodes() || el.getAttribute("data-type") !== "unknown-block-style")
|
|
739
|
+
return;
|
|
740
|
+
const style = el.getAttribute("data-style") ?? "";
|
|
741
|
+
return {
|
|
742
|
+
...blockTools.htmlToBlocks(el.outerHTML, blockContentType)[0],
|
|
743
|
+
style,
|
|
744
|
+
children: next2(el.childNodes)
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
},
|
|
748
|
+
//handle list items
|
|
749
|
+
{
|
|
750
|
+
deserialize(node2, next2) {
|
|
751
|
+
if (node2.nodeType !== 1)
|
|
752
|
+
return;
|
|
753
|
+
const el = node2;
|
|
754
|
+
if (!el.hasChildNodes() || el.tagName.toLowerCase() !== "li")
|
|
755
|
+
return;
|
|
756
|
+
const tagsToStyle = {
|
|
757
|
+
ul: "bullet",
|
|
758
|
+
ol: "number"
|
|
759
|
+
}, parent = el.parentNode;
|
|
760
|
+
if (!parent || !parent.tagName)
|
|
761
|
+
return;
|
|
762
|
+
const listItem = tagsToStyle[parent.tagName.toLowerCase()];
|
|
763
|
+
if (!listItem)
|
|
764
|
+
return;
|
|
765
|
+
const level = el.getAttribute("data-level") && parseInt(el.getAttribute("data-level") || "0", 10), _key = el.id;
|
|
766
|
+
let block = blockTools.htmlToBlocks(parent.outerHTML, blockContentType)[0];
|
|
767
|
+
const customStyle = el.children?.[0]?.getAttribute("data-style");
|
|
768
|
+
if (new RegExp(/<("[^"]*"|'[^']*'|[^'">])*>/).test(el.innerHTML)) {
|
|
769
|
+
const newBlock = blockTools.htmlToBlocks(el.innerHTML, blockContentType)[0];
|
|
770
|
+
if (newBlock && (block = {
|
|
771
|
+
...block,
|
|
772
|
+
...newBlock,
|
|
773
|
+
// @ts-ignore
|
|
774
|
+
style: customStyle ?? newBlock.style
|
|
775
|
+
}, customStyle))
|
|
776
|
+
return block;
|
|
777
|
+
}
|
|
778
|
+
return {
|
|
779
|
+
...block,
|
|
780
|
+
level,
|
|
781
|
+
_key,
|
|
782
|
+
listItem,
|
|
783
|
+
children: next2(el.childNodes)
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
];
|
|
788
|
+
function mergeBlocks(blocks) {
|
|
789
|
+
const mergedBlock = { ...blocks[0] };
|
|
790
|
+
mergedBlock.markDefs = mergedBlock.markDefs ?? [];
|
|
791
|
+
for (const [idx, block] of blocks.entries())
|
|
792
|
+
idx !== 0 && (mergedBlock.children.push(...block.children), mergedBlock.markDefs.push(...block.markDefs ?? []));
|
|
793
|
+
return mergedBlock._type = "block", mergedBlock;
|
|
794
|
+
}
|
|
795
|
+
const deserializeArray = (arrayHTML, deserializers = customDeserializers, blockDeserializers = customBlockDeserializers) => {
|
|
796
|
+
const output = [];
|
|
797
|
+
return Array.from(arrayHTML.children).forEach((child) => {
|
|
798
|
+
let deserializedObject;
|
|
799
|
+
try {
|
|
800
|
+
if (child.tagName?.toLowerCase() === "span")
|
|
801
|
+
deserializedObject = preprocess(child.innerHTML);
|
|
802
|
+
else if (child.className || child.getAttribute("data-type") === "object")
|
|
803
|
+
deserializedObject = deserializeObject(
|
|
804
|
+
child,
|
|
805
|
+
deserializers,
|
|
806
|
+
blockDeserializers
|
|
807
|
+
), deserializedObject && typeof deserializedObject == "object" && !Array.isArray(deserializedObject) && (deserializedObject._key = child.id);
|
|
808
|
+
else {
|
|
809
|
+
const blocks = blockTools.htmlToBlocks(child.outerHTML, blockContentType, {
|
|
810
|
+
rules: blockDeserializers
|
|
811
|
+
});
|
|
812
|
+
deserializedObject = mergeBlocks(
|
|
813
|
+
blocks
|
|
814
|
+
), deserializedObject._key = child.id;
|
|
815
|
+
}
|
|
816
|
+
} catch (e) {
|
|
817
|
+
console.debug(
|
|
818
|
+
`Tried to deserialize block: ${child.outerHTML} in an array but failed to identify it! Error: ${e}`
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
output.push(deserializedObject);
|
|
822
|
+
}), output;
|
|
823
|
+
}, deserializeObject = (objectHTML, deserializers = customDeserializers, blockDeserializers = customBlockDeserializers) => {
|
|
824
|
+
const deserialize = deserializers.types?.[objectHTML.className];
|
|
825
|
+
if (deserialize)
|
|
826
|
+
return deserialize(objectHTML);
|
|
827
|
+
const output = {};
|
|
828
|
+
return objectHTML.className && (output._type = objectHTML.className), Array.from(objectHTML.children).forEach((child) => {
|
|
829
|
+
if (child.tagName?.toLowerCase() === "span")
|
|
830
|
+
output[child.className] = preprocess(child.innerHTML);
|
|
831
|
+
else if (child.getAttribute("data-level") === "field") {
|
|
832
|
+
const deserialized = deserializeHTML(
|
|
833
|
+
child.outerHTML,
|
|
834
|
+
deserializers,
|
|
835
|
+
blockDeserializers
|
|
836
|
+
);
|
|
837
|
+
deserialized && Object.keys(deserialized).length ? output[child.className] = deserialized : console.debug(
|
|
838
|
+
`Deserializer: Skipping empty or unreadable HTML: ${child.outerHTML}`
|
|
839
|
+
);
|
|
840
|
+
} else child.getAttribute("data-type") === "array" && (output[child.className] = deserializeArray(
|
|
841
|
+
child,
|
|
842
|
+
deserializers,
|
|
843
|
+
blockDeserializers
|
|
844
|
+
));
|
|
845
|
+
}), output;
|
|
846
|
+
}, deserializeHTML = (html, deserializers, blockDeserializers) => {
|
|
847
|
+
let HTMLnode = new DOMParser().parseFromString(html, "text/html").body.children[0];
|
|
848
|
+
if (HTMLnode?.getAttribute("data-level") === "field" && (HTMLnode = HTMLnode.children[0]), !HTMLnode)
|
|
849
|
+
return {};
|
|
850
|
+
let output;
|
|
851
|
+
const deserialize = deserializers.types?.[HTMLnode.className];
|
|
852
|
+
return deserialize ? output = deserialize(HTMLnode) : HTMLnode.getAttribute("data-type") === "object" ? output = deserializeObject(HTMLnode, deserializers, blockDeserializers) : HTMLnode.getAttribute("data-type") === "array" ? output = deserializeArray(HTMLnode, deserializers, blockDeserializers) : (output = {}, console.debug(
|
|
853
|
+
`Tried to deserialize block ${HTMLnode.outerHTML} but failed to identify it!`
|
|
854
|
+
)), output;
|
|
855
|
+
}, deserializeDocument$1 = (serializedDoc, deserializers = customDeserializers, blockDeserializers = customBlockDeserializers) => {
|
|
856
|
+
const metadata = {}, head = new DOMParser().parseFromString(serializedDoc, "text/html").head;
|
|
857
|
+
return Array.from(head.children).forEach((metaTag) => {
|
|
858
|
+
const validTags = ["_id", "_rev", "_type"], metaName = metaTag.getAttribute("name");
|
|
859
|
+
metaName && validTags.includes(metaName) && (metadata[metaName] = metaTag.getAttribute("content"));
|
|
860
|
+
}), {
|
|
861
|
+
...deserializeHTML(
|
|
862
|
+
serializedDoc,
|
|
863
|
+
deserializers,
|
|
864
|
+
blockDeserializers
|
|
865
|
+
),
|
|
866
|
+
...metadata
|
|
867
|
+
};
|
|
868
|
+
}, BaseDocumentDeserializer = {
|
|
869
|
+
deserializeDocument: deserializeDocument$1,
|
|
870
|
+
deserializeHTML
|
|
871
|
+
}, META_FIELDS$1 = ["_key", "_type", "_id"], isRecord$2 = (value) => typeof value == "object" && value !== null && !Array.isArray(value), languageObjectFieldFilter = (obj, baseLang) => {
|
|
872
|
+
const filterToLangField = (childObj) => {
|
|
873
|
+
const filteredObj = {};
|
|
874
|
+
return filteredObj[baseLang] = childObj[baseLang], META_FIELDS$1.forEach((field) => {
|
|
875
|
+
childObj[field] && (filteredObj[field] = childObj[field]);
|
|
876
|
+
}), filteredObj;
|
|
877
|
+
}, findBaseLang = (childObj) => {
|
|
878
|
+
const filteredObj = {};
|
|
879
|
+
META_FIELDS$1.forEach((field) => {
|
|
880
|
+
childObj[field] && (filteredObj[field] = childObj[field]);
|
|
881
|
+
});
|
|
882
|
+
for (const key in childObj)
|
|
883
|
+
if (childObj.hasOwnProperty(key)) {
|
|
884
|
+
const value = childObj[key];
|
|
885
|
+
if (isRecord$2(value) && Object.hasOwn(value, baseLang))
|
|
886
|
+
filteredObj[key] = filterToLangField(value);
|
|
887
|
+
else if (Array.isArray(value) && value.length && typeof value[0] == "object") {
|
|
888
|
+
const validLangObjects = value.reduce(
|
|
889
|
+
(validArr, objInArray) => {
|
|
890
|
+
if (!isRecord$2(objInArray))
|
|
891
|
+
return validArr;
|
|
892
|
+
if (objInArray._type === "block")
|
|
893
|
+
validArr.push(objInArray);
|
|
894
|
+
else if (Object.hasOwn(objInArray, baseLang))
|
|
895
|
+
validArr.push(filterToLangField(objInArray));
|
|
896
|
+
else {
|
|
897
|
+
const filtered = findBaseLang(objInArray);
|
|
898
|
+
Object.keys(filtered).filter(
|
|
899
|
+
(objInArrayKey) => META_FIELDS$1.indexOf(objInArrayKey) === -1
|
|
402
900
|
).length && validArr.push(filtered);
|
|
403
901
|
}
|
|
404
902
|
return validArr;
|
|
@@ -507,240 +1005,78 @@ const isRecord$3 = (value) => typeof value == "object" && value !== null && !Arr
|
|
|
507
1005
|
);
|
|
508
1006
|
return schema2 && schema2.fields ? fieldFilter(block, schema2.fields, stopTypes) : block;
|
|
509
1007
|
}).map((obj) => typeof obj == "string" ? `<span>${obj}</span>` : serializeObject(obj, stopTypes, serializers));
|
|
510
|
-
return `<div class="${fieldName}" data-type="array">${output.join("")}</div>`;
|
|
511
|
-
};
|
|
512
|
-
return {
|
|
513
|
-
serializeDocument: (doc, translationLevel = "document", baseLang = "en", stopTypes = defaultStopTypes, serializers = customSerializers) => {
|
|
514
|
-
const schema2 = getSchema(doc._type);
|
|
515
|
-
let filteredObj = {};
|
|
516
|
-
translationLevel === "field" ? filteredObj = languageObjectFieldFilter(doc, baseLang) : filteredObj = fieldFilter(doc, schema2?.fields ?? [], stopTypes);
|
|
517
|
-
const serializedFields = {};
|
|
518
|
-
for (const key in filteredObj) {
|
|
519
|
-
if (filteredObj.hasOwnProperty(key) === !1) continue;
|
|
520
|
-
const value = filteredObj[key];
|
|
521
|
-
if (typeof value == "string")
|
|
522
|
-
serializedFields[key] = value;
|
|
523
|
-
else if (Array.isArray(value))
|
|
524
|
-
serializedFields[key] = serializeArray(
|
|
525
|
-
value.filter(
|
|
526
|
-
(item) => typeof item == "string" || isRecord$1(item)
|
|
527
|
-
),
|
|
528
|
-
key,
|
|
529
|
-
stopTypes,
|
|
530
|
-
serializers
|
|
531
|
-
);
|
|
532
|
-
else if (value && isRecord$1(value) && !stopTypes.find((stopType) => stopType == value?._type)) {
|
|
533
|
-
const serialized = serializeObject(
|
|
534
|
-
value,
|
|
535
|
-
stopTypes,
|
|
536
|
-
serializers
|
|
537
|
-
);
|
|
538
|
-
serializedFields[key] = `<div class="${key}" data-level='field'>${serialized}</div>`;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
const rawHTMLBody = document.createElement("body");
|
|
542
|
-
rawHTMLBody.innerHTML = serializeObject(
|
|
543
|
-
serializedFields,
|
|
544
|
-
stopTypes,
|
|
545
|
-
serializers
|
|
546
|
-
);
|
|
547
|
-
const rawHTMLHead = document.createElement("head");
|
|
548
|
-
["_id", "_type", "_rev"].forEach((field) => {
|
|
549
|
-
const metaEl = document.createElement("meta");
|
|
550
|
-
metaEl.setAttribute("name", field), metaEl.setAttribute("content", doc[field]), rawHTMLHead.appendChild(metaEl);
|
|
551
|
-
});
|
|
552
|
-
const versionMeta = document.createElement("meta");
|
|
553
|
-
versionMeta.setAttribute("name", "version"), versionMeta.setAttribute("content", "3"), rawHTMLHead.appendChild(versionMeta);
|
|
554
|
-
const rawHTML = document.createElement("html");
|
|
555
|
-
return rawHTML.appendChild(rawHTMLHead), rawHTML.appendChild(rawHTMLBody), {
|
|
556
|
-
name: doc._id,
|
|
557
|
-
content: rawHTML.outerHTML
|
|
558
|
-
};
|
|
559
|
-
},
|
|
560
|
-
fieldFilter,
|
|
561
|
-
languageObjectFieldFilter,
|
|
562
|
-
serializeArray,
|
|
563
|
-
serializeObject
|
|
564
|
-
};
|
|
565
|
-
};
|
|
566
|
-
function
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
idx !== 0 && (mergedBlock.children.push(...block.children), mergedBlock.markDefs.push(...block.markDefs ?? []));
|
|
571
|
-
return mergedBlock._type = "block", mergedBlock;
|
|
572
|
-
}
|
|
573
|
-
const deserializeArray = (arrayHTML, deserializers = customDeserializers, blockDeserializers = customBlockDeserializers) => {
|
|
574
|
-
const output = [];
|
|
575
|
-
return Array.from(arrayHTML.children).forEach((child) => {
|
|
576
|
-
let deserializedObject;
|
|
577
|
-
try {
|
|
578
|
-
if (child.tagName?.toLowerCase() === "span")
|
|
579
|
-
deserializedObject = preprocess(child.innerHTML);
|
|
580
|
-
else if (child.className || child.getAttribute("data-type") === "object")
|
|
581
|
-
deserializedObject = deserializeObject(
|
|
582
|
-
child,
|
|
583
|
-
deserializers,
|
|
584
|
-
blockDeserializers
|
|
585
|
-
), deserializedObject && typeof deserializedObject == "object" && !Array.isArray(deserializedObject) && (deserializedObject._key = child.id);
|
|
586
|
-
else {
|
|
587
|
-
const blocks = blockTools.htmlToBlocks(child.outerHTML, blockContentType, {
|
|
588
|
-
rules: blockDeserializers
|
|
589
|
-
});
|
|
590
|
-
deserializedObject = mergeBlocks(
|
|
591
|
-
blocks
|
|
592
|
-
), deserializedObject._key = child.id;
|
|
593
|
-
}
|
|
594
|
-
} catch (e) {
|
|
595
|
-
console.debug(
|
|
596
|
-
`Tried to deserialize block: ${child.outerHTML} in an array but failed to identify it! Error: ${e}`
|
|
597
|
-
);
|
|
598
|
-
}
|
|
599
|
-
output.push(deserializedObject);
|
|
600
|
-
}), output;
|
|
601
|
-
}, deserializeObject = (objectHTML, deserializers = customDeserializers, blockDeserializers = customBlockDeserializers) => {
|
|
602
|
-
const deserialize = deserializers.types?.[objectHTML.className];
|
|
603
|
-
if (deserialize)
|
|
604
|
-
return deserialize(objectHTML);
|
|
605
|
-
const output = {};
|
|
606
|
-
return objectHTML.className && (output._type = objectHTML.className), Array.from(objectHTML.children).forEach((child) => {
|
|
607
|
-
if (child.tagName?.toLowerCase() === "span")
|
|
608
|
-
output[child.className] = preprocess(child.innerHTML);
|
|
609
|
-
else if (child.getAttribute("data-level") === "field") {
|
|
610
|
-
const deserialized = deserializeHTML(
|
|
611
|
-
child.outerHTML,
|
|
612
|
-
deserializers,
|
|
613
|
-
blockDeserializers
|
|
614
|
-
);
|
|
615
|
-
deserialized && Object.keys(deserialized).length ? output[child.className] = deserialized : console.debug(
|
|
616
|
-
`Deserializer: Skipping empty or unreadable HTML: ${child.outerHTML}`
|
|
617
|
-
);
|
|
618
|
-
} else child.getAttribute("data-type") === "array" && (output[child.className] = deserializeArray(
|
|
619
|
-
child,
|
|
620
|
-
deserializers,
|
|
621
|
-
blockDeserializers
|
|
622
|
-
));
|
|
623
|
-
}), output;
|
|
624
|
-
}, deserializeHTML = (html, deserializers, blockDeserializers) => {
|
|
625
|
-
let HTMLnode = new DOMParser().parseFromString(html, "text/html").body.children[0];
|
|
626
|
-
if (HTMLnode?.getAttribute("data-level") === "field" && (HTMLnode = HTMLnode.children[0]), !HTMLnode)
|
|
627
|
-
return {};
|
|
628
|
-
let output;
|
|
629
|
-
const deserialize = deserializers.types?.[HTMLnode.className];
|
|
630
|
-
return deserialize ? output = deserialize(HTMLnode) : HTMLnode.getAttribute("data-type") === "object" ? output = deserializeObject(HTMLnode, deserializers, blockDeserializers) : HTMLnode.getAttribute("data-type") === "array" ? output = deserializeArray(HTMLnode, deserializers, blockDeserializers) : (output = {}, console.debug(
|
|
631
|
-
`Tried to deserialize block ${HTMLnode.outerHTML} but failed to identify it!`
|
|
632
|
-
)), output;
|
|
633
|
-
}, deserializeDocument$1 = (serializedDoc, deserializers = customDeserializers, blockDeserializers = customBlockDeserializers) => {
|
|
634
|
-
const metadata = {}, head = new DOMParser().parseFromString(serializedDoc, "text/html").head;
|
|
635
|
-
return Array.from(head.children).forEach((metaTag) => {
|
|
636
|
-
const validTags = ["_id", "_rev", "_type"], metaName = metaTag.getAttribute("name");
|
|
637
|
-
metaName && validTags.includes(metaName) && (metadata[metaName] = metaTag.getAttribute("content"));
|
|
638
|
-
}), {
|
|
639
|
-
...deserializeHTML(
|
|
640
|
-
serializedDoc,
|
|
641
|
-
deserializers,
|
|
642
|
-
blockDeserializers
|
|
643
|
-
),
|
|
644
|
-
...metadata
|
|
645
|
-
};
|
|
646
|
-
}, BaseDocumentDeserializer = {
|
|
647
|
-
deserializeDocument: deserializeDocument$1,
|
|
648
|
-
deserializeHTML
|
|
649
|
-
};
|
|
650
|
-
function forEachMatchingField(documentId, document2, fields, callback) {
|
|
651
|
-
const applicable = fields.filter(
|
|
652
|
-
(field) => field.documentId === documentId || field.documentId === void 0 || field.documentId === null
|
|
653
|
-
);
|
|
654
|
-
for (const entry of applicable)
|
|
655
|
-
if (entry.fields)
|
|
656
|
-
for (const field of entry.fields) {
|
|
657
|
-
const { property, type } = field;
|
|
658
|
-
try {
|
|
659
|
-
const results = jsonpathPlus.JSONPath({
|
|
660
|
-
json: document2,
|
|
661
|
-
path: property,
|
|
662
|
-
resultType: "all",
|
|
663
|
-
flatten: !0,
|
|
664
|
-
wrap: !0
|
|
665
|
-
});
|
|
666
|
-
results && results.length > 0 && results.forEach(
|
|
667
|
-
(result) => {
|
|
668
|
-
type !== void 0 ? typeof result.value == "object" && result.value !== null && !Array.isArray(result.value) && result.value._type === type && callback(result) : callback(result);
|
|
669
|
-
}
|
|
670
|
-
);
|
|
671
|
-
} catch (error) {
|
|
672
|
-
console.warn(`Invalid JSONPath: ${property}`, error);
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
function deleteMatchingFields(documentId, document2, fields) {
|
|
677
|
-
const arrayRemovals = [];
|
|
678
|
-
forEachMatchingField(documentId, document2, fields, (result) => {
|
|
679
|
-
Array.isArray(result.parent) ? arrayRemovals.push({
|
|
680
|
-
parent: result.parent,
|
|
681
|
-
index: Number(result.parentProperty)
|
|
682
|
-
}) : delete result.parent[result.parentProperty];
|
|
683
|
-
}), arrayRemovals.sort((a, b) => b.index - a.index);
|
|
684
|
-
for (const { parent, index } of arrayRemovals)
|
|
685
|
-
parent.splice(index, 1);
|
|
686
|
-
}
|
|
687
|
-
function applyDocuments(documentId, sourceDocument, targetDocument, ignore, skip = [], dedupe = [], localeId) {
|
|
688
|
-
const mergedDocument = JSON.parse(JSON.stringify(sourceDocument)), clonedTarget = JSON.parse(JSON.stringify(targetDocument));
|
|
689
|
-
for (const [key, value] of Object.entries(clonedTarget))
|
|
690
|
-
mergedDocument[key] = value;
|
|
691
|
-
return forEachMatchingField(documentId, sourceDocument, ignore, (result) => {
|
|
692
|
-
JSONPointer__default.default.set(mergedDocument, result.pointer, result.value);
|
|
693
|
-
}), forEachMatchingField(documentId, sourceDocument, dedupe, (result) => {
|
|
694
|
-
JSONPointer__default.default.set(
|
|
695
|
-
mergedDocument,
|
|
696
|
-
result.pointer,
|
|
697
|
-
dedupeFieldValue(result.value, localeId)
|
|
698
|
-
);
|
|
699
|
-
}), deleteMatchingFields(documentId, mergedDocument, skip), mergedDocument;
|
|
700
|
-
}
|
|
701
|
-
function dedupeFieldValue(value, localeId) {
|
|
702
|
-
if (!localeId) return value;
|
|
703
|
-
if (typeof value == "string")
|
|
704
|
-
return appendLocaleSuffix(value, localeId);
|
|
705
|
-
if (value && typeof value == "object" && !Array.isArray(value) && typeof value.current == "string") {
|
|
706
|
-
const slug = value;
|
|
707
|
-
return {
|
|
708
|
-
...slug,
|
|
709
|
-
current: appendLocaleSuffix(slug.current, localeId)
|
|
710
|
-
};
|
|
1008
|
+
return `<div class="${fieldName}" data-type="array">${output.join("")}</div>`;
|
|
1009
|
+
};
|
|
1010
|
+
return {
|
|
1011
|
+
serializeDocument: (doc, translationLevel = "document", baseLang = "en", stopTypes = defaultStopTypes, serializers = customSerializers) => {
|
|
1012
|
+
const schema2 = getSchema(doc._type);
|
|
1013
|
+
let filteredObj = {};
|
|
1014
|
+
translationLevel === "field" ? filteredObj = languageObjectFieldFilter(doc, baseLang) : filteredObj = fieldFilter(doc, schema2?.fields ?? [], stopTypes);
|
|
1015
|
+
const serializedFields = {};
|
|
1016
|
+
for (const key in filteredObj) {
|
|
1017
|
+
if (filteredObj.hasOwnProperty(key) === !1) continue;
|
|
1018
|
+
const value = filteredObj[key];
|
|
1019
|
+
if (typeof value == "string")
|
|
1020
|
+
serializedFields[key] = value;
|
|
1021
|
+
else if (Array.isArray(value))
|
|
1022
|
+
serializedFields[key] = serializeArray(
|
|
1023
|
+
value.filter(
|
|
1024
|
+
(item) => typeof item == "string" || isRecord$1(item)
|
|
1025
|
+
),
|
|
1026
|
+
key,
|
|
1027
|
+
stopTypes,
|
|
1028
|
+
serializers
|
|
1029
|
+
);
|
|
1030
|
+
else if (value && isRecord$1(value) && !stopTypes.find((stopType) => stopType == value?._type)) {
|
|
1031
|
+
const serialized = serializeObject(
|
|
1032
|
+
value,
|
|
1033
|
+
stopTypes,
|
|
1034
|
+
serializers
|
|
1035
|
+
);
|
|
1036
|
+
serializedFields[key] = `<div class="${key}" data-level='field'>${serialized}</div>`;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
const rawHTMLBody = document.createElement("body");
|
|
1040
|
+
rawHTMLBody.innerHTML = serializeObject(
|
|
1041
|
+
serializedFields,
|
|
1042
|
+
stopTypes,
|
|
1043
|
+
serializers
|
|
1044
|
+
);
|
|
1045
|
+
const rawHTMLHead = document.createElement("head");
|
|
1046
|
+
["_id", "_type", "_rev"].forEach((field) => {
|
|
1047
|
+
const metaEl = document.createElement("meta");
|
|
1048
|
+
metaEl.setAttribute("name", field), metaEl.setAttribute("content", doc[field]), rawHTMLHead.appendChild(metaEl);
|
|
1049
|
+
});
|
|
1050
|
+
const versionMeta = document.createElement("meta");
|
|
1051
|
+
versionMeta.setAttribute("name", "version"), versionMeta.setAttribute("content", "3"), rawHTMLHead.appendChild(versionMeta);
|
|
1052
|
+
const rawHTML = document.createElement("html");
|
|
1053
|
+
return rawHTML.appendChild(rawHTMLHead), rawHTML.appendChild(rawHTMLBody), {
|
|
1054
|
+
name: doc._id,
|
|
1055
|
+
content: rawHTML.outerHTML
|
|
1056
|
+
};
|
|
1057
|
+
},
|
|
1058
|
+
fieldFilter,
|
|
1059
|
+
languageObjectFieldFilter,
|
|
1060
|
+
serializeArray,
|
|
1061
|
+
serializeObject
|
|
1062
|
+
};
|
|
1063
|
+
};
|
|
1064
|
+
function collapseToSourceLocale(value, sourceLocale) {
|
|
1065
|
+
if (isInternationalizedArrayField(value)) {
|
|
1066
|
+
const sourceItem = findLocaleItem(value, sourceLocale);
|
|
1067
|
+
return sourceItem ? collapseToSourceLocale(sourceItem.value, sourceLocale) : void 0;
|
|
711
1068
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
return normalized ? `-${normalized}` : "";
|
|
722
|
-
}
|
|
723
|
-
function getPublishedId(documentId) {
|
|
724
|
-
return documentId.startsWith("drafts.") ? documentId.slice(7) : documentId;
|
|
725
|
-
}
|
|
726
|
-
function getDocumentPublishedId(document2) {
|
|
727
|
-
return getPublishedId(document2._id);
|
|
728
|
-
}
|
|
729
|
-
function dedupeDocumentsPreferDraft(documents) {
|
|
730
|
-
const byPublishedId = /* @__PURE__ */ new Map();
|
|
731
|
-
for (const document2 of documents) {
|
|
732
|
-
const publishedId = getDocumentPublishedId(document2);
|
|
733
|
-
(!byPublishedId.get(publishedId) || document2._id.startsWith("drafts.")) && byPublishedId.set(publishedId, document2);
|
|
1069
|
+
if (Array.isArray(value))
|
|
1070
|
+
return value.map((item) => collapseToSourceLocale(item, sourceLocale)).filter((item) => item !== void 0);
|
|
1071
|
+
if (isRecord$4(value)) {
|
|
1072
|
+
const collapsed = {};
|
|
1073
|
+
for (const key of Object.keys(value)) {
|
|
1074
|
+
const collapsedValue = collapseToSourceLocale(value[key], sourceLocale);
|
|
1075
|
+
collapsedValue !== void 0 && (collapsed[key] = collapsedValue);
|
|
1076
|
+
}
|
|
1077
|
+
return collapsed;
|
|
734
1078
|
}
|
|
735
|
-
return
|
|
736
|
-
}
|
|
737
|
-
function createTranslationStatusKey(branchId, documentId, versionId, localeId) {
|
|
738
|
-
const publishedId = getPublishedId(documentId);
|
|
739
|
-
return branchId ? `${branchId}:${publishedId}:${versionId}:${localeId}` : `${publishedId}:${versionId}:${localeId}`;
|
|
740
|
-
}
|
|
741
|
-
function createStableTranslationKey(branchId, documentId, localeId) {
|
|
742
|
-
const publishedId = getPublishedId(documentId);
|
|
743
|
-
return branchId ? `${branchId}:${publishedId}:${localeId}` : `${publishedId}:${localeId}`;
|
|
1079
|
+
return value;
|
|
744
1080
|
}
|
|
745
1081
|
function deserializeDocument(document2) {
|
|
746
1082
|
const deserializers = merge__default.default(
|
|
@@ -756,21 +1092,25 @@ function deserializeDocument(document2) {
|
|
|
756
1092
|
blockDeserializers
|
|
757
1093
|
);
|
|
758
1094
|
}
|
|
759
|
-
function serializeDocument(document2, schema2, baseLanguage) {
|
|
1095
|
+
function serializeDocument(document2, schema2, baseLanguage, level = "document") {
|
|
760
1096
|
const stopTypes = [
|
|
761
1097
|
...defaultStopTypes,
|
|
762
1098
|
...pluginConfig.getAdditionalStopTypes()
|
|
763
1099
|
], serializers = merge__default.default(
|
|
764
1100
|
customSerializers,
|
|
765
1101
|
pluginConfig.getAdditionalSerializers()
|
|
766
|
-
)
|
|
1102
|
+
);
|
|
1103
|
+
let docToSerialize = stripIgnoredFields(
|
|
767
1104
|
document2,
|
|
768
1105
|
pluginConfig.getIgnoreFields(),
|
|
769
1106
|
pluginConfig.getDedupeFields()
|
|
770
|
-
);
|
|
771
|
-
return
|
|
1107
|
+
), innerLevel = level;
|
|
1108
|
+
return level === "internationalizedArray" && (docToSerialize = collapseToSourceLocale(
|
|
1109
|
+
docToSerialize,
|
|
1110
|
+
baseLanguage
|
|
1111
|
+
), innerLevel = "document"), BaseDocumentSerializer(schema2).serializeDocument(
|
|
772
1112
|
docToSerialize,
|
|
773
|
-
|
|
1113
|
+
innerLevel,
|
|
774
1114
|
baseLanguage,
|
|
775
1115
|
stopTypes,
|
|
776
1116
|
serializers
|
|
@@ -786,6 +1126,32 @@ function stripIgnoredFields(document2, ignoreFields, dedupeFields) {
|
|
|
786
1126
|
fieldsToStrip
|
|
787
1127
|
), strippedDoc;
|
|
788
1128
|
}
|
|
1129
|
+
const documentAdapter = {
|
|
1130
|
+
level: "document",
|
|
1131
|
+
serialize: (document2, schema2, baseLanguage) => serializeDocument(document2, schema2, baseLanguage, "document"),
|
|
1132
|
+
patch: (docInfo, deserialized, localeId, client, mergeWithTargetLocale) => documentLevelPatch(
|
|
1133
|
+
docInfo,
|
|
1134
|
+
deserialized,
|
|
1135
|
+
localeId,
|
|
1136
|
+
client,
|
|
1137
|
+
pluginConfig.getLanguageField(),
|
|
1138
|
+
mergeWithTargetLocale
|
|
1139
|
+
)
|
|
1140
|
+
}, internationalizedArrayAdapter = {
|
|
1141
|
+
level: "internationalizedArray",
|
|
1142
|
+
serialize: (document2, schema2, baseLanguage) => serializeDocument(document2, schema2, baseLanguage, "internationalizedArray"),
|
|
1143
|
+
patch: (docInfo, deserialized, localeId, client) => internationalizedArrayPatch(docInfo, deserialized, localeId, client)
|
|
1144
|
+
};
|
|
1145
|
+
function matchesFieldLevel(type) {
|
|
1146
|
+
return type ? pluginConfig.getFieldLevelDocuments().some((filter2) => filter2.type === type) : !1;
|
|
1147
|
+
}
|
|
1148
|
+
function getTranslationStrategyForType(type) {
|
|
1149
|
+
const level = pluginConfig.getTranslationLevel();
|
|
1150
|
+
return level === "internationalizedArray" || level === "mixed" && matchesFieldLevel(type) ? internationalizedArrayAdapter : documentAdapter;
|
|
1151
|
+
}
|
|
1152
|
+
function getTranslationStrategy(document2) {
|
|
1153
|
+
return getTranslationStrategyForType(document2._type);
|
|
1154
|
+
}
|
|
789
1155
|
async function uploadFiles(documents, secrets) {
|
|
790
1156
|
return overrideConfig(secrets), await gt.uploadSourceFiles(
|
|
791
1157
|
documents.map(({ info, serializedDocument }) => ({
|
|
@@ -820,283 +1186,79 @@ async function initProject(uploadResult, options, secrets) {
|
|
|
820
1186
|
if (status[0].status === "completed") {
|
|
821
1187
|
setupCompleted = !0;
|
|
822
1188
|
break;
|
|
823
|
-
}
|
|
824
|
-
if (status[0].status === "failed") {
|
|
825
|
-
setupFailedMessage = status[0].error?.message || "Unknown error";
|
|
826
|
-
break;
|
|
827
|
-
}
|
|
828
|
-
if (Date.now() - start > setupTimeoutMs) {
|
|
829
|
-
setupFailedMessage = "Timed out while waiting for setup generation";
|
|
830
|
-
break;
|
|
831
|
-
}
|
|
832
|
-
await new Promise((r) => setTimeout(r, pollInterval));
|
|
833
|
-
}
|
|
834
|
-
console.log(setupCompleted ? "Setup successfully completed" : `Setup ${setupFailedMessage ? "failed" : "timed out"} \u2014 proceeding without setup${setupFailedMessage ? ` (${setupFailedMessage})` : ""}`);
|
|
835
|
-
}
|
|
836
|
-
return !0;
|
|
837
|
-
}
|
|
838
|
-
async function createJobs(uploadResult, localeIds, secrets) {
|
|
839
|
-
return overrideConfig(secrets), await gt.enqueueFiles(uploadResult.uploadedFiles, {
|
|
840
|
-
sourceLocale: gt.sourceLocale || internal.libraryDefaultLocale,
|
|
841
|
-
targetLocales: localeIds
|
|
842
|
-
});
|
|
843
|
-
}
|
|
844
|
-
async function downloadTranslations(files, secrets, maxRetries = 3, retryDelay = 1e3) {
|
|
845
|
-
overrideConfig(secrets);
|
|
846
|
-
let retries = 0;
|
|
847
|
-
for (; retries <= maxRetries; )
|
|
848
|
-
try {
|
|
849
|
-
return (await gt.downloadFileBatch(
|
|
850
|
-
files.map((file) => ({
|
|
851
|
-
fileId: file.fileId,
|
|
852
|
-
branchId: file.branchId,
|
|
853
|
-
versionId: file.versionId,
|
|
854
|
-
locale: file.locale
|
|
855
|
-
}))
|
|
856
|
-
)).files || [];
|
|
857
|
-
} catch {
|
|
858
|
-
retries++, await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
859
|
-
}
|
|
860
|
-
return [];
|
|
861
|
-
}
|
|
862
|
-
async function checkTranslationStatus(fileQueryData, downloadStatus, secrets) {
|
|
863
|
-
overrideConfig(secrets);
|
|
864
|
-
try {
|
|
865
|
-
const currentQueryData = fileQueryData.filter((item) => {
|
|
866
|
-
const statusKey = createTranslationStatusKey(
|
|
867
|
-
item.branchId,
|
|
868
|
-
item.fileId,
|
|
869
|
-
item.versionId,
|
|
870
|
-
item.locale
|
|
871
|
-
), stableKey = createStableTranslationKey(
|
|
872
|
-
item.branchId,
|
|
873
|
-
item.fileId,
|
|
874
|
-
item.locale
|
|
875
|
-
);
|
|
876
|
-
return !downloadStatus.downloaded.has(statusKey) && !downloadStatus.downloaded.has(stableKey) && !downloadStatus.failed.has(statusKey) && !downloadStatus.failed.has(stableKey) && !downloadStatus.skipped.has(statusKey) && !downloadStatus.skipped.has(stableKey);
|
|
877
|
-
});
|
|
878
|
-
return currentQueryData.length === 0 ? !0 : ((await gt.queryFileData({
|
|
879
|
-
translatedFiles: currentQueryData
|
|
880
|
-
})).translatedFiles || []).filter(
|
|
881
|
-
(translation) => translation.completedAt
|
|
882
|
-
);
|
|
883
|
-
} catch (error) {
|
|
884
|
-
return console.error("Error checking translation status", error), [];
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
const findLatestDraft = (documentId, client) => {
|
|
888
|
-
const publishedId = getPublishedId(documentId), query = "*[_id == $id || _id == $draftId]", params = { id: publishedId, draftId: `drafts.${publishedId}` };
|
|
889
|
-
return client.fetch(query, params).then(
|
|
890
|
-
(docs) => docs.find((doc) => doc._id.startsWith("drafts.")) ?? docs[0]
|
|
891
|
-
);
|
|
892
|
-
}, findDocumentAtRevision = async (documentId, rev, client) => {
|
|
893
|
-
const baseUrl = `/data/history/${client.config().dataset}/documents/${documentId}?revision=${rev}`, url = client.getUrl(baseUrl);
|
|
894
|
-
return await fetch(url, { credentials: "include" }).then((req) => req.json()).then((req) => req.documents && req.documents.length ? req.documents[0] : null);
|
|
895
|
-
};
|
|
896
|
-
function randomKey() {
|
|
897
|
-
return Math.random().toString(36).slice(2, 10);
|
|
898
|
-
}
|
|
899
|
-
async function createI18nDocAndPatchMetadata(sourceDocument, translatedDoc, localeId, client, translationMetadata, sourceDocumentId, languageField = "language") {
|
|
900
|
-
const publishedSourceDocumentId = getPublishedId(sourceDocumentId);
|
|
901
|
-
translatedDoc[languageField] = localeId;
|
|
902
|
-
const existingLocaleKey = translationMetadata.translations.find(
|
|
903
|
-
(translation) => translation.language === localeId
|
|
904
|
-
), operation = existingLocaleKey ? "replace" : "after", location = existingLocaleKey ? `translations[language == "${localeId}"]` : "translations[-1]", { _updatedAt, _createdAt, ...rest } = translatedDoc, appliedDocument = applyDocuments(
|
|
905
|
-
publishedSourceDocumentId,
|
|
906
|
-
sourceDocument,
|
|
907
|
-
rest,
|
|
908
|
-
pluginConfig.getIgnoreFields(),
|
|
909
|
-
pluginConfig.getSkipFields(),
|
|
910
|
-
pluginConfig.getDedupeFields(),
|
|
911
|
-
localeId
|
|
912
|
-
), isSingleton = pluginConfig.getSingletons().includes(publishedSourceDocumentId);
|
|
913
|
-
let createDocumentPromise;
|
|
914
|
-
if (isSingleton) {
|
|
915
|
-
const translatedDocId = pluginConfig.getSingletonMapping()(
|
|
916
|
-
publishedSourceDocumentId,
|
|
917
|
-
localeId
|
|
918
|
-
);
|
|
919
|
-
createDocumentPromise = client.create({
|
|
920
|
-
...appliedDocument,
|
|
921
|
-
_type: rest._type,
|
|
922
|
-
_id: `drafts.${translatedDocId}`
|
|
923
|
-
});
|
|
924
|
-
} else
|
|
925
|
-
createDocumentPromise = client.create({
|
|
926
|
-
...appliedDocument,
|
|
927
|
-
_type: rest._type,
|
|
928
|
-
_id: "drafts."
|
|
929
|
-
});
|
|
930
|
-
const doc = await createDocumentPromise, _ref = getPublishedId(doc._id);
|
|
931
|
-
await client.transaction().patch(
|
|
932
|
-
translationMetadata._id,
|
|
933
|
-
(p) => p.insert(operation, location, [
|
|
934
|
-
{
|
|
935
|
-
_key: randomKey(),
|
|
936
|
-
language: localeId,
|
|
937
|
-
_type: "internationalizedArrayReferenceValue",
|
|
938
|
-
value: {
|
|
939
|
-
_type: "reference",
|
|
940
|
-
_ref,
|
|
941
|
-
_weak: !0,
|
|
942
|
-
_strengthenOnPublish: {
|
|
943
|
-
type: doc._type
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
])
|
|
948
|
-
).commit();
|
|
949
|
-
}
|
|
950
|
-
const getOrCreateTranslationMetadata = async (documentId, baseDocument, client, baseLanguage) => {
|
|
951
|
-
const publishedId = getPublishedId(documentId), existingMetadata = await client.fetch(
|
|
952
|
-
`*[
|
|
953
|
-
_type == 'translation.metadata' &&
|
|
954
|
-
translations[language == $baseLanguage][0].value._ref == $id
|
|
955
|
-
][0]`,
|
|
956
|
-
{ baseLanguage, id: publishedId }
|
|
957
|
-
);
|
|
958
|
-
if (existingMetadata)
|
|
959
|
-
return existingMetadata;
|
|
960
|
-
const baseLangEntry = {
|
|
961
|
-
_key: randomKey(),
|
|
962
|
-
language: baseLanguage,
|
|
963
|
-
_type: "internationalizedArrayReferenceValue",
|
|
964
|
-
value: {
|
|
965
|
-
_type: "reference",
|
|
966
|
-
_ref: getPublishedId(baseDocument._id)
|
|
967
|
-
}
|
|
968
|
-
};
|
|
969
|
-
baseDocument._id.startsWith("drafts.") && (baseLangEntry.value = {
|
|
970
|
-
...baseLangEntry.value,
|
|
971
|
-
_weak: !0,
|
|
972
|
-
//this should reflect doc i18n config when this
|
|
973
|
-
//plugin is able to take that as a config option
|
|
974
|
-
_strengthenOnPublish: {
|
|
975
|
-
type: baseDocument._type
|
|
1189
|
+
}
|
|
1190
|
+
if (status[0].status === "failed") {
|
|
1191
|
+
setupFailedMessage = status[0].error?.message || "Unknown error";
|
|
1192
|
+
break;
|
|
1193
|
+
}
|
|
1194
|
+
if (Date.now() - start > setupTimeoutMs) {
|
|
1195
|
+
setupFailedMessage = "Timed out while waiting for setup generation";
|
|
1196
|
+
break;
|
|
1197
|
+
}
|
|
1198
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
976
1199
|
}
|
|
977
|
-
|
|
978
|
-
try {
|
|
979
|
-
return await client.createIfNotExists({
|
|
980
|
-
_id: `translation.metadata.${publishedId}`,
|
|
981
|
-
_type: "translation.metadata",
|
|
982
|
-
translations: [baseLangEntry]
|
|
983
|
-
});
|
|
984
|
-
} catch (error) {
|
|
985
|
-
const metadata = await client.fetch(
|
|
986
|
-
`*[
|
|
987
|
-
_type == 'translation.metadata' &&
|
|
988
|
-
translations[language == $baseLanguage][0].value._ref == $id
|
|
989
|
-
][0]`,
|
|
990
|
-
{ baseLanguage, id: publishedId }
|
|
991
|
-
);
|
|
992
|
-
if (metadata)
|
|
993
|
-
return metadata;
|
|
994
|
-
throw error;
|
|
1200
|
+
console.log(setupCompleted ? "Setup successfully completed" : `Setup ${setupFailedMessage ? "failed" : "timed out"} \u2014 proceeding without setup${setupFailedMessage ? ` (${setupFailedMessage})` : ""}`);
|
|
995
1201
|
}
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
});
|
|
1003
|
-
const cleanedSourceDocument = {};
|
|
1004
|
-
Object.entries(sourceDocument).forEach(([key, value]) => {
|
|
1005
|
-
isSystemField(key) || (cleanedSourceDocument[key] = value);
|
|
1202
|
+
return !0;
|
|
1203
|
+
}
|
|
1204
|
+
async function createJobs(uploadResult, localeIds, secrets) {
|
|
1205
|
+
return overrideConfig(secrets), await gt.enqueueFiles(uploadResult.uploadedFiles, {
|
|
1206
|
+
sourceLocale: gt.sourceLocale || internal.libraryDefaultLocale,
|
|
1207
|
+
targetLocales: localeIds
|
|
1006
1208
|
});
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1209
|
+
}
|
|
1210
|
+
async function downloadTranslations(files, secrets, maxRetries = 3, retryDelay = 1e3) {
|
|
1211
|
+
overrideConfig(secrets);
|
|
1212
|
+
let retries = 0;
|
|
1213
|
+
for (; retries <= maxRetries; )
|
|
1214
|
+
try {
|
|
1215
|
+
return (await gt.downloadFileBatch(
|
|
1216
|
+
files.map((file) => ({
|
|
1217
|
+
fileId: file.fileId,
|
|
1218
|
+
branchId: file.branchId,
|
|
1219
|
+
versionId: file.versionId,
|
|
1220
|
+
locale: file.locale
|
|
1221
|
+
}))
|
|
1222
|
+
)).files || [];
|
|
1223
|
+
} catch {
|
|
1224
|
+
retries++, await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
1020
1225
|
}
|
|
1021
|
-
|
|
1226
|
+
return [];
|
|
1022
1227
|
}
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
)).translations.find(
|
|
1037
|
-
(translation) => translation.language === localeId
|
|
1038
|
-
)?.value?._ref;
|
|
1039
|
-
i18nDocId && (i18nDoc = await findLatestDraft(i18nDocId, client)), mergeWithTargetLocale && i18nDoc ? baseDoc = i18nDoc : docInfo.documentId && docInfo.versionId && (baseDoc = await findDocumentAtRevision(
|
|
1040
|
-
docInfo.documentId,
|
|
1041
|
-
docInfo.versionId,
|
|
1042
|
-
client
|
|
1043
|
-
)), baseDoc || (baseDoc = await findLatestDraft(docInfo.documentId, client));
|
|
1044
|
-
const merged = BaseDocumentMerger.documentLevelMerge(
|
|
1045
|
-
translatedFields,
|
|
1046
|
-
baseDoc
|
|
1047
|
-
);
|
|
1048
|
-
if (i18nDoc)
|
|
1049
|
-
await patchI18nDoc(
|
|
1050
|
-
docInfo.documentId,
|
|
1051
|
-
i18nDoc._id,
|
|
1052
|
-
baseDoc,
|
|
1053
|
-
merged,
|
|
1054
|
-
translatedFields,
|
|
1055
|
-
client,
|
|
1056
|
-
i18nDoc
|
|
1057
|
-
);
|
|
1058
|
-
else {
|
|
1059
|
-
const freshTranslationMetadata = await getOrCreateTranslationMetadata(
|
|
1060
|
-
docInfo.documentId,
|
|
1061
|
-
baseDoc,
|
|
1062
|
-
client,
|
|
1063
|
-
baseLanguage
|
|
1064
|
-
), freshI18nDocId = freshTranslationMetadata.translations.find(
|
|
1065
|
-
(translation) => translation.language === localeId
|
|
1066
|
-
)?.value?._ref;
|
|
1067
|
-
if (freshI18nDocId) {
|
|
1068
|
-
const freshI18nDoc = await findLatestDraft(freshI18nDocId, client);
|
|
1069
|
-
await patchI18nDoc(
|
|
1070
|
-
docInfo.documentId,
|
|
1071
|
-
freshI18nDoc._id,
|
|
1072
|
-
baseDoc,
|
|
1073
|
-
merged,
|
|
1074
|
-
translatedFields,
|
|
1075
|
-
client,
|
|
1076
|
-
freshI18nDoc
|
|
1228
|
+
async function checkTranslationStatus(fileQueryData, downloadStatus, secrets) {
|
|
1229
|
+
overrideConfig(secrets);
|
|
1230
|
+
try {
|
|
1231
|
+
const currentQueryData = fileQueryData.filter((item) => {
|
|
1232
|
+
const statusKey = createTranslationStatusKey(
|
|
1233
|
+
item.branchId,
|
|
1234
|
+
item.fileId,
|
|
1235
|
+
item.versionId,
|
|
1236
|
+
item.locale
|
|
1237
|
+
), stableKey = createStableTranslationKey(
|
|
1238
|
+
item.branchId,
|
|
1239
|
+
item.fileId,
|
|
1240
|
+
item.locale
|
|
1077
1241
|
);
|
|
1078
|
-
return;
|
|
1079
|
-
}
|
|
1080
|
-
await
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
client,
|
|
1085
|
-
freshTranslationMetadata,
|
|
1086
|
-
docInfo.documentId,
|
|
1087
|
-
languageField
|
|
1242
|
+
return !downloadStatus.downloaded.has(statusKey) && !downloadStatus.downloaded.has(stableKey) && !downloadStatus.failed.has(statusKey) && !downloadStatus.failed.has(stableKey) && !downloadStatus.skipped.has(statusKey) && !downloadStatus.skipped.has(stableKey);
|
|
1243
|
+
});
|
|
1244
|
+
return currentQueryData.length === 0 ? !0 : ((await gt.queryFileData({
|
|
1245
|
+
translatedFiles: currentQueryData
|
|
1246
|
+
})).translatedFiles || []).filter(
|
|
1247
|
+
(translation) => translation.completedAt
|
|
1088
1248
|
);
|
|
1249
|
+
} catch (error) {
|
|
1250
|
+
return console.error("Error checking translation status", error), [];
|
|
1089
1251
|
}
|
|
1090
|
-
}
|
|
1252
|
+
}
|
|
1091
1253
|
async function importDocument(docInfo, localeId, document2, context, mergeWithTargetLocale = !1) {
|
|
1092
1254
|
const { client } = context, deserialized = deserializeDocument(document2);
|
|
1093
|
-
return
|
|
1255
|
+
return getTranslationStrategyForType(
|
|
1256
|
+
deserialized._type
|
|
1257
|
+
).patch(
|
|
1094
1258
|
docInfo,
|
|
1095
|
-
// versionId is not used here, since we just use the _rev id in the deserialized HTML itself
|
|
1096
1259
|
deserialized,
|
|
1097
1260
|
localeId,
|
|
1098
1261
|
client,
|
|
1099
|
-
pluginConfig.getLanguageField(),
|
|
1100
1262
|
mergeWithTargetLocale
|
|
1101
1263
|
);
|
|
1102
1264
|
}
|
|
@@ -1224,11 +1386,13 @@ async function processImportBatch(items, options = {}) {
|
|
|
1224
1386
|
), item.key),
|
|
1225
1387
|
{
|
|
1226
1388
|
...options,
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1389
|
+
// Serialize all locales of the same document when imports may patch the
|
|
1390
|
+
// source document in place: internationalized-array imports do a
|
|
1391
|
+
// read-merge-set, so concurrent locale imports would clobber each other
|
|
1392
|
+
// (last write wins). Document-level imports write to separate per-locale
|
|
1393
|
+
// documents and stay parallel. In 'mixed' mode the per-document strategy
|
|
1394
|
+
// is only known after deserialization, so serialize conservatively.
|
|
1395
|
+
getConcurrencyKey: (item) => pluginConfig.getTranslationLevel() === "document" ? void 0 : getPublishedId(item.docInfo.documentId),
|
|
1232
1396
|
onItemSuccess: (item, key) => {
|
|
1233
1397
|
successfulImports.push(key), options.onItemSuccess?.(item, key);
|
|
1234
1398
|
},
|
|
@@ -1324,7 +1488,34 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
|
|
|
1324
1488
|
localeId: locale,
|
|
1325
1489
|
description: gt.getLocaleProperties(locale).name,
|
|
1326
1490
|
enabled: !0
|
|
1327
|
-
})), TranslationsContext = o.createContext(null),
|
|
1491
|
+
})), TranslationsContext = o.createContext(null), getUploadedVersionsStorageKey = (projectId, dataset) => `gt-sanity:uploadedVersions:${projectId ?? ""}:${dataset ?? ""}`;
|
|
1492
|
+
function readUploadedVersions(storageKey) {
|
|
1493
|
+
try {
|
|
1494
|
+
const raw = window.sessionStorage.getItem(storageKey);
|
|
1495
|
+
if (!raw) return /* @__PURE__ */ new Map();
|
|
1496
|
+
const parsed = JSON.parse(raw);
|
|
1497
|
+
return isPlainRecord(parsed) ? new Map(
|
|
1498
|
+
Object.entries(parsed).filter(
|
|
1499
|
+
(entry) => typeof entry[1] == "string"
|
|
1500
|
+
)
|
|
1501
|
+
) : /* @__PURE__ */ new Map();
|
|
1502
|
+
} catch {
|
|
1503
|
+
return /* @__PURE__ */ new Map();
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
function writeUploadedVersions(storageKey, versions) {
|
|
1507
|
+
try {
|
|
1508
|
+
window.sessionStorage.setItem(
|
|
1509
|
+
storageKey,
|
|
1510
|
+
JSON.stringify(Object.fromEntries(versions))
|
|
1511
|
+
);
|
|
1512
|
+
} catch {
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
function isPlainRecord(value) {
|
|
1516
|
+
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
1517
|
+
}
|
|
1518
|
+
const useTranslations = () => {
|
|
1328
1519
|
const context = o.useContext(TranslationsContext);
|
|
1329
1520
|
if (!context)
|
|
1330
1521
|
throw new Error("useTranslations must be used within TranslationsProvider");
|
|
@@ -1345,13 +1536,21 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
|
|
|
1345
1536
|
downloaded: /* @__PURE__ */ new Set(),
|
|
1346
1537
|
failed: /* @__PURE__ */ new Set(),
|
|
1347
1538
|
skipped: /* @__PURE__ */ new Set()
|
|
1348
|
-
}), downloadStatusRef = o.useRef(downloadStatus), [translationStatuses, setTranslationStatuses] = o.useState(/* @__PURE__ */ new Map()), [isRefreshing, setIsRefreshing] = o.useState(!1), client = useClient(),
|
|
1539
|
+
}), downloadStatusRef = o.useRef(downloadStatus), [translationStatuses, setTranslationStatuses] = o.useState(/* @__PURE__ */ new Map()), [isRefreshing, setIsRefreshing] = o.useState(!1), client = useClient(), { projectId, dataset } = client.config(), uploadedVersionsStorageKey = getUploadedVersionsStorageKey(
|
|
1540
|
+
projectId,
|
|
1541
|
+
dataset
|
|
1542
|
+
), [uploadedVersions, setUploadedVersions] = o.useState(
|
|
1543
|
+
() => readUploadedVersions(uploadedVersionsStorageKey)
|
|
1544
|
+
), schema2 = sanity.useSchema(), translationContext = { client, schema: schema2 }, toast = ui.useToast(), { loading: loadingSecrets, secrets } = useSecrets(
|
|
1349
1545
|
pluginConfig.getSecretsNamespace()
|
|
1350
1546
|
), [branchId, setBranchId] = o.useState(void 0);
|
|
1351
1547
|
o.useEffect(() => {
|
|
1352
1548
|
downloadStatusRef.current = downloadStatus;
|
|
1353
1549
|
}, [downloadStatus]);
|
|
1354
|
-
const
|
|
1550
|
+
const getVersionId = o.useCallback(
|
|
1551
|
+
(document2) => uploadedVersions.get(getDocumentPublishedId(document2)) ?? document2._rev,
|
|
1552
|
+
[uploadedVersions]
|
|
1553
|
+
), fetchDocuments = o.useCallback(async () => {
|
|
1355
1554
|
setLoadingDocuments(!0);
|
|
1356
1555
|
try {
|
|
1357
1556
|
if (singleDocument) {
|
|
@@ -1423,7 +1622,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
|
|
|
1423
1622
|
const availableLocaleIds = locales.filter((locale) => locale.enabled !== !1).map((locale) => locale.localeId), transformedDocuments = documents.map((doc) => {
|
|
1424
1623
|
const { [pluginConfig.getLanguageField()]: _2, ...cleanDoc } = doc, baseLanguage = pluginConfig.getSourceLocale();
|
|
1425
1624
|
try {
|
|
1426
|
-
const serialized =
|
|
1625
|
+
const serialized = getTranslationStrategy(doc).serialize(
|
|
1427
1626
|
cleanDoc,
|
|
1428
1627
|
schema2,
|
|
1429
1628
|
baseLanguage
|
|
@@ -1440,7 +1639,11 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
|
|
|
1440
1639
|
}
|
|
1441
1640
|
return null;
|
|
1442
1641
|
}).filter((doc) => doc !== null), uploadResult = await uploadFiles(transformedDocuments, secrets);
|
|
1443
|
-
await initProject(uploadResult, { timeout: 600 }, secrets), await createJobs(uploadResult, availableLocaleIds, secrets)
|
|
1642
|
+
await initProject(uploadResult, { timeout: 600 }, secrets), await createJobs(uploadResult, availableLocaleIds, secrets);
|
|
1643
|
+
const nextUploadedVersions = new Map(uploadedVersions);
|
|
1644
|
+
for (const { info } of transformedDocuments)
|
|
1645
|
+
info.versionId && nextUploadedVersions.set(info.documentId, info.versionId);
|
|
1646
|
+
writeUploadedVersions(uploadedVersionsStorageKey, nextUploadedVersions), setUploadedVersions(nextUploadedVersions), toast.push({
|
|
1444
1647
|
title: `Translation tasks created for ${documents.length} documents`,
|
|
1445
1648
|
status: "success",
|
|
1446
1649
|
closable: !0
|
|
@@ -1455,7 +1658,14 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
|
|
|
1455
1658
|
setIsBusy(!1);
|
|
1456
1659
|
}
|
|
1457
1660
|
}
|
|
1458
|
-
}, [
|
|
1661
|
+
}, [
|
|
1662
|
+
secrets,
|
|
1663
|
+
documents,
|
|
1664
|
+
locales,
|
|
1665
|
+
schema2,
|
|
1666
|
+
uploadedVersions,
|
|
1667
|
+
uploadedVersionsStorageKey
|
|
1668
|
+
]), handleImportAll = o.useCallback(async () => {
|
|
1459
1669
|
if (!(!secrets || documents.length === 0 || !branchId)) {
|
|
1460
1670
|
setIsBusy(!0);
|
|
1461
1671
|
try {
|
|
@@ -1641,7 +1851,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
|
|
|
1641
1851
|
for (const localeId of availableLocaleIds) {
|
|
1642
1852
|
const documentId = getDocumentPublishedId(doc);
|
|
1643
1853
|
fileQueryData.push({
|
|
1644
|
-
versionId: doc
|
|
1854
|
+
versionId: getVersionId(doc),
|
|
1645
1855
|
fileId: documentId,
|
|
1646
1856
|
branchId,
|
|
1647
1857
|
locale: localeId
|
|
@@ -1656,7 +1866,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
|
|
|
1656
1866
|
const newStatuses = /* @__PURE__ */ new Map();
|
|
1657
1867
|
for (const doc of documents)
|
|
1658
1868
|
for (const localeId of availableLocaleIds) {
|
|
1659
|
-
const documentId = getDocumentPublishedId(doc), versionId = doc
|
|
1869
|
+
const documentId = getDocumentPublishedId(doc), versionId = getVersionId(doc), key = createTranslationStatusKey(
|
|
1660
1870
|
branchId,
|
|
1661
1871
|
documentId,
|
|
1662
1872
|
versionId,
|
|
@@ -1699,7 +1909,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
|
|
|
1699
1909
|
setIsRefreshing(!1);
|
|
1700
1910
|
}
|
|
1701
1911
|
}
|
|
1702
|
-
}, [secrets, documents, locales, branchId]), handleImportDocument = o.useCallback(
|
|
1912
|
+
}, [secrets, documents, locales, branchId, getVersionId]), handleImportDocument = o.useCallback(
|
|
1703
1913
|
async (documentId, versionId, localeId) => {
|
|
1704
1914
|
if (!secrets) return;
|
|
1705
1915
|
const key = createTranslationStatusKey(
|
|
@@ -1961,6 +2171,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
|
|
|
1961
2171
|
loadingSecrets,
|
|
1962
2172
|
secrets,
|
|
1963
2173
|
branchId,
|
|
2174
|
+
getVersionId,
|
|
1964
2175
|
// Actions
|
|
1965
2176
|
setLocales,
|
|
1966
2177
|
setAutoRefresh,
|
|
@@ -3247,7 +3458,8 @@ const WrapText = dt(ui.Box)`
|
|
|
3247
3458
|
autoPatchReferences,
|
|
3248
3459
|
setAutoPatchReferences,
|
|
3249
3460
|
autoPublish,
|
|
3250
|
-
setAutoPublish
|
|
3461
|
+
setAutoPublish,
|
|
3462
|
+
getVersionId
|
|
3251
3463
|
} = useTranslations(), [isImporting, setIsImporting] = o.useState(!1), [isPublishing, setIsPublishing] = o.useState(!1), toast = ui.useToast(), document2 = documents[0], currentDocumentLanguage = o.useMemo(() => {
|
|
3252
3464
|
if (!document2) return null;
|
|
3253
3465
|
const languageField = pluginConfig.getLanguageField();
|
|
@@ -3257,15 +3469,15 @@ const WrapText = dt(ui.Box)`
|
|
|
3257
3469
|
return locales.filter(
|
|
3258
3470
|
(locale) => locale.enabled !== !1 && locale.localeId !== sourceLocale
|
|
3259
3471
|
);
|
|
3260
|
-
}, [locales]), documentId = o.useMemo(() => document2 ? getDocumentPublishedId(document2) : null, [document2]), handleImportTranslations = o.useCallback(
|
|
3472
|
+
}, [locales]), documentId = o.useMemo(() => document2 ? getDocumentPublishedId(document2) : null, [document2]), versionId = o.useMemo(() => document2 ? getVersionId(document2) : null, [document2, getVersionId]), handleImportTranslations = o.useCallback(
|
|
3261
3473
|
async (options = {}) => {
|
|
3262
3474
|
const { autoOnly = !1 } = options;
|
|
3263
|
-
if (isImporting || !documentId || autoOnly && !autoImport) return;
|
|
3475
|
+
if (isImporting || !documentId || !versionId || autoOnly && !autoImport) return;
|
|
3264
3476
|
const readyTranslations = availableLocales.filter((locale) => {
|
|
3265
3477
|
const key = createTranslationStatusKey(
|
|
3266
3478
|
branchId,
|
|
3267
3479
|
documentId,
|
|
3268
|
-
|
|
3480
|
+
versionId,
|
|
3269
3481
|
locale.localeId
|
|
3270
3482
|
);
|
|
3271
3483
|
return translationStatuses.get(key)?.isReady && !importedTranslations.has(key);
|
|
@@ -3273,11 +3485,9 @@ const WrapText = dt(ui.Box)`
|
|
|
3273
3485
|
if (readyTranslations.length !== 0) {
|
|
3274
3486
|
setIsImporting(!0);
|
|
3275
3487
|
try {
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
)
|
|
3280
|
-
), autoPatchReferences && await handlePatchDocumentReferences(), autoPublish && await handlePublishAllTranslations();
|
|
3488
|
+
for (const locale of readyTranslations)
|
|
3489
|
+
await handleImportDocument(documentId, versionId, locale.localeId);
|
|
3490
|
+
autoPatchReferences && await handlePatchDocumentReferences(), autoPublish && await handlePublishAllTranslations();
|
|
3281
3491
|
} finally {
|
|
3282
3492
|
setIsImporting(!1);
|
|
3283
3493
|
}
|
|
@@ -3287,6 +3497,7 @@ const WrapText = dt(ui.Box)`
|
|
|
3287
3497
|
autoImport,
|
|
3288
3498
|
isImporting,
|
|
3289
3499
|
documentId,
|
|
3500
|
+
versionId,
|
|
3290
3501
|
availableLocales,
|
|
3291
3502
|
translationStatuses,
|
|
3292
3503
|
importedTranslations,
|
|
@@ -3361,7 +3572,7 @@ const WrapText = dt(ui.Box)`
|
|
|
3361
3572
|
}
|
|
3362
3573
|
)
|
|
3363
3574
|
] }),
|
|
3364
|
-
documentId && availableLocales.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 4, children: [
|
|
3575
|
+
documentId && versionId && availableLocales.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 4, children: [
|
|
3365
3576
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", justify: "space-between", children: [
|
|
3366
3577
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "h2", weight: "semibold", size: 2, children: "Translation Status" }),
|
|
3367
3578
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 3, align: "center", children: [
|
|
@@ -3391,7 +3602,7 @@ const WrapText = dt(ui.Box)`
|
|
|
3391
3602
|
const key = createTranslationStatusKey(
|
|
3392
3603
|
branchId,
|
|
3393
3604
|
documentId,
|
|
3394
|
-
|
|
3605
|
+
versionId,
|
|
3395
3606
|
locale.localeId
|
|
3396
3607
|
), status = translationStatuses.get(key), progress = status?.progress || 0, isImported = importedTranslations.has(key);
|
|
3397
3608
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3403,7 +3614,7 @@ const WrapText = dt(ui.Box)`
|
|
|
3403
3614
|
importFile: async () => {
|
|
3404
3615
|
!isImported && status?.isReady && await handleImportDocument(
|
|
3405
3616
|
documentId,
|
|
3406
|
-
|
|
3617
|
+
versionId,
|
|
3407
3618
|
locale.localeId
|
|
3408
3619
|
);
|
|
3409
3620
|
}
|
|
@@ -3426,7 +3637,7 @@ const WrapText = dt(ui.Box)`
|
|
|
3426
3637
|
const key = createTranslationStatusKey(
|
|
3427
3638
|
branchId,
|
|
3428
3639
|
documentId,
|
|
3429
|
-
|
|
3640
|
+
versionId,
|
|
3430
3641
|
locale.localeId
|
|
3431
3642
|
);
|
|
3432
3643
|
return !translationStatuses.get(key)?.isReady || importedTranslations.has(key);
|
|
@@ -3453,7 +3664,7 @@ const WrapText = dt(ui.Box)`
|
|
|
3453
3664
|
const key = createTranslationStatusKey(
|
|
3454
3665
|
branchId,
|
|
3455
3666
|
documentId,
|
|
3456
|
-
|
|
3667
|
+
versionId,
|
|
3457
3668
|
locale.localeId
|
|
3458
3669
|
);
|
|
3459
3670
|
return importedTranslations.has(key);
|
|
@@ -3463,7 +3674,7 @@ const WrapText = dt(ui.Box)`
|
|
|
3463
3674
|
const key = createTranslationStatusKey(
|
|
3464
3675
|
branchId,
|
|
3465
3676
|
documentId,
|
|
3466
|
-
|
|
3677
|
+
versionId,
|
|
3467
3678
|
locale.localeId
|
|
3468
3679
|
);
|
|
3469
3680
|
return translationStatuses.get(key)?.isReady;
|
|
@@ -3551,9 +3762,6 @@ const WrapText = dt(ui.Box)`
|
|
|
3551
3762
|
/* @__PURE__ */ jsxRuntime.jsx("code", { children: pluginConfig.getSourceLocale() }),
|
|
3552
3763
|
" documents."
|
|
3553
3764
|
] }) });
|
|
3554
|
-
}, TranslationTab = (props) => {
|
|
3555
|
-
const { displayed } = props.document;
|
|
3556
|
-
return /* @__PURE__ */ jsxRuntime.jsx(BaseTranslationWrapper, { showContainer: !1, children: /* @__PURE__ */ jsxRuntime.jsx(TranslationsProvider, { singleDocument: displayed, children: /* @__PURE__ */ jsxRuntime.jsx(TranslationView, {}) }) });
|
|
3557
3765
|
}, translateAction = (props) => {
|
|
3558
3766
|
const [dialogOpen, setDialogOpen] = o.useState(!1), document2 = props.draft || props.published;
|
|
3559
3767
|
return {
|
|
@@ -3568,7 +3776,228 @@ const WrapText = dt(ui.Box)`
|
|
|
3568
3776
|
content: /* @__PURE__ */ jsxRuntime.jsx(BaseTranslationWrapper, { showContainer: !1, children: /* @__PURE__ */ jsxRuntime.jsx(TranslationsProvider, { singleDocument: document2, children: /* @__PURE__ */ jsxRuntime.jsx(TranslationView, {}) }) })
|
|
3569
3777
|
} : null
|
|
3570
3778
|
};
|
|
3571
|
-
}
|
|
3779
|
+
};
|
|
3780
|
+
function readGTOptions(schemaType) {
|
|
3781
|
+
return schemaType?.options?.gtInternationalizedArray;
|
|
3782
|
+
}
|
|
3783
|
+
function toneFromValidation(validation) {
|
|
3784
|
+
if (validation?.length) {
|
|
3785
|
+
if (validation.some((marker) => marker.level === "error")) return "critical";
|
|
3786
|
+
if (validation.some((marker) => marker.level === "warning")) return "caution";
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
function RemoveLocaleButton(props) {
|
|
3790
|
+
const { isSource, readOnly, onRemove } = props, button = (
|
|
3791
|
+
// The span keeps the tooltip working when the button is disabled
|
|
3792
|
+
// (disabled buttons don't emit pointer events).
|
|
3793
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { paddingBottom: "2px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3794
|
+
ui.Button,
|
|
3795
|
+
{
|
|
3796
|
+
mode: "bleed",
|
|
3797
|
+
icon: icons.RemoveCircleIcon,
|
|
3798
|
+
tone: "critical",
|
|
3799
|
+
disabled: readOnly || isSource,
|
|
3800
|
+
onClick: onRemove
|
|
3801
|
+
}
|
|
3802
|
+
) })
|
|
3803
|
+
);
|
|
3804
|
+
return isSource ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3805
|
+
ui.Tooltip,
|
|
3806
|
+
{
|
|
3807
|
+
animate: !0,
|
|
3808
|
+
portal: !0,
|
|
3809
|
+
placement: "top",
|
|
3810
|
+
fallbackPlacements: ["right", "left"],
|
|
3811
|
+
content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: "Can't remove the source language" }),
|
|
3812
|
+
children: button
|
|
3813
|
+
}
|
|
3814
|
+
) : button;
|
|
3815
|
+
}
|
|
3816
|
+
function InternationalizedValueItem(props) {
|
|
3817
|
+
const { inputProps, parentSchemaType, schemaType, validation } = props, value = props.value, { onChange } = inputProps, gtOptions = readGTOptions(schemaType) ?? readGTOptions(parentSchemaType), language = value?.language, languageLabel = language ? gtOptions?.titles?.[language] ?? language : "Unknown language", isSource = !!language && language === gtOptions?.sourceLocale, wrappedOnChange = o.useCallback(
|
|
3818
|
+
(patch) => {
|
|
3819
|
+
if (!Array.isArray(patch)) {
|
|
3820
|
+
onChange(patch);
|
|
3821
|
+
return;
|
|
3822
|
+
}
|
|
3823
|
+
const currentValue = value?.value;
|
|
3824
|
+
if (!((currentValue == null || Array.isArray(currentValue) && currentValue.length === 0) && patch.some(
|
|
3825
|
+
(p) => p.type === "insert" && Array.isArray(p.path) && p.path.length > 0 && (p.path[0] === "value" || typeof p.path[0] == "number")
|
|
3826
|
+
))) {
|
|
3827
|
+
onChange(patch);
|
|
3828
|
+
return;
|
|
3829
|
+
}
|
|
3830
|
+
const rerooted = patch.map(
|
|
3831
|
+
(p) => p.type === "insert" && Array.isArray(p.path) && p.path[0] !== "value" ? { ...p, path: ["value", ...p.path] } : p
|
|
3832
|
+
);
|
|
3833
|
+
onChange(
|
|
3834
|
+
currentValue === void 0 ? [sanity.setIfMissing([], ["value"]), ...rerooted] : rerooted
|
|
3835
|
+
);
|
|
3836
|
+
},
|
|
3837
|
+
[onChange, value?.value]
|
|
3838
|
+
), members = o.useMemo(
|
|
3839
|
+
() => inputProps.members.filter(
|
|
3840
|
+
(member) => member.kind === "field" && member.name === "value"
|
|
3841
|
+
).map((member) => ({
|
|
3842
|
+
...member,
|
|
3843
|
+
field: {
|
|
3844
|
+
...member.field,
|
|
3845
|
+
schemaType: {
|
|
3846
|
+
...member.field.schemaType,
|
|
3847
|
+
title: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { muted: !0, size: 1, children: languageLabel })
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
})),
|
|
3851
|
+
[inputProps.members, languageLabel]
|
|
3852
|
+
), handleRemove = o.useCallback(() => {
|
|
3853
|
+
onChange(sanity.unset());
|
|
3854
|
+
}, [onChange]);
|
|
3855
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { paddingTop: 2, tone: toneFromValidation(validation), children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "flex-end", gap: 2, children: [
|
|
3856
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, children: inputProps.renderInput({
|
|
3857
|
+
...inputProps,
|
|
3858
|
+
members,
|
|
3859
|
+
onChange: wrappedOnChange
|
|
3860
|
+
// renderInput's parameter is typed as the base InputProps, which
|
|
3861
|
+
// doesn't know about object members.
|
|
3862
|
+
}) }),
|
|
3863
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3864
|
+
RemoveLocaleButton,
|
|
3865
|
+
{
|
|
3866
|
+
isSource,
|
|
3867
|
+
readOnly: !!inputProps.readOnly,
|
|
3868
|
+
onRemove: handleRemove
|
|
3869
|
+
}
|
|
3870
|
+
)
|
|
3871
|
+
] }) });
|
|
3872
|
+
}
|
|
3873
|
+
function InternationalizedArrayInput(props) {
|
|
3874
|
+
const { members, schemaType, value, readOnly, onItemAppend } = props, gtOptions = readGTOptions(schemaType), itemType = schemaType.of[0]?.name, handleAdd = o.useCallback(
|
|
3875
|
+
(language) => {
|
|
3876
|
+
const item = { _key: randomKey(), _type: itemType, language };
|
|
3877
|
+
onItemAppend(item);
|
|
3878
|
+
},
|
|
3879
|
+
[onItemAppend, itemType]
|
|
3880
|
+
);
|
|
3881
|
+
if (!gtOptions)
|
|
3882
|
+
return props.renderDefault(props);
|
|
3883
|
+
const allLocales = [gtOptions.sourceLocale, ...gtOptions.locales], existing = new Set(
|
|
3884
|
+
(value ?? []).map((item) => item.language).filter(Boolean)
|
|
3885
|
+
), missing = allLocales.filter((locale) => !existing.has(locale));
|
|
3886
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
3887
|
+
members.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 2, children: members.map(
|
|
3888
|
+
(member) => member.kind === "item" ? /* @__PURE__ */ jsxRuntime.jsx(sanity.ArrayOfObjectsItem, { ...props, member }, member.key) : /* @__PURE__ */ jsxRuntime.jsx(sanity.MemberItemError, { member }, member.key)
|
|
3889
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { border: !0, tone: "transparent", padding: 3, radius: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, muted: !0, children: "This internationalized field currently has no translations." }) }),
|
|
3890
|
+
!readOnly && missing.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Grid, { columns: Math.min(missing.length, 4), gap: 1, children: missing.map((locale) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3891
|
+
ui.Button,
|
|
3892
|
+
{
|
|
3893
|
+
icon: icons.AddIcon,
|
|
3894
|
+
mode: "ghost",
|
|
3895
|
+
text: gtOptions.titles?.[locale] ?? locale,
|
|
3896
|
+
onClick: () => handleAdd(locale)
|
|
3897
|
+
},
|
|
3898
|
+
locale
|
|
3899
|
+
)) }) : null
|
|
3900
|
+
] });
|
|
3901
|
+
}
|
|
3902
|
+
const DEFAULT_TYPE_PREFIX = "internationalizedArray";
|
|
3903
|
+
function resolveComponents(overrides) {
|
|
3904
|
+
const input = overrides?.input === !1 ? void 0 : overrides?.input ?? InternationalizedArrayInput, item = overrides?.item === !1 ? void 0 : overrides?.item ?? InternationalizedValueItem, defaultField = input === InternationalizedArrayInput ? (
|
|
3905
|
+
// Reset the field level so inline per-locale inputs don't inherit
|
|
3906
|
+
// nested-object indentation.
|
|
3907
|
+
((fieldProps) => fieldProps.renderDefault({ ...fieldProps, level: 0 }))
|
|
3908
|
+
) : void 0, field = overrides?.field === !1 ? void 0 : overrides?.field ?? defaultField;
|
|
3909
|
+
return { input, item, field };
|
|
3910
|
+
}
|
|
3911
|
+
function capitalize(value) {
|
|
3912
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
3913
|
+
}
|
|
3914
|
+
function fieldTypeName(fieldType) {
|
|
3915
|
+
return typeof fieldType == "string" ? fieldType : fieldType.name;
|
|
3916
|
+
}
|
|
3917
|
+
function valueField(fieldType) {
|
|
3918
|
+
if (fieldType === "string" || fieldType === "text")
|
|
3919
|
+
return { name: "value", type: fieldType, title: "Value" };
|
|
3920
|
+
if (fieldType === "block")
|
|
3921
|
+
return {
|
|
3922
|
+
name: "value",
|
|
3923
|
+
type: "array",
|
|
3924
|
+
title: "Value",
|
|
3925
|
+
of: [{ type: "block" }]
|
|
3926
|
+
};
|
|
3927
|
+
const { name: _name, ...rest } = fieldType;
|
|
3928
|
+
return { name: "value", title: "Value", ...rest };
|
|
3929
|
+
}
|
|
3930
|
+
function makeLanguageTitle(options) {
|
|
3931
|
+
const { languageTitles, getLanguageTitle, sourceLocale } = options;
|
|
3932
|
+
return (locale) => getLanguageTitle?.(locale) ?? languageTitles?.[locale] ?? generaltranslation.getLocaleProperties(locale, sourceLocale).name ?? locale;
|
|
3933
|
+
}
|
|
3934
|
+
function buildTypesForPrefix(prefix2, options) {
|
|
3935
|
+
const { sourceLocale, locales, fieldTypes } = options, languageTitle = makeLanguageTitle(options), components = resolveComponents(options.components);
|
|
3936
|
+
return fieldTypes.map((fieldType) => {
|
|
3937
|
+
const typeName = `${prefix2}${capitalize(fieldTypeName(fieldType))}`, valueTypeName = `${typeName}Value`, gtInternationalizedArray = {
|
|
3938
|
+
sourceLocale,
|
|
3939
|
+
locales,
|
|
3940
|
+
titles: Object.fromEntries(
|
|
3941
|
+
[sourceLocale, ...locales].map((locale) => [
|
|
3942
|
+
locale,
|
|
3943
|
+
languageTitle(locale)
|
|
3944
|
+
])
|
|
3945
|
+
)
|
|
3946
|
+
}, valueObject = {
|
|
3947
|
+
type: "object",
|
|
3948
|
+
name: valueTypeName,
|
|
3949
|
+
...components.item ? { components: { item: components.item } } : {},
|
|
3950
|
+
fields: [
|
|
3951
|
+
{
|
|
3952
|
+
name: "language",
|
|
3953
|
+
type: "string",
|
|
3954
|
+
title: "Language",
|
|
3955
|
+
readOnly: !0,
|
|
3956
|
+
// GT's inline item shows the locale as the value field's label;
|
|
3957
|
+
// with a custom or detached item, keep the field visible so the
|
|
3958
|
+
// locale is still discoverable in default/dialog rendering.
|
|
3959
|
+
hidden: components.item === InternationalizedValueItem
|
|
3960
|
+
},
|
|
3961
|
+
valueField(fieldType)
|
|
3962
|
+
],
|
|
3963
|
+
options: { gtInternationalizedArray },
|
|
3964
|
+
preview: {
|
|
3965
|
+
select: { language: "language", value: "value" },
|
|
3966
|
+
prepare(selection) {
|
|
3967
|
+
const localeLabel = selection.language ? languageTitle(selection.language) : "Unknown";
|
|
3968
|
+
return {
|
|
3969
|
+
title: typeof selection.value == "string" ? selection.value : localeLabel,
|
|
3970
|
+
subtitle: localeLabel
|
|
3971
|
+
};
|
|
3972
|
+
}
|
|
3973
|
+
}
|
|
3974
|
+
}, arrayComponents = {
|
|
3975
|
+
...components.input ? { input: components.input } : {},
|
|
3976
|
+
...components.field ? { field: components.field } : {}
|
|
3977
|
+
};
|
|
3978
|
+
return {
|
|
3979
|
+
name: typeName,
|
|
3980
|
+
type: "array",
|
|
3981
|
+
...Object.keys(arrayComponents).length ? { components: arrayComponents } : {},
|
|
3982
|
+
of: [valueObject],
|
|
3983
|
+
options: { gtInternationalizedArray }
|
|
3984
|
+
};
|
|
3985
|
+
});
|
|
3986
|
+
}
|
|
3987
|
+
function createInternationalizedArrayTypes(options) {
|
|
3988
|
+
const prefix2 = options.typePrefix ?? DEFAULT_TYPE_PREFIX, includeCompatibilityTypes = options.includeCompatibilityTypes ?? !0, types = buildTypesForPrefix(prefix2, options);
|
|
3989
|
+
return includeCompatibilityTypes && prefix2 !== DEFAULT_TYPE_PREFIX && types.push(...buildTypesForPrefix(DEFAULT_TYPE_PREFIX, options)), types;
|
|
3990
|
+
}
|
|
3991
|
+
function resolveFieldLevelConfig(config) {
|
|
3992
|
+
return {
|
|
3993
|
+
enabled: !1,
|
|
3994
|
+
fieldTypes: ["string", "text"],
|
|
3995
|
+
typePrefix: DEFAULT_TYPE_PREFIX,
|
|
3996
|
+
includeCompatibilityTypes: !0,
|
|
3997
|
+
...config
|
|
3998
|
+
};
|
|
3999
|
+
}
|
|
4000
|
+
const TranslationsTable = () => {
|
|
3572
4001
|
const {
|
|
3573
4002
|
documents,
|
|
3574
4003
|
locales,
|
|
@@ -3577,7 +4006,8 @@ const WrapText = dt(ui.Box)`
|
|
|
3577
4006
|
downloadStatus,
|
|
3578
4007
|
importedTranslations,
|
|
3579
4008
|
handleImportDocument,
|
|
3580
|
-
branchId
|
|
4009
|
+
branchId,
|
|
4010
|
+
getVersionId
|
|
3581
4011
|
} = useTranslations();
|
|
3582
4012
|
return loadingDocuments ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", justify: "center", padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, {}) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: { maxHeight: "60vh", overflowY: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 2, children: documents.map((document2) => /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { shadow: 1, padding: 3, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
3583
4013
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { justify: "space-between", align: "flex-start", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { flex: 1, children: [
|
|
@@ -3585,10 +4015,10 @@ const WrapText = dt(ui.Box)`
|
|
|
3585
4015
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, muted: !0, style: { marginTop: "2px" }, children: document2._type })
|
|
3586
4016
|
] }) }),
|
|
3587
4017
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 2, children: locales.length > 0 ? locales.filter((locale) => locale.enabled !== !1).map((locale) => {
|
|
3588
|
-
const documentId = getDocumentPublishedId(document2), key = createTranslationStatusKey(
|
|
4018
|
+
const documentId = getDocumentPublishedId(document2), versionId = getVersionId(document2), key = createTranslationStatusKey(
|
|
3589
4019
|
branchId,
|
|
3590
4020
|
documentId,
|
|
3591
|
-
|
|
4021
|
+
versionId,
|
|
3592
4022
|
locale.localeId
|
|
3593
4023
|
), status = translationStatuses.get(key), isDownloaded = downloadStatus.downloaded.has(key), isImported = importedTranslations.has(key);
|
|
3594
4024
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3600,12 +4030,12 @@ const WrapText = dt(ui.Box)`
|
|
|
3600
4030
|
importFile: async () => {
|
|
3601
4031
|
await handleImportDocument(
|
|
3602
4032
|
documentId,
|
|
3603
|
-
|
|
4033
|
+
versionId,
|
|
3604
4034
|
locale.localeId
|
|
3605
4035
|
);
|
|
3606
4036
|
}
|
|
3607
4037
|
},
|
|
3608
|
-
`${document2._id}-${
|
|
4038
|
+
`${document2._id}-${versionId}-${locale.localeId}`
|
|
3609
4039
|
);
|
|
3610
4040
|
}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, muted: !0, children: "No locales configured" }) })
|
|
3611
4041
|
] }) }, document2._id)) }) });
|
|
@@ -3959,7 +4389,10 @@ const WrapText = dt(ui.Box)`
|
|
|
3959
4389
|
}
|
|
3960
4390
|
)
|
|
3961
4391
|
] });
|
|
3962
|
-
}, TranslationsTool = () => /* @__PURE__ */ jsxRuntime.jsx(BaseTranslationWrapper, { showContainer: !1, children: /* @__PURE__ */ jsxRuntime.jsx(TranslationsProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(TranslationsToolContent, {}) }) }),
|
|
4392
|
+
}, TranslationsTool = () => /* @__PURE__ */ jsxRuntime.jsx(BaseTranslationWrapper, { showContainer: !1, children: /* @__PURE__ */ jsxRuntime.jsx(TranslationsProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(TranslationsToolContent, {}) }) }), TranslationTab = (props) => {
|
|
4393
|
+
const { displayed } = props.document;
|
|
4394
|
+
return /* @__PURE__ */ jsxRuntime.jsx(BaseTranslationWrapper, { showContainer: !1, children: /* @__PURE__ */ jsxRuntime.jsx(TranslationsProvider, { singleDocument: displayed, children: /* @__PURE__ */ jsxRuntime.jsx(TranslationView, {}) }) });
|
|
4395
|
+
}, gtPlugin = sanity.definePlugin(
|
|
3963
4396
|
({
|
|
3964
4397
|
languageField = "language",
|
|
3965
4398
|
sourceLocale,
|
|
@@ -3979,11 +4412,16 @@ const WrapText = dt(ui.Box)`
|
|
|
3979
4412
|
additionalSerializers = {},
|
|
3980
4413
|
additionalDeserializers = {},
|
|
3981
4414
|
additionalBlockDeserializers = [],
|
|
3982
|
-
showDocumentInternationalization = !0
|
|
4415
|
+
showDocumentInternationalization = !0,
|
|
4416
|
+
internationalizedArray,
|
|
4417
|
+
fieldLevelLocalization,
|
|
4418
|
+
translationLevel = "document",
|
|
4419
|
+
fieldLevelDocuments
|
|
3983
4420
|
}) => {
|
|
3984
|
-
const resolvedSourceLocale = sourceLocale ?? defaultLocale ?? internal.libraryDefaultLocale
|
|
3985
|
-
|
|
3986
|
-
|
|
4421
|
+
const resolvedSourceLocale = sourceLocale ?? defaultLocale ?? internal.libraryDefaultLocale, normalizeFilters = (entries) => entries?.map((entry) => typeof entry == "string" ? { type: entry } : entry).filter((filter2) => filter2.documentId || filter2.type), normalizedTranslateDocuments = normalizeFilters(translateDocuments), normalizedFieldLevelDocuments = normalizeFilters(fieldLevelDocuments) ?? [], fieldLevelConfig = resolveFieldLevelConfig(
|
|
4422
|
+
internationalizedArray ?? fieldLevelLocalization
|
|
4423
|
+
);
|
|
4424
|
+
pluginConfig.init(
|
|
3987
4425
|
secretsNamespace,
|
|
3988
4426
|
languageField,
|
|
3989
4427
|
resolvedSourceLocale,
|
|
@@ -3998,17 +4436,22 @@ const WrapText = dt(ui.Box)`
|
|
|
3998
4436
|
additionalStopTypes,
|
|
3999
4437
|
additionalSerializers,
|
|
4000
4438
|
additionalDeserializers,
|
|
4001
|
-
additionalBlockDeserializers
|
|
4439
|
+
additionalBlockDeserializers,
|
|
4440
|
+
translationLevel,
|
|
4441
|
+
normalizedFieldLevelDocuments,
|
|
4442
|
+
fieldLevelConfig.typePrefix
|
|
4002
4443
|
), gt.setConfig({
|
|
4003
4444
|
sourceLocale: resolvedSourceLocale,
|
|
4004
4445
|
customMapping,
|
|
4005
4446
|
apiKey,
|
|
4006
4447
|
projectId
|
|
4007
4448
|
});
|
|
4449
|
+
const arrayLocalizedTypes = /* @__PURE__ */ new Set();
|
|
4450
|
+
translationLevel === "internationalizedArray" ? normalizedTranslateDocuments?.map((filter2) => filter2.type).filter((type) => !!type).forEach((type) => arrayLocalizedTypes.add(type)) : translationLevel === "mixed" && normalizedFieldLevelDocuments.map((filter2) => filter2.type).filter((type) => !!type).forEach((type) => arrayLocalizedTypes.add(type));
|
|
4008
4451
|
const plugins = [];
|
|
4009
4452
|
if (showDocumentInternationalization) {
|
|
4010
|
-
const
|
|
4011
|
-
if (
|
|
4453
|
+
const schemaTypes2 = normalizedTranslateDocuments?.map((filter2) => filter2.type).filter((type) => !!type).filter((type) => !arrayLocalizedTypes.has(type)) ?? [];
|
|
4454
|
+
if (schemaTypes2.length > 0) {
|
|
4012
4455
|
const supportedLanguages = [resolvedSourceLocale, ...locales].map((locale) => {
|
|
4013
4456
|
const props = generaltranslation.getLocaleProperties(locale, resolvedSourceLocale);
|
|
4014
4457
|
return { id: locale, title: props.name };
|
|
@@ -4016,15 +4459,28 @@ const WrapText = dt(ui.Box)`
|
|
|
4016
4459
|
plugins.push(
|
|
4017
4460
|
documentInternationalization.documentInternationalization({
|
|
4018
4461
|
supportedLanguages,
|
|
4019
|
-
schemaTypes,
|
|
4462
|
+
schemaTypes: schemaTypes2,
|
|
4020
4463
|
languageField
|
|
4021
4464
|
})
|
|
4022
4465
|
);
|
|
4023
4466
|
}
|
|
4024
4467
|
}
|
|
4468
|
+
const schemaTypes = fieldLevelConfig.enabled ? createInternationalizedArrayTypes({
|
|
4469
|
+
sourceLocale: resolvedSourceLocale,
|
|
4470
|
+
locales,
|
|
4471
|
+
fieldTypes: fieldLevelConfig.fieldTypes,
|
|
4472
|
+
languageTitles: fieldLevelConfig.languageTitles,
|
|
4473
|
+
getLanguageTitle: fieldLevelConfig.getLanguageTitle,
|
|
4474
|
+
typePrefix: fieldLevelConfig.typePrefix,
|
|
4475
|
+
includeCompatibilityTypes: fieldLevelConfig.includeCompatibilityTypes,
|
|
4476
|
+
components: fieldLevelConfig.components
|
|
4477
|
+
}) : [];
|
|
4025
4478
|
return {
|
|
4026
4479
|
name: "gt-sanity",
|
|
4027
4480
|
plugins,
|
|
4481
|
+
schema: {
|
|
4482
|
+
types: schemaTypes
|
|
4483
|
+
},
|
|
4028
4484
|
tools: [
|
|
4029
4485
|
{
|
|
4030
4486
|
name: "translations",
|
|
@@ -4074,6 +4530,7 @@ exports.BaseDocumentMerger = BaseDocumentMerger;
|
|
|
4074
4530
|
exports.BaseDocumentSerializer = BaseDocumentSerializer;
|
|
4075
4531
|
exports.TranslationsTab = TranslationTab;
|
|
4076
4532
|
exports.attachGTData = attachGTData;
|
|
4533
|
+
exports.createInternationalizedArrayTypes = createInternationalizedArrayTypes;
|
|
4077
4534
|
exports.customSerializers = customSerializers;
|
|
4078
4535
|
exports.defaultStopTypes = defaultStopTypes;
|
|
4079
4536
|
exports.detachGTData = detachGTData;
|