@akson/cortex-shopify-translations
Version:
Unified Shopify translations management client with product extraction, translation sync, and CLI tools
187 lines (161 loc) • 6.39 kB
JavaScript
/**
* Split large translation file into manageable category-based files
* Adds status tracking for each translation
*/
import fs from 'fs/promises';
import path from 'path';
async function splitTranslations() {
console.log('🧠 Splitting translations into category files...');
try {
// Read the main translation file
const mainFile = path.join(process.cwd(), 'translations-to-edit.json');
const data = JSON.parse(await fs.readFile(mainFile, 'utf-8'));
// Initialize groups
const groups = {
checkout: [],
customer: [],
products: [],
myarmy: [],
navigation: [],
forms: [],
errors: [],
other: []
};
// Stats tracking
const stats = {
total: data.translations.length,
byCategory: {}
};
// Categorize translations
console.log(`📊 Processing ${data.translations.length} translations...`);
data.translations.forEach(translation => {
const key = translation.key.toLowerCase();
const frenchText = translation.fr_original.toLowerCase();
// Transform to new structure with status
const item = {
key: translation.key,
fr: translation.fr_original,
de: translation.de_current || '',
it: translation.it_current || '',
en: translation.en_current || '',
status: {
de: translation.de_current ? 'completed' : 'pending',
it: translation.it_current ? 'completed' : 'pending',
en: translation.en_current ? 'completed' : 'pending'
},
resourceId: translation.resourceId,
digest: translation.digest
};
// Categorize based on key patterns
if (key.includes('checkout') || key.includes('payment') || key.includes('shipping') ||
key.includes('billing') || key.includes('cart') || key.includes('order')) {
groups.checkout.push(item);
}
else if (key.includes('customer') || key.includes('account') || key.includes('login') ||
key.includes('register') || key.includes('profile')) {
groups.customer.push(item);
}
else if (key.includes('product') || key.includes('collection') || key.includes('variant') ||
key.includes('inventory') || key.includes('catalog')) {
groups.products.push(item);
}
else if (key.includes('badge') || key.includes('section') || key.includes('pull') ||
key.includes('slide') || frenchText.includes('badge') || frenchText.includes('section') ||
frenchText.includes('équipement') || frenchText.includes('pull')) {
groups.myarmy.push(item);
}
else if (key.includes('navigation') || key.includes('menu') || key.includes('header') ||
key.includes('footer') || key.includes('breadcrumb')) {
groups.navigation.push(item);
}
else if (key.includes('form') || key.includes('input') || key.includes('field') ||
key.includes('button') || key.includes('submit')) {
groups.forms.push(item);
}
else if (key.includes('error') || key.includes('invalid') || key.includes('required') ||
key.includes('failed') || key.includes('missing')) {
groups.errors.push(item);
}
else {
groups.other.push(item);
}
});
// Save each group to its own file
const contentDir = path.join(process.cwd(), 'translations', 'content');
// Create content directory if it doesn't exist
await fs.mkdir(contentDir, { recursive: true });
for (const [category, translations] of Object.entries(groups)) {
const filePath = path.join(contentDir, `${category}.json`);
// Calculate stats for this category
const categoryStats = {
total: translations.length,
de: { pending: 0, completed: 0 },
it: { pending: 0, completed: 0 },
en: { pending: 0, completed: 0 }
};
translations.forEach(t => {
['de', 'it', 'en'].forEach(lang => {
categoryStats[lang][t.status[lang]]++;
});
});
// Save file with metadata
const fileData = {
metadata: {
category,
total: translations.length,
stats: categoryStats,
created: new Date().toISOString()
},
translations
};
await fs.writeFile(filePath, JSON.stringify(fileData, null, 2), 'utf-8');
stats.byCategory[category] = categoryStats;
console.log(`✅ ${category}.json: ${translations.length} translations`);
console.log(` DE: ${categoryStats.de.completed} completed, ${categoryStats.de.pending} pending`);
console.log(` IT: ${categoryStats.it.completed} completed, ${categoryStats.it.pending} pending`);
console.log(` EN: ${categoryStats.en.completed} completed, ${categoryStats.en.pending} pending`);
}
// Create initial status file
const statusPath = path.join(process.cwd(), 'translations', 'status.json');
const statusData = {
summary: {
total_keys: data.translations.length,
created_at: new Date().toISOString(),
last_update: new Date().toISOString(),
source_language: 'fr',
target_languages: ['de', 'it', 'en']
},
progress: calculateProgress(stats.byCategory),
files: stats.byCategory
};
await fs.writeFile(statusPath, JSON.stringify(statusData, null, 2), 'utf-8');
console.log('\n📊 Summary:');
console.log(`Total translations: ${stats.total}`);
console.log('Files created:');
Object.entries(stats.byCategory).forEach(([cat, data]) => {
console.log(` - ${cat}: ${data.total} items`);
});
console.log('\n✅ Split completed successfully!');
console.log('📁 Files saved in: translations/content/');
} catch (error) {
console.error('❌ Error splitting translations:', error.message);
process.exit(1);
}
}
function calculateProgress(categoryStats) {
const progress = {
de: { pending: 0, completed: 0 },
it: { pending: 0, completed: 0 },
en: { pending: 0, completed: 0 }
};
Object.values(categoryStats).forEach(cat => {
['de', 'it', 'en'].forEach(lang => {
progress[lang].pending += cat[lang].pending;
progress[lang].completed += cat[lang].completed;
});
});
return progress;
}
// Run the script
splitTranslations();