pabal-resource-mcp 1.5.1 → 1.5.2

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.
@@ -3428,9 +3428,10 @@ function scanLocaleScreenshots(slug, locale) {
3428
3428
  }
3429
3429
 
3430
3430
  // src/tools/aso/utils/localize-screenshots/gemini-image-translator.util.ts
3431
- import { GoogleGenAI, Modality } from "@google/genai";
3431
+ import { GoogleGenAI } from "@google/genai";
3432
3432
  import fs10 from "fs";
3433
3433
  import path10 from "path";
3434
+ import sharp from "sharp";
3434
3435
  var LANGUAGE_NAMES = {
3435
3436
  "en-US": "English (US)",
3436
3437
  "en-GB": "English (UK)",
@@ -3506,11 +3507,29 @@ function readImageAsBase64(imagePath) {
3506
3507
  }
3507
3508
  return { data: base64, mimeType };
3508
3509
  }
3510
+ async function getImageDimensions(imagePath) {
3511
+ const metadata = await sharp(imagePath).metadata();
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";
3525
+ }
3509
3526
  async function translateImage(sourcePath, sourceLocale, targetLocale, outputPath) {
3510
3527
  try {
3511
3528
  const client = getGeminiClient();
3512
3529
  const sourceLanguage = getLanguageName(sourceLocale);
3513
3530
  const targetLanguage = getLanguageName(targetLocale);
3531
+ const { width, height } = await getImageDimensions(sourcePath);
3532
+ const aspectRatio = calculateAspectRatio(width, height);
3514
3533
  const { data: imageData, mimeType } = readImageAsBase64(sourcePath);
3515
3534
  const prompt = `This is an app screenshot with text in ${sourceLanguage}.
3516
3535
  Please translate ONLY the text/words in this image to ${targetLanguage}.
@@ -3522,24 +3541,27 @@ IMPORTANT INSTRUCTIONS:
3522
3541
  - Do NOT add any new elements or remove existing design elements
3523
3542
  - The output should look identical except the text language is ${targetLanguage}
3524
3543
  - Preserve all icons, images, and graphical elements exactly as they are`;
3525
- const response = await client.models.generateContent({
3526
- model: "imagen-3.0-generate-002",
3527
- contents: [
3544
+ const chat = client.chats.create({
3545
+ model: "gemini-3-pro-image-preview",
3546
+ config: {
3547
+ responseModalities: ["TEXT", "IMAGE"]
3548
+ }
3549
+ });
3550
+ const response = await chat.sendMessage({
3551
+ message: [
3552
+ { text: prompt },
3528
3553
  {
3529
- role: "user",
3530
- parts: [
3531
- { text: prompt },
3532
- {
3533
- inlineData: {
3534
- mimeType,
3535
- data: imageData
3536
- }
3537
- }
3538
- ]
3554
+ inlineData: {
3555
+ mimeType,
3556
+ data: imageData
3557
+ }
3539
3558
  }
3540
3559
  ],
3541
3560
  config: {
3542
- responseModalities: [Modality.TEXT, Modality.IMAGE]
3561
+ responseModalities: ["TEXT", "IMAGE"],
3562
+ imageConfig: {
3563
+ aspectRatio
3564
+ }
3543
3565
  }
3544
3566
  });
3545
3567
  const candidates = response.candidates;
@@ -3563,7 +3585,7 @@ IMPORTANT INSTRUCTIONS:
3563
3585
  if (!fs10.existsSync(outputDir)) {
3564
3586
  fs10.mkdirSync(outputDir, { recursive: true });
3565
3587
  }
3566
- fs10.writeFileSync(outputPath, imageBuffer);
3588
+ await sharp(imageBuffer).png().toFile(outputPath);
3567
3589
  return {
3568
3590
  success: true,
3569
3591
  outputPath
@@ -3586,13 +3608,18 @@ async function translateImagesWithProgress(translations, onProgress) {
3586
3608
  let successful = 0;
3587
3609
  let failed = 0;
3588
3610
  const errors = [];
3589
- for (const translation of translations) {
3611
+ const total = translations.length;
3612
+ for (let i = 0; i < translations.length; i++) {
3613
+ const translation = translations[i];
3614
+ const current = i + 1;
3590
3615
  const progress = {
3591
3616
  sourceLocale: translation.sourceLocale,
3592
3617
  targetLocale: translation.targetLocale,
3593
3618
  deviceType: translation.deviceType,
3594
3619
  filename: translation.filename,
3595
- status: "translating"
3620
+ status: "translating",
3621
+ current,
3622
+ total
3596
3623
  };
3597
3624
  onProgress?.(progress);
3598
3625
  const result = await translateImage(
@@ -3608,7 +3635,10 @@ async function translateImagesWithProgress(translations, onProgress) {
3608
3635
  failed++;
3609
3636
  progress.status = "failed";
3610
3637
  progress.error = result.error;
3611
- errors.push({ path: translation.sourcePath, error: result.error || "Unknown error" });
3638
+ errors.push({
3639
+ path: translation.sourcePath,
3640
+ error: result.error || "Unknown error"
3641
+ });
3612
3642
  }
3613
3643
  onProgress?.(progress);
3614
3644
  await new Promise((resolve) => setTimeout(resolve, 500));
@@ -3617,10 +3647,10 @@ async function translateImagesWithProgress(translations, onProgress) {
3617
3647
  }
3618
3648
 
3619
3649
  // src/tools/aso/utils/localize-screenshots/image-resizer.util.ts
3620
- import sharp from "sharp";
3650
+ import sharp2 from "sharp";
3621
3651
  import fs11 from "fs";
3622
- async function getImageDimensions(imagePath) {
3623
- const metadata = await sharp(imagePath).metadata();
3652
+ async function getImageDimensions2(imagePath) {
3653
+ const metadata = await sharp2(imagePath).metadata();
3624
3654
  if (!metadata.width || !metadata.height) {
3625
3655
  throw new Error(`Unable to read dimensions from ${imagePath}`);
3626
3656
  }
@@ -3630,7 +3660,7 @@ async function getImageDimensions(imagePath) {
3630
3660
  };
3631
3661
  }
3632
3662
  async function resizeImage(inputPath, outputPath, targetDimensions) {
3633
- await sharp(inputPath).resize(targetDimensions.width, targetDimensions.height, {
3663
+ await sharp2(inputPath).resize(targetDimensions.width, targetDimensions.height, {
3634
3664
  fit: "fill",
3635
3665
  // Exact resize to target dimensions
3636
3666
  withoutEnlargement: false
@@ -3639,8 +3669,8 @@ async function resizeImage(inputPath, outputPath, targetDimensions) {
3639
3669
  fs11.renameSync(outputPath + ".tmp", outputPath);
3640
3670
  }
3641
3671
  async function validateAndResizeImage(sourcePath, translatedPath) {
3642
- const sourceDimensions = await getImageDimensions(sourcePath);
3643
- const translatedDimensions = await getImageDimensions(translatedPath);
3672
+ const sourceDimensions = await getImageDimensions2(sourcePath);
3673
+ const translatedDimensions = await getImageDimensions2(translatedPath);
3644
3674
  const needsResize = sourceDimensions.width !== translatedDimensions.width || sourceDimensions.height !== translatedDimensions.height;
3645
3675
  if (needsResize) {
3646
3676
  await resizeImage(translatedPath, translatedPath, sourceDimensions);
@@ -3928,13 +3958,18 @@ ${screenshotsDir2}/${primaryLocale}/tablet/1.png, 2.png, ...`
3928
3958
  const translationResult = await translateImagesWithProgress(
3929
3959
  tasks,
3930
3960
  (progress) => {
3931
- if (progress.status === "completed") {
3961
+ const progressPrefix = `[${progress.current}/${progress.total}]`;
3962
+ if (progress.status === "translating") {
3963
+ console.log(
3964
+ `\u{1F504} ${progressPrefix} Translating ${progress.targetLocale}/${progress.deviceType}/${progress.filename}...`
3965
+ );
3966
+ } else if (progress.status === "completed") {
3932
3967
  console.log(
3933
- `\u2705 ${progress.targetLocale}/${progress.deviceType}/${progress.filename}`
3968
+ `\u2705 ${progressPrefix} ${progress.targetLocale}/${progress.deviceType}/${progress.filename}`
3934
3969
  );
3935
3970
  } else if (progress.status === "failed") {
3936
3971
  console.log(
3937
- `\u274C ${progress.targetLocale}/${progress.deviceType}/${progress.filename}: ${progress.error}`
3972
+ `\u274C ${progressPrefix} ${progress.targetLocale}/${progress.deviceType}/${progress.filename}: ${progress.error}`
3938
3973
  );
3939
3974
  }
3940
3975
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pabal-resource-mcp",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "type": "module",
5
5
  "description": "MCP server for ASO data management with shared types and utilities",
6
6
  "author": "skyu",