@braze/sanity-plugin-ai-translation 0.1.7 → 0.1.76

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.js CHANGED
@@ -1106,9 +1106,10 @@ const ICON_SIZE = 64, progressIconMap = {
1106
1106
  }), fetchTranslationPrompts = async ({
1107
1107
  client,
1108
1108
  sourceLanguage,
1109
+ sourceDocument,
1109
1110
  targetLanguages
1110
1111
  }) => {
1111
- const translationSettings2 = await client.fetch(
1112
+ const sourceDocumentString = JSON.stringify(sourceDocument), translationSettings2 = await client.fetch(
1112
1113
  `*[_id == "translation-settings"][0] {
1113
1114
  globalPrompt,
1114
1115
  localePrompts[locale in $targetLanguages],
@@ -1118,19 +1119,23 @@ const ICON_SIZE = 64, progressIconMap = {
1118
1119
  ), translationGlossaryTerms = await client.fetch(
1119
1120
  `*[
1120
1121
  _type == "translationGlossaryTerm"
1121
- && count(translations[locale in $targetLanguages]) > 0
1122
- && count(translations[locale == $sourceLanguage]) > 0
1122
+ && count(translations[_key in $targetLanguages]) > 0
1123
+ && count(translations[_key == $sourceLanguage]) > 0
1123
1124
  ].translations`,
1124
1125
  { targetLanguages, sourceLanguage }
1125
- ) || [], glossaryTermsByLocale = {};
1126
+ ) || [];
1127
+ console.log("translationGlossaryTerms", translationGlossaryTerms);
1128
+ const glossaryTermsByLocale = {};
1126
1129
  for (const targetLanguage of targetLanguages) {
1127
- const relevantTranslations = translationGlossaryTerms.filter(
1130
+ let relevantTranslations = translationGlossaryTerms.filter(
1128
1131
  (termTranslations) => termTranslations.some((translation) => translation._key === targetLanguage)
1129
1132
  ).map((termTranslations) => {
1130
1133
  const from = termTranslations.find((translation) => translation._key === sourceLanguage)?.value, to = termTranslations.find((translation) => translation._key === targetLanguage)?.value;
1131
1134
  return !from || !to ? null : { from, to };
1132
1135
  }).filter((item) => item !== null);
1133
- glossaryTermsByLocale[targetLanguage] = relevantTranslations;
1136
+ console.log("relevantTranslations", relevantTranslations), sourceDocument && (relevantTranslations = relevantTranslations.filter(
1137
+ ({ from }) => termAppearsInDocument(from, sourceDocumentString)
1138
+ ), console.log("relevantTranslations", relevantTranslations)), glossaryTermsByLocale[targetLanguage] = relevantTranslations;
1134
1139
  }
1135
1140
  return {
1136
1141
  globalPrompt: translationSettings2?.globalPrompt,
@@ -1145,12 +1150,17 @@ const ICON_SIZE = 64, progressIconMap = {
1145
1150
  ])
1146
1151
  )
1147
1152
  };
1153
+ }, termAppearsInDocument = (term, documentString) => {
1154
+ const baseTerm = term.split(":")[0].trim();
1155
+ return documentString.includes(baseTerm.toLowerCase());
1148
1156
  }, formatGlossaryTermInstruction = (terms) => {
1149
1157
  const instructions = [
1150
- "Translate the following terms exactly as described below. When a term includes a colon, the suffix following the colon describes how the term should be translated for the female gender."
1158
+ "## Glossary Terms",
1159
+ "Translate the following terms exactly as described below.",
1160
+ "When a term includes a colon, the suffix following the colon describes how the term should be translated for the female gender."
1151
1161
  ];
1152
1162
  return terms.forEach(({ from, to }) => {
1153
- instructions.push(`"${from}" -> "${to}"`);
1163
+ instructions.push(`Always translate "${from}" to "${to}".`);
1154
1164
  }), instructions.join(`
1155
1165
  `);
1156
1166
  }, findKeyValues = (obj, targetKey) => {
@@ -1383,7 +1393,11 @@ const setupTranslationJobStatuses = (dispatch, sourceDocuments, targetLanguages)
1383
1393
  }
1384
1394
  });
1385
1395
  } catch (error) {
1386
- setJobStatus(dispatch, sourceDocument._id, targetLanguage, "error"), console.error("Error translating document:", error);
1396
+ const errorMessage = error instanceof Error ? error.message : String(error);
1397
+ setJobStatus(dispatch, sourceDocument._id, targetLanguage, "error", {
1398
+ errorMessage
1399
+ }), console.error("Error translating document:", error);
1400
+ return;
1387
1401
  }
1388
1402
  }, assembleLanguageSpecs = ({
1389
1403
  sourceDocument,
@@ -1479,11 +1493,15 @@ const setupTranslationJobStatuses = (dispatch, sourceDocuments, targetLanguages)
1479
1493
  newDocumentRev: newDocument._rev
1480
1494
  }), devLog.timeEnd("translateEntireDocument"), devLog.groupEnd(), newDocument;
1481
1495
  } catch (error) {
1482
- throw devLog.error(
1496
+ const errorMessage = error instanceof Error ? error.message : String(error);
1497
+ devLog.error(
1483
1498
  "translateEntireDocument failed",
1484
1499
  error instanceof Error ? error : new Error(String(error)),
1485
1500
  logContext
1486
- ), devLog.timeEnd("translateEntireDocument"), devLog.groupEnd(), error;
1501
+ ), setJobStatus(dispatch, sourceDocument._id, targetLanguage, "error", {
1502
+ errorMessage
1503
+ }), devLog.timeEnd("translateEntireDocument"), devLog.groupEnd();
1504
+ return;
1487
1505
  }
1488
1506
  }, updateTranslationMetadata = async ({
1489
1507
  client,
@@ -1644,7 +1662,11 @@ const setupTranslationJobStatuses = (dispatch, sourceDocuments, targetLanguages)
1644
1662
  newDocumentId: newDocument._id
1645
1663
  }), devLog.timeEnd("translateDocument"), devLog.groupEnd(), newDocument._id;
1646
1664
  } catch (error) {
1647
- throw devLog.error("Translation failed", error instanceof Error ? error : new Error(String(error)), logContext), setJobStatus(dispatch, sourceDocument._id, targetLanguage, "error"), devLog.timeEnd("translateDocument"), devLog.groupEnd(), error;
1665
+ const errorMessage = error instanceof Error ? error.message : String(error);
1666
+ devLog.error("Translation failed", error instanceof Error ? error : new Error(String(error)), logContext), setJobStatus(dispatch, sourceDocument._id, targetLanguage, "error", {
1667
+ errorMessage
1668
+ }), devLog.timeEnd("translateDocument"), devLog.groupEnd();
1669
+ return;
1648
1670
  }
1649
1671
  }, patchTranslationTarget = async ({
1650
1672
  client,
@@ -1719,36 +1741,54 @@ const setupTranslationJobStatuses = (dispatch, sourceDocuments, targetLanguages)
1719
1741
  const translationPrompts = await fetchTranslationPrompts({
1720
1742
  client,
1721
1743
  sourceLanguage,
1722
- targetLanguages
1744
+ targetLanguages,
1745
+ sourceDocument
1723
1746
  });
1724
1747
  devLog.info("Translation prompts", translationPrompts), setupTranslationJobStatuses(dispatch, sourceDocuments, targetLanguages);
1725
1748
  const translationTasks = sourceDocumentIds.flatMap(
1726
1749
  (documentId) => targetLanguages.map(async (targetLanguage) => {
1727
- await translationSemaphore.withPermit(async () => {
1728
- const document = await client.withConfig({
1729
- // This enables us to detect documents that might be stale due to unpublished changes
1730
- perspective: "raw"
1731
- }).fetch("*[_id == $id][0]", {
1732
- id: documentId
1733
- });
1734
- if (document) {
1735
- const targetDocumentId = await translateDocument({
1736
- dispatch,
1737
- client,
1738
- sourceDocument: document,
1739
- targetLanguage,
1740
- languageFieldName,
1741
- shouldOverwriteFreshTranslations,
1742
- schemaId,
1743
- shouldTranslateDiffs,
1744
- translationPrompts
1750
+ try {
1751
+ await translationSemaphore.withPermit(async () => {
1752
+ const document = await client.withConfig({
1753
+ // This enables us to detect documents that might be stale due to unpublished changes
1754
+ perspective: "raw"
1755
+ }).fetch("*[_id == $id][0]", {
1756
+ id: documentId
1745
1757
  });
1746
- targetDocumentId && targetDocumentIds.push(targetDocumentId);
1747
- }
1748
- });
1758
+ if (document) {
1759
+ const targetDocumentId = await translateDocument({
1760
+ dispatch,
1761
+ client,
1762
+ sourceDocument: document,
1763
+ targetLanguage,
1764
+ languageFieldName,
1765
+ shouldOverwriteFreshTranslations,
1766
+ schemaId,
1767
+ shouldTranslateDiffs,
1768
+ translationPrompts
1769
+ });
1770
+ targetDocumentId && targetDocumentIds.push(targetDocumentId);
1771
+ }
1772
+ });
1773
+ } catch (error) {
1774
+ devLog.error(
1775
+ "Individual translation task failed",
1776
+ error instanceof Error ? error : new Error(String(error)),
1777
+ {
1778
+ ...logContext,
1779
+ failedDocumentId: documentId,
1780
+ failedTargetLanguage: targetLanguage
1781
+ }
1782
+ );
1783
+ }
1749
1784
  })
1750
- );
1751
- await Promise.all(translationTasks), devLog.info("All translation tasks completed", {
1785
+ ), results = await Promise.allSettled(translationTasks), succeeded = results.filter((r) => r.status === "fulfilled").length, failed = results.filter((r) => r.status === "rejected").length;
1786
+ devLog.info("Translation tasks summary", {
1787
+ ...logContext,
1788
+ total: results.length,
1789
+ succeeded,
1790
+ failed
1791
+ }), devLog.info("All translation tasks completed", {
1752
1792
  ...logContext,
1753
1793
  targetDocumentIds: targetDocumentIds.length
1754
1794
  }), dispatch({
@@ -1765,9 +1805,19 @@ const setupTranslationJobStatuses = (dispatch, sourceDocuments, targetLanguages)
1765
1805
  languageFieldName
1766
1806
  });
1767
1807
  })
1768
- ), devLog.info("Document set translation completed successfully", logContext), devLog.timeEnd("translateDocumentSet"), devLog.groupEnd(), dispatch({ type: "SET_OVERALL_STATUS", payload: "completed" });
1808
+ );
1809
+ const hasAnyFailures = failed > 0;
1810
+ hasAnyFailures && succeeded === 0 ? (devLog.error("All translation tasks failed", void 0, logContext), dispatch({ type: "SET_OVERALL_STATUS", payload: "error" })) : hasAnyFailures ? (devLog.warn("Translation completed with some failures", {
1811
+ ...logContext,
1812
+ succeeded,
1813
+ failed
1814
+ }), dispatch({ type: "SET_OVERALL_STATUS", payload: "completed" })) : (devLog.info("Document set translation completed successfully", logContext), dispatch({ type: "SET_OVERALL_STATUS", payload: "completed" })), devLog.timeEnd("translateDocumentSet"), devLog.groupEnd();
1769
1815
  } catch (error) {
1770
- return devLog.error("translateDocumentSet failed", error instanceof Error ? error : new Error(String(error)), logContext), devLog.timeEnd("translateDocumentSet"), devLog.groupEnd(), dispatch({ type: "SET_OVERALL_STATUS", payload: "error" }), Promise.reject(error);
1816
+ throw devLog.error(
1817
+ "translateDocumentSet failed with unexpected error",
1818
+ error instanceof Error ? error : new Error(String(error)),
1819
+ logContext
1820
+ ), devLog.timeEnd("translateDocumentSet"), devLog.groupEnd(), dispatch({ type: "SET_OVERALL_STATUS", payload: "error" }), error;
1771
1821
  }
1772
1822
  }, ActionButtonBar = ({ setIsDialogOpen }) => {
1773
1823
  const {
@@ -2086,7 +2136,7 @@ const setupTranslationJobStatuses = (dispatch, sourceDocuments, targetLanguages)
2086
2136
  /* @__PURE__ */ jsx(Label, { children: "Translations" }),
2087
2137
  /* @__PURE__ */ jsx(Card, { padding: 2, tone: "transparent", children: /* @__PURE__ */ jsx(Stack, { space: 2, children: /* @__PURE__ */ jsx("ul", { style: { listStyleType: "none", paddingInlineStart: "0" }, children: jobs.map((job) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Box, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
2088
2138
  /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
2089
- /* @__PURE__ */ jsx(Flex, { align: "center", justify: "center", style: { width: "24px", height: "24px" }, children: ["completed", "skipped"].includes(job.status) ? /* @__PURE__ */ jsx(CheckmarkIcon, { fontSize: 24 }) : job.status === "queued" ? /* @__PURE__ */ jsx(CircleIcon, { fontSize: 24 }) : /* @__PURE__ */ jsx(Spinner, {}) }),
2139
+ /* @__PURE__ */ jsx(Flex, { align: "center", justify: "center", style: { width: "24px", height: "24px" }, children: ["completed", "skipped"].includes(job.status) ? /* @__PURE__ */ jsx(CheckmarkIcon, { fontSize: 24 }) : job.status === "error" ? /* @__PURE__ */ jsx(Box, { style: { color: "var(--card-critical-fg-color)" }, children: /* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 24 }) }) : job.status === "queued" ? /* @__PURE__ */ jsx(CircleIcon, { fontSize: 24 }) : /* @__PURE__ */ jsx(Spinner, {}) }),
2090
2140
  /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
2091
2141
  /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
2092
2142
  /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: job.title || "Untitled Document" }),
@@ -2097,11 +2147,16 @@ const setupTranslationJobStatuses = (dispatch, sourceDocuments, targetLanguages)
2097
2147
  job._type,
2098
2148
  " \u2014 ",
2099
2149
  job._id.slice(-6)
2100
- ] })
2150
+ ] }),
2151
+ job.status === "error" && job.errorMessage ? /* @__PURE__ */ jsx(Card, { tone: "critical", padding: 2, radius: 2, children: /* @__PURE__ */ jsxs(Text, { size: 1, children: [
2152
+ "Error: ",
2153
+ job.errorMessage
2154
+ ] }) }) : null
2101
2155
  ] })
2102
2156
  ] }),
2103
2157
  /* @__PURE__ */ jsxs(Flex, { gap: 2, align: "center", children: [
2104
2158
  job.status === "skipped" ? /* @__PURE__ */ jsx(SkippedBadge, {}) : null,
2159
+ job.status === "error" ? /* @__PURE__ */ jsx(ErrorBadge, {}) : null,
2105
2160
  job.targetId ? /* @__PURE__ */ jsx(
2106
2161
  TranslationOpenerButton,
2107
2162
  {
@@ -2165,6 +2220,13 @@ const setupTranslationJobStatuses = (dispatch, sourceDocuments, targetLanguages)
2165
2220
  content: /* @__PURE__ */ jsx(Box, { padding: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "There was already a fresh translation for this document and language." }) }),
2166
2221
  children: /* @__PURE__ */ jsx(Badge, { tone: "neutral", children: "Skipped" })
2167
2222
  }
2223
+ ), ErrorBadge = () => /* @__PURE__ */ jsx(
2224
+ Tooltip,
2225
+ {
2226
+ portal: !0,
2227
+ content: /* @__PURE__ */ jsx(Box, { padding: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "This translation failed. Check the error message for details." }) }),
2228
+ children: /* @__PURE__ */ jsx(Badge, { tone: "critical", children: "Failed" })
2229
+ }
2168
2230
  ), STATES_IN_WHICH_TO_SHOW_CONFIG = ["fetching_metadata", "idle"], STATES_IN_WHICH_TO_SHOW_TRANSLATION_PROGRESS = [
2169
2231
  "translating",
2170
2232
  "linking_references",