UNPKG

@dmvicent3/tcli

Version:

A CLI tool for managing translations in projects using next-translate

107 lines (106 loc) 4.38 kB
import { text, confirm, isCancel } from '@clack/prompts'; import { requireConfig, getApiKey } from '../lib/config.js'; import { loadTranslationFile, saveTranslationFile } from '../lib/files.js'; import { GeminiTranslator } from '../lib/gemini.js'; export async function addCommand(key, value, namespace, lang) { const config = requireConfig(); const ns = namespace || config.defaultNamespace; if (!config.namespaces.includes(ns)) { console.error(`[${config.defaultNamespace}] Namespace '${ns}' not found`); process.exit(1); } const targetLang = lang || config.sourceLang; if (!config.langs.includes(targetLang)) { console.error(`[${config.defaultNamespace}] Language '${targetLang}' not supported`); process.exit(1); } if (!key) { const keyInput = await text({ message: 'Enter translation key:', validate: (v) => (v.length === 0 ? 'Key is required' : undefined), }); if (isCancel(keyInput)) { console.log('[tcli] Operation cancelled'); process.exit(0); } key = keyInput; } const translations = loadTranslationFile(config.langDir, targetLang, ns); if (getNestedValue(translations, key)) { const overwrite = await confirm({ message: `Key '${key}' already exists. Overwrite?`, }); if (isCancel(overwrite)) { console.log('[tcli] Operation cancelled'); process.exit(0); } if (!overwrite) return; } if (!value && targetLang === config.sourceLang) { const valueInput = await text({ message: `Enter value for '${key}':`, validate: (v) => (v.length === 0 ? 'Value is required' : undefined), }); if (isCancel(valueInput)) { console.log('[tcli] Operation cancelled'); process.exit(0); } value = valueInput; } if (targetLang === config.sourceLang) { if (!value) { console.error(`[${config.defaultNamespace}] Value is required for source language`); process.exit(1); } setNestedValue(translations, key, value); saveTranslationFile(config.langDir, targetLang, ns, translations); console.log(`[${ns}] Added successfully`); const translator = new GeminiTranslator(getApiKey()); for (const otherLang of config.langs) { if (otherLang === config.sourceLang) continue; const otherTranslations = loadTranslationFile(config.langDir, otherLang, ns); const translatedValue = await translator.translate(value, config.sourceLang, otherLang); setNestedValue(otherTranslations, key, translatedValue); saveTranslationFile(config.langDir, otherLang, ns, otherTranslations); } console.log(`[${ns}] Translated to all languages`); } else { const sourceTranslations = loadTranslationFile(config.langDir, config.sourceLang, ns); const sourceValue = getNestedValue(sourceTranslations, key); if (!sourceValue) { console.error(`[${config.defaultNamespace}] Source key '${key}' not found in ${config.sourceLang}`); process.exit(1); } const translator = new GeminiTranslator(getApiKey()); const translatedValue = await translator.translate(sourceValue, config.sourceLang, targetLang); setNestedValue(translations, key, translatedValue); saveTranslationFile(config.langDir, targetLang, ns, translations); console.log(`[${ns}] Added successfully`); } } function getNestedValue(obj, key) { const parts = key.split('.'); let current = obj; for (const part of parts) { if (typeof current !== 'object' || current === null || !(part in current)) { return undefined; } current = current[part]; } return typeof current === 'string' ? current : undefined; } function setNestedValue(obj, key, value) { const parts = key.split('.'); let current = obj; for (let i = 0; i < parts.length - 1; i++) { const part = parts[i]; if (!(part in current) || typeof current[part] !== 'object') { current[part] = {}; } current = current[part]; } current[parts[parts.length - 1]] = value; }