UNPKG

i18n-ai

Version:

AI-powered translation tool for i18n JSON files

40 lines (38 loc) 29.1 kB
'use strict';var oe=require('axios'),le=require('dotenv'),I=require('fs'),O=require('path'),process$1=require('process');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var oe__default=/*#__PURE__*/_interopDefault(oe);var le__namespace=/*#__PURE__*/_interopNamespace(le);var I__namespace=/*#__PURE__*/_interopNamespace(I);var O__namespace=/*#__PURE__*/_interopNamespace(O);var Z=Object.defineProperty;var ke=Object.getOwnPropertyDescriptor;var ve=Object.getOwnPropertyNames;var Te=Object.prototype.hasOwnProperty;var we=(s,e)=>()=>(s&&(e=s(s=0)),e);var xe=(s,e)=>{for(var o in e)Z(s,o,{get:e[o],enumerable:true});},$e=(s,e,o,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of ve(e))!Te.call(s,r)&&r!==o&&Z(s,r,{get:()=>e[r],enumerable:!(t=ke(e,r))||t.enumerable});return s};var Pe=s=>$e(Z({},"__esModule",{value:true}),s);var ce={};xe(ce,{CustomProvider:()=>exports.o});function Oe(s){I__namespace.existsSync(s)||I__namespace.mkdirSync(s,{recursive:true});}function Ee(){return new Date().toISOString().replace(/:/g,"-").replace(/\..+/,"")}function ee(s){let e=/```(?:json)?\s*([\s\S]*?)\s*```/,o=s.match(e);return o&&o[1]?o[1].trim():s}exports.o=void 0;var X=we(()=>{le__namespace.config();exports.o=class s{constructor(e,o){this.name="custom";this.model="custom-model";this.config=e,this.translationConfig=o,s.logFilePaths=[];}static{this.logFilePaths=[];}logErrorToFile(e,o,t){try{let r=O__namespace.join(process.cwd(),"i18n_ai_logs");Oe(r);let n=Ee(),l=O__namespace.join(r,`custom-provider-error-${n}.log`),i=`[${new Date().toISOString()}] Custom Provider Error `;i+=`Error Message: ${e.message} `,e.stack&&(i+=`Stack Trace: ${e.stack} `),e.response&&(i+=`Response Status: ${e.response.status} `,i+=`Response Status Text: ${e.response.statusText} `),t&&(i+=`Request Data: ${JSON.stringify(t,null,2)} `),I__namespace.writeFileSync(l,i),console.error(`Error log written to: ${l}`);let c;if(o||e.response){let d=o||e.response?.data;d&&(c=O__namespace.join(r,`custom-provider-response-${n}.json`),typeof d=="object"?I__namespace.writeFileSync(c,JSON.stringify(d,null,2)):I__namespace.writeFileSync(c,String(d)),console.error(`Response data written to: ${c}`));}let a={errorLogPath:O__namespace.resolve(l),responseLogPath:c?O__namespace.resolve(c):void 0};return s.logFilePaths.push(a),a}catch(r){return console.error("Failed to write error log:",r),{}}}async translate(e,o){let t,r;try{let{url:n,method:l="POST",headers:i={},body:c,responsePath:a}=this.config;t=this.prepareRequestBody(c,e,o),r=await oe__default.default({method:l,url:n,headers:i,data:l==="POST"?t:void 0,params:l==="GET"?t:void 0});let d;if(a){let p=r.data;if(typeof p=="string"){let u=ee(p);if(u.trim().startsWith("{")||u.trim().startsWith("["))try{p=JSON.parse(u);}catch(h){console.warn("Failed to parse extracted content as JSON:",h.message),console.warn("Content:",u);}else return u}let y=a.replace(/\[(\d+)\]/g,".$1").split(".");for(let u of y){if(!p){let h=new Error(`Response path '${a}' failed at '${u}': previous part was null or undefined`),g=this.logErrorToFile(h,r.data,t);throw new Error(`Response path '${a}' failed at '${u}': previous part was null or undefined. Logs created at: ${g.errorLogPath}`)}if(/^\d+$/.test(u)&&Array.isArray(p)){let h=parseInt(u,10);if(h>=p.length){let g=new Error(`Response path '${a}' failed: array index ${h} is out of bounds (length: ${p.length})`),k=this.logErrorToFile(g,r.data,t);throw new Error(`Response path '${a}' failed: array index ${h} is out of bounds. Logs created at: ${k.errorLogPath}`)}p=p[h];}else if(typeof p=="object"&&u in p)p=p[u];else {let h=new Error(`Response path '${a}' failed: property '${u}' not found in ${JSON.stringify(p).substring(0,100)}...`),g=this.logErrorToFile(h,r.data,t);throw new Error(`Response path '${a}' failed: property '${u}' not found. Logs created at: ${g.errorLogPath}`)}}if(typeof p=="string")d=p;else if(p!=null)d=String(p);else {let u=new Error(`Translation result is not a string and cannot be converted to a string: ${JSON.stringify(p)}`),h=this.logErrorToFile(u,r.data,t);throw new Error(`Translation result is not a string. Logs created at: ${h.errorLogPath}`)}typeof d=="string"&&(d=ee(d));}else typeof r.data=="string"?d=ee(r.data):d=JSON.stringify(r.data);return d}catch(n){if(n.message.includes("Logs created at:"))throw n;console.error("Custom provider translation failed:",n.message);let l=this.logErrorToFile(n,r?.data,t),i=`Custom provider translation failed: ${n.message}`,c=l.errorLogPath?` Error details logged to: ${l.errorLogPath}`:"";throw new Error(`${i}${c}`)}}prepareRequestBody(e,o,t){let r;if(typeof e=="string"){r=e.replace(/{{text}}/g,o).replace(/{{targetLang}}/g,t).replace(/{{sourceLang}}/g,this.translationConfig.source.code);try{(r.trim().startsWith("{")||r.trim().startsWith("["))&&(r=JSON.parse(r));}catch{}}else if(e&&typeof e=="object"){r=JSON.parse(JSON.stringify(e));let n=l=>{for(let i in l)typeof l[i]=="string"?l[i]=l[i].replace(/{{text}}/g,o).replace(/{{targetLang}}/g,t).replace(/{{sourceLang}}/g,this.translationConfig.source.code):typeof l[i]=="object"&&l[i]!==null&&n(l[i]);};n(r);}else r={text:o,targetLanguage:t,sourceLanguage:this.translationConfig.source.code};return r}};});var K=class{constructor(e,o="gpt-4o-mini",t){this.name="openai";this.apiKey=e,this.model=o,this.config=t;}async translate(e,o){try{let t=`You are a professional translator. Translate the following JSON content to ${o}.`;return this.config.description&&(t+=` Context: ${this.config.description}`),this.config.tone&&(t+=` Use a ${this.config.tone} tone in the translations.`),t+=` Preserve all JSON structure and keys. Only translate the values. DO NOT modify, translate, or convert numeric keys or values. Return ONLY the translated text without any explanation or markdown.`,(await oe__default.default.post("https://api.openai.com/v1/chat/completions",{model:this.model,messages:[{role:"system",content:t},{role:"user",content:e}],response_format:{type:"json_object"},temperature:.1},{headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"}})).data.choices[0].message.content.trim()}catch(t){throw oe__default.default.isAxiosError(t)?new Error(`Translation failed: ${t.response?.data?.error?.message||t.message}`):t}}};var J=class{constructor(e,o="claude-3-5-haiku-latest",t){this.name="anthropic";this.lastRequestTime=0;this.minRequestInterval=200;this.apiKey=e,this.model=o,this.config=t;}async rateLimit(){let o=Date.now()-this.lastRequestTime;o<this.minRequestInterval&&await new Promise(t=>setTimeout(t,this.minRequestInterval-o)),this.lastRequestTime=Date.now();}async translate(e,o){try{await this.rateLimit(),console.log("Translating text with Anthropic");let t=`You are a professional translator. Translate the following JSON content to ${o}.`;this.config.description&&(t+=` Context: ${this.config.description}`),this.config.tone&&(t+=` Use a ${this.config.tone} tone in the translations.`),t+=` Preserve all JSON structure and keys. Only translate the values. DO NOT modify, translate, or convert numeric keys or values. Return ONLY the translated text without any explanation or markdown. output in JSON format.`,console.log("Sending request to Anthropic");let r=await oe__default.default.post("https://api.anthropic.com/v1/messages",{model:this.model,messages:[{role:"user",content:`${t} ${e}`}],max_tokens:4096},{headers:{"x-api-key":this.apiKey,"anthropic-version":"2023-06-01","content-type":"application/json"}});if(!r.data.content||!r.data.content[0]?.text)throw new Error("Invalid response format from Anthropic API");let n=r.data.content[0].text.trim();try{JSON.parse(n);}catch{console.warn("Response is not valid JSON, but proceeding with raw text");}return n}catch(t){if(oe__default.default.isAxiosError(t)){let r=t.response?.status,n=t.response?.data?.error?.message||t.message;if(r===429){let l=parseInt(t.response?.headers["retry-after"]||"5");return await new Promise(i=>setTimeout(i,l*1e3)),this.translate(e,o)}throw new Error(`Translation failed (${r}): ${n}`)}throw t}}};var B=class{constructor(e,o="gemini-2.0-flash-lite",t){this.name="gemini";this.apiKey=e,this.model=o,this.config=t;}async translate(e,o){try{let t=`Translate the following JSON content to ${o}.`;this.config.description&&(t+=` Context: ${this.config.description}`),this.config.tone&&(t+=` Use a ${this.config.tone} tone in the translations.`),t+=` Preserve all JSON structure and keys. Only translate the values. DO NOT modify, translate, or convert numeric keys or values. Return ONLY the translated text without any explanation or markdown. `,t+=e;let n=(await oe__default.default.post(`https://generativelanguage.googleapis.com/v1beta/models/${this.model}:generateContent?key=${this.apiKey}`,{contents:[{role:"user",parts:[{text:t}]}],generationConfig:{temperature:.1,topK:1,topP:1,maxOutputTokens:8192}})).data.candidates[0].content.parts[0].text;n=n.replace(/^```json\n/,"").replace(/\n```$/,"");try{let l=JSON.parse(n),i=Object.fromEntries(Object.entries(l).map(([c,a])=>[c,typeof a=="string"?a.replace(/^"|"$/g,""):a]));return JSON.stringify(i,null,2)}catch(l){return console.error("Failed to parse Gemini response as JSON:",l),n.trim()}}catch(t){throw oe__default.default.isAxiosError(t)?new Error(`Translation failed: ${t.response?.data?.error?.message||t.message}`):t}}};var F=class{constructor(e,o="deepseek-chat",t){this.name="deepseek";this.apiKey=e,this.model=o,this.config=t;}async translate(e,o){try{let t=`You are a professional translator. Translate the following JSON content to ${o}.`;return this.config.description&&(t+=` Context: ${this.config.description}`),this.config.tone&&(t+=` Use a ${this.config.tone} tone in the translations.`),t+=` Preserve all JSON structure and keys. Only translate the values. DO NOT modify, translate, or convert numeric keys or values. Return ONLY the translated text without any explanation or markdown.`,(await oe__default.default.post("https://api.deepseek.com/v1/chat/completions",{model:this.model,messages:[{role:"system",content:t},{role:"user",content:e}],temperature:.1,max_tokens:4096,response_format:{type:"json_object"}},{headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"}})).data.choices[0].message.content.trim()}catch(t){throw oe__default.default.isAxiosError(t)?new Error(`Translation failed: ${t.response?.data?.error?.message||t.message}`):t}}};var _=class{constructor(e,o="grok-2-1212",t){this.name="xai";this.apiKey=e,this.model=o,this.config=t;}async translate(e,o){try{let t=`You are a professional translator. Translate the following JSON content to ${o}.`;return this.config.description&&(t+=` Context: ${this.config.description}`),this.config.tone&&(t+=` Use a ${this.config.tone} tone in the translations.`),t+=` Preserve all JSON structure and keys. Only translate the values. DO NOT modify, translate, or convert numeric keys or values. Return ONLY the translated text without any explanation or markdown.`,(await oe__default.default.post("https://api.xai.com/v1/chat/completions",{model:this.model,messages:[{role:"system",content:t},{role:"user",content:e}],temperature:.1,max_tokens:4096},{headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"}})).data.choices[0].message.content.trim()}catch(t){throw oe__default.default.isAxiosError(t)?new Error(`Translation failed: ${t.response?.data?.error?.message||t.message}`):t}}};var G={"gpt-4":{id:"gpt-4",name:"GPT-4",maxTokens:128e3,outputTokens:4096},"gpt-4-turbo-preview":{id:"gpt-4-turbo-preview",name:"GPT-4 Turbo Preview",maxTokens:128e3,outputTokens:4096},"gpt-3.5-turbo":{id:"gpt-3.5-turbo",name:"GPT-3.5 Turbo",maxTokens:16385,outputTokens:4096},"gpt-4o":{id:"gpt-4o",name:"GPT-4 Opus",maxTokens:128e3,outputTokens:16384},"chatgpt-4o-latest":{id:"chatgpt-4o-latest",name:"ChatGPT-4 Opus Latest",maxTokens:128e3,outputTokens:16384},"gpt-4o-mini":{id:"gpt-4o-mini",name:"GPT-4 Opus Mini",maxTokens:128e3,outputTokens:16384},o1:{id:"o1",name:"Opus One",maxTokens:128e3,outputTokens:16384},"o1-mini":{id:"o1-mini",name:"Opus One Mini",maxTokens:128e3,outputTokens:16384},"o3-mini":{id:"o3-mini",name:"Opus Three Mini",maxTokens:128e3,outputTokens:16384}},U={"claude-3-5-sonnet-latest":{id:"claude-3-5-sonnet-latest",name:"Claude 3.5 Sonnet Latest",maxTokens:2e5,outputTokens:8192},"claude-3-5-haiku-latest":{id:"claude-3-5-haiku-latest",name:"Claude 3.5 Haiku Latest",maxTokens:2e5,outputTokens:8192},"claude-3-opus-latest":{id:"claude-3-opus-latest",name:"Claude 3 Opus Latest",maxTokens:2e5,outputTokens:8192},"claude-3-sonnet":{id:"claude-3-sonnet",name:"Claude 3 Sonnet",maxTokens:2e5,outputTokens:8192},"claude-3-haiku":{id:"claude-3-haiku",name:"Claude 3 Haiku",maxTokens:2e5,outputTokens:8192}},q={"gemini-2.0-flash":{id:"gemini-2.0-flash",name:"Gemini 2.0 Flash",maxTokens:1e6,outputTokens:8192},"gemini-2.0-flash-lite":{id:"gemini-2.0-flash-lite",name:"Gemini 2.0 Flash Lite",maxTokens:1e6,outputTokens:8192},"gemini-1.5-flash":{id:"gemini-1.5-flash",name:"Gemini 1.5 Flash",maxTokens:1e6,outputTokens:8192},"gemini-1.5-pro":{id:"gemini-1.5-pro",name:"Gemini 1.5 Pro",maxTokens:2e6,outputTokens:8192}},W={"deepseek-chat":{id:"deepseek-chat",name:"DeepSeek Chat",maxTokens:32768,outputTokens:2048}},Y={"grok-2-1212":{id:"grok-2-1212",name:"grok-2-1212",maxTokens:8192,outputTokens:2048}};function Ye(s){return {...G,...U,...q,...W,...Y}[s]?.isDeprecated||false}function Ce(s){return {...G,...U,...q,...W,...Y}[s]}function P(s){switch(s){case "openai":return "gpt-4o-mini";case "anthropic":return "claude-3-5-haiku-latest";case "gemini":return "gemini-2.0-flash";case "deepseek":return "deepseek-chat";case "xai":return "grok-2-1212";default:throw new Error(`Unknown provider: ${s}`)}}function z(s,e){let o=Ce(e);if(!o){console.warn(`Warning: Using custom model "${e}" for provider "${s}". This model is not in our verified list. Make sure it exists in the provider's API.`);return}o.isDeprecated&&console.warn(`Warning: Model "${e}" is deprecated${o.deprecationDate?` since ${o.deprecationDate}`:""}.${o.replacedBy?` Consider using ${o.replacedBy} instead.`:""}`);}X();X();function ot(){return {providers:["openai","anthropic","gemini","deepseek","xai","custom"],models:{openai:G,anthropic:U,gemini:q,deepseek:W,xai:Y,custom:{"custom-model":{id:"custom-model",name:"Custom Provider Model",maxTokens:0,outputTokens:0}}},defaultModels:{openai:P("openai"),anthropic:P("anthropic"),gemini:P("gemini"),deepseek:P("deepseek"),xai:P("xai"),custom:"custom-model"}}}function de(s,e,o,t){if(o.customProvider&&o.customProvider.url)return new exports.o(o.customProvider,o);let r=t||P(s);switch(z(s,r),s){case "openai":return new K(e,r,o);case "anthropic":return new J(e,r,o);case "gemini":return new B(e,r,o);case "deepseek":return new F(e,r,o);case "xai":return new _(e,r,o);case "custom":if(!o.customProvider||!o.customProvider.url)throw new Error("Custom provider selected but no configuration provided. Please add a 'customProvider' section to your config.");return new exports.o(o.customProvider,o);default:throw new Error(`Unsupported provider: ${s}`)}}le.config();var Me={provider:"openai",chunkSize:50,concurrency:3,overwrite:false};function ue(s){let e=O__namespace.default.resolve(process.cwd(),"translator.config.json"),o=s||e;if(!I__namespace.default.existsSync(o))throw new Error(`Config file not found at ${o}`);try{let t=I__namespace.default.readFileSync(o,"utf-8"),r=JSON.parse(t),n={...Me,...r};return n.model||(n.model=P(n.provider)),n}catch(t){throw new Error(`Failed to load config file: ${t instanceof Error?t.message:String(t)}`)}}function ge(s){if(!s.source||!s.source.path||!s.source.code)throw new Error("Source file configuration is missing or invalid");if(!I__namespace.default.existsSync(s.source.path))throw new Error(`Source file not found: ${s.source.path}`);if(!s.targets||!Array.isArray(s.targets)||s.targets.length===0)throw new Error("At least one target language must be specified");for(let o of s.targets){if(!o.path||!o.code)throw new Error("Target file configuration is missing or invalid");let t=O__namespace.default.dirname(o.path);I__namespace.default.existsSync(t)||I__namespace.default.mkdirSync(t,{recursive:true});}if(z(s.provider,s.model||P(s.provider)),!process.env[`${s.provider.toUpperCase()}_API_KEY`])throw new Error(`${s.provider.toUpperCase()}_API_KEY environment variable is required`)}function E(s,e=""){let o={};for(let[t,r]of Object.entries(s)){let n=e?`${e}.${t}`:t;r&&typeof r=="object"?Array.isArray(r)?r.forEach((l,i)=>{o[`${n}.${i}`]=String(l);}):Object.assign(o,E(r,n)):o[n]=String(r);}return o}function fe(s){let e={},o=new Map,t=new Set;for(let n of Object.keys(s)){let l=n.split("."),i="";for(let c=0;c<l.length-1;c++){let a=l[c],d=l[c+1];i=i?`${i}.${a}`:a,!isNaN(Number(d))&&String(parseInt(d,10))===d?(o.has(i)||o.set(i,new Set),o.get(i)?.add(parseInt(d,10))):t.add(i);}}let r=new Set;o.forEach((n,l)=>{if(t.has(l))return;let i=Array.from(n).sort((c,a)=>c-a);i[0]===0&&i.every((c,a)=>c===a)&&r.add(l);});for(let[n,l]of Object.entries(s)){let i=n.split("."),c=e,a="";for(let f=0;f<i.length-1;f++){let y=i[f];a=a?`${a}.${y}`:y,c[y]||(c[y]=r.has(a)?[]:{}),c=c[y];}let d=i[i.length-1],p=!isNaN(Number(l))&&l!==""&&String(Number(l))===l?Number(l):l;c[d]=p;}return e}var he=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],H=class{constructor(e=""){this.message=e,this.currentFrame=0,this.interval=null,this.isSpinning=false;}start(e){e&&(this.message=e),!this.isSpinning&&(this.isSpinning=true,this.interval=setInterval(()=>{this.currentFrame=(this.currentFrame+1)%he.length,this.render();},80),this.render());}stop(){this.interval&&(clearInterval(this.interval),this.interval=null),this.isSpinning=false,process$1.stdout.clearLine(0),process$1.stdout.cursorTo(0);}succeed(e){this.stop(),console.log(`\u2713 ${e||this.message}`);}fail(e){this.stop(),console.log(`\u2717 ${e||this.message}`);}update(e){this.message=e,this.isSpinning&&this.render();}render(){process$1.stdout.clearLine(0),process$1.stdout.cursorTo(0),process$1.stdout.write(`${he[this.currentFrame]} ${this.message}`);}};var V=class{constructor(e={}){this.config={maxConcurrent:3,delayBetweenBatches:1e3,retryAttempts:3,...e};}getMaxConcurrent(){return this.config.maxConcurrent}getDelayBetweenBatches(){return this.config.delayBetweenBatches}getRetryAttempts(){return this.config.retryAttempts}async delay(e){return new Promise(o=>setTimeout(o,e))}async processWithRetry(e,o=0){try{return {success:!0,result:await e()}}catch(t){return o<this.config.retryAttempts?(await this.delay(Math.pow(2,o)*1e3),this.processWithRetry(e,o+1)):{success:false,error:t,retryCount:o}}}async processBatch(e,o){let t=new Array(e.length);for(let r=0;r<e.length;r+=this.config.maxConcurrent){let n=e.slice(r,r+this.config.maxConcurrent);for(let l=0;l<n.length;l++){let i=r+l;t[i]=await this.processWithRetry(()=>o(n[l]));}r+this.config.maxConcurrent<e.length&&await this.delay(this.config.delayBetweenBatches);}return t}};function Ie(s,e){let o=Object.entries(s),t=[],r=[],n="",l=c=>c.split(".")[0],i=()=>{r.length>0&&(t.push([...r]),r=[]);};for(let c=0;c<o.length;c++){let[a,d]=o[c],p=l(a);(r.length>=e||p!==n&&r.length>=Math.min(e*.8,10))&&(i(),n=p),r.length===0&&(n=p),r.push({key:a,value:typeof d=="string"?d:JSON.stringify(d)});}return i(),t}function Ne(s,e=[]){return e.some(o=>s===o||s.startsWith(o+"."))}function te(s){let e=s.reduce((o,[t,r])=>(o[t]=r,o),{});return JSON.stringify(e,null,2)}function re(s,e){try{let o=JSON.parse(s.trim()),t={};return e.forEach(r=>{if(typeof o[r]=="string"){let n=o[r].trim();n&&n.length>0?t[r]=n:console.warn(`Empty translation found for key: ${r}`);}else console.warn(`Missing or invalid translation for key: ${r}`);}),t}catch(o){console.error("Failed to parse translation response as JSON:",o);let t={};return s.trim().split(` `).forEach((n,l)=>{let i=e[l];if(i)try{let c=n.indexOf(":");if(c===-1){console.warn(`No separator found in line: ${n}`);return}let a=n.substring(c+1).trim().replace(/^["']|["']$/g,"").trim();a&&a.length>0?t[i]=a:console.warn(`Empty translation found for key: ${i}`);}catch(c){console.error(`Error parsing line: ${n}`,c);}}),t}}async function Ae(s,e,o,t){let r=new H,n={totalKeys:0,newKeys:0,skippedKeys:0,errors:0,totalChunks:0,processedChunks:0,failedChunkIndex:null,errorDetails:null};r.start("Reading source file...");let l=I__namespace.default.readFileSync(s,"utf-8"),i=JSON.parse(l),c=E(i);n.totalKeys=Object.keys(c).length,r.succeed(),r.start("Reading existing translations...");let a={};try{if(I__namespace.default.existsSync(e)){let g=I__namespace.default.readFileSync(e,"utf-8");a=E(JSON.parse(g)),r.succeed();}}catch{r.fail(),console.warn(`Warning: Could not read existing translations from ${e}`);}r.start("Analyzing translation needs...");let d={};for(let[g,k]of Object.entries(c)){if(Ne(g,t.ignoreKeys)){n.skippedKeys++,a[g]?d[g]=a[g]:d[g]=k;continue}a[g]&&!t.overwrite?(n.skippedKeys++,d[g]=a[g]):d[g]=k;}if(r.succeed(),Object.keys(d).length===0)return console.log("No new keys to translate"),n;r.start("Initializing translation provider...");let p=de(t.provider,process.env[`${t.provider.toUpperCase()}_API_KEY`]||"",t,t.model);r.succeed();let y=t.customProvider&&t.customProvider.url?`Custom provider (${t.customProvider.url})`:`${t.provider.toUpperCase()} (model: ${p.model})`;console.log(`Using translation provider: ${y}`);let u={},h=new V({maxConcurrent:3,delayBetweenBatches:2e3,retryAttempts:3});if(t.translateAllAtOnce){r.start(`Translating ${Object.keys(d).length} keys to ${o} all at once...`);try{let g=Object.entries(d),k=te(g),T=await p.translate(k,o);try{let m=Object.keys(d),w=re(T,m);Object.entries(w).forEach(([A,M])=>{u[A]=M,n.newKeys++;}),r.succeed();}catch(m){r.fail(),console.error("Error parsing translation:",m),n.errors++,n.errorDetails=m instanceof Error?m:new Error(String(m)),Object.keys(u).length>0&&(await b(e,u,a),r.succeed(`Saved ${Object.keys(u).length} successfully translated keys to ${e}`));}}catch(g){r.fail(),console.error("Error translating:",g),n.errors++,n.errorDetails=g instanceof Error?g:new Error(String(g)),Object.keys(u).length>0&&(await b(e,u,a),r.succeed(`Saved ${Object.keys(u).length} successfully translated keys to ${e}`));}}else {let g=Ie(d,t.chunkSize||1e4);if(n.totalChunks=g.length,r.start(`Translating ${Object.keys(d).length} keys to ${o}...`),r.succeed(`Split into ${g.length} chunks`),t.provider==="anthropic"){r.start("Using batch processing for Anthropic");let k=false,T=h.getMaxConcurrent();for(let m=0;m<g.length&&!k;m+=T){let w=Math.min(m+T,g.length),A=g.slice(m,w);r.start(`Processing batch ${m+1}-${w} of ${g.length}...`);let M=await h.processBatch(A,async x=>{let C=x.map($=>[$.key,$.value]),v=te(C),L=await p.translate(v,o),Q=x.map($=>$.key);return {translatedText:L,keys:Q}});for(let x=0;x<M.length;x++){let C=M[x],v=m+x;if(n.processedChunks++,C.success&&C.result){let{translatedText:L,keys:Q}=C.result;try{let $=re(L,Q);Object.entries($).forEach(([me,ye])=>{u[me]=ye,n.newKeys++;}),r.succeed(`Chunk ${v+1}/${g.length} completed`);}catch($){r.fail(`Error parsing translation for chunk ${v+1}`),console.error("Error details:",$),n.errors++,n.failedChunkIndex=v+1,n.errorDetails=$ instanceof Error?$:new Error(String($)),k=true;break}}else {r.fail(`Failed to translate chunk ${v+1}`),console.error("Error details:",C.error),n.errors++,n.failedChunkIndex=v+1,n.errorDetails=C.error||null,k=true;break}}if(k){r.start(`Translation stopped at chunk ${n.failedChunkIndex} due to an error`),r.stop();break}m+w<g.length&&(r.start("Waiting before next batch..."),await new Promise(x=>setTimeout(x,1e3)));}Object.keys(u).length>0&&(await b(e,u,a),r.succeed(`Saved ${Object.keys(u).length} successfully translated keys to ${e}`)),n.totalKeys>0&&n.processedChunks===n.totalChunks&&(r.start("All translations complete"),r.stop());}else {let k=false;for(let T=0;T<g.length&&!k;T++){let m=g[T];r.start(`Translating chunk ${T+1}/${g.length}...`),n.processedChunks++;try{let w=m.map(v=>[v.key,v.value]),A=te(w),M=await p.translate(A,o),x=m.map(v=>v.key),C=re(M,x);Object.entries(C).forEach(([v,L])=>{u[v]=L,n.newKeys++;}),r.succeed(`Chunk ${T+1}/${g.length} completed`),await b(e,u,a),r.succeed(`Progress saved (${Object.keys(u).length} keys so far)`);}catch(w){r.fail(`Error in chunk ${T+1}/${g.length}`),console.error("Error translating chunk:",w),n.errors++,n.failedChunkIndex=T+1,n.errorDetails=w instanceof Error?w:new Error(String(w)),k=true,Object.keys(u).length>0&&(await b(e,u,a),r.succeed(`Saved ${Object.keys(u).length} successfully translated keys to ${e}`));break}}!k&&Object.keys(u).length>0&&(await b(e,u,a),r.succeed(`Translations saved to ${e}`));}}return n.errors===0?Object.keys(u).length>0&&(await b(e,u,a),r.succeed(`Translation saved to ${e}`)):(n.failedChunkIndex!==null&&console.error(` Translation process stopped at chunk ${n.failedChunkIndex}/${n.totalChunks}`),n.errorDetails&&console.error(`Error details: ${n.errorDetails.message}`),console.info(` Partial translations were saved. Successfully translated ${n.processedChunks-1} of ${n.totalChunks} chunks.`)),n}async function b(s,e,o){let t={...o,...e},r={};for(let[i,c]of Object.entries(t))if(i.includes("_part")){let[a,d]=i.split("_part");r[a]||(r[a]=""),r[a]+=c;}else r[i]=c;let n=O__namespace.default.dirname(s);I__namespace.default.existsSync(n)||I__namespace.default.mkdirSync(n,{recursive:true});let l=fe(r);I__namespace.default.writeFileSync(s,JSON.stringify(l,null,2));}async function Et(s={}){let e=ue(s.configPath);ge(e),s.overwrite!==void 0&&(e.overwrite=s.overwrite);let o=e.customProvider&&e.customProvider.url,t=o?"Custom provider":e.provider.toUpperCase(),r=o?e.customProvider.url.split("/").pop()||"custom endpoint":e.model||"default model",n={totalKeys:0,newKeys:0,skippedKeys:0,errors:0,totalChunks:0,processedChunks:0,failedChunkIndex:null,errorDetails:null},l=e.stopOnError!==false,i=false;for(let c of e.targets){console.log(` Processing target language: ${c.code}`);try{let a=await Ae(e.source.path,c.path,c.code,e);if(n.totalKeys+=a.totalKeys,n.newKeys+=a.newKeys,n.skippedKeys+=a.skippedKeys,n.errors+=a.errors,n.totalChunks+=a.totalChunks,n.processedChunks+=a.processedChunks,a.errors>0&&(i=!0,l)){console.log(` Stopping translation process due to errors in ${c.code}`);break}}catch(a){if(console.error(` Unexpected error processing ${c.code}:`,a),n.errors++,i=true,l)break}}if(console.log(` Translation Summary:`),console.log(`Provider: ${t}`),console.log(`Model: ${r}`),console.log(`Total keys: ${n.totalKeys}`),console.log(`New translations: ${n.newKeys}`),console.log(`Skipped existing: ${n.skippedKeys}`),console.log(`Chunks processed: ${n.processedChunks}/${n.totalChunks}`),console.log(`Errors: ${n.errors}`),i&&(console.log(` Note: Some translations were not completed due to errors.`),console.log("The successfully translated chunks were saved to preserve progress.")),o&&n.errors>0)try{let{CustomProvider:c}=(X(),Pe(ce));if(c.logFilePaths&&c.logFilePaths.length>0){console.log(` Error Logs:`);let a=new Set,d=new Set;c.logFilePaths.forEach(p=>{p.errorLogPath&&a.add(p.errorLogPath),p.responseLogPath&&d.add(p.responseLogPath);}),a.size>0&&(console.log(` Error details:`),a.forEach(p=>console.log(`- ${p}`))),d.size>0&&(console.log(` Response data:`),d.forEach(p=>console.log(`- ${p}`)));}}catch(c){console.debug("Failed to display log file paths:",c);}}async function Nt(s,e={}){let{outputPath:o=s.export?.outputPath||"./translations-export.csv",delimiter:t=s.export?.delimiter||","}=e,r=JSON.parse(I__namespace.default.readFileSync(s.source.path,"utf-8")),n=E(r),l=Object.keys(n),i={[s.source.code]:n};for(let f of s.targets)try{if(I__namespace.default.existsSync(f.path)){let y=JSON.parse(I__namespace.default.readFileSync(f.path,"utf-8"));i[f.code]=E(y);}else console.warn(`Warning: Target file not found: ${f.path}`),i[f.code]={};}catch(y){console.error(`Error reading target file ${f.path}:`,y),i[f.code]={};}let c=[s.source.code,...s.targets.map(f=>f.code)],d=[["Key",...c].join(t)];for(let f of l){let y=[f.includes(t)?`"${f}"`:f,...c.map(u=>{let h=i[u]?.[f]||"";return h.includes(t)||h.includes(` `)?`"${h.replace(/"/g,'""')}"`:h})];d.push(y.join(t));}let p=O__namespace.default.dirname(o);I__namespace.default.existsSync(p)||I__namespace.default.mkdirSync(p,{recursive:true}),I__namespace.default.writeFileSync(o,d.join(` `),"utf-8"),console.log(`Translations exported to: ${o}`),console.log(`Total keys: ${l.length}`),console.log(`Languages: ${c.join(", ")}`);}exports.a=K;exports.b=J;exports.c=B;exports.d=F;exports.e=_;exports.f=G;exports.g=U;exports.h=q;exports.i=W;exports.j=Y;exports.k=Ye;exports.l=Ce;exports.m=P;exports.n=z;exports.p=ot;exports.q=de;exports.r=ue;exports.s=ge;exports.t=fe;exports.u=Et;exports.v=Nt;