vite-plugin-ai-auto-i18n 0.5.7 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +3 -3
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{A as e,C as t,D as n,E as r,F as i,I as a,L as o,M as s,N as c,O as l,P as u,R as d,S as f,T as p,_ as m,b as h,c as g,g as _,i as v,j as y,k as b,l as x,m as S,n as C,o as w,r as T,t as E,u as D,w as O,x as k,y as A}from"./registry-4CzY0FGn.js";import{n as ee,t as te}from"./resolve-ELDMKdoA.js";import*as j from"valibot";import{glob as ne}from"tinyglobby";import{readFile as re,rm as ie,stat as ae}from"node:fs/promises";import M from"node:path";import{createHash as oe}from"node:crypto";import{parseSync as se}from"oxc-parser";import ce from"magic-string";async function le(e,t,n){let r=Array(e.length),i=0;return await Promise.all(Array.from({length:Math.min(Math.max(1,t),e.length)},async()=>{for(;i<e.length;){let t=i++;try{r[t]={status:`fulfilled`,value:await n(e[t])}}catch(e){r[t]={status:`rejected`,reason:e}}}})),r}var ue=class{available;waiters=[];constructor(e){this.available=Math.max(1,Math.floor(e))}async run(e){await this.acquire();try{return await e()}finally{this.release()}}acquire(){return this.available>0?(this.available--,Promise.resolve()):new Promise(e=>this.waiters.push(e))}release(){let e=this.waiters.shift();e?e():this.available++}};function de(e){return[...e.matchAll(A)].map(e=>e[1])}function fe(e,t){let n=new Set(e),r=new Set(t);return n.size===r.size&&[...n].every(e=>r.has(e))}function N(e,t){let n=de(e);return e.trim()!==``&&n.length===t.length&&fe(n,t)}var P=class extends Error{partial;failed;constructor(e,t,n){super(e),this.partial=t,this.failed=n,this.name=`PartialTranslationError`}};async function pe(e){let{provider:t,sourceLocale:n,locale:r,requests:i,previous:a,debug:o}=e,s=new Set(i.map(e=>e.id)),c=b(a.messages,s).catalog,l=b(a.sources,s).catalog,u=i.filter(e=>c[e.id]===void 0||l[e.id]!==e.source),f={},p=0,m;if(u.length&&t){if(o)for(let e of u)d(`sent ${n} -> ${r} ${e.id}: ${JSON.stringify(e.source)} (context: ${e.context})`);try{f=await t.translate({sourceLocale:n,targetLocale:r,messages:u})}catch(e){if(!(e instanceof P))throw e;f=e.partial,p=e.failed,m=e.message}if(o)for(let e of u){let t=f[e.id];d(`received ${n} -> ${r} ${e.id}: ${typeof t==`string`?JSON.stringify(t):`(no translation)`}`)}}let h={...c},g={...l},_=0;for(let e of u){delete h[e.id],delete g[e.id];let t=f[e.id];typeof t==`string`&&t.trim()&&(e.kind===`mixed`&&!N(t,e.placeholders??[])?_++:(h[e.id]=t,g[e.id]=e.source))}let v=i.filter(e=>h[e.id]===void 0).length;return{file:{messages:h,sources:g},untranslated:v,rejected:_,requested:u.length,failed:p,failure:m}}async function me(e){let t=structuredClone(e.registry),{ambiguous:r,messages:i}=T(t,e.files.flatMap(e=>e.messages)),a=C(t,e.orphanRetentionMinutes),o={};for(let e of i)o[e.id]=e.source;let s=i.map(e=>({id:e.id,source:e.source,context:`${e.component} > ${e.context}`,kind:e.kind,placeholders:e.placeholders})),c=await le(e.locales,e.localeConcurrency,t=>pe({provider:e.provider,sourceLocale:e.sourceLocale,locale:t,requests:s,previous:e.previous.get(t)??n(),debug:e.debug})),l=/* @__PURE__ */ new Map,u=/* @__PURE__ */ new Map;return c.forEach((t,n)=>{let r=e.locales[n];t.status===`fulfilled`?l.set(r,t.value):u.set(r,t.reason)}),{registry:t,ambiguous:r,pruned:a,messages:i,sourceFile:{messages:o,sources:{}},locales:l,failures:u}}function F(e){return e.replace(/\s+/g,` `).trim()}function I(e){let t=[F(e.source),e.kind,e.tag.toLowerCase(),e.attribute??``,e.context].join(``);return oe(`sha256`).update(t).digest(`hex`).slice(0,24)}function L(e,t){let n=se(t,e,{lang:`tsx`,sourceType:`unambiguous`});if(n.errors.length)throw SyntaxError(`${t}: ${n.errors[0].message}`);return{program:n.program,commentsByEnd:new Map(n.comments.map(e=>[e.end,e]))}}function R(e,t){let n=[],r=e=>{if(t(e,n)!==!1){n.push(e);for(let t of Object.keys(e)){if(t===`parent`)continue;let n=e[t];Array.isArray(n)?n.forEach(e=>z(e)&&r(e)):z(n)&&r(n)}n.pop()}};r(e)}function z(e){return typeof e==`object`&&!!e&&typeof e.type==`string`}function B(e){return z(e)&&e.type===`Literal`&&typeof e.value==`string`}function he(e,t,n,r){let i=n;for(;;){let n=i;for(;n>0&&/\s/.test(e[n-1]);)n--;let a=t.get(n);if(!a)return!1;if(a.type===`Block`&&a.value.trim()===r)return!0;i=a.start}}function V(e){return e.includes(`&`)?e.replace(k,(e,t,n)=>{if(n!==void 0)return m.get(n)??e;let r=t.startsWith(`x`)?parseInt(t.slice(1),16):parseInt(t,10);return r<=1114111?String.fromCodePoint(r):e}):e}function H(e){return B(e)?V(e.value):void 0}function U(e){return V(e.value)}function ge(e){return e.attributes.some(e=>e.type===`JSXAttribute`&&e.name.type===`JSXIdentifier`&&e.name.name===`translate`&&H(e.value)===`no`)}function _e(e){return e.type===`JSXIdentifier`&&!g.test(e.name)&&!S.has(e.name)}function W(e){if(e.type===`Identifier`)return e.name;if(e.type===`MemberExpression`&&!e.computed&&e.property.type===`Identifier`){let t=W(e.object);return t?`${t}.${e.property.name}`:void 0}}const ve=(e,t)=>e.type===`FunctionExpression`?!(t?.type===`MethodDefinition`||t?.type===`Property`&&(t.method||t.kind!==`init`)):e.type===`FunctionDeclaration`||e.type===`ArrowFunctionExpression`;function ye(e,t){for(let n=e.length-1;n>=0;n--)if(t(e[n]))return n;return-1}function G(e){return e.some(e=>{let t=e.type===`JSXOpeningElement`?e:e.type===`JSXElement`?e.openingElement:void 0;return t!==void 0&&ge(t)})}function K(e,t,n){let r=e.attributes.filter(e=>e.type===`JSXAttribute`&&e.name.type===`JSXIdentifier`&&[`aria-label`,`title`,`name`,`type`,`role`].includes(e.name.name)).map(e=>`${e.name.name}=${H(e.value)??`{expr}`}`).sort().join(`;`),i=e.attributes.filter(e=>e.type===`JSXAttribute`&&e.name.type===`JSXIdentifier`&&/^on[A-Z]/.test(e.name.name)).map(e=>e.name.name).sort().join(`,`);return[t,n??``,r,i].filter(Boolean).join(` | `)}function be(e,t,n={}){let{program:r,commentsByEnd:i}=L(e,t),a=[],o=e=>Object.prototype.hasOwnProperty.call(n.componentProps??{},e)?n.componentProps[e]:[],s=e=>{if(e.type!==`JSXIdentifier`)return!1;let t=e.name;return _e(e)||g.test(t)&&o(t).includes(`children`)};function c(e){let t=e.length-1;for(;t>=0&&!ve(e[t],e[t-1]);)t--;if(t<0)return`<module>`;let n=e[t],r=e[t-1];return r?.type===`VariableDeclarator`&&r.id.type===`Identifier`?r.id.name:n.type===`FunctionDeclaration`&&n.id?n.id.name:`<anonymous>`}function l(e,n){if(G([...n,e]))return;let r=e.children,i=r.filter(e=>e.type===`JSXExpressionContainer`);if(!i.length||r.some(e=>e.type!==`JSXText`&&e.type!==`JSXExpressionContainer`)||!i.every(e=>W(e.expression)!==void 0)||!r.some(e=>e.type===`JSXText`&&/[A-Za-z]/.test(U(e))))return;let o=e.openingElement.name;if(!s(o))return;let l=[];for(let e of i){let t=W(e.expression),n=t;for(let e=2;l.includes(n);e++)n=`${t}_${e}`;l.push(n)}let u=``,d=0;for(let e of r)u+=e.type===`JSXText`?U(e):`{${l[d++]}}`;let f=F(u);if(!f)return;let p=o.name,m={source:f,prefix:u.match(/^\s*/)?.[0]??``,suffix:u.match(/\s*$/)?.[0]??``,kind:`mixed`,placeholders:l,file:t,start:e.start,end:e.end,tag:p,component:c(n),context:K(e.openingElement,p),fingerprint:``};m.fingerprint=I(m),a.push(m)}function u(e,n){if(G([...n,e]))return;let r=U(e),i=F(r);if(!i)return;let o=ye(n,e=>e.type===`JSXElement`);if(o<0)return;let l=n[o];if(l.children.some(e=>e.type===`JSXExpressionContainer`))return;let u=l.openingElement.name;if(!s(u))return;let d=u.name,f={source:i,prefix:r.match(/^\s*/)?.[0]??``,suffix:r.match(/\s*$/)?.[0]??``,kind:`text`,file:t,start:e.start,end:e.end,tag:d,component:c(n.slice(0,o)),context:K(l.openingElement,d),fingerprint:``};f.fingerprint=I(f),a.push(f)}function d(e,n){if(e.name.type!==`JSXIdentifier`)return;let r=e.name.name,i=n[n.length-1];if(i?.type!==`JSXOpeningElement`)return;let s=i.name.type===`JSXIdentifier`?i.name.name:``;if(!(_e(i.name)?p.has(r):o(s).includes(r))||G([...n,e])||!B(e.value))return;let l=F(V(e.value.value));if(!l||!/[A-Za-z]/.test(l))return;let u=ye(n,e=>e.type===`JSXElement`);if(u<0)return;let d=n[u],f={source:l,kind:`attribute`,file:t,start:e.value.start,end:e.value.end,tag:s,component:c(n.slice(0,u)),attribute:r,context:K(d.openingElement,s,r),fingerprint:``};f.fingerprint=I(f),a.push(f)}function f(r,o){if(!B(r)||o[o.length-1]?.type===`JSXAttribute`||o.some(e=>e.start===r.start)||!he(e,i,r.start,n.stringMarker??`i18n`))return;let s=F(r.value);if(!s||!/[A-Za-z]/.test(s))return;let l={source:s,kind:`string`,file:t,start:r.start,end:r.end,tag:``,component:c(o),context:``,fingerprint:``};l.fingerprint=I(l),a.push(l)}return R(r,(e,t)=>{switch(e.type){case`JSXElement`:return l(e,t);case`JSXText`:return u(e,t);case`JSXAttribute`:return d(e,t);case`Literal`:return f(e,t)}}),a.sort((e,t)=>e.start-t.start)}function xe(e,n,r,i,a,o=!1,s=`en`){let{program:c}=L(e,n),l={mixed:/* @__PURE__ */ new Map,text:/* @__PURE__ */ new Map,attribute:/* @__PURE__ */ new Map,string:/* @__PURE__ */ new Map};for(let e of r)l[e.kind]?.set(e.start,e);let u=r.map(e=>e.start).sort((e,t)=>e-t),d=(e,t)=>{let n=0,r=u.length;for(;n<r;){let t=n+r>>1;u[t]<e?n=t+1:r=t}return n<u.length&&u[n]<t},p=[];R(c,e=>{if(!d(e.start,e.end))return!1;if(e.type===`JSXElement`){let t=l.mixed.get(e.start);t&&p.push({kind:`mixed`,node:e,message:t})}else if(e.type===`JSXText`){let t=l.text.get(e.start);t&&p.push({kind:`text`,node:e,message:t})}else if(e.type===`JSXAttribute`&&e.value?.type===`Literal`){let t=l.attribute.get(e.value.start);t&&p.push({kind:`attribute`,node:e.value,message:t})}else if(e.type===`Literal`&&typeof e.value==`string`){let t=l.string.get(e.start);t&&p.push({kind:`string`,node:e,message:t})}});let m=new ce(e),h=!1,g=!1,_=e=>i===s?e.source:a[e.id]??e.source,v=e=>o?(h=!0,`${t}(${JSON.stringify(e.id)}, ${JSON.stringify(e.source)})`):JSON.stringify(_(e)),y=e=>{let t=e.prefix??``,n=e.suffix??``;return o?[t&&JSON.stringify(t),v(e),n&&JSON.stringify(n)].filter(Boolean).join(` + `):JSON.stringify(`${t}${_(e)}${n}`)};for(let e of p.reverse()){let{message:t}=e;if(e.kind===`mixed`){let n=e.node;if(!n.closingElement)continue;let r=t.placeholders??[],i=n.children.flatMap(e=>e.type===`JSXExpressionContainer`?[e.expression]:[]),a=e=>m.slice(i[e].start,i[e].end),s=n.openingElement.end,c=n.closingElement.start;if(o){g=!0;let e=r.map((e,t)=>`${JSON.stringify(e)}: ${a(t)}`).join(`, `);m.overwrite(s,c,`{${f}(${y(t)}, {${e}})}`);continue}let l=_(t),u=N(l,r)?l:t.source,d=[],p=0,h=e=>{e&&d.push(`{${JSON.stringify(e)}}`)};h(t.prefix??``);for(let e of u.matchAll(A))h(u.slice(p,e.index)),d.push(`{${a(r.indexOf(e[1]))}}`),p=e.index+e[0].length;h(u.slice(p)+(t.suffix??``)),m.overwrite(s,c,d.join(``))}else e.kind===`text`?m.overwrite(e.node.start,e.node.end,`{${y(t)}}`):e.kind===`attribute`?m.overwrite(e.node.start,e.node.end,o?`{${v(t)}}`:v(t)):m.overwrite(e.node.start,e.node.end,v(t))}let b=[...h?[`t as ${t}`]:[],...g?[`format as ${f}`]:[]];return b.length&&m.prepend(`import { ${b.join(`, `)} } from "${O}";\n`),{code:m.toString(),map:m.generateMap({source:n,hires:!0,includeContent:!0})}}function Se(e,t,n){let r=[],i=0;for(let a of e.matchAll(n)){if(!Object.hasOwn(t,a[1]))continue;let n=a.index??0;n>i&&r.push(e.slice(i,n)),r.push(t[a[1]]),i=n+a[0].length}return i<e.length&&r.push(e.slice(i)),r}function Ce(e,t){return[`const loaders = {\n${Object.entries(e).map(([e,t])=>` ${JSON.stringify(e)}: () => import(${JSON.stringify(t)}).then(m => (m.default ?? m).messages)`).join(`,
|
|
2
|
-
`)}\n};`,`const sourceLocale = ${JSON.stringify(t)};`,`const resolveLocale = ${
|
|
1
|
+
import{A as e,C as t,D as n,E as r,F as i,I as a,L as o,M as s,N as c,O as l,P as u,R as d,S as f,T as p,_ as m,b as h,c as g,g as _,i as v,j as y,k as b,l as x,m as ee,n as S,o as C,r as w,t as T,u as E,w as D,x as O,y as k}from"./registry-4CzY0FGn.js";import{n as te,t as ne}from"./resolve-ELDMKdoA.js";import*as A from"valibot";import{glob as re,readFile as ie,rm as ae,stat as oe}from"node:fs/promises";import j from"node:path";import{createHash as se}from"node:crypto";import{parseSync as ce}from"rolldown/utils";import le from"magic-string";async function ue(e,t,n){let r=Array(e.length),i=0;return await Promise.all(Array.from({length:Math.min(Math.max(1,t),e.length)},async()=>{for(;i<e.length;){let t=i++;try{r[t]={status:`fulfilled`,value:await n(e[t])}}catch(e){r[t]={status:`rejected`,reason:e}}}})),r}var de=class{available;waiters=[];constructor(e){this.available=Math.max(1,Math.floor(e))}async run(e){await this.acquire();try{return await e()}finally{this.release()}}acquire(){return this.available>0?(this.available--,Promise.resolve()):new Promise(e=>this.waiters.push(e))}release(){let e=this.waiters.shift();e?e():this.available++}};function fe(e){return[...e.matchAll(k)].map(e=>e[1])}function pe(e,t){let n=new Set(e),r=new Set(t);return n.size===r.size&&[...n].every(e=>r.has(e))}function M(e,t){let n=fe(e);return e.trim()!==``&&n.length===t.length&&pe(n,t)}var N=class extends Error{partial;failed;constructor(e,t,n){super(e),this.partial=t,this.failed=n,this.name=`PartialTranslationError`}};async function me(e){let{provider:t,sourceLocale:n,locale:r,requests:i,previous:a,debug:o}=e,s=new Set(i.map(e=>e.id)),c=b(a.messages,s).catalog,l=b(a.sources,s).catalog,u=i.filter(e=>c[e.id]===void 0||l[e.id]!==e.source),f={},p=0,m;if(u.length&&t){if(o)for(let e of u)d(`sent ${n} -> ${r} ${e.id}: ${JSON.stringify(e.source)} (context: ${e.context})`);try{f=await t.translate({sourceLocale:n,targetLocale:r,messages:u})}catch(e){if(!(e instanceof N))throw e;f=e.partial,p=e.failed,m=e.message}if(o)for(let e of u){let t=f[e.id];d(`received ${n} -> ${r} ${e.id}: ${typeof t==`string`?JSON.stringify(t):`(no translation)`}`)}}let h={...c},g={...l},_=0;for(let e of u){delete h[e.id],delete g[e.id];let t=f[e.id];typeof t==`string`&&t.trim()&&(e.kind===`mixed`&&!M(t,e.placeholders??[])?_++:(h[e.id]=t,g[e.id]=e.source))}let v=i.filter(e=>h[e.id]===void 0).length;return{file:{messages:h,sources:g},untranslated:v,rejected:_,requested:u.length,failed:p,failure:m}}async function he(e){let t=structuredClone(e.registry),{ambiguous:r,messages:i}=w(t,e.files.flatMap(e=>e.messages)),a=S(t,e.orphanRetentionMinutes),o={};for(let e of i)o[e.id]=e.source;let s=i.map(e=>({id:e.id,source:e.source,context:`${e.component} > ${e.context}`,kind:e.kind,placeholders:e.placeholders})),c=await ue(e.locales,e.localeConcurrency,t=>me({provider:e.provider,sourceLocale:e.sourceLocale,locale:t,requests:s,previous:e.previous.get(t)??n(),debug:e.debug})),l=/* @__PURE__ */ new Map,u=/* @__PURE__ */ new Map;return c.forEach((t,n)=>{let r=e.locales[n];t.status===`fulfilled`?l.set(r,t.value):u.set(r,t.reason)}),{registry:t,ambiguous:r,pruned:a,messages:i,sourceFile:{messages:o,sources:{}},locales:l,failures:u}}function P(e){return e.replace(/\s+/g,` `).trim()}function F(e){let t=[P(e.source),e.kind,e.tag.toLowerCase(),e.attribute??``,e.context].join(``);return se(`sha256`).update(t).digest(`hex`).slice(0,24)}function I(e,t){let n=ce(t,e,{lang:`tsx`,sourceType:`unambiguous`});if(n.errors.length)throw SyntaxError(`${t}: ${n.errors[0].message}`);return{program:n.program,commentsByEnd:new Map(n.comments.map(e=>[e.end,e]))}}function L(e,t){let n=[],r=e=>{if(t(e,n)!==!1){n.push(e);for(let t of Object.keys(e)){if(t===`parent`)continue;let n=e[t];Array.isArray(n)?n.forEach(e=>R(e)&&r(e)):R(n)&&r(n)}n.pop()}};r(e)}function R(e){return typeof e==`object`&&!!e&&typeof e.type==`string`}function z(e){return R(e)&&e.type===`Literal`&&typeof e.value==`string`}function ge(e,t,n,r){let i=n;for(;;){let n=i;for(;n>0&&/\s/.test(e[n-1]);)n--;let a=t.get(n);if(!a)return!1;if(a.type===`Block`&&a.value.trim()===r)return!0;i=a.start}}function B(e){return e.includes(`&`)?e.replace(O,(e,t,n)=>{if(n!==void 0)return m.get(n)??e;let r=t.startsWith(`x`)?parseInt(t.slice(1),16):parseInt(t,10);return r<=1114111?String.fromCodePoint(r):e}):e}function V(e){return z(e)?B(e.value):void 0}function H(e){return B(e.value)}function _e(e){return e.attributes.some(e=>e.type===`JSXAttribute`&&e.name.type===`JSXIdentifier`&&e.name.name===`translate`&&V(e.value)===`no`)}function U(e){return e.type===`JSXIdentifier`&&!g.test(e.name)&&!ee.has(e.name)}function W(e){if(e.type===`Identifier`)return e.name;if(e.type===`MemberExpression`&&!e.computed&&e.property.type===`Identifier`){let t=W(e.object);return t?`${t}.${e.property.name}`:void 0}}const ve=(e,t)=>e.type===`FunctionExpression`?!(t?.type===`MethodDefinition`||t?.type===`Property`&&(t.method||t.kind!==`init`)):e.type===`FunctionDeclaration`||e.type===`ArrowFunctionExpression`;function ye(e,t){for(let n=e.length-1;n>=0;n--)if(t(e[n]))return n;return-1}function G(e){return e.some(e=>{let t=e.type===`JSXOpeningElement`?e:e.type===`JSXElement`?e.openingElement:void 0;return t!==void 0&&_e(t)})}function K(e,t,n){let r=e.attributes.filter(e=>e.type===`JSXAttribute`&&e.name.type===`JSXIdentifier`&&[`aria-label`,`title`,`name`,`type`,`role`].includes(e.name.name)).map(e=>`${e.name.name}=${V(e.value)??`{expr}`}`).sort().join(`;`),i=e.attributes.filter(e=>e.type===`JSXAttribute`&&e.name.type===`JSXIdentifier`&&/^on[A-Z]/.test(e.name.name)).map(e=>e.name.name).sort().join(`,`);return[t,n??``,r,i].filter(Boolean).join(` | `)}function be(e,t,n={}){let{program:r,commentsByEnd:i}=I(e,t),a=[],o=e=>Object.prototype.hasOwnProperty.call(n.componentProps??{},e)?n.componentProps[e]:[],s=e=>{if(e.type!==`JSXIdentifier`)return!1;let t=e.name;return U(e)||g.test(t)&&o(t).includes(`children`)};function c(e){let t=e.length-1;for(;t>=0&&!ve(e[t],e[t-1]);)t--;if(t<0)return`<module>`;let n=e[t],r=e[t-1];return r?.type===`VariableDeclarator`&&r.id.type===`Identifier`?r.id.name:n.type===`FunctionDeclaration`&&n.id?n.id.name:`<anonymous>`}function l(e,n){if(G([...n,e]))return;let r=e.children,i=r.filter(e=>e.type===`JSXExpressionContainer`);if(!i.length||r.some(e=>e.type!==`JSXText`&&e.type!==`JSXExpressionContainer`)||!i.every(e=>W(e.expression)!==void 0)||!r.some(e=>e.type===`JSXText`&&/[A-Za-z]/.test(H(e))))return;let o=e.openingElement.name;if(!s(o))return;let l=[];for(let e of i){let t=W(e.expression),n=t;for(let e=2;l.includes(n);e++)n=`${t}_${e}`;l.push(n)}let u=``,d=0;for(let e of r)u+=e.type===`JSXText`?H(e):`{${l[d++]}}`;let f=P(u);if(!f)return;let p=o.name,m={source:f,prefix:u.match(/^\s*/)?.[0]??``,suffix:u.match(/\s*$/)?.[0]??``,kind:`mixed`,placeholders:l,file:t,start:e.start,end:e.end,tag:p,component:c(n),context:K(e.openingElement,p),fingerprint:``};m.fingerprint=F(m),a.push(m)}function u(e,n){if(G([...n,e]))return;let r=H(e),i=P(r);if(!i)return;let o=ye(n,e=>e.type===`JSXElement`);if(o<0)return;let l=n[o];if(l.children.some(e=>e.type===`JSXExpressionContainer`))return;let u=l.openingElement.name;if(!s(u))return;let d=u.name,f={source:i,prefix:r.match(/^\s*/)?.[0]??``,suffix:r.match(/\s*$/)?.[0]??``,kind:`text`,file:t,start:e.start,end:e.end,tag:d,component:c(n.slice(0,o)),context:K(l.openingElement,d),fingerprint:``};f.fingerprint=F(f),a.push(f)}function d(e,n){if(e.name.type!==`JSXIdentifier`)return;let r=e.name.name,i=n[n.length-1];if(i?.type!==`JSXOpeningElement`)return;let s=i.name.type===`JSXIdentifier`?i.name.name:``;if(!(U(i.name)?p.has(r):o(s).includes(r))||G([...n,e])||!z(e.value))return;let l=P(B(e.value.value));if(!l||!/[A-Za-z]/.test(l))return;let u=ye(n,e=>e.type===`JSXElement`);if(u<0)return;let d=n[u],f={source:l,kind:`attribute`,file:t,start:e.value.start,end:e.value.end,tag:s,component:c(n.slice(0,u)),attribute:r,context:K(d.openingElement,s,r),fingerprint:``};f.fingerprint=F(f),a.push(f)}function f(r,o){if(!z(r)||o[o.length-1]?.type===`JSXAttribute`||o.some(e=>e.start===r.start)||!ge(e,i,r.start,n.stringMarker??`i18n`))return;let s=P(r.value);if(!s||!/[A-Za-z]/.test(s))return;let l={source:s,kind:`string`,file:t,start:r.start,end:r.end,tag:``,component:c(o),context:``,fingerprint:``};l.fingerprint=F(l),a.push(l)}return L(r,(e,t)=>{switch(e.type){case`JSXElement`:return l(e,t);case`JSXText`:return u(e,t);case`JSXAttribute`:return d(e,t);case`Literal`:return f(e,t)}}),a.sort((e,t)=>e.start-t.start)}function xe(e,n,r,i,a,o=!1,s=`en`){let{program:c}=I(e,n),l={mixed:/* @__PURE__ */ new Map,text:/* @__PURE__ */ new Map,attribute:/* @__PURE__ */ new Map,string:/* @__PURE__ */ new Map};for(let e of r)l[e.kind]?.set(e.start,e);let u=r.map(e=>e.start).sort((e,t)=>e-t),d=(e,t)=>{let n=0,r=u.length;for(;n<r;){let t=n+r>>1;u[t]<e?n=t+1:r=t}return n<u.length&&u[n]<t},p=[];L(c,e=>{if(!d(e.start,e.end))return!1;if(e.type===`JSXElement`){let t=l.mixed.get(e.start);t&&p.push({kind:`mixed`,node:e,message:t})}else if(e.type===`JSXText`){let t=l.text.get(e.start);t&&p.push({kind:`text`,node:e,message:t})}else if(e.type===`JSXAttribute`&&e.value?.type===`Literal`){let t=l.attribute.get(e.value.start);t&&p.push({kind:`attribute`,node:e.value,message:t})}else if(e.type===`Literal`&&typeof e.value==`string`){let t=l.string.get(e.start);t&&p.push({kind:`string`,node:e,message:t})}});let m=new le(e),h=!1,g=!1,_=e=>i===s?e.source:a[e.id]??e.source,v=e=>o?(h=!0,`${t}(${JSON.stringify(e.id)}, ${JSON.stringify(e.source)})`):JSON.stringify(_(e)),y=e=>{let t=e.prefix??``,n=e.suffix??``;return o?[t&&JSON.stringify(t),v(e),n&&JSON.stringify(n)].filter(Boolean).join(` + `):JSON.stringify(`${t}${_(e)}${n}`)};for(let e of p.reverse()){let{message:t}=e;if(e.kind===`mixed`){let n=e.node;if(!n.closingElement)continue;let r=t.placeholders??[],i=n.children.flatMap(e=>e.type===`JSXExpressionContainer`?[e.expression]:[]),a=e=>m.slice(i[e].start,i[e].end),s=n.openingElement.end,c=n.closingElement.start;if(o){g=!0;let e=r.map((e,t)=>`${JSON.stringify(e)}: ${a(t)}`).join(`, `);m.overwrite(s,c,`{${f}(${y(t)}, {${e}})}`);continue}let l=_(t),u=M(l,r)?l:t.source,d=[],p=0,h=e=>{e&&d.push(`{${JSON.stringify(e)}}`)};h(t.prefix??``);for(let e of u.matchAll(k))h(u.slice(p,e.index)),d.push(`{${a(r.indexOf(e[1]))}}`),p=e.index+e[0].length;h(u.slice(p)+(t.suffix??``)),m.overwrite(s,c,d.join(``))}else e.kind===`text`?m.overwrite(e.node.start,e.node.end,`{${y(t)}}`):e.kind===`attribute`?m.overwrite(e.node.start,e.node.end,o?`{${v(t)}}`:v(t)):m.overwrite(e.node.start,e.node.end,v(t))}let b=[...h?[`t as ${t}`]:[],...g?[`format as ${f}`]:[]];return b.length&&m.prepend(`import { ${b.join(`, `)} } from "${D}";\n`),{code:m.toString(),map:m.generateMap({source:n,hires:!0,includeContent:!0})}}function Se(e,t,n){let r=[],i=0;for(let a of e.matchAll(n)){if(!Object.hasOwn(t,a[1]))continue;let n=a.index??0;n>i&&r.push(e.slice(i,n)),r.push(t[a[1]]),i=n+a[0].length}return i<e.length&&r.push(e.slice(i)),r}function Ce(e,t){return[`const loaders = {\n${Object.entries(e).map(([e,t])=>` ${JSON.stringify(e)}: () => import(${JSON.stringify(t)}).then(m => (m.default ?? m).messages)`).join(`,
|
|
2
|
+
`)}\n};`,`const sourceLocale = ${JSON.stringify(t)};`,`const resolveLocale = ${ne.toString()};`,`const createLocaleLoader = ${te.toString()};`,`const formatPlaceholders = ${Se.toString()};`,`const PLACEHOLDER = new RegExp(${JSON.stringify(h)}, "g");`,`const loadLocale = createLocaleLoader(loaders, sourceLocale);`,`const listeners = new Set();`,`let currentLocale = sourceLocale;`,`let messages = {};`,`let version = 0;`,`let latestRequest = 0;`,`export const locales = Object.keys(loaders);`,`export function getLocale() { return currentLocale; }`,`export function getVersion() { return version; }`,`export function resolveSupported(preferred) { return resolveLocale(preferred, locales, sourceLocale); }`,`export async function setLocale(locale) {`,` const request = ++latestRequest;`,` let selected = loaders[locale] ? locale : sourceLocale;`,` let catalog;`,` try {`,` catalog = await loadLocale(selected);`,` } catch (error) {`,` console.warn('autoi18n: could not load "' + selected + '", falling back to "' + sourceLocale + '".', error);`,` selected = sourceLocale;`,` try {`,` catalog = await loadLocale(selected);`,` } catch (fallbackError) {`,` // Keep the current locale and messages so the UI stays consistent. Texts without a catalogue show their source.`,` console.error('autoi18n: could not load the source catalogue "' + sourceLocale + '".', fallbackError);`,` return;`,` }`,` }`,` // A slower earlier request must not overwrite the locale the user picked last.`,` if (request !== latestRequest) return;`,` messages = catalog;`,` currentLocale = selected;`,` notify();`,`}`,`function notify() {`,` version++;`,` listeners.forEach(fn => fn(currentLocale));`,`}`,`export function subscribe(fn) { listeners.add(fn); return () => { listeners.delete(fn); }; }`,`export function t(id, source) { return messages[id] ?? source; }`,`export function format(text, values) { return formatPlaceholders(text, values, PLACEHOLDER); }`,`// Dev server pushes the catalogues that changed after a source change; no page reload is needed.`,`if (import.meta.hot) {`,` import.meta.hot.on("autoi18n:update", data => {`,` for (const [locale, catalog] of Object.entries(data.catalogs)) loadLocale.prime(locale, catalog);`,` if (!data.catalogs[currentLocale]) return;`,` messages = data.catalogs[currentLocale];`,` notify();`,` });`,`}`].join(`
|
|
3
3
|
`)+`
|
|
4
|
-
`}async function q(e){try{let t=await ae(e);return`${t.mtimeMs}:${t.size}`}catch{return}}function we(e,t){if(!e)return!1;let n=Object.keys(t);return n.length===Object.keys(e).length&&n.every(n=>e[n]===t[n])}var Te=class{extractions=/* @__PURE__ */ new Map;fileMessages=/* @__PURE__ */ new Map;catalogs=/* @__PURE__ */ new Map;catalogFiles={};warnedFiles=/* @__PURE__ */ new Set;legacySidecarsRemoved=!1;localeFiles=/* @__PURE__ */ new Map;registryCache;hashOf(e){return this.extractions.get(e)?.hash}async readLocale(t,n){let r=await q(t),i=this.localeFiles.get(t);if(r!==void 0&&i?.stamp===r)return i.value;let a=await e(t,n);return r!==void 0&&this.localeFiles.set(t,{stamp:r,value:a}),a}async writeLocale(e,t){await y(e,t);let n=await q(e);n!==void 0&&this.localeFiles.set(e,{stamp:n,value:t})}async readRegistry(e,t){let n=await q(e);if(n!==void 0&&this.registryCache?.stamp===n)return this.registryCache.value;let r=await E(e,t);return n!==void 0&&(this.registryCache={stamp:n,value:r}),r}async writeRegistry(e,t){await v(e,t);let n=await q(e);n!==void 0&&(this.registryCache={stamp:n,value:t})}},Ee=class{providers;onFallback;constructor(e,t=()=>{}){this.providers=e,this.onFallback=t}async translate(e){let t={},n=e.messages,r,i;for(let[a,{name:o,provider:s}]of this.providers.entries()){try{Object.assign(t,await s.translate({...e,messages:n}))}catch(e){r??=e,i=e,e instanceof P&&Object.assign(t,e.partial);let s=this.providers[a+1];s&&n.some(e=>t[e.id]===void 0)&&this.onFallback(`${o} failed (${De(e)}); sending the rest to ${s.name}.`)}if(n=n.filter(e=>t[e.id]===void 0),!n.length)return t}throw Object.keys(t).length===0?r:new P(`${n.length} messages failed to translate: ${De(i)}`,t,n.length)}};const De=e=>e instanceof Error?e.message:String(e),Oe=e=>typeof e==`object`&&!!e&&typeof e.translate==`function`;function ke(e,t){if(e===void 0)return;if(Oe(e))return e;let{primary:n,...r}=e,i=[];for(let[e,t]of Object.entries(r))if(t!==void 0){if(!Oe(t))throw Error(`autoi18n: provider "${e}" must be an object with a translate(input) method.`);i.push({name:e,provider:t})}if(n!==void 0){let e=i.findIndex(e=>e.name===n);if(e<0)throw Error(`autoi18n: primary provider "${n}" is not configured.`);i.unshift(...i.splice(e,1))}if(i.length!==0)return i.length===1?i[0].provider:new Ee(i,t)}var J=class extends Error{retryable;retryAfterMs;constructor(e,t,n){super(e),this.retryable=t,this.retryAfterMs=n}};function Ae(e,t=Date.now()){if(!e)return;let n=Number(e);if(Number.isFinite(n))return Math.min(Math.max(n,0)*1e3,_);let r=Date.parse(e);if(!Number.isNaN(r))return Math.min(Math.max(r-t,0),_)}const je=e=>new Promise(t=>setTimeout(t,e));function Y(e){return`You are a professional software localization engine. Translate UI messages from ${e.sourceLocale} to ${e.targetLocale}. Preserve placeholders exactly. Respect context and UI conventions. Return ONLY a JSON object mapping message IDs to translated strings. Do not translate product names or code.`}function X(e){return JSON.stringify(e.map(e=>({id:e.id,text:e.source,context:e.context,kind:e.kind})))}async function Z(e){let t=e.status===408||e.status===409||e.status===429||e.status>=500;return await e.body?.cancel().catch(()=>void 0),new J(`Translation API failed (${e.status})`,t,Ae(e.headers.get(`retry-after`)))}var Q=class{options;slots;constructor(e){this.options=e,this.slots=new ue(e.concurrency??4)}async translate(e){let t=Math.max(1,this.options.batchSize??40),n=[];for(let r=0;r<e.messages.length;r+=t)n.push(e.messages.slice(r,r+t));let r=await Promise.allSettled(n.map(t=>this.slots.run(()=>this.translateBatch({...e,messages:t})))),i={},a=[],o=0,s=0;if(r.forEach((e,t)=>{e.status===`fulfilled`?(s++,Object.assign(i,e.value)):(a.push(e.reason),o+=n[t].length)}),!a.length)return i;throw s?new P(`${o} messages failed to translate: ${a[0].message}`,i,o):a[0]}async translateBatch(e){let t=this.options.maxRetries??2,n=this.options.retryDelayMs??500;for(let r=0;;r++)try{return await this.request(e)}catch(e){if(e instanceof J&&!e.retryable||r>=t)throw e;let i=e instanceof J?e.retryAfterMs:void 0;await je(i??n*2**r*(.5+Math.random()/2))}}toCatalog(e,t){if(!e)throw new J(`Translation provider returned no content`,!0);let n;try{n=JSON.parse(e)}catch{throw new J(`Translation provider returned invalid JSON`,!0)}let r=j.safeParse(a,n);if(!r.success)throw new J(`Translation provider returned a non-object`,!0);let i=new Set(t.map(e=>e.id)),o={};for(let[e,t]of Object.entries(r.output))i.has(e)&&typeof t==`string`&&t.trim()&&(o[e]=t);return o}},Me=class extends Q{async request(e){let t=await fetch(`${this.options.baseURL??`https://api.openai.com/v1`}/chat/completions`,{method:`POST`,signal:AbortSignal.timeout(this.options.timeoutMs??6e4),headers:{Authorization:`Bearer ${this.options.apiKey}`,"Content-Type":`application/json`},body:JSON.stringify({model:this.options.model,temperature:0,response_format:{type:`json_object`},messages:[{role:`system`,content:Y(e)},{role:`user`,content:X(e.messages)}]})});if(!t.ok)throw await Z(t);let n=j.safeParse(c,await t.json());return this.toCatalog(n.success?n.output.choices[0].message.content??void 0:void 0,e.messages)}},Ne=class extends Q{async request(e){let t=await fetch(`${this.options.baseURL??`https://api.anthropic.com/v1`}/messages`,{method:`POST`,signal:AbortSignal.timeout(this.options.timeoutMs??6e4),headers:{"x-api-key":this.options.apiKey,"anthropic-version":w,"content-type":`application/json`},body:JSON.stringify({model:this.options.model,max_tokens:this.options.maxTokens??8192,system:Y(e),messages:[{role:`user`,content:X(e.messages)}]})});if(!t.ok)throw await Z(t);let n=j.safeParse(s,await t.json()),r=n.success?n.output.content.filter(e=>e.type===`text`).map(e=>e.text??``).join(``):``;return this.toCatalog(r.trim().replace(/^```(?:json)?\s*|\s*```$/g,``)||void 0,e.messages)}},Pe=class extends Q{async request(e){let t=this.options.baseURL??`https://generativelanguage.googleapis.com/v1beta`,n=await fetch(`${t}/models/${encodeURIComponent(this.options.model)}:generateContent`,{method:`POST`,signal:AbortSignal.timeout(this.options.timeoutMs??6e4),headers:{"x-goog-api-key":this.options.apiKey,"content-type":`application/json`},body:JSON.stringify({systemInstruction:{parts:[{text:Y(e)}]},contents:[{role:`user`,parts:[{text:X(e.messages)}]}],generationConfig:{responseMimeType:`application/json`,maxOutputTokens:this.options.maxOutputTokens??8192}})});if(!n.ok)throw await Z(n);let r=j.safeParse(u,await n.json()),i=r.success?(r.output.candidates[0]?.content?.parts??[]).map(e=>e.text??``).join(``):``;return this.toCatalog(i.trim().replace(/^```(?:json)?\s*|\s*```$/g,``)||void 0,e.messages)}};function Fe(e){let t=j.safeParse(i,e);if(t.success)return;let n=t.issues.map(e=>`${e.path?.map(e=>e.key).join(`.`)||`options`}: ${e.message}`).join(`; `);throw Error(`autoi18n: invalid options (${n}).`)}const $=e=>({info:t=>e.info(t),warn:t=>e.warn(t),error:t=>e.error(t)});async function Ie(e,t){await Promise.all(t.map(t=>ie(M.join(e,`${t}.sources.json`),{force:!0})))}function Le(e){Fe(e);let t=e.sourceLocale??`en`,n=e.directory??`.autoi18n`,i=e.delivery??`build`,a=e.debug??!1,s={componentProps:e.componentProps,stringMarker:e.stringMarker},c=e.orphanRetentionMinutes??43200,u,f=ke(e.provider,e=>u?.warn(e)),p,m=``,h=new Te,g,_=Promise.resolve(),v,y=()=>e.locale??process.env.AUTOI18N_LOCALE??t;function b(){let n=e.locales.filter(e=>e!==t),r=e.locale??process.env.AUTOI18N_LOCALE;return i===`build`&&r&&p.command!==`serve`?n.filter(e=>e===r):n}async function S(r,i){u=r;let g=i!==void 0&&h.extractions.has(i),_=g?[...h.extractions.keys()]:await ne(e.include??D,{cwd:p.root,ignore:e.exclude??x,absolute:!0}),v=/* @__PURE__ */ new Map,y=[];for(let e of _){let t=h.extractions.get(e),n;if(t&&g&&e!==i)n=t;else{let r=await re(e,`utf8`),i=o(r);n=t?.hash===i?t:{hash:i,messages:be(r,e,s)}}v.set(e,n),y.push({file:e,messages:n.messages})}let S=M.resolve(p.root,n,`locales`),C=b(),w=/* @__PURE__ */ new Map;for(let e of C)w.set(e,await h.readLocale(l(S,e),r.warn));let T=await me({files:y,registry:await h.readRegistry(m,r.warn),orphanRetentionMinutes:c,sourceLocale:t,locales:C,localeConcurrency:Math.max(1,Math.floor(e.localeConcurrency??2)),previous:w,provider:f,debug:a});if(a)for(let e of T.pruned)d(`removed ${e.id} ${JSON.stringify(e.source)} (last seen ${e.lastSeen})`);if(T.pruned.length&&r.info(`autoi18n: removed ${T.pruned.length} registry entries no longer in the source.`),await h.writeRegistry(m,T.registry),T.ambiguous.length){let t=`autoi18n: ${T.ambiguous.length} duplicated texts changed occurrence count, so their IDs may have moved (e.g. "${T.ambiguous[0]}").`;e.onAmbiguous===`error`?r.error(t):r.warn(t)}await h.writeLocale(l(S,t),T.sourceFile),h.legacySidecarsRemoved||=(await Ie(S,[t,...e.locales]),!0);let E=/* @__PURE__ */ new Map([[t,T.sourceFile.messages]]);for(let[e,t]of T.locales)await h.writeLocale(l(S,e),t.file),E.set(e,t.file.messages);for(let e of T.failures.keys())E.set(e,w.get(e)?.messages??{});let O=[...E].filter(([e,t])=>!we(h.catalogs.get(e),t)).map(([e])=>e),k=0;h.fileMessages=/* @__PURE__ */ new Map;for(let{file:e,messages:t}of y)h.fileMessages.set(e,T.messages.slice(k,k+t.length)),k+=t.length;h.extractions=v,h.catalogs=E,h.catalogFiles=Object.fromEntries(e.locales.map(e=>[e,l(S,e)]));for(let[t,n]of T.locales)n.requested&&!f&&e.failOnMissingProvider&&r.error(`Missing ${n.requested} ${t} translations and no provider is configured.`),n.rejected&&r.info(`autoi18n: rejected ${n.rejected} ${t} translations with changed placeholders.`),n.untranslated&&(f?r.warn:r.info)(`autoi18n: ${n.untranslated} ${t} messages have no translation and fall back to the source text.`),n.failed&&r.warn(`autoi18n: ${n.failed} ${t} translation batches failed (${n.failure}); they will be requested again on the next build.`);T.messages.length&&r.info(`autoi18n: indexed ${T.messages.length} messages across ${_.length} files.`);let A=[...T.failures];for(let[e,t]of A.slice(1))r.warn(`autoi18n: ${e} translation failed: ${t.message}`);if(A.length)throw A[0][1];return O}function C(e,t){let n=_.then(()=>S(e,t));return _=n.then(()=>void 0,()=>void 0),n}function w(e){e.length&&g?.ws.send({type:`custom`,event:r,data:{catalogs:Object.fromEntries(e.map(e=>[e,h.catalogs.get(e)]))}})}async function T(e){try{w(await C($(p.logger),e))}catch(e){p.logger.error(`autoi18n: re-translation failed: ${e.message}`)}}function E(){clearTimeout(v),v=setTimeout(()=>void T(),150)}function k(t){if(!/\.[jt]sx?$/.test(t))return!1;let n=M.relative(p.root,t).split(M.sep).join(`/`);return(e.include??D).some(e=>M.matchesGlob(n,e))&&!(e.exclude??x).some(e=>M.matchesGlob(n,e))}return{name:`vite-plugin-autoi18n`,enforce:`pre`,configResolved(r){p=r,m=M.resolve(p.root,n,`registry.json`);let i=y();if(i!==t&&!e.locales.includes(i))throw Error(`autoi18n: locale "${i}" is not one of the configured locales (${e.locales.join(`, `)}).`)},resolveId(e){if(e===`virtual:autoi18n`)return`\0${O}`},load(e){if(e===`\0virtual:autoi18n`)return Ce(h.catalogFiles,t)},configureServer(e){g=e,e.watcher.on(`add`,e=>{k(e)&&E()}),e.watcher.on(`unlink`,e=>{h.fileMessages.has(e)&&E()})},closeBundle(){clearTimeout(v)},async buildStart(){await S({info:e=>this.info(e),warn:e=>this.warn(e),error:e=>this.error(e)})},async transform(e,n){let r=n.split(`?`)[0];if(!h.fileMessages.has(r))return null;let a=o(e);a!==h.hashOf(r)&&await C($(p.logger),r);let s=h.fileMessages.get(r);if(!s||a!==h.hashOf(r))return h.warnedFiles.has(r)||(h.warnedFiles.add(r),this.warn(`autoi18n: ${r} changed while it was being indexed; its messages are left untranslated.`)),null;let c=p.command===`serve`?t:y(),l=xe(e,r,s,c,h.catalogs.get(c)??{},i===`runtime`,t);return{code:l.code,map:l.map}},async handleHotUpdate({file:e}){if(e.startsWith(M.resolve(p.root,n,`locales`)+M.sep))return[];h.fileMessages.has(e)&&await T(e)}}}export{Ne as AnthropicProvider,Ee as FallbackProvider,Pe as GeminiProvider,Me as OpenAICompatibleProvider,P as PartialTranslationError,Le as default,ke as resolveProvider};
|
|
4
|
+
`}async function q(e){try{let t=await oe(e);return`${t.mtimeMs}:${t.size}`}catch{return}}function we(e,t){if(!e)return!1;let n=Object.keys(t);return n.length===Object.keys(e).length&&n.every(n=>e[n]===t[n])}var Te=class{extractions=/* @__PURE__ */ new Map;fileMessages=/* @__PURE__ */ new Map;catalogs=/* @__PURE__ */ new Map;catalogFiles={};warnedFiles=/* @__PURE__ */ new Set;legacySidecarsRemoved=!1;localeFiles=/* @__PURE__ */ new Map;registryCache;hashOf(e){return this.extractions.get(e)?.hash}async readLocale(t,n){let r=await q(t),i=this.localeFiles.get(t);if(r!==void 0&&i?.stamp===r)return i.value;let a=await e(t,n);return r!==void 0&&this.localeFiles.set(t,{stamp:r,value:a}),a}async writeLocale(e,t){await y(e,t);let n=await q(e);n!==void 0&&this.localeFiles.set(e,{stamp:n,value:t})}async readRegistry(e,t){let n=await q(e);if(n!==void 0&&this.registryCache?.stamp===n)return this.registryCache.value;let r=await T(e,t);return n!==void 0&&(this.registryCache={stamp:n,value:r}),r}async writeRegistry(e,t){await v(e,t);let n=await q(e);n!==void 0&&(this.registryCache={stamp:n,value:t})}},Ee=class{providers;onFallback;constructor(e,t=()=>{}){this.providers=e,this.onFallback=t}async translate(e){let t={},n=e.messages,r,i;for(let[a,{name:o,provider:s}]of this.providers.entries()){try{Object.assign(t,await s.translate({...e,messages:n}))}catch(e){r??=e,i=e,e instanceof N&&Object.assign(t,e.partial);let s=this.providers[a+1];s&&n.some(e=>t[e.id]===void 0)&&this.onFallback(`${o} failed (${De(e)}); sending the rest to ${s.name}.`)}if(n=n.filter(e=>t[e.id]===void 0),!n.length)return t}throw Object.keys(t).length===0?r:new N(`${n.length} messages failed to translate: ${De(i)}`,t,n.length)}};const De=e=>e instanceof Error?e.message:String(e),Oe=e=>typeof e==`object`&&!!e&&typeof e.translate==`function`;function ke(e,t){if(e===void 0)return;if(Oe(e))return e;let{primary:n,...r}=e,i=[];for(let[e,t]of Object.entries(r))if(t!==void 0){if(!Oe(t))throw Error(`autoi18n: provider "${e}" must be an object with a translate(input) method.`);i.push({name:e,provider:t})}if(n!==void 0){let e=i.findIndex(e=>e.name===n);if(e<0)throw Error(`autoi18n: primary provider "${n}" is not configured.`);i.unshift(...i.splice(e,1))}if(i.length!==0)return i.length===1?i[0].provider:new Ee(i,t)}var J=class extends Error{retryable;retryAfterMs;constructor(e,t,n){super(e),this.retryable=t,this.retryAfterMs=n}};function Ae(e,t=Date.now()){if(!e)return;let n=Number(e);if(Number.isFinite(n))return Math.min(Math.max(n,0)*1e3,_);let r=Date.parse(e);if(!Number.isNaN(r))return Math.min(Math.max(r-t,0),_)}const je=e=>new Promise(t=>setTimeout(t,e));function Y(e){return`You are a professional software localization engine. Translate UI messages from ${e.sourceLocale} to ${e.targetLocale}. Preserve placeholders exactly. Respect context and UI conventions. Return ONLY a JSON object mapping message IDs to translated strings. Do not translate product names or code.`}function X(e){return JSON.stringify(e.map(e=>({id:e.id,text:e.source,context:e.context,kind:e.kind})))}async function Z(e){let t=e.status===408||e.status===409||e.status===429||e.status>=500;return await e.body?.cancel().catch(()=>void 0),new J(`Translation API failed (${e.status})`,t,Ae(e.headers.get(`retry-after`)))}var Q=class{options;slots;constructor(e){this.options=e,this.slots=new de(e.concurrency??4)}async translate(e){let t=Math.max(1,this.options.batchSize??40),n=[];for(let r=0;r<e.messages.length;r+=t)n.push(e.messages.slice(r,r+t));let r=await Promise.allSettled(n.map(t=>this.slots.run(()=>this.translateBatch({...e,messages:t})))),i={},a=[],o=0,s=0;if(r.forEach((e,t)=>{e.status===`fulfilled`?(s++,Object.assign(i,e.value)):(a.push(e.reason),o+=n[t].length)}),!a.length)return i;throw s?new N(`${o} messages failed to translate: ${a[0].message}`,i,o):a[0]}async translateBatch(e){let t=this.options.maxRetries??2,n=this.options.retryDelayMs??500;for(let r=0;;r++)try{return await this.request(e)}catch(e){if(e instanceof J&&!e.retryable||r>=t)throw e;let i=e instanceof J?e.retryAfterMs:void 0;await je(i??n*2**r*(.5+Math.random()/2))}}toCatalog(e,t){if(!e)throw new J(`Translation provider returned no content`,!0);let n;try{n=JSON.parse(e)}catch{throw new J(`Translation provider returned invalid JSON`,!0)}let r=A.safeParse(a,n);if(!r.success)throw new J(`Translation provider returned a non-object`,!0);let i=new Set(t.map(e=>e.id)),o={};for(let[e,t]of Object.entries(r.output))i.has(e)&&typeof t==`string`&&t.trim()&&(o[e]=t);return o}},Me=class extends Q{async request(e){let t=await fetch(`${this.options.baseURL??`https://api.openai.com/v1`}/chat/completions`,{method:`POST`,signal:AbortSignal.timeout(this.options.timeoutMs??6e4),headers:{Authorization:`Bearer ${this.options.apiKey}`,"Content-Type":`application/json`},body:JSON.stringify({model:this.options.model,temperature:0,response_format:{type:`json_object`},messages:[{role:`system`,content:Y(e)},{role:`user`,content:X(e.messages)}]})});if(!t.ok)throw await Z(t);let n=A.safeParse(c,await t.json());return this.toCatalog(n.success?n.output.choices[0].message.content??void 0:void 0,e.messages)}},Ne=class extends Q{async request(e){let t=await fetch(`${this.options.baseURL??`https://api.anthropic.com/v1`}/messages`,{method:`POST`,signal:AbortSignal.timeout(this.options.timeoutMs??6e4),headers:{"x-api-key":this.options.apiKey,"anthropic-version":C,"content-type":`application/json`},body:JSON.stringify({model:this.options.model,max_tokens:this.options.maxTokens??8192,system:Y(e),messages:[{role:`user`,content:X(e.messages)}]})});if(!t.ok)throw await Z(t);let n=A.safeParse(s,await t.json()),r=n.success?n.output.content.filter(e=>e.type===`text`).map(e=>e.text??``).join(``):``;return this.toCatalog(r.trim().replace(/^```(?:json)?\s*|\s*```$/g,``)||void 0,e.messages)}},Pe=class extends Q{async request(e){let t=this.options.baseURL??`https://generativelanguage.googleapis.com/v1beta`,n=await fetch(`${t}/models/${encodeURIComponent(this.options.model)}:generateContent`,{method:`POST`,signal:AbortSignal.timeout(this.options.timeoutMs??6e4),headers:{"x-goog-api-key":this.options.apiKey,"content-type":`application/json`},body:JSON.stringify({systemInstruction:{parts:[{text:Y(e)}]},contents:[{role:`user`,parts:[{text:X(e.messages)}]}],generationConfig:{responseMimeType:`application/json`,maxOutputTokens:this.options.maxOutputTokens??8192}})});if(!n.ok)throw await Z(n);let r=A.safeParse(u,await n.json()),i=r.success?(r.output.candidates[0]?.content?.parts??[]).map(e=>e.text??``).join(``):``;return this.toCatalog(i.trim().replace(/^```(?:json)?\s*|\s*```$/g,``)||void 0,e.messages)}};function Fe(e){let t=A.safeParse(i,e);if(t.success)return;let n=t.issues.map(e=>`${e.path?.map(e=>e.key).join(`.`)||`options`}: ${e.message}`).join(`; `);throw Error(`autoi18n: invalid options (${n}).`)}const $=e=>({info:t=>e.info(t),warn:t=>e.warn(t),error:t=>e.error(t)});async function Ie(e,t){await Promise.all(t.map(t=>ae(j.join(e,`${t}.sources.json`),{force:!0})))}function Le(e){Fe(e);let t=e.sourceLocale??`en`,n=e.directory??`.autoi18n`,i=e.delivery??`build`,a=e.debug??!1,s={componentProps:e.componentProps,stringMarker:e.stringMarker},c=e.orphanRetentionMinutes??43200,u,f=ke(e.provider,e=>u?.warn(e)),p,m=``,h=new Te,g,_=Promise.resolve(),v,y=()=>e.locale??process.env.AUTOI18N_LOCALE??t;function b(){let n=e.locales.filter(e=>e!==t),r=e.locale??process.env.AUTOI18N_LOCALE;return i===`build`&&r&&p.command!==`serve`?n.filter(e=>e===r):n}async function ee(){let t=[];for await(let n of re(e.include??E,{cwd:p.root,exclude:e.exclude??x}))t.push(j.resolve(p.root,n));return t}async function S(r,i){u=r;let g=i!==void 0&&h.extractions.has(i),_=g?[...h.extractions.keys()]:await ee(),v=/* @__PURE__ */ new Map,y=[];for(let e of _){let t=h.extractions.get(e),n;if(t&&g&&e!==i)n=t;else{let r=await ie(e,`utf8`),i=o(r);n=t?.hash===i?t:{hash:i,messages:be(r,e,s)}}v.set(e,n),y.push({file:e,messages:n.messages})}let x=j.resolve(p.root,n,`locales`),S=b(),C=/* @__PURE__ */ new Map;for(let e of S)C.set(e,await h.readLocale(l(x,e),r.warn));let w=await he({files:y,registry:await h.readRegistry(m,r.warn),orphanRetentionMinutes:c,sourceLocale:t,locales:S,localeConcurrency:Math.max(1,Math.floor(e.localeConcurrency??2)),previous:C,provider:f,debug:a});if(a)for(let e of w.pruned)d(`removed ${e.id} ${JSON.stringify(e.source)} (last seen ${e.lastSeen})`);if(w.pruned.length&&r.info(`autoi18n: removed ${w.pruned.length} registry entries no longer in the source.`),await h.writeRegistry(m,w.registry),w.ambiguous.length){let t=`autoi18n: ${w.ambiguous.length} duplicated texts changed occurrence count, so their IDs may have moved (e.g. "${w.ambiguous[0]}").`;e.onAmbiguous===`error`?r.error(t):r.warn(t)}await h.writeLocale(l(x,t),w.sourceFile),h.legacySidecarsRemoved||=(await Ie(x,[t,...e.locales]),!0);let T=/* @__PURE__ */ new Map([[t,w.sourceFile.messages]]);for(let[e,t]of w.locales)await h.writeLocale(l(x,e),t.file),T.set(e,t.file.messages);for(let e of w.failures.keys())T.set(e,C.get(e)?.messages??{});let E=[...T].filter(([e,t])=>!we(h.catalogs.get(e),t)).map(([e])=>e),D=0;h.fileMessages=/* @__PURE__ */ new Map;for(let{file:e,messages:t}of y)h.fileMessages.set(e,w.messages.slice(D,D+t.length)),D+=t.length;h.extractions=v,h.catalogs=T,h.catalogFiles=Object.fromEntries(e.locales.map(e=>[e,l(x,e)]));for(let[t,n]of w.locales)n.requested&&!f&&e.failOnMissingProvider&&r.error(`Missing ${n.requested} ${t} translations and no provider is configured.`),n.rejected&&r.info(`autoi18n: rejected ${n.rejected} ${t} translations with changed placeholders.`),n.untranslated&&(f?r.warn:r.info)(`autoi18n: ${n.untranslated} ${t} messages have no translation and fall back to the source text.`),n.failed&&r.warn(`autoi18n: ${n.failed} ${t} translation batches failed (${n.failure}); they will be requested again on the next build.`);w.messages.length&&r.info(`autoi18n: indexed ${w.messages.length} messages across ${_.length} files.`);let O=[...w.failures];for(let[e,t]of O.slice(1))r.warn(`autoi18n: ${e} translation failed: ${t.message}`);if(O.length)throw O[0][1];return E}function C(e,t){let n=_.then(()=>S(e,t));return _=n.then(()=>void 0,()=>void 0),n}function w(e){e.length&&g?.ws.send({type:`custom`,event:r,data:{catalogs:Object.fromEntries(e.map(e=>[e,h.catalogs.get(e)]))}})}async function T(e){try{w(await C($(p.logger),e))}catch(e){p.logger.error(`autoi18n: re-translation failed: ${e.message}`)}}function O(){clearTimeout(v),v=setTimeout(()=>void T(),150)}function k(t){if(!/\.[jt]sx?$/.test(t))return!1;let n=j.relative(p.root,t).split(j.sep).join(`/`);return(e.include??E).some(e=>j.matchesGlob(n,e))&&!(e.exclude??x).some(e=>j.matchesGlob(n,e))}return{name:`vite-plugin-autoi18n`,enforce:`pre`,configResolved(r){p=r,m=j.resolve(p.root,n,`registry.json`);let i=y();if(i!==t&&!e.locales.includes(i))throw Error(`autoi18n: locale "${i}" is not one of the configured locales (${e.locales.join(`, `)}).`)},resolveId(e){if(e===`virtual:autoi18n`)return`\0${D}`},load(e){if(e===`\0virtual:autoi18n`)return Ce(h.catalogFiles,t)},configureServer(e){g=e,e.watcher.on(`add`,e=>{k(e)&&O()}),e.watcher.on(`unlink`,e=>{h.fileMessages.has(e)&&O()})},closeBundle(){clearTimeout(v)},async buildStart(){await S({info:e=>this.info(e),warn:e=>this.warn(e),error:e=>this.error(e)})},async transform(e,n){let r=n.split(`?`)[0];if(!h.fileMessages.has(r))return null;let a=o(e);a!==h.hashOf(r)&&await C($(p.logger),r);let s=h.fileMessages.get(r);if(!s||a!==h.hashOf(r))return h.warnedFiles.has(r)||(h.warnedFiles.add(r),this.warn(`autoi18n: ${r} changed while it was being indexed; its messages are left untranslated.`)),null;let c=p.command===`serve`?t:y(),l=xe(e,r,s,c,h.catalogs.get(c)??{},i===`runtime`,t);return{code:l.code,map:l.map}},async handleHotUpdate({file:e}){if(e.startsWith(j.resolve(p.root,n,`locales`)+j.sep))return[];h.fileMessages.has(e)&&await T(e)}}}export{Ne as AnthropicProvider,Ee as FallbackProvider,Pe as GeminiProvider,Me as OpenAICompatibleProvider,N as PartialTranslationError,Le as default,ke as resolveProvider};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-ai-auto-i18n",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Implicit, build-time AI localization for JSX applications",
|
|
6
6
|
"license": "ISC",
|
|
@@ -52,12 +52,11 @@
|
|
|
52
52
|
"typecheck": "tsc --noEmit"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
|
+
"rolldown": "^1.2.18",
|
|
55
56
|
"vite": "^8.0.0"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
59
|
"magic-string": "^1.4.5",
|
|
59
|
-
"oxc-parser": "^0.158.0",
|
|
60
|
-
"tinyglobby": "^0.2.17",
|
|
61
60
|
"valibot": "^1.5.0"
|
|
62
61
|
},
|
|
63
62
|
"devDependencies": {
|
|
@@ -66,6 +65,7 @@
|
|
|
66
65
|
"@vitest/coverage-v8": "^5.1.0",
|
|
67
66
|
"react": "^19.3.1",
|
|
68
67
|
"react-dom": "^19.3.1",
|
|
68
|
+
"rolldown": "^1.3.2",
|
|
69
69
|
"rollup-plugin-visualizer": "^7.1.3",
|
|
70
70
|
"tsdown": "^0.23.7",
|
|
71
71
|
"typescript": "^7.1.0-beta",
|