@smartcat/sanity-plugin 1.0.1 → 1.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/_chunks-cjs/index.cjs +10 -4
- package/dist/_chunks-cjs/index.cjs.map +1 -1
- package/dist/_chunks-cjs/index2.cjs +34 -7
- package/dist/_chunks-cjs/index2.cjs.map +1 -1
- package/dist/_chunks-es/index.js +10 -4
- package/dist/_chunks-es/index.js.map +1 -1
- package/dist/_chunks-es/index2.js +35 -8
- package/dist/_chunks-es/index2.js.map +1 -1
- package/dist/import.cjs +1 -1
- package/dist/import.cjs.map +1 -1
- package/dist/import.js +2 -2
- package/dist/import.js.map +1 -1
- package/dist/index.cjs +96 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +100 -31
- package/dist/index.js.map +1 -1
- package/dist/locjson.d.cts +5 -1
- package/dist/locjson.d.ts +5 -1
- package/dist/progress.d.cts +24 -9
- package/dist/progress.d.ts +24 -9
- package/package.json +1 -1
- package/src/actions/AddToProjectAction.tsx +21 -5
- package/src/import/index.ts +3 -3
- package/src/lib/locjson/filename.ts +10 -3
- package/src/lib/locjson/locjson.test.ts +78 -8
- package/src/lib/locjson/portableText.ts +71 -12
- package/src/lib/projectItems.ts +14 -0
- package/src/lib/resolveConfig.ts +7 -0
- package/src/progress/core.ts +37 -15
- package/src/progress/progress.test.ts +22 -0
- package/src/schema/translationProject.ts +4 -0
- package/src/tool/Dashboard.tsx +3 -1
- package/src/tool/ProjectView.tsx +35 -6
- package/src/tool/data.ts +7 -0
- package/src/tool/processing.test.ts +79 -4
- package/src/tool/processing.ts +84 -11
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { defineType, defineField, defineArrayMember, useClient, prepareForPreview, useSchema, useRelativeTime, useValuePreview, useWorkspace, useFormValue, definePlugin } from "sanity";
|
|
1
|
+
import { defineType, defineField, defineArrayMember, useClient, prepareForPreview, useSchema, usePerspective, useRelativeTime, useValuePreview, useWorkspace, useFormValue, definePlugin } from "sanity";
|
|
2
2
|
import { TranslateIcon, CogIcon, AddIcon, LaunchIcon, CheckmarkIcon, CopyIcon, SyncIcon, ArrowLeftIcon, TrashIcon, PublishIcon, DownloadIcon, CloseIcon, RemoveCircleIcon, JsonIcon } from "@sanity/icons";
|
|
3
3
|
import { TRANSLATION_PROJECT_TYPE, SETTINGS_TYPE, API_VERSION, SETTINGS_DOC_ID, requireSourceLanguage } from "./_chunks-es/constants.js";
|
|
4
4
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
5
5
|
import { useState, useRef, useEffect, useCallback, useMemo, useLayoutEffect, Fragment as Fragment$1 } from "react";
|
|
6
|
-
import { Select, useToast, Flex, Spinner, Stack, Label, TextInput, Card, Text, Switch, Button,
|
|
6
|
+
import { Select, useToast, Flex, Spinner, Stack, Label, TextInput, Card, Text, Badge, Switch, Button, Heading, Dialog, Box, Inline, useTheme_v2, useTheme, Checkbox, Container } from "@sanity/ui";
|
|
7
7
|
import { uuid } from "@sanity/uuid";
|
|
8
8
|
import { TEMPLATE_PREFIX, STANDARD_WORKFLOW_OPTIONS, isWorkflowValid } from "./_chunks-es/workflow.js";
|
|
9
|
-
import { ITEM_ID, ITEM_ID_FROM_SUBQUERY, itemDocDeref, summarizeCompletion, buildLanguageMappings, findDuplicateSmartcatLanguages, targetPercent } from "./_chunks-es/index.js";
|
|
10
|
-
import { getTranslatableFields, deserializeFromLocjson, serializeToLocjson, buildLocjsonFilename, localizationMode,
|
|
9
|
+
import { ITEM_ID, ITEM_ID_FROM_SUBQUERY, itemDocDeref, summarizeCompletion, buildLanguageMappings, findDuplicateSmartcatLanguages, itemDocDerefRespectingDraft, targetPercent } from "./_chunks-es/index.js";
|
|
10
|
+
import { getTranslatableFields, deserializeFromLocjson, serializeToLocjson, getAtPath, buildLocjsonFilename, localizationMode, enumerateLeaves, setAtPath, isInternationalizedArrayType, innerValueType } from "./_chunks-es/index2.js";
|
|
11
11
|
import { useIntentLink, useRouter, useRouterState, route } from "sanity/router";
|
|
12
12
|
import styled, { keyframes, css } from "styled-components";
|
|
13
13
|
const STATUS_OPTIONS = [
|
|
@@ -89,7 +89,11 @@ function createTranslationProjectType() {
|
|
|
89
89
|
title: "Project item",
|
|
90
90
|
fields: [
|
|
91
91
|
defineField({ name: "docId", title: "Document ID", type: "string" }),
|
|
92
|
-
defineField({ name: "docType", title: "Document type", type: "string" })
|
|
92
|
+
defineField({ name: "docType", title: "Document type", type: "string" }),
|
|
93
|
+
// Set when the item was added from the published perspective, so the
|
|
94
|
+
// export translates the published document. Absent/false (incl. all
|
|
95
|
+
// legacy items) prefers the draft — see itemDocDerefRespectingDraft.
|
|
96
|
+
defineField({ name: "sourceIsPublished", title: "Source is published", type: "boolean" })
|
|
93
97
|
],
|
|
94
98
|
preview: { select: { title: "docId", subtitle: "docType" } }
|
|
95
99
|
})
|
|
@@ -435,7 +439,7 @@ const PROJECTS_QUERY$1 = `*[_type == $type] | order(name asc){
|
|
|
435
439
|
function createAddToProjectAction(config) {
|
|
436
440
|
const sourceLanguage = config.sourceLanguage;
|
|
437
441
|
return (props) => {
|
|
438
|
-
const { id, draft, published, onComplete } = props, client = useClient({ apiVersion: API_VERSION }), schema = useSchema(), toast = useToast(), [open, setOpen] = useState(!1), [projects, setProjects] = useState(null), [selection, setSelection] = useState(CREATE_NEW), [newName, setNewName] = useState(""), [busy, setBusy] = useState(!1), [includeLinked, setIncludeLinked] = useState(!0), { templates, loaded, requestRefresh } = useTemplates(), [workflow, setWorkflow] = useWorkflowSelection(open, templates, loaded), publishedId2 = id.replace(/^drafts\./, ""), doc = draft ?? published, docTitle = doc && resolveDocumentTitle(schema, doc) || UNTITLED;
|
|
442
|
+
const { id, draft, published, onComplete } = props, client = useClient({ apiVersion: API_VERSION }), schema = useSchema(), toast = useToast(), { selectedPerspectiveName } = usePerspective(), sourceIsPublished = selectedPerspectiveName === "published" || !draft, [open, setOpen] = useState(!1), [projects, setProjects] = useState(null), [selection, setSelection] = useState(CREATE_NEW), [newName, setNewName] = useState(""), [busy, setBusy] = useState(!1), [includeLinked, setIncludeLinked] = useState(!0), { templates, loaded, requestRefresh } = useTemplates(), [workflow, setWorkflow] = useWorkflowSelection(open, templates, loaded), publishedId2 = id.replace(/^drafts\./, ""), doc = draft ?? published, docTitle = doc && resolveDocumentTitle(schema, doc) || UNTITLED;
|
|
439
443
|
useEffect(() => {
|
|
440
444
|
if (!open) return;
|
|
441
445
|
requestRefresh();
|
|
@@ -457,7 +461,8 @@ function createAddToProjectAction(config) {
|
|
|
457
461
|
_type: "smartcat.projectItem",
|
|
458
462
|
_key: uuid(),
|
|
459
463
|
docId,
|
|
460
|
-
docType
|
|
464
|
+
docType,
|
|
465
|
+
sourceIsPublished
|
|
461
466
|
}), collected = /* @__PURE__ */ new Map([[publishedId2, doc?._type]]);
|
|
462
467
|
if (includeLinked) {
|
|
463
468
|
const linked = await gatherLinkedDocuments({ client, rootId: publishedId2, isRoot: (type) => config.rootTypes.includes(type), isTranslatable: (type) => getTranslatableFields(schema.get(type), { exclude: [config.documentI18nLanguageField] }).length > 0 });
|
|
@@ -499,7 +504,7 @@ function createAddToProjectAction(config) {
|
|
|
499
504
|
} finally {
|
|
500
505
|
setBusy(!1);
|
|
501
506
|
}
|
|
502
|
-
}, [selection, newName, workflow, publishedId2, doc, includeLinked, schema, client, projects, close]), content = useMemo(() => projects === null ? /* @__PURE__ */ jsx(Flex, { align: "center", justify: "center", padding: 4, children: /* @__PURE__ */ jsx(Spinner, { muted: !0 }) }) : /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
507
|
+
}, [selection, newName, workflow, publishedId2, doc, includeLinked, sourceIsPublished, schema, client, projects, close]), content = useMemo(() => projects === null ? /* @__PURE__ */ jsx(Flex, { align: "center", justify: "center", padding: 4, children: /* @__PURE__ */ jsx(Spinner, { muted: !0 }) }) : /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
503
508
|
/* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
504
509
|
/* @__PURE__ */ jsx(Label, { size: 1, children: "Project" }),
|
|
505
510
|
/* @__PURE__ */ jsxs(
|
|
@@ -550,7 +555,20 @@ function createAddToProjectAction(config) {
|
|
|
550
555
|
] }),
|
|
551
556
|
/* @__PURE__ */ jsx(Card, { padding: 3, radius: 2, tone: "transparent", border: !0, children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
552
557
|
/* @__PURE__ */ jsxs(Text, { size: 1, muted: !0, children: [
|
|
553
|
-
"Adding
|
|
558
|
+
"Adding",
|
|
559
|
+
" ",
|
|
560
|
+
/* @__PURE__ */ jsx(
|
|
561
|
+
Badge,
|
|
562
|
+
{
|
|
563
|
+
tone: sourceIsPublished ? "positive" : "caution",
|
|
564
|
+
fontSize: 1,
|
|
565
|
+
paddingX: 2,
|
|
566
|
+
style: { verticalAlign: "middle" },
|
|
567
|
+
children: sourceIsPublished ? "Published" : "Draft"
|
|
568
|
+
}
|
|
569
|
+
),
|
|
570
|
+
" ",
|
|
571
|
+
"version of ",
|
|
554
572
|
/* @__PURE__ */ jsx("strong", { children: docTitle }),
|
|
555
573
|
" to the selected project."
|
|
556
574
|
] }),
|
|
@@ -583,7 +601,7 @@ function createAddToProjectAction(config) {
|
|
|
583
601
|
}
|
|
584
602
|
)
|
|
585
603
|
] })
|
|
586
|
-
] }), [projects, selection, newName, workflow, templates, busy, includeLinked, docTitle, close, handleConfirm]);
|
|
604
|
+
] }), [projects, selection, newName, workflow, templates, busy, includeLinked, docTitle, sourceIsPublished, close, handleConfirm]);
|
|
587
605
|
return {
|
|
588
606
|
label: "Add to translation project",
|
|
589
607
|
icon: TranslateIcon,
|
|
@@ -619,6 +637,7 @@ const PROJECTS_QUERY = `*[_type == "${TRANSLATION_PROJECT_TYPE}"] | order(_creat
|
|
|
619
637
|
items[]{
|
|
620
638
|
_key,
|
|
621
639
|
"docId": ${ITEM_ID},
|
|
640
|
+
sourceIsPublished,
|
|
622
641
|
"doc": ${itemDocDeref("{_id, _type}")},
|
|
623
642
|
"translations": *[_type == "translation.metadata" && references(${ITEM_ID_FROM_SUBQUERY})][0]
|
|
624
643
|
.translations[]{language, "id": value._ref}
|
|
@@ -794,6 +813,16 @@ function valuePreview(value) {
|
|
|
794
813
|
function errorMessage(err) {
|
|
795
814
|
return err instanceof Error ? err.message : String(err);
|
|
796
815
|
}
|
|
816
|
+
function memberLocalesWithContent(members, languageKey) {
|
|
817
|
+
if (!Array.isArray(members)) return [];
|
|
818
|
+
const locales = [];
|
|
819
|
+
for (const member of members) {
|
|
820
|
+
if (!member || typeof member != "object") continue;
|
|
821
|
+
const locale = member[languageKey], value = member.value, hasContent = typeof value == "string" ? value.trim().length > 0 : Array.isArray(value) ? value.length > 0 : value != null;
|
|
822
|
+
typeof locale == "string" && hasContent && locales.push(locale);
|
|
823
|
+
}
|
|
824
|
+
return locales;
|
|
825
|
+
}
|
|
797
826
|
function schemaFieldNames(schema, type) {
|
|
798
827
|
return (schema.get(type)?.fields ?? []).map((f) => f?.name).filter((n) => typeof n == "string" && !n.startsWith("_"));
|
|
799
828
|
}
|
|
@@ -801,7 +830,14 @@ function blockContentTypeFor(schema, type, fieldPath) {
|
|
|
801
830
|
const fieldType = schema.get(type)?.fields?.find((f) => f.name === fieldPath)?.type;
|
|
802
831
|
return isInternationalizedArrayType(fieldType) ? innerValueType(fieldType) : fieldType;
|
|
803
832
|
}
|
|
804
|
-
const ITEMS_QUERY = `*[_id == $id][0]{
|
|
833
|
+
const ITEMS_QUERY = `*[_id == $id][0]{
|
|
834
|
+
sourceLanguage,
|
|
835
|
+
items[]{
|
|
836
|
+
"docId": ${ITEM_ID},
|
|
837
|
+
"docType": docType,
|
|
838
|
+
"doc": ${itemDocDerefRespectingDraft()}
|
|
839
|
+
}
|
|
840
|
+
}`;
|
|
805
841
|
async function prepareExport({
|
|
806
842
|
client,
|
|
807
843
|
schema,
|
|
@@ -809,6 +845,7 @@ async function prepareExport({
|
|
|
809
845
|
targetLanguages,
|
|
810
846
|
sourceLanguage,
|
|
811
847
|
languages,
|
|
848
|
+
translatableTypes,
|
|
812
849
|
exclude,
|
|
813
850
|
fieldLanguageKey,
|
|
814
851
|
deletions = [],
|
|
@@ -822,15 +859,22 @@ async function prepareExport({
|
|
|
822
859
|
const detail = dups.map((d) => `${d.sanityIds.join(", ")} \u2192 ${d.smartcatLanguage}`).join("; ");
|
|
823
860
|
throw new Error(`Multiple target languages map to the same Smartcat language: ${detail}`);
|
|
824
861
|
}
|
|
825
|
-
const deletedDocIds = new Set(deletions.map((d) => d.sourceDocId)),
|
|
862
|
+
const deletedDocIds = new Set(deletions.map((d) => d.sourceDocId)), items = (project?.items ?? []).filter(
|
|
863
|
+
(item) => !(item.docId && deletedDocIds.has(item.docId))
|
|
864
|
+
), unresolved = items.filter((item) => !item.doc), docs = items.map((item) => item.doc).filter((d) => !!d), fieldsByType = /* @__PURE__ */ new Map(), fieldsFor = (type) => {
|
|
826
865
|
let fields = fieldsByType.get(type);
|
|
827
866
|
return fields || (fields = getTranslatableFields(schema.get(type), { exclude }), fieldsByType.set(type, fields)), fields;
|
|
828
|
-
};
|
|
829
|
-
log({ level: "info", message: `
|
|
867
|
+
}, configuredLanguages = languages.map((l) => l.id).join(", ") || "(none)", configuredTypes = translatableTypes === void 0 ? "all types" : translatableTypes.join(", ") || "(none)";
|
|
868
|
+
log({ level: "info", message: `Config \u2014 source language: ${sourceLanguage}` }), log({ level: "info", indent: !0, message: `languages: ${configuredLanguages}` }), log({ level: "info", indent: !0, message: `translatable types: ${configuredTypes}` }), log({ level: "info", message: `Project \u2014 source: ${source} \u2192 targets: ${targetLanguages.join(", ") || "(no targets)"}` }), log({ level: "info", message: `Export \u2014 ${docs.length} document(s)` });
|
|
869
|
+
for (const item of unresolved)
|
|
870
|
+
log({
|
|
871
|
+
level: "error",
|
|
872
|
+
message: `${item.docId ?? "unknown document"} (${item.docType ?? "unknown type"}): no document found \u2014 it may be unpublished or deleted; skipped`
|
|
873
|
+
});
|
|
830
874
|
const outbox = [];
|
|
831
|
-
for (const
|
|
832
|
-
const name = resolveDocumentTitle(schema, doc);
|
|
833
|
-
log({ level: "info", message: `${name || doc._id} \xB7 ${doc._type}` });
|
|
875
|
+
for (const rawDoc of docs) {
|
|
876
|
+
const isDraft = rawDoc._id.startsWith("drafts."), doc = isDraft ? { ...rawDoc, _id: publishedId(rawDoc._id) } : rawDoc, name = resolveDocumentTitle(schema, doc);
|
|
877
|
+
log({ level: "info", message: `${name || doc._id} \xB7 ${doc._type}${isDraft ? " (draft)" : ""}` });
|
|
834
878
|
try {
|
|
835
879
|
const fields = fieldsFor(doc._type), skippedBlockTypes = /* @__PURE__ */ new Map(), locjson = serializeToLocjson(doc, fields, {
|
|
836
880
|
sourceLanguage: source,
|
|
@@ -839,11 +883,18 @@ async function prepareExport({
|
|
|
839
883
|
}), unitByKey = new Map(locjson.units.map((u) => [u.key, u]));
|
|
840
884
|
for (const field of fields) {
|
|
841
885
|
const unit = unitByKey.get(field.path), skippedTypes = skippedBlockTypes.get(field.path);
|
|
842
|
-
|
|
843
|
-
level: "
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
886
|
+
if (unit)
|
|
887
|
+
log({ level: "success", indent: !0, message: `${field.title || field.path}: serialized (${field.kind})`, value: unit.source.join("") });
|
|
888
|
+
else if (skippedTypes)
|
|
889
|
+
log({
|
|
890
|
+
level: "error",
|
|
891
|
+
indent: !0,
|
|
892
|
+
message: `${field.title || field.path}: not translated \u2014 contains block type(s) that can't be translated: ${skippedTypes.join(", ")}. The whole field was left untranslated to avoid losing this content.`
|
|
893
|
+
});
|
|
894
|
+
else {
|
|
895
|
+
const otherLocales = field.localization === "field" ? memberLocalesWithContent(getAtPath(doc, field.path), fieldLanguageKey).filter((l) => l !== source) : [], reason = otherLocales.length ? `no '${source}' content (I see only: ${otherLocales.join(", ")})` : "no source content";
|
|
896
|
+
log({ level: "skip", indent: !0, message: `${field.title || field.path}: skipped \u2014 ${reason}` });
|
|
897
|
+
}
|
|
847
898
|
}
|
|
848
899
|
const selected = new Set(fields.map((f) => f.path)), excluded = new Set(exclude ?? []);
|
|
849
900
|
for (const fieldName of schemaFieldNames(schema, doc._type))
|
|
@@ -860,7 +911,7 @@ async function prepareExport({
|
|
|
860
911
|
_key: uuid(),
|
|
861
912
|
sourceDocId: doc._id,
|
|
862
913
|
title: name,
|
|
863
|
-
filename: buildLocjsonFilename(doc._type, doc._id, name),
|
|
914
|
+
filename: buildLocjsonFilename(doc._type, doc._id, name, { draft: isDraft }),
|
|
864
915
|
locjson: JSON.stringify(locjson)
|
|
865
916
|
});
|
|
866
917
|
} catch (err) {
|
|
@@ -1418,20 +1469,23 @@ const CodeArea = styled.textarea`
|
|
|
1418
1469
|
tab-size: 2;
|
|
1419
1470
|
`;
|
|
1420
1471
|
function ViewLocjsonButton(props) {
|
|
1421
|
-
const { docId, type, client, schema, sourceLanguage, documentI18nLanguageField, fieldI18nLanguageField } = props, [open, setOpen] = useState(!1), [content, setContent] = useState(null), [filename, setFilename] = useState(null), [error, setError] = useState(null), build = useCallback(async () => {
|
|
1472
|
+
const { docId, type, sourceIsPublished, client, schema, sourceLanguage, documentI18nLanguageField, fieldI18nLanguageField } = props, [open, setOpen] = useState(!1), [content, setContent] = useState(null), [filename, setFilename] = useState(null), [error, setError] = useState(null), build = useCallback(async () => {
|
|
1422
1473
|
setOpen(!0), setContent(null), setFilename(null), setError(null);
|
|
1423
1474
|
try {
|
|
1424
|
-
const
|
|
1425
|
-
|
|
1426
|
-
|
|
1475
|
+
const raw = await client.fetch(
|
|
1476
|
+
sourceIsPublished ? "*[_id == $id][0]" : 'coalesce(*[_id == "drafts." + $id][0], *[_id == $id][0])',
|
|
1477
|
+
{ id: docId }
|
|
1478
|
+
);
|
|
1479
|
+
if (!raw) throw new Error(`Document not found: ${docId}`);
|
|
1480
|
+
const isDraft = typeof raw._id == "string" && raw._id.startsWith("drafts."), doc = isDraft ? { ...raw, _id: docId } : raw, fields = getTranslatableFields(schema.get(type), { exclude: [documentI18nLanguageField] }), locjson = serializeToLocjson(doc, fields, {
|
|
1427
1481
|
sourceLanguage,
|
|
1428
1482
|
fieldLanguageKey: fieldI18nLanguageField
|
|
1429
|
-
}), smartcatName = buildLocjsonFilename(type, docId, resolveDocumentTitle(schema, doc));
|
|
1483
|
+
}), smartcatName = buildLocjsonFilename(type, docId, resolveDocumentTitle(schema, doc), { draft: isDraft });
|
|
1430
1484
|
setFilename(smartcatName.split("/").pop() || smartcatName), setContent(JSON.stringify(locjson, null, 2));
|
|
1431
1485
|
} catch (err) {
|
|
1432
1486
|
setError(err instanceof Error ? err.message : String(err));
|
|
1433
1487
|
}
|
|
1434
|
-
}, [client, schema, docId, type, sourceLanguage, documentI18nLanguageField, fieldI18nLanguageField]), download = useCallback(() => {
|
|
1488
|
+
}, [client, schema, docId, type, sourceIsPublished, sourceLanguage, documentI18nLanguageField, fieldI18nLanguageField]), download = useCallback(() => {
|
|
1435
1489
|
if (content == null || !filename) return;
|
|
1436
1490
|
const url = URL.createObjectURL(new Blob([content], { type: "application/json" })), anchor = document.createElement("a");
|
|
1437
1491
|
anchor.href = url, anchor.download = filename, anchor.click(), URL.revokeObjectURL(url);
|
|
@@ -1490,6 +1544,7 @@ function ProjectView({
|
|
|
1490
1544
|
onBack,
|
|
1491
1545
|
languages,
|
|
1492
1546
|
sourceLanguage,
|
|
1547
|
+
translatableTypes,
|
|
1493
1548
|
documentI18nLanguageField,
|
|
1494
1549
|
fieldI18nLanguageField
|
|
1495
1550
|
}) {
|
|
@@ -1635,6 +1690,7 @@ function ProjectView({
|
|
|
1635
1690
|
targetLanguages: targets,
|
|
1636
1691
|
sourceLanguage,
|
|
1637
1692
|
languages,
|
|
1693
|
+
translatableTypes,
|
|
1638
1694
|
exclude: [documentI18nLanguageField],
|
|
1639
1695
|
fieldLanguageKey: fieldI18nLanguageField,
|
|
1640
1696
|
deletions,
|
|
@@ -1846,13 +1902,23 @@ Smartcat language code: '${l.smartcatLanguage || l.id}'`,
|
|
|
1846
1902
|
children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
1847
1903
|
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 3, children: [
|
|
1848
1904
|
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
1905
|
+
/* @__PURE__ */ jsx(
|
|
1906
|
+
Badge,
|
|
1907
|
+
{
|
|
1908
|
+
tone: item.sourceIsPublished ? "positive" : "caution",
|
|
1909
|
+
paddingX: 2,
|
|
1910
|
+
title: item.sourceIsPublished ? "The published version is the translation source" : "The draft version is the translation source",
|
|
1911
|
+
children: item.sourceIsPublished ? "Published" : "Draft"
|
|
1912
|
+
}
|
|
1913
|
+
),
|
|
1849
1914
|
/* @__PURE__ */ jsx(Text, { weight: "medium", children: /* @__PURE__ */ jsx("span", { style: isMarked ? { textDecoration: "line-through" } : void 0, children: /* @__PURE__ */ jsx(DocTitle, { doc: item.doc }) }) }),
|
|
1850
|
-
item.doc?._type && /* @__PURE__ */ jsx(Badge, { tone: "primary", children: item.doc._type }),
|
|
1915
|
+
item.doc?._type && /* @__PURE__ */ jsx(Badge, { tone: "primary", paddingX: 2, children: item.doc._type }),
|
|
1851
1916
|
item.doc?._type && modeByType.has(item.doc._type) && /* @__PURE__ */ jsx(
|
|
1852
1917
|
Badge,
|
|
1853
1918
|
{
|
|
1854
1919
|
tone: "default",
|
|
1855
1920
|
fontSize: 0,
|
|
1921
|
+
paddingX: 2,
|
|
1856
1922
|
title: modeByType.get(item.doc._type) === "field" ? "This item is translated in field mode; translations will be stored as language variants of each field" : "This item is translated in document mode; translations will be stored as linked documents",
|
|
1857
1923
|
children: modeByType.get(item.doc._type) === "field" ? "fields" : "document"
|
|
1858
1924
|
}
|
|
@@ -1863,6 +1929,7 @@ Smartcat language code: '${l.smartcatLanguage || l.id}'`,
|
|
|
1863
1929
|
{
|
|
1864
1930
|
docId: item.doc._id,
|
|
1865
1931
|
type: item.doc._type,
|
|
1932
|
+
sourceIsPublished: item.sourceIsPublished,
|
|
1866
1933
|
client,
|
|
1867
1934
|
schema,
|
|
1868
1935
|
sourceLanguage,
|
|
@@ -1938,7 +2005,7 @@ Smartcat language code: '${l.smartcatLanguage || l.id}'`,
|
|
|
1938
2005
|
] });
|
|
1939
2006
|
}
|
|
1940
2007
|
function createDashboardComponent(config) {
|
|
1941
|
-
const { sourceLanguage, languages, documentI18nLanguageField, fieldI18nLanguageField } = config;
|
|
2008
|
+
const { sourceLanguage, languages, translatableTypes, documentI18nLanguageField, fieldI18nLanguageField } = config;
|
|
1942
2009
|
return function() {
|
|
1943
2010
|
const router = useRouter(), projectId = useRouterState(
|
|
1944
2011
|
useCallback((state) => state.projectId ?? null, [])
|
|
@@ -1950,6 +2017,7 @@ function createDashboardComponent(config) {
|
|
|
1950
2017
|
onBack: goBack,
|
|
1951
2018
|
languages,
|
|
1952
2019
|
sourceLanguage,
|
|
2020
|
+
translatableTypes,
|
|
1953
2021
|
documentI18nLanguageField,
|
|
1954
2022
|
fieldI18nLanguageField
|
|
1955
2023
|
}
|
|
@@ -2069,6 +2137,7 @@ function resolveConfig(config) {
|
|
|
2069
2137
|
const translatableTypes = config.translatableTypes;
|
|
2070
2138
|
return {
|
|
2071
2139
|
isTranslatableType: translatableTypes ? (type) => translatableTypes.includes(type) : (type) => !PLUGIN_TYPES.has(type),
|
|
2140
|
+
translatableTypes,
|
|
2072
2141
|
// `rootTypes` inherits the *explicitly-configured* translatableTypes (not the
|
|
2073
2142
|
// resolved "everything") so an unconfigured Studio gets no crawl boundary
|
|
2074
2143
|
// rather than every type being a root (which would stop the crawl at once).
|