pabal-resource-mcp 1.5.3 → 1.5.5
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/bin/mcp-server.js +175 -52
- package/package.json +1 -1
package/dist/bin/mcp-server.js
CHANGED
|
@@ -3432,6 +3432,87 @@ import { GoogleGenAI } from "@google/genai";
|
|
|
3432
3432
|
import fs10 from "fs";
|
|
3433
3433
|
import path10 from "path";
|
|
3434
3434
|
import sharp from "sharp";
|
|
3435
|
+
var GEMINI_ASPECT_RATIOS = {
|
|
3436
|
+
"1:1": { ratio: 1 / 1, width: 2048, height: 2048 },
|
|
3437
|
+
"2:3": { ratio: 2 / 3, width: 1696, height: 2528 },
|
|
3438
|
+
"3:2": { ratio: 3 / 2, width: 2528, height: 1696 },
|
|
3439
|
+
"3:4": { ratio: 3 / 4, width: 1792, height: 2400 },
|
|
3440
|
+
"4:3": { ratio: 4 / 3, width: 2400, height: 1792 },
|
|
3441
|
+
"4:5": { ratio: 4 / 5, width: 1856, height: 2304 },
|
|
3442
|
+
"5:4": { ratio: 5 / 4, width: 2304, height: 1856 },
|
|
3443
|
+
"9:16": { ratio: 9 / 16, width: 1536, height: 2752 },
|
|
3444
|
+
"16:9": { ratio: 16 / 9, width: 2752, height: 1536 },
|
|
3445
|
+
"21:9": { ratio: 21 / 9, width: 1584, height: 672 }
|
|
3446
|
+
};
|
|
3447
|
+
var DEVICE_ASPECT_RATIOS = {
|
|
3448
|
+
phone: "9:16",
|
|
3449
|
+
tablet: "3:4"
|
|
3450
|
+
};
|
|
3451
|
+
var GEMINI_SUPPORTED_LOCALES = {
|
|
3452
|
+
// English variants
|
|
3453
|
+
"en": "EN",
|
|
3454
|
+
"en-US": "EN",
|
|
3455
|
+
"en-GB": "EN",
|
|
3456
|
+
"en-AU": "EN",
|
|
3457
|
+
"en-CA": "EN",
|
|
3458
|
+
// Arabic
|
|
3459
|
+
"ar": "ar-EG",
|
|
3460
|
+
"ar-EG": "ar-EG",
|
|
3461
|
+
"ar-SA": "ar-EG",
|
|
3462
|
+
// German
|
|
3463
|
+
"de": "de-DE",
|
|
3464
|
+
"de-DE": "de-DE",
|
|
3465
|
+
// Spanish
|
|
3466
|
+
"es": "es-MX",
|
|
3467
|
+
"es-MX": "es-MX",
|
|
3468
|
+
"es-ES": "es-MX",
|
|
3469
|
+
"es-419": "es-MX",
|
|
3470
|
+
// French
|
|
3471
|
+
"fr": "fr-FR",
|
|
3472
|
+
"fr-FR": "fr-FR",
|
|
3473
|
+
"fr-CA": "fr-FR",
|
|
3474
|
+
// Hindi
|
|
3475
|
+
"hi": "hi-IN",
|
|
3476
|
+
"hi-IN": "hi-IN",
|
|
3477
|
+
// Indonesian
|
|
3478
|
+
"id": "id-ID",
|
|
3479
|
+
"id-ID": "id-ID",
|
|
3480
|
+
// Italian
|
|
3481
|
+
"it": "it-IT",
|
|
3482
|
+
"it-IT": "it-IT",
|
|
3483
|
+
// Japanese
|
|
3484
|
+
"ja": "ja-JP",
|
|
3485
|
+
"ja-JP": "ja-JP",
|
|
3486
|
+
// Korean
|
|
3487
|
+
"ko": "ko-KR",
|
|
3488
|
+
"ko-KR": "ko-KR",
|
|
3489
|
+
// Portuguese
|
|
3490
|
+
"pt": "pt-BR",
|
|
3491
|
+
"pt-BR": "pt-BR",
|
|
3492
|
+
"pt-PT": "pt-BR",
|
|
3493
|
+
// Russian
|
|
3494
|
+
"ru": "ru-RU",
|
|
3495
|
+
"ru-RU": "ru-RU",
|
|
3496
|
+
// Ukrainian
|
|
3497
|
+
"uk": "ua-UA",
|
|
3498
|
+
"uk-UA": "ua-UA",
|
|
3499
|
+
"ua-UA": "ua-UA",
|
|
3500
|
+
// Vietnamese
|
|
3501
|
+
"vi": "vi-VN",
|
|
3502
|
+
"vi-VN": "vi-VN",
|
|
3503
|
+
// Chinese
|
|
3504
|
+
"zh": "zh-CN",
|
|
3505
|
+
"zh-CN": "zh-CN",
|
|
3506
|
+
"zh-Hans": "zh-CN",
|
|
3507
|
+
"zh-TW": "zh-CN",
|
|
3508
|
+
"zh-Hant": "zh-CN"
|
|
3509
|
+
};
|
|
3510
|
+
function isGeminiSupportedLocale(locale) {
|
|
3511
|
+
return locale in GEMINI_SUPPORTED_LOCALES;
|
|
3512
|
+
}
|
|
3513
|
+
function getUnsupportedLocales(locales) {
|
|
3514
|
+
return locales.filter((locale) => !isGeminiSupportedLocale(locale));
|
|
3515
|
+
}
|
|
3435
3516
|
var LANGUAGE_NAMES = {
|
|
3436
3517
|
"en-US": "English (US)",
|
|
3437
3518
|
"en-GB": "English (UK)",
|
|
@@ -3507,30 +3588,18 @@ function readImageAsBase64(imagePath) {
|
|
|
3507
3588
|
}
|
|
3508
3589
|
return { data: base64, mimeType };
|
|
3509
3590
|
}
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
return {
|
|
3513
|
-
width: metadata.width || 1080,
|
|
3514
|
-
height: metadata.height || 1920
|
|
3515
|
-
};
|
|
3516
|
-
}
|
|
3517
|
-
function calculateAspectRatio(width, height) {
|
|
3518
|
-
const ratio = width / height;
|
|
3519
|
-
if (Math.abs(ratio - 1) < 0.1) return "1:1";
|
|
3520
|
-
if (Math.abs(ratio - 9 / 16) < 0.1) return "9:16";
|
|
3521
|
-
if (Math.abs(ratio - 16 / 9) < 0.1) return "16:9";
|
|
3522
|
-
if (Math.abs(ratio - 3 / 4) < 0.1) return "3:4";
|
|
3523
|
-
if (Math.abs(ratio - 4 / 3) < 0.1) return "4:3";
|
|
3524
|
-
return ratio < 1 ? "9:16" : "16:9";
|
|
3591
|
+
function getAspectRatioForDevice(deviceType) {
|
|
3592
|
+
return DEVICE_ASPECT_RATIOS[deviceType];
|
|
3525
3593
|
}
|
|
3526
|
-
async function translateImage(sourcePath, sourceLocale, targetLocale, outputPath) {
|
|
3594
|
+
async function translateImage(sourcePath, sourceLocale, targetLocale, outputPath, deviceType, preserveWords) {
|
|
3527
3595
|
try {
|
|
3528
3596
|
const client = getGeminiClient();
|
|
3529
3597
|
const sourceLanguage = getLanguageName(sourceLocale);
|
|
3530
3598
|
const targetLanguage = getLanguageName(targetLocale);
|
|
3531
|
-
const
|
|
3532
|
-
const aspectRatio = calculateAspectRatio(width, height);
|
|
3599
|
+
const aspectRatio = getAspectRatioForDevice(deviceType);
|
|
3533
3600
|
const { data: imageData, mimeType } = readImageAsBase64(sourcePath);
|
|
3601
|
+
const preserveInstruction = preserveWords && preserveWords.length > 0 ? `
|
|
3602
|
+
- Do NOT translate these words, keep them exactly as-is: ${preserveWords.join(", ")}` : "";
|
|
3534
3603
|
const prompt = `This is an app screenshot with text in ${sourceLanguage}.
|
|
3535
3604
|
Please translate ONLY the text/words in this image to ${targetLanguage}.
|
|
3536
3605
|
|
|
@@ -3540,7 +3609,7 @@ IMPORTANT INSTRUCTIONS:
|
|
|
3540
3609
|
- Maintain the same font style and text positioning as much as possible
|
|
3541
3610
|
- Do NOT add any new elements or remove existing design elements
|
|
3542
3611
|
- The output should look identical except the text language is ${targetLanguage}
|
|
3543
|
-
- Preserve all icons, images, and graphical elements exactly as they are`;
|
|
3612
|
+
- Preserve all icons, images, and graphical elements exactly as they are${preserveInstruction}`;
|
|
3544
3613
|
const chat = client.chats.create({
|
|
3545
3614
|
model: "gemini-3-pro-image-preview",
|
|
3546
3615
|
config: {
|
|
@@ -3604,7 +3673,7 @@ IMPORTANT INSTRUCTIONS:
|
|
|
3604
3673
|
};
|
|
3605
3674
|
}
|
|
3606
3675
|
}
|
|
3607
|
-
async function translateImagesWithProgress(translations, onProgress) {
|
|
3676
|
+
async function translateImagesWithProgress(translations, onProgress, preserveWords) {
|
|
3608
3677
|
let successful = 0;
|
|
3609
3678
|
let failed = 0;
|
|
3610
3679
|
const errors = [];
|
|
@@ -3626,7 +3695,9 @@ async function translateImagesWithProgress(translations, onProgress) {
|
|
|
3626
3695
|
translation.sourcePath,
|
|
3627
3696
|
translation.sourceLocale,
|
|
3628
3697
|
translation.targetLocale,
|
|
3629
|
-
translation.outputPath
|
|
3698
|
+
translation.outputPath,
|
|
3699
|
+
translation.deviceType,
|
|
3700
|
+
preserveWords
|
|
3630
3701
|
);
|
|
3631
3702
|
if (result.success) {
|
|
3632
3703
|
successful++;
|
|
@@ -3649,7 +3720,7 @@ async function translateImagesWithProgress(translations, onProgress) {
|
|
|
3649
3720
|
// src/tools/aso/utils/localize-screenshots/image-resizer.util.ts
|
|
3650
3721
|
import sharp2 from "sharp";
|
|
3651
3722
|
import fs11 from "fs";
|
|
3652
|
-
async function
|
|
3723
|
+
async function getImageDimensions(imagePath) {
|
|
3653
3724
|
const metadata = await sharp2(imagePath).metadata();
|
|
3654
3725
|
if (!metadata.width || !metadata.height) {
|
|
3655
3726
|
throw new Error(`Unable to read dimensions from ${imagePath}`);
|
|
@@ -3659,7 +3730,7 @@ async function getImageDimensions2(imagePath) {
|
|
|
3659
3730
|
height: metadata.height
|
|
3660
3731
|
};
|
|
3661
3732
|
}
|
|
3662
|
-
async function
|
|
3733
|
+
async function detectCornerColor(imagePath) {
|
|
3663
3734
|
const image = sharp2(imagePath);
|
|
3664
3735
|
const metadata = await image.metadata();
|
|
3665
3736
|
const width = metadata.width || 100;
|
|
@@ -3667,14 +3738,17 @@ async function detectEdgeColor(imagePath) {
|
|
|
3667
3738
|
const { data, info } = await image.raw().toBuffer({ resolveWithObject: true });
|
|
3668
3739
|
const channels = info.channels;
|
|
3669
3740
|
const colorCounts = /* @__PURE__ */ new Map();
|
|
3670
|
-
const
|
|
3741
|
+
const cornerWidth = Math.min(100, Math.max(10, Math.floor(width * 0.05)));
|
|
3742
|
+
const cornerHeight = Math.min(100, Math.max(10, Math.floor(height * 0.05)));
|
|
3743
|
+
const samplePixel = (x, y) => {
|
|
3744
|
+
if (x < 0 || x >= width || y < 0 || y >= height) return;
|
|
3671
3745
|
const idx = (y * width + x) * channels;
|
|
3672
3746
|
const r = data[idx];
|
|
3673
3747
|
const g = data[idx + 1];
|
|
3674
3748
|
const b = data[idx + 2];
|
|
3675
|
-
const qr = Math.round(r /
|
|
3676
|
-
const qg = Math.round(g /
|
|
3677
|
-
const qb = Math.round(b /
|
|
3749
|
+
const qr = Math.round(r / 8) * 8;
|
|
3750
|
+
const qg = Math.round(g / 8) * 8;
|
|
3751
|
+
const qb = Math.round(b / 8) * 8;
|
|
3678
3752
|
const key = `${qr},${qg},${qb}`;
|
|
3679
3753
|
const existing = colorCounts.get(key);
|
|
3680
3754
|
if (existing) {
|
|
@@ -3683,13 +3757,22 @@ async function detectEdgeColor(imagePath) {
|
|
|
3683
3757
|
colorCounts.set(key, { count: 1, color: { r: qr, g: qg, b: qb } });
|
|
3684
3758
|
}
|
|
3685
3759
|
};
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3760
|
+
const corners = [
|
|
3761
|
+
{ startX: 0, startY: 0 },
|
|
3762
|
+
// Top-left
|
|
3763
|
+
{ startX: width - cornerWidth, startY: 0 },
|
|
3764
|
+
// Top-right
|
|
3765
|
+
{ startX: 0, startY: height - cornerHeight },
|
|
3766
|
+
// Bottom-left
|
|
3767
|
+
{ startX: width - cornerWidth, startY: height - cornerHeight }
|
|
3768
|
+
// Bottom-right
|
|
3769
|
+
];
|
|
3770
|
+
for (const corner of corners) {
|
|
3771
|
+
for (let y = corner.startY; y < corner.startY + cornerHeight; y += 2) {
|
|
3772
|
+
for (let x = corner.startX; x < corner.startX + cornerWidth; x += 2) {
|
|
3773
|
+
samplePixel(x, y);
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3693
3776
|
}
|
|
3694
3777
|
let maxCount = 0;
|
|
3695
3778
|
let dominantColor = { r: 255, g: 255, b: 255 };
|
|
@@ -3702,20 +3785,22 @@ async function detectEdgeColor(imagePath) {
|
|
|
3702
3785
|
return dominantColor;
|
|
3703
3786
|
}
|
|
3704
3787
|
async function resizeImage(inputPath, outputPath, targetDimensions) {
|
|
3705
|
-
const bgColor = await
|
|
3788
|
+
const bgColor = await detectCornerColor(inputPath);
|
|
3706
3789
|
await sharp2(inputPath).resize(targetDimensions.width, targetDimensions.height, {
|
|
3707
3790
|
fit: "contain",
|
|
3708
3791
|
// Preserve aspect ratio
|
|
3709
3792
|
withoutEnlargement: false,
|
|
3710
3793
|
// Allow enlargement if needed
|
|
3711
|
-
background: bgColor
|
|
3794
|
+
background: bgColor,
|
|
3712
3795
|
// Use detected edge color
|
|
3796
|
+
kernel: "lanczos3"
|
|
3797
|
+
// High-quality downscaling algorithm
|
|
3713
3798
|
}).flatten({ background: bgColor }).png().toFile(outputPath + ".tmp");
|
|
3714
3799
|
fs11.renameSync(outputPath + ".tmp", outputPath);
|
|
3715
3800
|
}
|
|
3716
3801
|
async function validateAndResizeImage(sourcePath, translatedPath) {
|
|
3717
|
-
const sourceDimensions = await
|
|
3718
|
-
const translatedDimensions = await
|
|
3802
|
+
const sourceDimensions = await getImageDimensions(sourcePath);
|
|
3803
|
+
const translatedDimensions = await getImageDimensions(translatedPath);
|
|
3719
3804
|
const needsResize = sourceDimensions.width !== translatedDimensions.width || sourceDimensions.height !== translatedDimensions.height;
|
|
3720
3805
|
if (needsResize) {
|
|
3721
3806
|
await resizeImage(translatedPath, translatedPath, sourceDimensions);
|
|
@@ -3763,8 +3848,17 @@ var localizeScreenshotsInputSchema = z7.object({
|
|
|
3763
3848
|
deviceTypes: z7.array(z7.enum(["phone", "tablet"])).optional().default(["phone", "tablet"]).describe("Device types to process (default: both phone and tablet)"),
|
|
3764
3849
|
dryRun: z7.boolean().optional().default(false).describe("Preview mode - shows what would be translated without actually translating"),
|
|
3765
3850
|
skipExisting: z7.boolean().optional().default(true).describe("Skip translation if target file already exists (default: true)"),
|
|
3766
|
-
screenshotNumbers: z7.
|
|
3767
|
-
|
|
3851
|
+
screenshotNumbers: z7.union([
|
|
3852
|
+
z7.array(z7.number().int().positive()),
|
|
3853
|
+
z7.object({
|
|
3854
|
+
phone: z7.array(z7.number().int().positive()).optional(),
|
|
3855
|
+
tablet: z7.array(z7.number().int().positive()).optional()
|
|
3856
|
+
})
|
|
3857
|
+
]).optional().describe(
|
|
3858
|
+
"Specific screenshot numbers to process. Can be:\n- Array for all devices: [1, 3, 5]\n- Object for per-device: { phone: [1, 2], tablet: [1, 3, 5] }\nIf not provided, all screenshots will be processed."
|
|
3859
|
+
),
|
|
3860
|
+
preserveWords: z7.array(z7.string()).optional().describe(
|
|
3861
|
+
'Words to keep untranslated (e.g., brand names, product names). Example: ["Pabal", "Pro", "AI"]'
|
|
3768
3862
|
)
|
|
3769
3863
|
});
|
|
3770
3864
|
var jsonSchema7 = zodToJsonSchema7(localizeScreenshotsInputSchema, {
|
|
@@ -3841,12 +3935,14 @@ function getTargetLocales(allLocales, primaryLocale, requestedTargets) {
|
|
|
3841
3935
|
);
|
|
3842
3936
|
if (invalidTargets.length > 0) {
|
|
3843
3937
|
console.warn(
|
|
3844
|
-
`Warning: Some requested locales are not
|
|
3938
|
+
`Warning: Some requested locales are not in product: ${invalidTargets.join(", ")}`
|
|
3845
3939
|
);
|
|
3846
3940
|
}
|
|
3847
3941
|
targets = validTargets.filter((t) => t !== primaryLocale);
|
|
3848
3942
|
}
|
|
3849
|
-
|
|
3943
|
+
const skippedLocales = getUnsupportedLocales(targets);
|
|
3944
|
+
const supportedTargets = targets.filter((t) => isGeminiSupportedLocale(t));
|
|
3945
|
+
return { targets: supportedTargets, skippedLocales };
|
|
3850
3946
|
}
|
|
3851
3947
|
function buildTranslationTasks(slug, screenshots, primaryLocale, targetLocales, skipExisting) {
|
|
3852
3948
|
const tasks = [];
|
|
@@ -3881,7 +3977,8 @@ async function handleLocalizeScreenshots(input) {
|
|
|
3881
3977
|
deviceTypes = ["phone", "tablet"],
|
|
3882
3978
|
dryRun = false,
|
|
3883
3979
|
skipExisting = true,
|
|
3884
|
-
screenshotNumbers
|
|
3980
|
+
screenshotNumbers,
|
|
3981
|
+
preserveWords
|
|
3885
3982
|
} = input;
|
|
3886
3983
|
const results = [];
|
|
3887
3984
|
let appInfo;
|
|
@@ -3916,36 +4013,58 @@ async function handleLocalizeScreenshots(input) {
|
|
|
3916
4013
|
]
|
|
3917
4014
|
};
|
|
3918
4015
|
}
|
|
3919
|
-
const targetLocales = getTargetLocales(
|
|
4016
|
+
const { targets: targetLocales, skippedLocales } = getTargetLocales(
|
|
3920
4017
|
allLocales,
|
|
3921
4018
|
primaryLocale,
|
|
3922
4019
|
requestedTargetLocales
|
|
3923
4020
|
);
|
|
3924
4021
|
if (targetLocales.length === 0) {
|
|
4022
|
+
const skippedMsg = skippedLocales.length > 0 ? ` (Skipped due to Gemini limitation: ${skippedLocales.join(", ")})` : "";
|
|
3925
4023
|
return {
|
|
3926
4024
|
content: [
|
|
3927
4025
|
{
|
|
3928
4026
|
type: "text",
|
|
3929
|
-
text: `\u274C No target locales to translate to. Primary locale: ${primaryLocale}, Available: ${allLocales.join(", ")}`
|
|
4027
|
+
text: `\u274C No target locales to translate to. Primary locale: ${primaryLocale}, Available: ${allLocales.join(", ")}${skippedMsg}`
|
|
3930
4028
|
}
|
|
3931
4029
|
]
|
|
3932
4030
|
};
|
|
3933
4031
|
}
|
|
3934
4032
|
results.push(`\u{1F3AF} Target locales: ${targetLocales.join(", ")}`);
|
|
4033
|
+
if (skippedLocales.length > 0) {
|
|
4034
|
+
results.push(`\u26A0\uFE0F Skipped locales (not supported by Gemini): ${skippedLocales.join(", ")}`);
|
|
4035
|
+
}
|
|
3935
4036
|
const sourceScreenshots = scanLocaleScreenshots(appInfo.slug, primaryLocale);
|
|
3936
4037
|
let filteredScreenshots = sourceScreenshots.filter(
|
|
3937
4038
|
(s) => deviceTypes.includes(s.type)
|
|
3938
4039
|
);
|
|
3939
|
-
if (screenshotNumbers
|
|
4040
|
+
if (screenshotNumbers) {
|
|
4041
|
+
const isArray = Array.isArray(screenshotNumbers);
|
|
4042
|
+
const phoneNumbers = isArray ? screenshotNumbers : screenshotNumbers.phone;
|
|
4043
|
+
const tabletNumbers = isArray ? screenshotNumbers : screenshotNumbers.tablet;
|
|
3940
4044
|
filteredScreenshots = filteredScreenshots.filter((s) => {
|
|
3941
4045
|
const match = s.filename.match(/^(\d+)\./);
|
|
3942
|
-
if (match)
|
|
3943
|
-
|
|
3944
|
-
|
|
4046
|
+
if (!match) return false;
|
|
4047
|
+
const num = parseInt(match[1], 10);
|
|
4048
|
+
const numbersForDevice = s.type === "phone" ? phoneNumbers : tabletNumbers;
|
|
4049
|
+
if (!numbersForDevice || numbersForDevice.length === 0) {
|
|
4050
|
+
return true;
|
|
3945
4051
|
}
|
|
3946
|
-
return
|
|
4052
|
+
return numbersForDevice.includes(num);
|
|
3947
4053
|
});
|
|
3948
|
-
|
|
4054
|
+
const filterParts = [];
|
|
4055
|
+
if (isArray) {
|
|
4056
|
+
filterParts.push(`all: ${screenshotNumbers.join(", ")}`);
|
|
4057
|
+
} else {
|
|
4058
|
+
if (phoneNumbers && phoneNumbers.length > 0) {
|
|
4059
|
+
filterParts.push(`phone: ${phoneNumbers.join(", ")}`);
|
|
4060
|
+
}
|
|
4061
|
+
if (tabletNumbers && tabletNumbers.length > 0) {
|
|
4062
|
+
filterParts.push(`tablet: ${tabletNumbers.join(", ")}`);
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
if (filterParts.length > 0) {
|
|
4066
|
+
results.push(`\u{1F522} Filtering screenshots: ${filterParts.join(" | ")}`);
|
|
4067
|
+
}
|
|
3949
4068
|
}
|
|
3950
4069
|
if (filteredScreenshots.length === 0) {
|
|
3951
4070
|
const screenshotsDir2 = getScreenshotsDir(appInfo.slug);
|
|
@@ -4015,6 +4134,9 @@ ${screenshotsDir2}/${primaryLocale}/tablet/1.png, 2.png, ...`
|
|
|
4015
4134
|
}
|
|
4016
4135
|
results.push(`
|
|
4017
4136
|
\u{1F680} Starting translations...`);
|
|
4137
|
+
if (preserveWords && preserveWords.length > 0) {
|
|
4138
|
+
results.push(`\u{1F512} Preserving words: ${preserveWords.join(", ")}`);
|
|
4139
|
+
}
|
|
4018
4140
|
const translationResult = await translateImagesWithProgress(
|
|
4019
4141
|
tasks,
|
|
4020
4142
|
(progress) => {
|
|
@@ -4032,7 +4154,8 @@ ${screenshotsDir2}/${primaryLocale}/tablet/1.png, 2.png, ...`
|
|
|
4032
4154
|
`\u274C ${progressPrefix} ${progress.targetLocale}/${progress.deviceType}/${progress.filename}: ${progress.error}`
|
|
4033
4155
|
);
|
|
4034
4156
|
}
|
|
4035
|
-
}
|
|
4157
|
+
},
|
|
4158
|
+
preserveWords
|
|
4036
4159
|
);
|
|
4037
4160
|
results.push(`
|
|
4038
4161
|
\u{1F4CA} Translation Results:`);
|