@braze/sanity-plugin-ai-translation 0.2.69 → 0.2.71
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.d.ts +204 -0
- package/dist/index.js +223 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1039,6 +1039,57 @@ const fetchTranslationPrompts = async ({
|
|
|
1039
1039
|
payload
|
|
1040
1040
|
}), mainSourceDocumentId && updateActiveTranslationJob(mainSourceDocumentId, payload);
|
|
1041
1041
|
}
|
|
1042
|
+
}, emitTelemetryEvent = (config, event) => {
|
|
1043
|
+
if (config?.onEvent)
|
|
1044
|
+
try {
|
|
1045
|
+
config.onEvent(event), devLog.debug("Telemetry event emitted", { eventName: event.name });
|
|
1046
|
+
} catch (error) {
|
|
1047
|
+
devLog.warn("Failed to emit telemetry event", {
|
|
1048
|
+
eventName: event.name,
|
|
1049
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
}, emitTelemetryError = (config, bundle) => {
|
|
1053
|
+
if (config?.onError)
|
|
1054
|
+
try {
|
|
1055
|
+
config.onError(bundle), devLog.debug("Telemetry error emitted", {
|
|
1056
|
+
documentId: bundle.documentId,
|
|
1057
|
+
errorType: bundle.error.type
|
|
1058
|
+
});
|
|
1059
|
+
} catch (error) {
|
|
1060
|
+
devLog.warn("Failed to emit telemetry error", {
|
|
1061
|
+
documentId: bundle.documentId,
|
|
1062
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
}, buildErrorBundle = (params) => {
|
|
1066
|
+
const durationMs = Date.now() - params.startTime;
|
|
1067
|
+
return {
|
|
1068
|
+
documentId: params.documentId,
|
|
1069
|
+
documentType: params.documentType,
|
|
1070
|
+
targetLanguage: params.targetLanguage,
|
|
1071
|
+
sourceLanguage: params.sourceLanguage,
|
|
1072
|
+
translationMode: params.translationMode,
|
|
1073
|
+
error: {
|
|
1074
|
+
message: params.error.message,
|
|
1075
|
+
stack: params.error.stack,
|
|
1076
|
+
type: params.errorType
|
|
1077
|
+
},
|
|
1078
|
+
debug: {
|
|
1079
|
+
originalDocument: params.originalDocument,
|
|
1080
|
+
serializedDocument: params.serializedDocument,
|
|
1081
|
+
openaiResponse: params.openaiResponse,
|
|
1082
|
+
translationPrompts: params.translationPrompts,
|
|
1083
|
+
validationErrors: params.validationErrors
|
|
1084
|
+
},
|
|
1085
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1086
|
+
durationMs
|
|
1087
|
+
};
|
|
1088
|
+
}, createTimestamp = () => (/* @__PURE__ */ new Date()).toISOString(), classifyError = (error, context) => {
|
|
1089
|
+
if (context)
|
|
1090
|
+
return context;
|
|
1091
|
+
const message = error.message.toLowerCase();
|
|
1092
|
+
return message.includes("network") || message.includes("fetch") || message.includes("timeout") || message.includes("econnrefused") || message.includes("enotfound") ? "network" : message.includes("openai") || message.includes("gpt") || message.includes("api error") ? "openai_api" : message.includes("validation") || message.includes("structure") || message.includes("invalid") ? "validation" : message.includes("deserialize") || message.includes("parse") ? "deserialization" : message.includes("serialize") || message.includes("xml") ? "serialization" : message.includes("agent") || message.includes("sanity") ? "sanity_agent" : "unknown";
|
|
1042
1093
|
}, updateTranslationMetadata = async ({
|
|
1043
1094
|
client,
|
|
1044
1095
|
targetLanguage,
|
|
@@ -2231,16 +2282,18 @@ const globalTransformRegistry = new TransformRegistry(), callGPT5 = async (apiKe
|
|
|
2231
2282
|
translationPrompts,
|
|
2232
2283
|
targetLanguage,
|
|
2233
2284
|
openaiConfig,
|
|
2234
|
-
previousError,
|
|
2235
|
-
errorContext
|
|
2285
|
+
previousError: _previousError,
|
|
2286
|
+
errorContext,
|
|
2287
|
+
telemetryConfig
|
|
2236
2288
|
}) => {
|
|
2237
|
-
const sourceLanguage = sourceDocument[languageFieldName], logContext = {
|
|
2289
|
+
const startTime = Date.now(), sourceLanguage = sourceDocument[languageFieldName], logContext = {
|
|
2238
2290
|
sourceId: sourceDocument._id,
|
|
2239
2291
|
sourceLanguage
|
|
2240
2292
|
};
|
|
2293
|
+
let serializedDocument, openaiResponseContent;
|
|
2241
2294
|
try {
|
|
2242
2295
|
const sourceText = serializeDocument(sourceDocument);
|
|
2243
|
-
devLog.info("Serialized document for OpenAI", {
|
|
2296
|
+
serializedDocument = sourceText, devLog.info("Serialized document for OpenAI", {
|
|
2244
2297
|
...logContext,
|
|
2245
2298
|
characterCount: sourceText.length,
|
|
2246
2299
|
estimatedTokens: Math.ceil(sourceText.length / 4),
|
|
@@ -2263,7 +2316,7 @@ const globalTransformRegistry = new TransformRegistry(), callGPT5 = async (apiKe
|
|
|
2263
2316
|
model: openaiConfig.model,
|
|
2264
2317
|
reasoningEffort: openaiConfig.reasoningEffort
|
|
2265
2318
|
});
|
|
2266
|
-
devLog.info("OpenAI translation response received", {
|
|
2319
|
+
openaiResponseContent = response.content, devLog.info("OpenAI translation response received", {
|
|
2267
2320
|
...logContext,
|
|
2268
2321
|
tokensUsed: response.tokensUsed,
|
|
2269
2322
|
cost: response.cost,
|
|
@@ -2301,9 +2354,35 @@ const globalTransformRegistry = new TransformRegistry(), callGPT5 = async (apiKe
|
|
|
2301
2354
|
})), setJobStatus(dispatch, sourceDocument._id, targetLanguage, "translating_with_openai", {
|
|
2302
2355
|
tokensUsed: response.tokensUsed.total,
|
|
2303
2356
|
estimatedCost: response.cost
|
|
2304
|
-
}),
|
|
2357
|
+
}), {
|
|
2358
|
+
document: result,
|
|
2359
|
+
tokensUsed: response.tokensUsed.total,
|
|
2360
|
+
cost: response.cost
|
|
2361
|
+
};
|
|
2305
2362
|
} catch (error) {
|
|
2306
|
-
|
|
2363
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
2364
|
+
throw devLog.error("OpenAI translation failed", err, logContext), emitTelemetryError(
|
|
2365
|
+
telemetryConfig,
|
|
2366
|
+
buildErrorBundle({
|
|
2367
|
+
documentId: sourceDocument._id,
|
|
2368
|
+
documentType: sourceDocument._type,
|
|
2369
|
+
targetLanguage,
|
|
2370
|
+
sourceLanguage,
|
|
2371
|
+
translationMode: "openai-only",
|
|
2372
|
+
error: err,
|
|
2373
|
+
errorType: classifyError(err, "openai_api"),
|
|
2374
|
+
startTime,
|
|
2375
|
+
originalDocument: sourceDocument,
|
|
2376
|
+
serializedDocument,
|
|
2377
|
+
openaiResponse: openaiResponseContent,
|
|
2378
|
+
translationPrompts: {
|
|
2379
|
+
globalPrompt: translationPrompts.globalPrompt,
|
|
2380
|
+
localePrompt: translationPrompts.localeInstructions[targetLanguage]?.prompt,
|
|
2381
|
+
protectedPhrases: translationPrompts.protectedPhrases,
|
|
2382
|
+
glossaryTerms: translationPrompts.localeInstructions[targetLanguage]?.glossaryTerms ? [translationPrompts.localeInstructions[targetLanguage].glossaryTerms] : void 0
|
|
2383
|
+
}
|
|
2384
|
+
})
|
|
2385
|
+
), error;
|
|
2307
2386
|
}
|
|
2308
2387
|
}, buildTranslationPrompt$1 = ({
|
|
2309
2388
|
sourceText,
|
|
@@ -2539,9 +2618,10 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2539
2618
|
releaseId,
|
|
2540
2619
|
excludeFields = [],
|
|
2541
2620
|
replaceExisting = !1,
|
|
2542
|
-
mainSourceDocumentId
|
|
2621
|
+
mainSourceDocumentId,
|
|
2622
|
+
telemetryConfig
|
|
2543
2623
|
}) => {
|
|
2544
|
-
const safeExcludeFields = excludeFields.filter((field) => field !== languageFieldName);
|
|
2624
|
+
const startTime = Date.now(), sourceLanguage = sourceDocument[languageFieldName], safeExcludeFields = excludeFields.filter((field) => field !== languageFieldName);
|
|
2545
2625
|
excludeFields.length !== safeExcludeFields.length && devLog.warn("Language field was in excludeFields - removing it to prevent translation errors", {
|
|
2546
2626
|
documentId: sourceDocument._id,
|
|
2547
2627
|
languageFieldName,
|
|
@@ -2580,29 +2660,55 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2580
2660
|
documentId: sourceDocument._id,
|
|
2581
2661
|
documentType: sourceDocument._type
|
|
2582
2662
|
}), documentToTranslate = filteredDocument;
|
|
2583
|
-
let translatedDoc, previousError = null;
|
|
2663
|
+
let translatedDoc, translationMetrics = {}, previousError = null;
|
|
2584
2664
|
const performTranslation = async (errorContext) => {
|
|
2585
2665
|
switch (translationMode) {
|
|
2586
|
-
case "sanity-only":
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2666
|
+
case "sanity-only": {
|
|
2667
|
+
setJobStatus(dispatch, sourceDocument._id, targetLanguage, "translating", void 0, mainSourceDocumentId);
|
|
2668
|
+
try {
|
|
2669
|
+
return { document: await getSanityAgentTranslation({
|
|
2670
|
+
sourceDocument: documentToTranslate,
|
|
2671
|
+
targetLanguage,
|
|
2672
|
+
languageFieldName,
|
|
2673
|
+
schemaId,
|
|
2674
|
+
client,
|
|
2675
|
+
translationPrompts
|
|
2676
|
+
}) };
|
|
2677
|
+
} catch (error) {
|
|
2678
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
2679
|
+
throw emitTelemetryError(
|
|
2680
|
+
telemetryConfig,
|
|
2681
|
+
buildErrorBundle({
|
|
2682
|
+
documentId: sourceDocument._id,
|
|
2683
|
+
documentType: sourceDocument._type,
|
|
2684
|
+
targetLanguage,
|
|
2685
|
+
sourceLanguage,
|
|
2686
|
+
translationMode: "sanity-only",
|
|
2687
|
+
error: err,
|
|
2688
|
+
errorType: classifyError(err, "sanity_agent"),
|
|
2689
|
+
startTime,
|
|
2690
|
+
originalDocument: sourceDocument,
|
|
2691
|
+
translationPrompts: {
|
|
2692
|
+
globalPrompt: translationPrompts.globalPrompt,
|
|
2693
|
+
localePrompt: translationPrompts.localeInstructions[targetLanguage]?.prompt,
|
|
2694
|
+
protectedPhrases: translationPrompts.protectedPhrases
|
|
2695
|
+
}
|
|
2696
|
+
})
|
|
2697
|
+
), error;
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2595
2700
|
case "openai-only": {
|
|
2596
2701
|
if (!openaiConfig?.enabled || !openaiConfig?.apiKey)
|
|
2597
2702
|
throw new Error("OpenAI is not configured but openai-only mode was selected");
|
|
2598
|
-
|
|
2703
|
+
setJobStatus(
|
|
2599
2704
|
dispatch,
|
|
2600
2705
|
sourceDocument._id,
|
|
2601
2706
|
targetLanguage,
|
|
2602
2707
|
"translating_with_openai",
|
|
2603
2708
|
void 0,
|
|
2604
2709
|
mainSourceDocumentId
|
|
2605
|
-
)
|
|
2710
|
+
);
|
|
2711
|
+
const result = await getOpenAITranslation({
|
|
2606
2712
|
dispatch,
|
|
2607
2713
|
sourceDocument: documentToTranslate,
|
|
2608
2714
|
targetLanguage,
|
|
@@ -2610,14 +2716,23 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2610
2716
|
translationPrompts,
|
|
2611
2717
|
openaiConfig,
|
|
2612
2718
|
previousError: errorContext && previousError ? previousError : void 0,
|
|
2613
|
-
errorContext
|
|
2719
|
+
errorContext,
|
|
2720
|
+
telemetryConfig
|
|
2614
2721
|
});
|
|
2722
|
+
return result ? {
|
|
2723
|
+
document: result.document,
|
|
2724
|
+
tokensUsed: result.tokensUsed,
|
|
2725
|
+
cost: result.cost
|
|
2726
|
+
} : { document: null };
|
|
2615
2727
|
}
|
|
2616
2728
|
default:
|
|
2617
2729
|
throw new Error(`Invalid translation mode: ${translationMode}`);
|
|
2618
2730
|
}
|
|
2619
|
-
};
|
|
2620
|
-
if (translatedDoc =
|
|
2731
|
+
}, translationResult = await performTranslation();
|
|
2732
|
+
if (translatedDoc = translationResult.document, translationMetrics = {
|
|
2733
|
+
tokensUsed: translationResult.tokensUsed,
|
|
2734
|
+
cost: translationResult.cost
|
|
2735
|
+
}, !translatedDoc)
|
|
2621
2736
|
return null;
|
|
2622
2737
|
let transformedResult;
|
|
2623
2738
|
Object.keys(originalStructure).length > 0 ? (devLog.debug("Restoring field transforms after translation", {
|
|
@@ -2680,9 +2795,13 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2680
2795
|
targetLanguage,
|
|
2681
2796
|
error: error instanceof Error ? error.message : String(error)
|
|
2682
2797
|
}), previousError = error instanceof Error ? error : new Error(String(error));
|
|
2683
|
-
const errorContext = `Previous translation attempt failed with Sanity validation error: ${previousError.message}. Please ensure the translated document structure exactly matches the source document structure
|
|
2684
|
-
if (translatedDoc =
|
|
2798
|
+
const errorContext = `Previous translation attempt failed with Sanity validation error: ${previousError.message}. Please ensure the translated document structure exactly matches the source document structure.`, retryResult = await performTranslation(errorContext);
|
|
2799
|
+
if (translatedDoc = retryResult.document, !translatedDoc)
|
|
2685
2800
|
throw new Error("Translation retry failed: no document returned");
|
|
2801
|
+
translationMetrics = {
|
|
2802
|
+
tokensUsed: retryResult.tokensUsed,
|
|
2803
|
+
cost: retryResult.cost
|
|
2804
|
+
};
|
|
2686
2805
|
let retryTransformedResult;
|
|
2687
2806
|
Object.keys(originalStructure).length > 0 ? retryTransformedResult = restoreTransforms({
|
|
2688
2807
|
translatedDocument: translatedDoc,
|
|
@@ -2713,11 +2832,19 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2713
2832
|
isRetry: !0
|
|
2714
2833
|
}
|
|
2715
2834
|
}
|
|
2716
|
-
),
|
|
2835
|
+
), {
|
|
2836
|
+
document: retryNewDoc,
|
|
2837
|
+
tokensUsed: translationMetrics.tokensUsed,
|
|
2838
|
+
cost: translationMetrics.cost
|
|
2839
|
+
};
|
|
2717
2840
|
}
|
|
2718
2841
|
throw error;
|
|
2719
2842
|
}
|
|
2720
|
-
return
|
|
2843
|
+
return {
|
|
2844
|
+
document: newDoc,
|
|
2845
|
+
tokensUsed: translationMetrics.tokensUsed,
|
|
2846
|
+
cost: translationMetrics.cost
|
|
2847
|
+
};
|
|
2721
2848
|
}, translateDocument = async ({
|
|
2722
2849
|
dispatch,
|
|
2723
2850
|
client,
|
|
@@ -2732,9 +2859,10 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2732
2859
|
releaseId,
|
|
2733
2860
|
excludeFields,
|
|
2734
2861
|
replaceExisting,
|
|
2735
|
-
mainSourceDocumentId
|
|
2862
|
+
mainSourceDocumentId,
|
|
2863
|
+
telemetryConfig
|
|
2736
2864
|
}) => {
|
|
2737
|
-
const logContext = {
|
|
2865
|
+
const jobStartTime = Date.now(), logContext = {
|
|
2738
2866
|
documentId: sourceDocument._id,
|
|
2739
2867
|
targetLanguage,
|
|
2740
2868
|
schemaId,
|
|
@@ -2746,7 +2874,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2746
2874
|
client,
|
|
2747
2875
|
sourceDocument,
|
|
2748
2876
|
sourceLanguage
|
|
2749
|
-
}), existingTranslationId = getExistingTranslationId(translationMetadata, targetLanguage),
|
|
2877
|
+
}), existingTranslationId = getExistingTranslationId(translationMetadata, targetLanguage), translationResult = await handleTranslation({
|
|
2750
2878
|
dispatch,
|
|
2751
2879
|
client,
|
|
2752
2880
|
schemaId,
|
|
@@ -2760,8 +2888,9 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2760
2888
|
releaseId,
|
|
2761
2889
|
excludeFields,
|
|
2762
2890
|
replaceExisting,
|
|
2763
|
-
mainSourceDocumentId
|
|
2764
|
-
|
|
2891
|
+
mainSourceDocumentId,
|
|
2892
|
+
telemetryConfig
|
|
2893
|
+
}), newDocument = translationResult?.document;
|
|
2765
2894
|
if (!newDocument) {
|
|
2766
2895
|
devLog.error("Translation failed: no document returned", new Error("Translation returned null"), logContext), setJobStatus(
|
|
2767
2896
|
dispatch,
|
|
@@ -2798,12 +2927,27 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2798
2927
|
targetLanguage,
|
|
2799
2928
|
"completed",
|
|
2800
2929
|
{
|
|
2801
|
-
targetId: newDocument._id
|
|
2930
|
+
targetId: newDocument._id,
|
|
2931
|
+
tokensUsed: translationResult?.tokensUsed,
|
|
2932
|
+
estimatedCost: translationResult?.cost
|
|
2802
2933
|
},
|
|
2803
2934
|
mainSourceDocumentId
|
|
2804
2935
|
), devLog.info("Translation completed successfully", {
|
|
2805
2936
|
...logContext,
|
|
2806
2937
|
newDocumentId: newDocument._id
|
|
2938
|
+
}), emitTelemetryEvent(telemetryConfig, {
|
|
2939
|
+
name: "translation.job_completed",
|
|
2940
|
+
timestamp: createTimestamp(),
|
|
2941
|
+
data: {
|
|
2942
|
+
documentId: sourceDocument._id,
|
|
2943
|
+
documentType: sourceDocument._type,
|
|
2944
|
+
sourceLanguage,
|
|
2945
|
+
targetLanguage,
|
|
2946
|
+
translationMode,
|
|
2947
|
+
durationMs: Date.now() - jobStartTime,
|
|
2948
|
+
tokensUsed: translationResult?.tokensUsed,
|
|
2949
|
+
estimatedCost: translationResult?.cost
|
|
2950
|
+
}
|
|
2807
2951
|
}), devLog.timeEnd("translateDocument"), devLog.groupEnd(), newDocument._id;
|
|
2808
2952
|
} catch (error) {
|
|
2809
2953
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -2831,9 +2975,10 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2831
2975
|
translationMode,
|
|
2832
2976
|
openaiConfig,
|
|
2833
2977
|
excludeFields,
|
|
2834
|
-
releaseConfig
|
|
2978
|
+
releaseConfig,
|
|
2979
|
+
telemetryConfig
|
|
2835
2980
|
}) => {
|
|
2836
|
-
const logContext = {
|
|
2981
|
+
const batchStartTime = Date.now(), logContext = {
|
|
2837
2982
|
documentId: sourceDocument._id,
|
|
2838
2983
|
documentRev: sourceDocument._rev,
|
|
2839
2984
|
targetLanguages,
|
|
@@ -2847,7 +2992,19 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2847
2992
|
const sourceLanguage = sourceDocument[languageFieldName];
|
|
2848
2993
|
if (!sourceLanguage)
|
|
2849
2994
|
throw devLog.error("Source language not found"), new Error("Source language not found");
|
|
2850
|
-
if (
|
|
2995
|
+
if (emitTelemetryEvent(telemetryConfig, {
|
|
2996
|
+
name: "translation.batch_started",
|
|
2997
|
+
timestamp: createTimestamp(),
|
|
2998
|
+
data: {
|
|
2999
|
+
documentId: sourceDocument._id,
|
|
3000
|
+
documentType: sourceDocument._type,
|
|
3001
|
+
sourceLanguage,
|
|
3002
|
+
targetLanguages,
|
|
3003
|
+
translationMode,
|
|
3004
|
+
referenceCount: references.length,
|
|
3005
|
+
releaseMode: releaseConfig.mode
|
|
3006
|
+
}
|
|
3007
|
+
}), maxConcurrentTranslationJobs && translationSemaphore.updatePermits(maxConcurrentTranslationJobs), dispatch({
|
|
2851
3008
|
type: "SET_OVERALL_STATUS",
|
|
2852
3009
|
payload: "translating"
|
|
2853
3010
|
}), releaseConfig.mode === "existing" && releaseConfig.existingReleaseId)
|
|
@@ -2940,7 +3097,8 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2940
3097
|
excludeFields,
|
|
2941
3098
|
replaceExisting: releaseConfig.replaceExisting,
|
|
2942
3099
|
// Pass main source document ID for active translations tracking
|
|
2943
|
-
mainSourceDocumentId: sourceDocument._id
|
|
3100
|
+
mainSourceDocumentId: sourceDocument._id,
|
|
3101
|
+
telemetryConfig
|
|
2944
3102
|
});
|
|
2945
3103
|
versionedTargetDocumentId && versionedTargetDocumentIds.push(versionedTargetDocumentId);
|
|
2946
3104
|
}
|
|
@@ -2965,6 +3123,20 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2965
3123
|
failed,
|
|
2966
3124
|
skipped: skippedCount,
|
|
2967
3125
|
targetDocuments: versionedTargetDocumentIds.length
|
|
3126
|
+
}), emitTelemetryEvent(telemetryConfig, {
|
|
3127
|
+
name: "translation.batch_completed",
|
|
3128
|
+
timestamp: createTimestamp(),
|
|
3129
|
+
data: {
|
|
3130
|
+
documentId: sourceDocument._id,
|
|
3131
|
+
documentType: sourceDocument._type,
|
|
3132
|
+
sourceLanguage,
|
|
3133
|
+
targetLanguages,
|
|
3134
|
+
translationMode,
|
|
3135
|
+
succeeded,
|
|
3136
|
+
failed,
|
|
3137
|
+
skipped: skippedCount,
|
|
3138
|
+
durationMs: Date.now() - batchStartTime
|
|
3139
|
+
}
|
|
2968
3140
|
}), dispatch({
|
|
2969
3141
|
type: "SET_OVERALL_STATUS",
|
|
2970
3142
|
payload: "linking_references"
|
|
@@ -3110,7 +3282,8 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3110
3282
|
// Use the override release ID if provided (from conflict context),
|
|
3111
3283
|
// otherwise use the current releaseConfig value
|
|
3112
3284
|
existingReleaseId: overrideReleaseId ?? releaseConfig.existingReleaseId
|
|
3113
|
-
}
|
|
3285
|
+
},
|
|
3286
|
+
telemetryConfig: config.telemetry
|
|
3114
3287
|
});
|
|
3115
3288
|
},
|
|
3116
3289
|
[
|
|
@@ -3124,6 +3297,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3124
3297
|
config.maxReferenceDepth,
|
|
3125
3298
|
config.openai,
|
|
3126
3299
|
config.excludeFields,
|
|
3300
|
+
config.telemetry,
|
|
3127
3301
|
filteredReferences,
|
|
3128
3302
|
translationMode,
|
|
3129
3303
|
releaseConfig
|
|
@@ -3343,7 +3517,9 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3343
3517
|
}), error;
|
|
3344
3518
|
}
|
|
3345
3519
|
}, ReconcileReferencesButton = ({ sourceLanguage }) => {
|
|
3346
|
-
const {
|
|
3520
|
+
const { releaseConfig, overallStatus, config } = useTranslationContext(), client = useClient({ apiVersion: "vX" }), [documentCount, setDocumentCount] = useState(null), [isLoadingCount, setIsLoadingCount] = useState(!1), [reconcilingStatus, setReconcilingStatus] = useState("idle"), [reconciliationProgress, setReconciliationProgress] = useState(
|
|
3521
|
+
void 0
|
|
3522
|
+
), releaseId = releaseConfig.existingReleaseId, languageFieldName = config?.languageFieldName ?? "language";
|
|
3347
3523
|
useEffect(() => {
|
|
3348
3524
|
if (!releaseId || releaseConfig.mode !== "existing") {
|
|
3349
3525
|
setDocumentCount(null);
|
|
@@ -3378,7 +3554,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3378
3554
|
releaseId,
|
|
3379
3555
|
sourceLanguage,
|
|
3380
3556
|
component: "ReconcileReferencesButton"
|
|
3381
|
-
}),
|
|
3557
|
+
}), setReconcilingStatus("reconciling");
|
|
3382
3558
|
try {
|
|
3383
3559
|
const result = await reconcileReleaseReferences({
|
|
3384
3560
|
client,
|
|
@@ -3386,27 +3562,24 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3386
3562
|
sourceLanguage,
|
|
3387
3563
|
languageFieldName,
|
|
3388
3564
|
onProgress: (current, total) => {
|
|
3389
|
-
|
|
3390
|
-
type: "SET_RECONCILIATION_PROGRESS",
|
|
3391
|
-
payload: { current, total }
|
|
3392
|
-
});
|
|
3565
|
+
setReconciliationProgress({ current, total });
|
|
3393
3566
|
}
|
|
3394
3567
|
});
|
|
3395
3568
|
devLog.info("Reference reconciliation completed", {
|
|
3396
3569
|
releaseId,
|
|
3397
3570
|
...result,
|
|
3398
3571
|
component: "ReconcileReferencesButton"
|
|
3399
|
-
}),
|
|
3400
|
-
|
|
3572
|
+
}), setReconcilingStatus("completed"), setTimeout(() => {
|
|
3573
|
+
setReconcilingStatus("idle"), setReconciliationProgress(void 0);
|
|
3401
3574
|
}, 2e3);
|
|
3402
3575
|
} catch (error) {
|
|
3403
3576
|
devLog.error("Reference reconciliation failed", error instanceof Error ? error : new Error(String(error)), {
|
|
3404
3577
|
releaseId,
|
|
3405
3578
|
component: "ReconcileReferencesButton"
|
|
3406
|
-
}),
|
|
3579
|
+
}), setReconcilingStatus("error"), setReconciliationProgress(void 0);
|
|
3407
3580
|
}
|
|
3408
3581
|
}
|
|
3409
|
-
}, [releaseId, sourceLanguage, languageFieldName, client
|
|
3582
|
+
}, [releaseId, sourceLanguage, languageFieldName, client]);
|
|
3410
3583
|
if (releaseConfig.mode !== "existing" || !releaseId)
|
|
3411
3584
|
return null;
|
|
3412
3585
|
const isTranslating = overallStatus === "translating" || overallStatus === "linking_references", isReconciling = reconcilingStatus === "reconciling";
|
|
@@ -3583,7 +3756,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3583
3756
|
}
|
|
3584
3757
|
)
|
|
3585
3758
|
] }),
|
|
3586
|
-
|
|
3759
|
+
isSelected && sourceLanguage && showReconcileUI && /* @__PURE__ */ jsx(ReconcileReferencesButton, { sourceLanguage })
|
|
3587
3760
|
] })
|
|
3588
3761
|
},
|
|
3589
3762
|
release._id
|