@akson/cortex-shopify-translations
Version:
Unified Shopify translations management client with product extraction, translation sync, and CLI tools
122 lines (100 loc) • 4.02 kB
JavaScript
/**
* Search for specific translations across all files
* Useful for finding and reviewing specific keys or content
*/
import fs from 'fs/promises';
import path from 'path';
async function searchTranslations(searchTerm, options = {}) {
const contentDir = path.join(process.cwd(), 'translations', 'content');
const { language, status, exact } = options;
console.log(`\n🔍 Searching for: "${searchTerm}"\n`);
try {
const files = await fs.readdir(contentDir);
const categoryFiles = files.filter(f => f.endsWith('.json'));
let totalMatches = 0;
const searchLower = searchTerm.toLowerCase();
for (const fileName of categoryFiles) {
const filePath = path.join(contentDir, fileName);
const data = JSON.parse(await fs.readFile(filePath, 'utf-8'));
const matches = [];
for (const translation of data.translations) {
let isMatch = false;
// Check if it matches the search criteria
if (exact) {
// Exact key match
isMatch = translation.key === searchTerm;
} else {
// Search in key and all language content
const keyMatch = translation.key.toLowerCase().includes(searchLower);
const frMatch = translation.fr.toLowerCase().includes(searchLower);
const deMatch = translation.de && translation.de.toLowerCase().includes(searchLower);
const itMatch = translation.it && translation.it.toLowerCase().includes(searchLower);
const enMatch = translation.en && translation.en.toLowerCase().includes(searchLower);
isMatch = keyMatch || frMatch || deMatch || itMatch || enMatch;
}
// Filter by status if specified
if (isMatch && status && language) {
isMatch = translation.status[language] === status;
}
if (isMatch) {
matches.push(translation);
}
}
if (matches.length > 0) {
console.log(`📁 ${fileName} (${matches.length} matches)`);
console.log('─'.repeat(60));
matches.forEach(t => {
console.log(`\nKey: ${t.key}`);
console.log(`FR: ${t.fr}`);
if (language) {
// Show specific language
if (t[language]) {
console.log(`${language.toUpperCase()}: ${t[language]}`);
console.log(`Status: ${t.status[language]}`);
} else {
console.log(`${language.toUpperCase()}: [${t.status[language]}]`);
}
} else {
// Show all languages with content
if (t.de) console.log(`DE: ${t.de} [${t.status.de}]`);
if (t.it) console.log(`IT: ${t.it} [${t.status.it}]`);
if (t.en) console.log(`EN: ${t.en} [${t.status.en}]`);
}
});
console.log();
totalMatches += matches.length;
}
}
console.log(`\n✅ Found ${totalMatches} matches\n`);
} catch (error) {
console.error(`❌ Error: ${error.message}`);
process.exit(1);
}
}
// CLI
const args = process.argv.slice(2);
if (args.length === 0) {
console.log('Usage: search-translations.mjs <search-term> [options]');
console.log('\nOptions:');
console.log(' --lang=<de|it|en> Filter by language');
console.log(' --status=<status> Filter by status (pending, completed, reviewed, failed)');
console.log(' --exact Match exact key only');
console.log('\nExamples:');
console.log(' search-translations.mjs badge');
console.log(' search-translations.mjs "ton équipement" --lang=de');
console.log(' search-translations.mjs checkout.payment --exact');
process.exit(0);
}
const searchTerm = args[0];
const options = {};
args.slice(1).forEach(arg => {
if (arg.startsWith('--lang=')) {
options.language = arg.split('=')[1];
} else if (arg.startsWith('--status=')) {
options.status = arg.split('=')[1];
} else if (arg === '--exact') {
options.exact = true;
}
});
searchTranslations(searchTerm, options);