Skip to content

Commit e369553

Browse files
committed
add in image preservation to obz
1 parent e0c6351 commit e369553

2 files changed

Lines changed: 113 additions & 14 deletions

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Merge translated board JSONs back into the original OBZ archive so that
5+
* we can keep the original media assets (images/sounds/etc.) alongside the new text.
6+
*
7+
* Usage:
8+
* node scripts/translation/merge-translation-assets.js \
9+
* original.obz translated.obz \
10+
* merged-with-assets.obz
11+
*/
12+
13+
const path = require('path');
14+
const fs = require('fs');
15+
const AdmZip = require('adm-zip');
16+
17+
function printUsage() {
18+
console.log('Usage: node scripts/translation/merge-translation-assets.js <original.obz> <translated.obz> [output.obz]');
19+
console.log('If no output path is supplied, the script will append "-with-assets" to the translated file name.');
20+
}
21+
22+
async function main() {
23+
const [, , originalPath, translatedPath, outputArg] = process.argv;
24+
25+
if (!originalPath || !translatedPath) {
26+
printUsage();
27+
process.exit(1);
28+
}
29+
30+
if (!fs.existsSync(originalPath)) {
31+
console.error(`Original file not found: ${originalPath}`);
32+
process.exit(1);
33+
}
34+
35+
if (!fs.existsSync(translatedPath)) {
36+
console.error(`Translated file not found: ${translatedPath}`);
37+
process.exit(1);
38+
}
39+
40+
const outputPath =
41+
outputArg ||
42+
path.join(
43+
path.dirname(translatedPath),
44+
`${path.basename(translatedPath, path.extname(translatedPath))}-with-assets${path.extname(translatedPath)}`
45+
);
46+
47+
const originalZip = new AdmZip(originalPath);
48+
const translatedZip = new AdmZip(translatedPath);
49+
50+
const resultZip = new AdmZip();
51+
52+
const normalizeName = (name) => {
53+
if (name.endsWith('.obf.obf')) {
54+
return name.replace(/\.obf\.obf$/, '.obf');
55+
}
56+
return name;
57+
};
58+
59+
const translationEntries = translatedZip.getEntries().map((entry) => ({
60+
entry,
61+
normalizedName: normalizeName(entry.entryName),
62+
}));
63+
64+
const translationNames = new Set(translationEntries.map((item) => item.normalizedName));
65+
66+
originalZip.getEntries().forEach((entry) => {
67+
const normalized = normalizeName(entry.entryName);
68+
69+
if (translationNames.has(normalized)) {
70+
return;
71+
}
72+
73+
const data = entry.isDirectory ? Buffer.alloc(0) : entry.getData();
74+
resultZip.addFile(entry.entryName, data, entry.comment || '');
75+
});
76+
77+
translationEntries.forEach(({ entry, normalizedName }) => {
78+
const data = entry.isDirectory ? Buffer.alloc(0) : entry.getData();
79+
resultZip.addFile(normalizedName, data, entry.comment || '');
80+
});
81+
82+
resultZip.writeZip(outputPath);
83+
console.log(`Merged archive written to ${outputPath}`);
84+
}
85+
86+
main().catch((error) => {
87+
console.error('Failed to merge translation assets:', error);
88+
process.exit(1);
89+
});

src/processors/obfProcessor.ts

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -622,20 +622,30 @@ class ObfProcessor extends BaseProcessor {
622622
columns,
623623
order,
624624
},
625-
buttons: page.buttons.map((button) => ({
626-
id: button.id,
627-
label: button.label,
628-
vocalization: button.message || button.label,
629-
load_board:
630-
button.semanticAction?.intent === AACSemanticIntent.NAVIGATE_TO && button.targetPageId
631-
? {
632-
path: button.targetPageId,
633-
}
634-
: undefined,
635-
background_color: button.style?.backgroundColor,
636-
border_color: button.style?.borderColor,
637-
box_id: buttonPositions.get(String(button.id ?? '')),
638-
})),
625+
buttons: page.buttons.map((button) => {
626+
const extraButtonInfo = button as AACButton & { image_id?: string; imageId?: string };
627+
const imageId =
628+
button.parameters?.image_id ||
629+
button.parameters?.imageId ||
630+
extraButtonInfo.image_id ||
631+
extraButtonInfo.imageId;
632+
633+
return {
634+
id: button.id,
635+
label: button.label,
636+
vocalization: button.message || button.label,
637+
load_board:
638+
button.semanticAction?.intent === AACSemanticIntent.NAVIGATE_TO && button.targetPageId
639+
? {
640+
path: button.targetPageId,
641+
}
642+
: undefined,
643+
background_color: button.style?.backgroundColor,
644+
border_color: button.style?.borderColor,
645+
box_id: buttonPositions.get(String(button.id ?? '')),
646+
image_id: imageId,
647+
};
648+
}),
639649
images: Array.isArray(page.images) ? page.images : [],
640650
sounds: Array.isArray(page.sounds) ? page.sounds : [],
641651
};

0 commit comments

Comments
 (0)