@akson/cortex-shopify-translations
Version:
Unified Shopify translations management client with product extraction, translation sync, and CLI tools
140 lines (117 loc) ⢠4.78 kB
JavaScript
/**
* Merge split translation files back to Shopify format
* Creates a file ready for publish-translations.mjs
*/
import fs from 'fs/promises';
import path from 'path';
async function mergeBack(outputFile = 'translations-to-edit.json') {
console.log('š Merging translations back to publishable format...\n');
const contentDir = path.join(process.cwd(), 'translations', 'content');
const outputPath = path.join(process.cwd(), outputFile);
try {
// Get all category files
const files = await fs.readdir(contentDir);
const categoryFiles = files.filter(f => f.endsWith('.json'));
const mergedData = {
metadata: {
createdAt: new Date().toISOString(),
resourceType: 'ONLINE_STORE_THEME',
resourceCount: 1,
totalTranslations: 0,
sourceLanguage: 'fr',
targetLanguages: ['de', 'it', 'en'],
note: 'fr_original contains the source language content for translations',
instructions: {
howToEdit: "Edit the '*_fixed' fields with proper translations FROM the fr_original field.",
workflow: [
'1. Look at fr_original (this is the source text)',
'2. Fix the *_fixed fields for target languages: de, it, en',
'3. Save your changes',
'4. Run: node publish-translations.mjs online_store_theme --force'
]
},
categories_merged: []
},
translations: []
};
const stats = {
total: 0,
by_status: {
de: { pending: 0, completed: 0, reviewed: 0, failed: 0 },
it: { pending: 0, completed: 0, reviewed: 0, failed: 0 },
en: { pending: 0, completed: 0, reviewed: 0, failed: 0 }
}
};
// Process each category file
for (const fileName of categoryFiles) {
const filePath = path.join(contentDir, fileName);
const data = JSON.parse(await fs.readFile(filePath, 'utf-8'));
console.log(`š Processing ${fileName}: ${data.translations.length} translations`);
mergedData.metadata.categories_merged.push(fileName.replace('.json', ''));
// Convert back to publish format (with _fixed fields for editing)
data.translations.forEach(t => {
const shopifyFormat = {
key: t.key,
resourceId: t.resourceId || 'gid://shopify/OnlineStoreTheme/185946079581',
fr_original: t.fr,
digest: t.digest,
de_current: t.de || '',
de_fixed: t.de || '', // Use current value as starting point
it_current: t.it || '',
it_fixed: t.it || '', // Use current value as starting point
en_current: t.en || '',
en_fixed: t.en || '' // Use current value as starting point
};
// Include all translations for complete file
mergedData.translations.push(shopifyFormat);
// Update stats
['de', 'it', 'en'].forEach(lang => {
const status = t.status[lang] || 'pending';
if (stats.by_status[lang][status] !== undefined) {
stats.by_status[lang][status]++;
}
});
stats.total++;
});
}
// Update metadata with final counts
mergedData.metadata.totalTranslations = mergedData.translations.length;
// Add summary stats
mergedData.metadata.stats = {
total_keys: stats.total,
merged_keys: mergedData.translations.length,
by_language: {}
};
['de', 'it', 'en'].forEach(lang => {
const completed = stats.by_status[lang].completed + stats.by_status[lang].reviewed;
mergedData.metadata.stats.by_language[lang] = {
translated: completed,
percentage: Math.round((completed / stats.total) * 100)
};
});
// Write merged file
await fs.writeFile(outputPath, JSON.stringify(mergedData, null, 2));
console.log('\nā
Merge complete!');
console.log(`š Total translations: ${stats.total}`);
console.log(`š Translated entries: ${mergedData.translations.length}`);
console.log('\nš Language completion:');
['de', 'it', 'en'].forEach(lang => {
const langStats = mergedData.metadata.stats.by_language[lang];
console.log(` ${lang.toUpperCase()}: ${langStats.translated} (${langStats.percentage}%)`);
});
console.log(`\nš¾ Output saved to: ${outputFile}`);
// Show publish command if ready
if (mergedData.translations.length > 0) {
console.log('\nš¤ Ready to publish to Shopify:');
console.log(` node publish-translations.mjs ${outputFile}`);
}
} catch (error) {
console.error(`ā Error: ${error.message}`);
process.exit(1);
}
}
// CLI
const args = process.argv.slice(2);
const outputFile = args[0] || 'translations-to-edit.json';
mergeBack(outputFile);