i18n-ai
Version:
AI-powered translation tool for i18n JSON files
71 lines (68 loc) • 6.96 kB
JavaScript
import {u,r,v,p as p$1,t,j,i,h,g,f}from'./chunk-AOEQIIBE.js';import {Command}from'commander';import c from'fs';import _ from'path';function $(t,e=","){let o=t.split(/\r?\n/),s=[];for(let r of o){if(!r.trim())continue;let m=[],l="",n=false;for(let a=0;a<r.length;a++){let u=r[a];u==='"'?n&&r[a+1]==='"'?(l+='"',a++):n=!n:u===e&&!n?(m.push(l),l=""):l+=u;}m.push(l),s.push(m);}return s}async function V(t$1,e){let{inputPath:o,delimiter:s=",",skipHeader:r=true,overwrite:m=false}=e;if(!c.existsSync(o))throw new Error(`CSV file not found: ${o}`);let l=c.readFileSync(o,"utf-8"),n=$(l,s);if(n.length===0)throw new Error("CSV file is empty");let a=r?n[0]:null,u=r?1:0;if(a){let[,...i]=a,f=[t$1.source.code,...t$1.targets.map(g=>g.code)].filter(g=>!i.includes(g));if(f.length>0)throw new Error(`Missing language columns in CSV: ${f.join(", ")}`)}let j=[{...t$1.source,index:1},...t$1.targets.map((i,d)=>({...i,index:d+2}))];for(let i of j){let d={},f={};c.existsSync(i.path)&&(f=JSON.parse(c.readFileSync(i.path,"utf-8")));for(let h=u;h<n.length;h++){let O=n[h],y=O[0],C=O[i.index];y&&C&&(d[y]=C);}let g=m?{...f,...t(d)}:{...t(d),...f},E=_.dirname(i.path);c.existsSync(E)||c.mkdirSync(E,{recursive:true}),c.writeFileSync(i.path,JSON.stringify(g,null,2),"utf-8"),console.log(`Updated translations for ${i.code}: ${i.path}`);}console.log(`
CSV import completed successfully!`);}var p=new Command;p.name("i18n-ai").description(`AI-powered translation tool for i18n JSON files
Features:
\u2022 Translates i18n JSON files using AI language models
\u2022 Supports multiple AI providers (OpenAI, Anthropic, Gemini, DeepSeek, XAI)
\u2022 Preserves JSON structure and nested keys
\u2022 Smart chunking for large files
\u2022 Handles existing translations
\u2022 Configurable translation settings`).version("0.1.0");p.command("translate").description("Translate i18n JSON files").option("-c, --config <path>","Path to config file (default: translator.config.json)").option("-o, --overwrite","Overwrite existing translations").addHelpText("after",`
Configuration File (translator.config.json):
{
"source": {
"path": "./locales/en.json", // Source language file
"code": "en" // Source language code
},
"targets": [{ // Target languages to translate to
"path": "./locales/es.json",
"code": "es"
}],
"provider": "openai", // AI provider to use
"model": "gpt-4", // Model to use (optional)
"chunkSize": 50, // Number of keys per chunk (default: 50)
"description": "My app context", // Project context for better translations
"tone": "formal", // Desired tone (formal/casual/technical)
"translateAllAtOnce": false, // Translate entire file at once
"overwrite": false, // Overwrite existing translations
"customProvider": { // Custom translation API configuration
"url": "https://api.example.com/translate", // API endpoint
"method": "POST", // HTTP method (default: POST)
"headers": {}, // Custom HTTP headers
"body": {}, // Request body template (supports placeholders)
"responsePath": "translation", // Path to extract result from response
"apiKeyEnvVar": "CUSTOM_API_KEY" // Env var with API key
}
}
Environment Variables:
OPENAI_API_KEY - OpenAI API key
ANTHROPIC_API_KEY - Anthropic API key
GEMINI_API_KEY - Google Gemini API key
DEEPSEEK_API_KEY - DeepSeek API key
XAI_API_KEY - XAI API key
[] - For custom provider if configured
Examples:
$ i18n-ai translate
$ i18n-ai translate -c custom-config.json
$ i18n-ai translate --overwrite
`).action(async t=>{try{await u({configPath:t.config,overwrite:t.overwrite});}catch(e){console.error("Translation failed:",e),process.exit(1);}});p.command("models").description("List available AI models").option("-p, --provider <provider>","Show models for specific provider (openai, anthropic, gemini, deepseek, xai)").addHelpText("after",`
Examples:
$ i18n-ai models
$ i18n-ai models --provider openai
`).action(t=>{let e=(o,s)=>{console.log(`
${o.toUpperCase()}:`);let r=Object.keys(s).join(" | ");console.log(r),console.log();};if(t.provider){let o=t.provider.toLowerCase();switch(o){case "openai":e("OpenAI",f);break;case "anthropic":e("Anthropic",g);break;case "gemini":e("Gemini",h);break;case "deepseek":e("DeepSeek",i);break;case "xai":e("XAI",j);break;default:console.error(`Unknown provider: ${o}`),process.exit(1);}}else e("OpenAI",f),e("Anthropic",g),e("Gemini",h),e("DeepSeek",i),e("XAI",j);});p.command("export").description("Export translations to CSV format").option("-c, --config <path>","Path to config file (default: translator.config.json)").option("-o, --output <path>","Output path for CSV file (default: translations-export.csv)").option("-d, --delimiter <char>","Delimiter to use in CSV (default: ,)").addHelpText("after",`
Examples:
$ i18n-ai export
$ i18n-ai export --output ./exports/translations.csv
$ i18n-ai export --delimiter ";"
$ i18n-ai export -c custom-config.json
`).action(async t=>{try{let e=r(t.config);await v(e,{outputPath:t.output,delimiter:t.delimiter});}catch(e){console.error("Export failed:",e),process.exit(1);}});p.command("import").description("Import translations from a CSV file").option("-c, --config <path>","Path to config file (default: translator.config.json)").option("-i, --input <path>","Input CSV file path").option("-d, --delimiter <char>","Delimiter to use in CSV (default: ,)").option("--no-header","Skip header row in CSV").option("-o, --overwrite","Overwrite existing translations").addHelpText("after",`
Examples:
$ i18n-ai import -i translations.csv
$ i18n-ai import -i ./data/translations.csv
$ i18n-ai import -i translations.csv -d ";"
$ i18n-ai import -i translations.csv --no-header
$ i18n-ai import -i translations.csv --overwrite
$ i18n-ai import -c custom-config.json -i translations.csv
`).action(async t=>{try{let e=r(t.config);await V(e,{inputPath:t.input,delimiter:t.delimiter,skipHeader:t.header!==!1,overwrite:t.overwrite});}catch(e){console.error("Import failed:",e),process.exit(1);}});p.command("providers").description("List all available translation providers").action(()=>{let t=p$1();Object.entries(t.models).forEach(([e,o])=>{console.log(`
${e.toUpperCase()}:`);let s=Object.keys(o).join(" | ");console.log(s);});});p.parse();