@braze/sanity-plugin-ai-translation 0.2.51 → 0.2.53
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 +51 -0
- package/dist/index.js +308 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -446,6 +446,21 @@ declare interface TranslatableVTTCaptions {
|
|
|
446
446
|
_originalMetadata: VTTCaptionMetadata[];
|
|
447
447
|
}
|
|
448
448
|
|
|
449
|
+
/**
|
|
450
|
+
* Special type to track transformed Wistia captions.
|
|
451
|
+
* This combines metadata separation for token efficiency with compact text format for translation.
|
|
452
|
+
*/
|
|
453
|
+
declare interface TranslatableWistiaCaptions {
|
|
454
|
+
_type: "translatable.wistia.captions";
|
|
455
|
+
translationText: string;
|
|
456
|
+
_originalMetadata: WistiaCaptionsMetadata;
|
|
457
|
+
_srtCues: Array<{
|
|
458
|
+
index: number;
|
|
459
|
+
startTime: string;
|
|
460
|
+
endTime: string;
|
|
461
|
+
}>;
|
|
462
|
+
}
|
|
463
|
+
|
|
449
464
|
/**
|
|
450
465
|
* Schema for translation history
|
|
451
466
|
*
|
|
@@ -497,4 +512,40 @@ export declare const vttCaptionTransform: FieldTransform<
|
|
|
497
512
|
TranslatableVTTCaptions
|
|
498
513
|
>;
|
|
499
514
|
|
|
515
|
+
/**
|
|
516
|
+
* Represents a Wistia captions object with SRT content and metadata.
|
|
517
|
+
*/
|
|
518
|
+
declare interface WistiaCaptions {
|
|
519
|
+
captionContent?: string;
|
|
520
|
+
captionFileName?: string;
|
|
521
|
+
isoLanguage?: string;
|
|
522
|
+
captionUploadStatus?: string;
|
|
523
|
+
captionUploadMessage?: string;
|
|
524
|
+
[key: string]: string | undefined;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Wistia captions metadata without captionContent, used for preservation during translation.
|
|
529
|
+
*/
|
|
530
|
+
declare interface WistiaCaptionsMetadata {
|
|
531
|
+
captionFileName?: string;
|
|
532
|
+
isoLanguage?: string;
|
|
533
|
+
captionUploadStatus?: string;
|
|
534
|
+
captionUploadMessage?: string;
|
|
535
|
+
_originalIndex: number;
|
|
536
|
+
[key: string]: string | number | undefined;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Transform for handling Wistia captions in documents using SRT format.
|
|
541
|
+
* This stores metadata separately for token efficiency while formatting
|
|
542
|
+
* text content in a compact indexed format for better translation results.
|
|
543
|
+
*
|
|
544
|
+
* @public
|
|
545
|
+
*/
|
|
546
|
+
export declare const wistiaCaptionTransform: FieldTransform<
|
|
547
|
+
WistiaCaptions,
|
|
548
|
+
TranslatableWistiaCaptions
|
|
549
|
+
>;
|
|
550
|
+
|
|
500
551
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -80,7 +80,9 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
80
80
|
}, updateActiveTranslationJob = (documentId, job) => {
|
|
81
81
|
const entry = activeTranslations.get(documentId);
|
|
82
82
|
if (entry) {
|
|
83
|
-
const jobKey = `${job._id}_${job.language}`, existingJob = entry.state.translationJobs.get(jobKey),
|
|
83
|
+
const jobKey = `${job._id}_${job.language}`, existingJob = entry.state.translationJobs.get(jobKey), jobWithDefinedValues = Object.fromEntries(
|
|
84
|
+
Object.entries(job).filter(([_, value]) => value !== void 0)
|
|
85
|
+
), mergedJob = existingJob ? { ...existingJob, ...jobWithDefinedValues } : jobWithDefinedValues;
|
|
84
86
|
entry.state.translationJobs.set(jobKey, mergedJob), notifySubscribers(entry);
|
|
85
87
|
}
|
|
86
88
|
}, getActiveTranslation = (documentId) => activeTranslations.get(documentId)?.state ?? null, subscribeToActiveTranslation = (documentId, callback) => {
|
|
@@ -1251,7 +1253,9 @@ function restoreTransforms({
|
|
|
1251
1253
|
schemaType,
|
|
1252
1254
|
document: translatedDocument
|
|
1253
1255
|
};
|
|
1254
|
-
devLog.debug("Restoring transform for field", { fieldPath, schemaType })
|
|
1256
|
+
devLog.debug("Restoring transform for field", { fieldPath, schemaType });
|
|
1257
|
+
const restoredValue = transform.fromTranslatable(value, originalValue, context);
|
|
1258
|
+
restoredObj[key] = restoredValue;
|
|
1255
1259
|
} else
|
|
1256
1260
|
restoredObj[key] = restoreTransforms({
|
|
1257
1261
|
translatedDocument: value,
|
|
@@ -1489,9 +1493,9 @@ const globalTransformRegistry = new TransformRegistry(), callGPT5 = async (apiKe
|
|
|
1489
1493
|
}, modelPricing = pricing[model] || pricing["gpt-5"], cachedInputRate = model === "gpt-5.1" ? 0.125 / 1e6 : modelPricing.input;
|
|
1490
1494
|
return Math.max(0, tokens.prompt - tokens.cached) * modelPricing.input + tokens.cached * cachedInputRate + tokens.completion * modelPricing.output + tokens.reasoning * modelPricing.reasoning;
|
|
1491
1495
|
}, deserializeDocument = (originalDoc, reviewedText) => {
|
|
1492
|
-
const parsed = parseReviewFormat(reviewedText), result = cloneDeep(originalDoc);
|
|
1496
|
+
const parsed = parseReviewFormat(reviewedText, originalDoc), result = cloneDeep(originalDoc);
|
|
1493
1497
|
return applyTextChanges(result, parsed), result;
|
|
1494
|
-
}, parseReviewFormat = (text) => {
|
|
1498
|
+
}, parseReviewFormat = (text, originalDoc) => {
|
|
1495
1499
|
const root = [], stack = [], lines = text.split(`
|
|
1496
1500
|
`);
|
|
1497
1501
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -1524,8 +1528,16 @@ const globalTransformRegistry = new TransformRegistry(), callGPT5 = async (apiKe
|
|
|
1524
1528
|
}
|
|
1525
1529
|
const content = contentLines.join(`
|
|
1526
1530
|
`);
|
|
1527
|
-
let contentType
|
|
1528
|
-
|
|
1531
|
+
let contentType;
|
|
1532
|
+
try {
|
|
1533
|
+
const fieldValue = get(originalDoc, [fieldName]);
|
|
1534
|
+
if (fieldValue && typeof fieldValue == "object" && fieldValue !== null) {
|
|
1535
|
+
const fieldType = fieldValue._type;
|
|
1536
|
+
typeof fieldType == "string" && fieldType.startsWith("translatable.") && (contentType = fieldType);
|
|
1537
|
+
}
|
|
1538
|
+
} catch {
|
|
1539
|
+
}
|
|
1540
|
+
contentType || (content.includes("<block") || content.includes("<span") ? contentType = "translatable.richtext" : contentType = "translatable.vtt.captions");
|
|
1529
1541
|
const node = {
|
|
1530
1542
|
type: "field",
|
|
1531
1543
|
name: fieldName,
|
|
@@ -1562,7 +1574,7 @@ const globalTransformRegistry = new TransformRegistry(), callGPT5 = async (apiKe
|
|
|
1562
1574
|
parent && parent.children.push(node);
|
|
1563
1575
|
} else
|
|
1564
1576
|
root.push(node);
|
|
1565
|
-
else if (attributes.type
|
|
1577
|
+
else if (attributes.type && typeof attributes.type == "string" && attributes.type.startsWith("translatable.")) {
|
|
1566
1578
|
const contentLines = [];
|
|
1567
1579
|
for (i++; i < lines.length; ) {
|
|
1568
1580
|
const currentLine = lines[i];
|
|
@@ -1624,14 +1636,13 @@ const globalTransformRegistry = new TransformRegistry(), callGPT5 = async (apiKe
|
|
|
1624
1636
|
applyFieldChanges(doc, path, node);
|
|
1625
1637
|
}
|
|
1626
1638
|
}, applyFieldChanges = (doc, path, node) => {
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
fieldValue && typeof fieldValue == "object" && fieldValue._type === "translatable.vtt.captions" && node.text && set(doc, [...path, "translationText"], node.text);
|
|
1630
|
-
return;
|
|
1631
|
-
}
|
|
1632
|
-
if (node.attributes.type === "translatable.richtext") {
|
|
1639
|
+
const nodeType = node.attributes.type;
|
|
1640
|
+
if (typeof nodeType == "string" && nodeType.startsWith("translatable.")) {
|
|
1633
1641
|
const fieldValue = get(doc, path);
|
|
1634
|
-
fieldValue && typeof fieldValue == "object" && fieldValue
|
|
1642
|
+
if (fieldValue && typeof fieldValue == "object" && fieldValue !== null) {
|
|
1643
|
+
const fieldType = fieldValue._type;
|
|
1644
|
+
typeof fieldType == "string" && fieldType === nodeType && node.text && set(doc, [...path, "translationText"], node.text);
|
|
1645
|
+
}
|
|
1635
1646
|
return;
|
|
1636
1647
|
}
|
|
1637
1648
|
if (node.attributes.type === "array") {
|
|
@@ -1719,12 +1730,9 @@ const globalTransformRegistry = new TransformRegistry(), callGPT5 = async (apiKe
|
|
|
1719
1730
|
return;
|
|
1720
1731
|
}
|
|
1721
1732
|
if (isPlainObject(value)) {
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
}
|
|
1726
|
-
if (value._type === "translatable.richtext" && typeof value.translationText == "string") {
|
|
1727
|
-
lines.push(`${indentStr}--- ${fieldName} ---`), lines.push(value.translationText), lines.push(`${indentStr}--- /${fieldName} ---`);
|
|
1733
|
+
const valueObj = value, valueType = valueObj._type, translationText = valueObj.translationText;
|
|
1734
|
+
if (typeof valueType == "string" && valueType.startsWith("translatable.") && typeof translationText == "string") {
|
|
1735
|
+
lines.push(`${indentStr}--- ${fieldName} ---`), lines.push(translationText), lines.push(`${indentStr}--- /${fieldName} ---`);
|
|
1728
1736
|
return;
|
|
1729
1737
|
}
|
|
1730
1738
|
lines.push(`${indentStr}<field name="${fieldName}" type="object">`);
|
|
@@ -3799,6 +3807,284 @@ function deserializeVTTCaptionText(translationText, originalMetadata) {
|
|
|
3799
3807
|
resultExample: result.length > 0 ? result[0] : null
|
|
3800
3808
|
}), result;
|
|
3801
3809
|
}
|
|
3810
|
+
const LOCALE_TO_ISO = {
|
|
3811
|
+
// English variants
|
|
3812
|
+
"en-us": "eng",
|
|
3813
|
+
"en-US": "eng",
|
|
3814
|
+
"en-gb": "eng",
|
|
3815
|
+
"en-GB": "eng",
|
|
3816
|
+
"en-ca": "eng",
|
|
3817
|
+
"en-CA": "eng",
|
|
3818
|
+
"en-au": "eng",
|
|
3819
|
+
"en-AU": "eng",
|
|
3820
|
+
// Spanish variants
|
|
3821
|
+
es: "spa",
|
|
3822
|
+
"es-es": "spa",
|
|
3823
|
+
"es-ES": "spa",
|
|
3824
|
+
"es-mx": "spa",
|
|
3825
|
+
"es-MX": "spa",
|
|
3826
|
+
// French variants
|
|
3827
|
+
fr: "fra",
|
|
3828
|
+
"fr-fr": "fra",
|
|
3829
|
+
"fr-FR": "fra",
|
|
3830
|
+
"fr-ca": "fra",
|
|
3831
|
+
"fr-CA": "fra",
|
|
3832
|
+
// German variants
|
|
3833
|
+
de: "ger",
|
|
3834
|
+
"de-de": "ger",
|
|
3835
|
+
"de-DE": "ger",
|
|
3836
|
+
"de-at": "ger",
|
|
3837
|
+
"de-AT": "ger",
|
|
3838
|
+
// Italian variants
|
|
3839
|
+
it: "ita",
|
|
3840
|
+
"it-it": "ita",
|
|
3841
|
+
"it-IT": "ita",
|
|
3842
|
+
// Portuguese variants
|
|
3843
|
+
pt: "por",
|
|
3844
|
+
"pt-br": "por",
|
|
3845
|
+
"pt-BR": "por",
|
|
3846
|
+
"pt-pt": "por",
|
|
3847
|
+
"pt-PT": "por",
|
|
3848
|
+
// Russian variants
|
|
3849
|
+
ru: "rus",
|
|
3850
|
+
"ru-ru": "rus",
|
|
3851
|
+
"ru-RU": "rus",
|
|
3852
|
+
// Japanese variants
|
|
3853
|
+
ja: "jpn",
|
|
3854
|
+
"ja-jp": "jpn",
|
|
3855
|
+
"ja-JP": "jpn",
|
|
3856
|
+
// Korean variants
|
|
3857
|
+
ko: "kor",
|
|
3858
|
+
"ko-kr": "kor",
|
|
3859
|
+
"ko-KR": "kor",
|
|
3860
|
+
// Chinese variants
|
|
3861
|
+
zh: "chi",
|
|
3862
|
+
"zh-cn": "chi",
|
|
3863
|
+
"zh-CN": "chi",
|
|
3864
|
+
"zh-tw": "chi",
|
|
3865
|
+
"zh-TW": "chi",
|
|
3866
|
+
"zh-hk": "chi",
|
|
3867
|
+
"zh-HK": "chi"
|
|
3868
|
+
}, normalizeToIsoLanguageCode = (code) => {
|
|
3869
|
+
const normalizedCode = code.toLowerCase();
|
|
3870
|
+
return LOCALE_TO_ISO[normalizedCode];
|
|
3871
|
+
}, wistiaCaptionTransform = {
|
|
3872
|
+
matcher: {
|
|
3873
|
+
fieldName: "wistiaCaptions"
|
|
3874
|
+
},
|
|
3875
|
+
toTranslatable: (wistiaCaptions, context) => {
|
|
3876
|
+
if (devLog.info("Wistia captions toTranslatable - input:", {
|
|
3877
|
+
fieldPath: context.fieldPath,
|
|
3878
|
+
hasCaptionContent: !!wistiaCaptions?.captionContent,
|
|
3879
|
+
captionContentLength: wistiaCaptions?.captionContent?.length ?? 0,
|
|
3880
|
+
isoLanguage: wistiaCaptions?.isoLanguage
|
|
3881
|
+
}), !wistiaCaptions || !wistiaCaptions.captionContent)
|
|
3882
|
+
return devLog.debug("Wistia caption field is missing or has no content, returning empty transform", {
|
|
3883
|
+
fieldPath: context.fieldPath,
|
|
3884
|
+
value: wistiaCaptions
|
|
3885
|
+
}), {
|
|
3886
|
+
_type: "translatable.wistia.captions",
|
|
3887
|
+
translationText: "",
|
|
3888
|
+
_originalMetadata: {
|
|
3889
|
+
captionFileName: wistiaCaptions?.captionFileName,
|
|
3890
|
+
isoLanguage: wistiaCaptions?.isoLanguage,
|
|
3891
|
+
captionUploadStatus: wistiaCaptions?.captionUploadStatus,
|
|
3892
|
+
captionUploadMessage: wistiaCaptions?.captionUploadMessage,
|
|
3893
|
+
_originalIndex: 0
|
|
3894
|
+
},
|
|
3895
|
+
_srtCues: []
|
|
3896
|
+
};
|
|
3897
|
+
devLog.info("Applying Wistia caption transform", {
|
|
3898
|
+
fieldPath: context.fieldPath,
|
|
3899
|
+
captionContentPreview: wistiaCaptions.captionContent.substring(0, 200)
|
|
3900
|
+
});
|
|
3901
|
+
const srtCues = parseSRTContent(wistiaCaptions.captionContent);
|
|
3902
|
+
devLog.debug("Parsed SRT cues:", {
|
|
3903
|
+
fieldPath: context.fieldPath,
|
|
3904
|
+
cueCount: srtCues.length,
|
|
3905
|
+
firstCue: srtCues.length > 0 ? srtCues[0] : null
|
|
3906
|
+
});
|
|
3907
|
+
const translationText = serializeWistiaCaptionText(srtCues), originalMetadata = {
|
|
3908
|
+
captionFileName: wistiaCaptions.captionFileName,
|
|
3909
|
+
isoLanguage: wistiaCaptions.isoLanguage,
|
|
3910
|
+
captionUploadStatus: wistiaCaptions.captionUploadStatus,
|
|
3911
|
+
captionUploadMessage: wistiaCaptions.captionUploadMessage,
|
|
3912
|
+
_originalIndex: 0
|
|
3913
|
+
}, srtCuesMetadata = srtCues.map((cue) => ({
|
|
3914
|
+
index: cue.index,
|
|
3915
|
+
startTime: cue.startTime,
|
|
3916
|
+
endTime: cue.endTime
|
|
3917
|
+
}));
|
|
3918
|
+
return devLog.info("Wistia captions serialized:", {
|
|
3919
|
+
fieldPath: context.fieldPath,
|
|
3920
|
+
translationTextLength: translationText.length,
|
|
3921
|
+
translationTextPreview: translationText.substring(0, 200) + (translationText.length > 200 ? "..." : ""),
|
|
3922
|
+
cueCount: srtCues.length
|
|
3923
|
+
}), {
|
|
3924
|
+
_type: "translatable.wistia.captions",
|
|
3925
|
+
translationText,
|
|
3926
|
+
_originalMetadata: originalMetadata,
|
|
3927
|
+
_srtCues: srtCuesMetadata
|
|
3928
|
+
};
|
|
3929
|
+
},
|
|
3930
|
+
fromTranslatable: (translatedValue, originalValue, context) => {
|
|
3931
|
+
if (devLog.info("Wistia captions fromTranslatable - input:", {
|
|
3932
|
+
fieldPath: context.fieldPath,
|
|
3933
|
+
valueType: typeof translatedValue,
|
|
3934
|
+
isCorrectType: translatedValue._type === "translatable.wistia.captions",
|
|
3935
|
+
hasText: !!translatedValue.translationText,
|
|
3936
|
+
hasMetadata: !!translatedValue._originalMetadata,
|
|
3937
|
+
hasCues: Array.isArray(translatedValue._srtCues)
|
|
3938
|
+
}), !translatedValue || translatedValue._type !== "translatable.wistia.captions" || !translatedValue._originalMetadata || !Array.isArray(translatedValue._srtCues))
|
|
3939
|
+
return devLog.debug("Value is not a translatable Wistia caption object, returning original", {
|
|
3940
|
+
fieldPath: context.fieldPath,
|
|
3941
|
+
valueType: typeof translatedValue,
|
|
3942
|
+
translatedValue
|
|
3943
|
+
}), originalValue || {};
|
|
3944
|
+
devLog.info("Processing translated Wistia captions", {
|
|
3945
|
+
fieldPath: context.fieldPath,
|
|
3946
|
+
cueCount: translatedValue._srtCues.length
|
|
3947
|
+
});
|
|
3948
|
+
const { translationText, _originalMetadata, _srtCues } = translatedValue;
|
|
3949
|
+
devLog.info("Wistia captions translationText:", {
|
|
3950
|
+
fieldPath: context.fieldPath,
|
|
3951
|
+
translationTextLength: translationText.length,
|
|
3952
|
+
translationTextPreview: translationText.substring(0, 200) + (translationText.length > 200 ? "..." : "")
|
|
3953
|
+
});
|
|
3954
|
+
const reconstructedCaptionContent = deserializeWistiaCaptionText(translationText, _srtCues), documentLanguage = getDocumentLanguage(context.document);
|
|
3955
|
+
let updatedIsoLanguage = _originalMetadata.isoLanguage;
|
|
3956
|
+
if (documentLanguage) {
|
|
3957
|
+
const isoCode = normalizeToIsoLanguageCode(documentLanguage);
|
|
3958
|
+
isoCode ? (updatedIsoLanguage = isoCode, devLog.debug("Updated isoLanguage based on document language", {
|
|
3959
|
+
fieldPath: context.fieldPath,
|
|
3960
|
+
documentLanguage,
|
|
3961
|
+
isoCode
|
|
3962
|
+
})) : devLog.debug("Could not convert document language to ISO code, preserving original", {
|
|
3963
|
+
fieldPath: context.fieldPath,
|
|
3964
|
+
documentLanguage,
|
|
3965
|
+
originalIsoLanguage: _originalMetadata.isoLanguage
|
|
3966
|
+
});
|
|
3967
|
+
} else
|
|
3968
|
+
devLog.debug("Document language field not found, preserving original isoLanguage", {
|
|
3969
|
+
fieldPath: context.fieldPath,
|
|
3970
|
+
originalIsoLanguage: _originalMetadata.isoLanguage
|
|
3971
|
+
});
|
|
3972
|
+
const result = {
|
|
3973
|
+
captionContent: reconstructedCaptionContent,
|
|
3974
|
+
captionFileName: _originalMetadata.captionFileName,
|
|
3975
|
+
isoLanguage: updatedIsoLanguage,
|
|
3976
|
+
captionUploadStatus: _originalMetadata.captionUploadStatus,
|
|
3977
|
+
captionUploadMessage: _originalMetadata.captionUploadMessage
|
|
3978
|
+
};
|
|
3979
|
+
return devLog.info("Wistia captions final result:", {
|
|
3980
|
+
fieldPath: context.fieldPath,
|
|
3981
|
+
hasCaptionContent: !!result.captionContent,
|
|
3982
|
+
captionContentLength: result.captionContent?.length ?? 0,
|
|
3983
|
+
isoLanguage: result.isoLanguage
|
|
3984
|
+
}), result;
|
|
3985
|
+
}
|
|
3986
|
+
};
|
|
3987
|
+
function parseSRTContent(content) {
|
|
3988
|
+
if (devLog.debug("parseSRTContent - input:", {
|
|
3989
|
+
contentLength: content.length,
|
|
3990
|
+
contentPreview: content.substring(0, 100) + (content.length > 100 ? "..." : "")
|
|
3991
|
+
}), !content || content.trim() === "")
|
|
3992
|
+
return [];
|
|
3993
|
+
let normalizedContent = content;
|
|
3994
|
+
content.includes("\\n") && !content.includes(`
|
|
3995
|
+
`) && (normalizedContent = content.replace(/\\n/g, `
|
|
3996
|
+
`), devLog.debug("Unescaped newlines in SRT content", {
|
|
3997
|
+
originalLength: content.length,
|
|
3998
|
+
normalizedLength: normalizedContent.length
|
|
3999
|
+
}));
|
|
4000
|
+
const cues = [], cueBlocks = normalizedContent.split(/\n\s*\n/);
|
|
4001
|
+
for (const block of cueBlocks) {
|
|
4002
|
+
const lines = block.trim().split(`
|
|
4003
|
+
`);
|
|
4004
|
+
if (lines.length < 3)
|
|
4005
|
+
continue;
|
|
4006
|
+
const cueNumber = Number.parseInt(lines[0].trim(), 10);
|
|
4007
|
+
if (Number.isNaN(cueNumber)) {
|
|
4008
|
+
devLog.warn("Invalid SRT cue number", { line: lines[0] });
|
|
4009
|
+
continue;
|
|
4010
|
+
}
|
|
4011
|
+
const timestampLine = lines[1].trim(), timestampMatch = timestampLine.match(/^(\d{2}:\d{2}:\d{2}[,.]\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2}[,.]\d{3})$/);
|
|
4012
|
+
if (!timestampMatch) {
|
|
4013
|
+
devLog.warn("Invalid SRT timestamp format", { line: timestampLine });
|
|
4014
|
+
continue;
|
|
4015
|
+
}
|
|
4016
|
+
const startTime = timestampMatch[1].replace(".", ","), endTime = timestampMatch[2].replace(".", ","), text = lines.slice(2).join(`
|
|
4017
|
+
`).trim();
|
|
4018
|
+
text && cues.push({
|
|
4019
|
+
index: cueNumber,
|
|
4020
|
+
startTime,
|
|
4021
|
+
endTime,
|
|
4022
|
+
text
|
|
4023
|
+
});
|
|
4024
|
+
}
|
|
4025
|
+
return devLog.debug("parseSRTContent - output:", {
|
|
4026
|
+
cueCount: cues.length,
|
|
4027
|
+
firstCue: cues.length > 0 ? cues[0] : null
|
|
4028
|
+
}), cues;
|
|
4029
|
+
}
|
|
4030
|
+
function serializeWistiaCaptionText(cues) {
|
|
4031
|
+
if (devLog.debug("serializeWistiaCaptionText - input:", {
|
|
4032
|
+
cuesCount: cues.length,
|
|
4033
|
+
firstCue: cues.length > 0 ? cues[0] : null
|
|
4034
|
+
}), !Array.isArray(cues) || cues.length === 0)
|
|
4035
|
+
return "";
|
|
4036
|
+
const result = cues.map((cue) => (devLog.debug(`Processing cue ${cue.index}:`, {
|
|
4037
|
+
text: cue.text,
|
|
4038
|
+
hasText: typeof cue.text == "string"
|
|
4039
|
+
}), `[${cue.index}] ${cue.text}`)).join(`
|
|
4040
|
+
`);
|
|
4041
|
+
return devLog.debug("serializeWistiaCaptionText - output:", {
|
|
4042
|
+
resultLength: result.length,
|
|
4043
|
+
resultPreview: result.substring(0, 100) + (result.length > 100 ? "..." : "")
|
|
4044
|
+
}), result;
|
|
4045
|
+
}
|
|
4046
|
+
function deserializeWistiaCaptionText(translationText, srtCuesMetadata) {
|
|
4047
|
+
if (devLog.debug("deserializeWistiaCaptionText - input:", {
|
|
4048
|
+
translationTextLength: translationText.length,
|
|
4049
|
+
translationTextPreview: translationText.substring(0, 100) + (translationText.length > 100 ? "..." : ""),
|
|
4050
|
+
metadataCount: srtCuesMetadata.length,
|
|
4051
|
+
metadataExample: srtCuesMetadata.length > 0 ? srtCuesMetadata[0] : null
|
|
4052
|
+
}), !translationText || translationText.trim() === "")
|
|
4053
|
+
return "";
|
|
4054
|
+
const result = [], lines = translationText.split(`
|
|
4055
|
+
`), lineRegex = /^\[(\d+)\]\s*(.*)$/, metadataByIndex = /* @__PURE__ */ new Map();
|
|
4056
|
+
for (const metadata of srtCuesMetadata)
|
|
4057
|
+
metadataByIndex.set(metadata.index, { startTime: metadata.startTime, endTime: metadata.endTime });
|
|
4058
|
+
for (const line of lines) {
|
|
4059
|
+
const match = line.match(lineRegex);
|
|
4060
|
+
if (!match) {
|
|
4061
|
+
devLog.warn("Failed to parse caption line", { line });
|
|
4062
|
+
continue;
|
|
4063
|
+
}
|
|
4064
|
+
const index = Number.parseInt(match[1], 10), text = match[2];
|
|
4065
|
+
devLog.debug("Found caption:", {
|
|
4066
|
+
index,
|
|
4067
|
+
text
|
|
4068
|
+
});
|
|
4069
|
+
const metadata = metadataByIndex.get(index);
|
|
4070
|
+
metadata ? (devLog.debug(`Found matching metadata for index ${index}`), result.push(`${index}`), result.push(`${metadata.startTime} --> ${metadata.endTime}`), result.push(text), result.push("")) : devLog.warn("Missing metadata for caption", { index });
|
|
4071
|
+
}
|
|
4072
|
+
result.length > 0 && result[result.length - 1] === "" && result.pop();
|
|
4073
|
+
const reconstructed = result.join(`
|
|
4074
|
+
`);
|
|
4075
|
+
return devLog.debug("deserializeWistiaCaptionText - output:", {
|
|
4076
|
+
resultLength: reconstructed.length,
|
|
4077
|
+
resultPreview: reconstructed.substring(0, 200) + (reconstructed.length > 200 ? "..." : "")
|
|
4078
|
+
}), reconstructed;
|
|
4079
|
+
}
|
|
4080
|
+
function getDocumentLanguage(document) {
|
|
4081
|
+
if (!document || typeof document != "object")
|
|
4082
|
+
return;
|
|
4083
|
+
const languageFieldNames = ["language", "lang", "locale"];
|
|
4084
|
+
for (const fieldName of languageFieldNames)
|
|
4085
|
+
if (fieldName in document && typeof document[fieldName] == "string")
|
|
4086
|
+
return document[fieldName];
|
|
4087
|
+
}
|
|
3802
4088
|
const aiTranslationPlugin = definePlugin((config) => (config.fieldTransforms?.length && (devLog.info(`Registering ${config.fieldTransforms.length} custom field transforms`), config.fieldTransforms.forEach((transform) => {
|
|
3803
4089
|
globalTransformRegistry.register(transform);
|
|
3804
4090
|
})), {
|
|
@@ -3818,6 +4104,7 @@ export {
|
|
|
3818
4104
|
restoreExcludedFields,
|
|
3819
4105
|
richTextTransform,
|
|
3820
4106
|
translationHistorySchema,
|
|
3821
|
-
vttCaptionTransform
|
|
4107
|
+
vttCaptionTransform,
|
|
4108
|
+
wistiaCaptionTransform
|
|
3822
4109
|
};
|
|
3823
4110
|
//# sourceMappingURL=index.js.map
|