UNPKG

qwik-speak

Version:

Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps

26 lines (25 loc) 14.4 kB
"use strict";/** * @license * Qwik Speak * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://github.com/robisim74/qwik-speak/blob/main/LICENSE */Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=require("fs/promises"),B=require("fs"),k=require("path"),ee=require("crypto");function te(e,t=0){const n=[],r=[],l=[];let u="",i=t;const o=p=>(t=i,{type:p,value:d(),position:{start:t,end:i}}),s=p=>{p.value=d(),p.position.start=t,p.position.end=i},a=()=>e[++i],f=()=>i<e.length-1?e[i+1]:"",y=()=>i>0?e[i-1]:"",d=()=>e.substring(t,i+1),g=p=>/["'`0-9+-]/.test(p),b=p=>/[a-zA-Z_$]/.test(p),$=p=>/[(){},:;.[\]?!=<>]/.test(p),w=p=>/\//.test(p)&&/\*/.test(f()),S=(p,h)=>{if(!h)h=o("Literal"),n.push(h);else{if(l.length===0&&!/[0-9.]/.test(p))return I(p);s(h)}return l.length===0&&/["'`]/.test(p)?l.push(p):l.length>0&&l[l.length-1]===p&&(/\\/.test(y())||l.pop()),S(a(),h)},c=(p,h)=>{if(!h)u=p,h=o("Identifier"),n.push(h);else if(/[0-9a-zA-Z_$. ]/.test(p))u+=p,(u=="null"||u=="undefined"||u=="true"||u=="false"||u=="void 0")&&(h.type="Literal"),s(h);else return I(p);return c(a(),h)},m=(p,h)=>(h=o("Punctuator"),n.push(h),/\(/.test(p)?r.push(p):/\)/.test(p)&&r.pop(),I(a())),v=p=>/\//.test(p)&&/\*/.test(y())?I(p):v(a()),Y=()=>n[n.length-1]?.type==="Punctuator"&&r.length===0||i===e.length,I=(p=e[i])=>Y()?n:g(p)?S(p):b(p)?c(p):$(p)?m(p):w(p)?v(p):I(a());return I()}function ne(e,t,n){let r,l=0;const u=[],i=()=>l<e.length-1?e[l+1]:{type:"",value:"",position:{start:0,end:0}},o=()=>e[++l],s=()=>e[e.length-1],a=c=>c.replace(/^["'`]|["'`]$/g,""),f=c=>(r.arguments.push({type:"Literal",value:a(c.value)}),w(o())),y=c=>(r.arguments.push({type:"Identifier",value:c.value}),w(o())),d=(c,m,v)=>(v||(v={type:"Property",key:{type:"Identifier",value:c.value},value:{type:"Literal",value:""}},m.push(v)),!/^:$/.test(c.value)&&!/^:$/.test(i().value)?c.type==="Literal"?(v.value.value=a(c.value),b(o(),m)):(v.value.type="Expression",g(c,m,v)):d(o(),m,v)),g=(c,m,v)=>(v.value.value+=c.value,/^[({]$/.test(c.value)?u.push(c.value):/^[)}]$/.test(c.value)&&u.pop(),/^[,}]$/.test(i().value)&&u.length===0?b(o(),m):g(o(),m,v)),b=(c,m)=>(m||(m=[],r.arguments.push({type:"ObjectExpression",properties:m})),/^}$/.test(c.value)?w(o()):/^:$/.test(i().value)?d(c,m):b(o(),m)),$=(c,m)=>(m||(m=[],r.arguments.push({type:"ArrayExpression",elements:m})),/^]$/.test(c.value)?w(o()):(c.type==="Literal"&&m.push({type:"Literal",value:a(c.value)}),c.type==="Identifier"&&m.push({type:"Identifier",value:c.value}),$(o(),m))),w=c=>Object.is(c,s())?r:c.type==="Literal"?f(c):c.type==="Identifier"&&/^\($/.test(i().value)?S(c):c.type==="Identifier"?y(c):/^{$/.test(c.value)?b(c):/^\[$/.test(c.value)?$(c):w(o()),S=(c,m,v=c.position.start)=>m?/^\)$/.test(c.value)?(m.value=t.substring(v,c.position.end+1),w(o())):S(o(),m,v):new RegExp(n).test(c.value)?(r={type:"CallExpression",value:t.substring(v,s().position.end+1),arguments:[]},w(o())):(m={type:"CallExpression",value:""},r.arguments.push(m),S(o(),m,v));return S(e[l])}function se(e,t){const n=new RegExp(`${t}\\(`,"gs"),r=[];let l;for(;(l=n.exec(e))!==null;)r.push(l.index);return r}function E(e,t){const n=[],r=se(e,t);let l=[];for(const u of r){try{l=te(e,u)}catch(i){console.error(i),console.error(` \x1B[31mQwik Speak Tokenizer error\x1B[0m %s`,e.substring(u,u+100)+` [...] `)}if(l.length>0)try{const i=ne(l,e,t);i&&n.push(i)}catch(i){console.error(i),console.error(` \x1B[31mQwik Speak Parser error\x1B[0m %s`,e.substring(u,l[l.length-1].position.end)+` `)}}return n}function F(e){return/inlineTranslate/.test(e)}function z(e){return/inlinePlural/.test(e)}function J(e){let t=e.match(/(?<=\bconst\s).*?(?=\s?=\s?inlineTranslate\(\);?)/)?.[0]?.trim();return t?(t.startsWith("$")||(t=`\\b${t}`),t=t.replace(/\$/g,"\\$"),t):null}function Q(e){let t=e.match(/(?<=\bconst\s).*?(?=\s?=\s?inlinePlural\(\);?)/)?.[0]?.trim();return t?(t.startsWith("$")||(t=`\\b${t}`),t=t.replace(/\$/g,"\\$"),t):null}function re(e){return JSON.parse(e,(t,n)=>n===null?void 0:n)}function ie(e,t){const n=new Set;for(let r=0;r<20;r++){const l=new Intl.PluralRules(e,t).select(r);n.add(l)}return Array.from(n)}function le(e){let t;if(e){t={};for(const n of e)t={...t,[n.key.value]:n.value.value}}return t}function ae(e,t){return e={...e,...t},e}function W(e){return Object.keys(e).sort().reduce((t,n)=>(e[n]!==null&&typeof e[n]=="object"&&!Array.isArray(e[n])?t[n]=W(e[n]):t[n]=e[n],t),{})}function G(e){let t="";switch(typeof e){case"string":t=e;break;case"object":t=JSON.stringify(W(e));break;case"number":t=e.toString();break}return`autoKey_${ue(t)}`}function N(e,t,n){if(!e)return!1;const r=t.split(n);let l=!1;if(e instanceof Map)for(const u of e.values()){let i=u;for(const o of r){if(i[o]!==void 0)l=!0;else{l=!1;break}i=i[o]}if(!l)break}else if(typeof e=="object"){let u=e;for(const i of r){if(u[i]!==void 0)l=!0;else{l=!1;break}u=u[i]}}return l}function ue(e){return ee.createHash("md5").update(e).digest("hex")}const q="__qsInlineTranslate",R="__qsInlinePlural",O=[],V=[],oe=(e,t)=>`${e} - ${t}`,fe=(e,t)=>`dynamic ${t}: ${e}`;let P,A,L;function ce(e){let t="";const n=async s=>{const a=k.normalize(`${t}/${s}`);let f={};if(B.existsSync(a)){const y=await j.readdir(a);if(y.length>0){const d=k.extname(y[0]),g=y.map($=>j.readFile(`${a}/${$}`,"utf8")),b=await Promise.all(g);for(const $ of b)if($){let w={};switch(d){case".json":w=re($);break}f=ae(f,w)}}}return f},r={...e,basePath:e.basePath??"./",assetsPath:e.assetsPath??"i18n",loadAssets:e.loadAssets??n,outDir:e.outDir??"dist",keySeparator:e.keySeparator??".",keyValueSeparator:e.keyValueSeparator??"@@",autoKeys:e.autoKeys??!1};t=`${r.basePath}/${r.assetsPath}`;const l=Object.fromEntries(r.supportedLangs.map(s=>[s,{}]));let u;const i=new Set;return{name:"vite-plugin-qwik-speak-inline",enforce:"post",apply:void 0,async configResolved(s){s.build?.ssr||s.mode==="ssr"?P="ssr":s.mode==="lib"?P="lib":s.mode==="test"?P="test":P="client",A=s.isProduction||s.mode==="production"?"prod":"dev";const a=s.build?.rollupOptions?.input;a&&(Array.isArray(a)?L=a[0]:typeof a=="string"&&(L=a)),L=L?.split("/")?.pop(),await Promise.all(r.supportedLangs.map(async f=>{const y=await r.loadAssets(f);Object.assign(l[f],y)}))},configureServer(s){A==="dev"&&s.ws.on("qwik-speak:lang",a=>{if(u&&u!==a.msg){for(const f of i){const y=s.moduleGraph.getModuleById(f);y&&s.moduleGraph.invalidateModule(y)}i.clear()}u=a.msg})},async handleHotUpdate({file:s,server:a}){if(new RegExp(r.assetsPath).test(s)&&/\.(json)$/.test(s)){for(const f of r.supportedLangs)new RegExp(f).test(s)&&await n(f);for(const f of i){const y=a.moduleGraph.getModuleById(f);y&&a.moduleGraph.invalidateModule(y)}i.clear()}},async transform(s,a,f){return r.autoKeys&&/\/src\//.test(a)&&/\.(js|cjs|mjs|jsx|ts|tsx)$/.test(a)&&(z(s)&&(s=me(s,r,l)),F(s)&&(s=ye(s,r,l))),(P==="client"||P==="ssr"&&f?.ssr===!1)&&/\/src\//.test(a)&&/\.(js|cjs|mjs|jsx|ts|tsx)$/.test(a)&&(z(s)&&(s=ge(s)),F(s)&&(s=de(s)),A==="dev"&&(s.includes(q)||s.includes(R))&&(s=U(s,u,r,l),i.add(a))),P==="ssr"&&(a.endsWith("entry.ssr.tsx")||a.endsWith("entry.ssr.jsx"))&&(/(?<!\/\/\s*)base:\s*extractBase/.test(s)||(console.log(` \x1B[31mQwik Speak Inline error\x1B[0m %s`,"Missing 'base' option in 'entry.ssr.tsx' file: see https://robisim74.gitbook.io/qwik-speak/tools/setup"),process.exit(1))),s},async writeBundle(s,a){if(P==="client"){const f=s.dir?s.dir:k.normalize(`${r.basePath}/${r.outDir}`),y=Object.values(a),d=r.supportedLangs.map(g=>pe(g,y,f,l,r));await Promise.all(d)}},async closeBundle(){if(P==="client"){const s=B.createWriteStream("./qwik-speak-inline.log",{flags:"w"});s.write(`${P}: `+(L??"-")+` `),O.length>0&&(s.write(` Missing value for keys: `),O.forEach(a=>s.write(a+` `))),V.length>0&&(s.write(` Make sure the keys are in 'runtimeAssets': `),V.forEach(a=>s.write(a+` `))),s.write(` Qwik Speak Inline: build ends at ${new Date().toLocaleString()} `),(O.length>0||V.length>0)&&console.log(` \x1B[33mQwik Speak Inline warn\x1B[0m %s`,"There are missing values or dynamic keys: see ./qwik-speak-inline.log")}}}}async function pe(e,t,n,r,l){const u=k.normalize(`${n}/build/${e}`);B.existsSync(u)||B.mkdirSync(u,{recursive:!0});for(const i of t){const o=[];if(i.type==="chunk"&&"code"in i&&/build\//.test(i.fileName)){const s=k.normalize(`${u}/${i.fileName.split("/")[1]}`);let a=i.code;if(a=U(a,e,l,r),o.push(j.writeFile(s,a)),e===l.defaultLang){const f=k.normalize(`${n}/build`),y=k.normalize(`${f}/${i.fileName.split("/")[1]}`);o.push(j.writeFile(y,a))}}else if(i.type==="asset"&&"source"in i&&/build\//.test(i.fileName)&&i.fileName.includes("q-bundle-graph")){const s=k.normalize(`${u}/${i.fileName.split("/")[1]}`);o.push(j.writeFile(s,i.source))}await Promise.all(o)}}function ye(e,t,n){const r=J(e);if(!r)return e;const l=E(e,r);if(l.length===0)return e;for(const u of l){const i=u.value,o=u.arguments;if(o?.length>0){if(H(o,i))continue;if(o[0].value){const s=o[0].value,[a]=D(s,t.keyValueSeparator),f=G(s);if(!N(n[t.defaultLang],a,t.keySeparator)&&N(n[t.defaultLang],f,t.keySeparator)){const y=i.replace(s,`${f}${t.keyValueSeparator}${s}`);e=e.replace(i,y)}}}}return e}function me(e,t,n){const r=Q(e);if(!r)return e;const l=E(e,r);if(l.length===0)return e;for(const u of l){const i=u.value,o=u.arguments;if(o?.length>0){if(Z(o,i))continue;if(o[1]?.value){const s=g=>!g||g==="undefined"||g==="null",a=o[1].value;let f,y;a&&([f,y]=D(a,t.keyValueSeparator),!y&&/^{.*}$/.test(f)&&(y=f,f=void 0));const d=y?JSON.parse(y):void 0;if(s(f)&&d){const g=G(d);if(N(n[t.defaultLang],g,t.keySeparator)){const b=i.replace(a,`${g}${t.keyValueSeparator}${y}`);e=e.replace(i,b)}}}}}return e}function de(e){const t=J(e);if(!t)return e;let n=!1;const r=E(e,t);if(r.length===0)return e;for(const l of r){const u=l.value,i=l.arguments;if(i?.length>0){if(H(i,u)){n=!0;continue}const o=u.replace(new RegExp(`${t}\\(`),`${q}(`);e=e.replace(u,o)}}return n||(e=Le(e,t)),e}function ge(e){const t=Q(e);if(!t)return e;let n=!1;const r=E(e,t);if(r.length===0)return e;for(const l of r){const u=l.value,i=l.arguments;if(i?.length>0){if(Z(i,u)){n=!0;continue}const o=u.replace(new RegExp(`${t}\\(`),`${R}(`);e=e.replace(u,o)}}return n||(e=je(e,t)),e}function U(e,t,n,r){return e.includes(R)&&(e=ve(e,R,q,t,n)),e.includes(q)&&(e=$e(e,r,q,t,n)),e}function $e(e,t,n,r,l){const u=E(e,n);if(u.length===0)return e;for(const i of u){const o=i.value,s=i.arguments;if(s?.length>0){const a=X(r,s[2],l);let f=x("");if(s[0].type==="ArrayExpression"){const d=we(s[0]),g=[];for(const b of d){const $=M(b,t[a],s[1],l.keySeparator,l.keyValueSeparator,a);g.push($)}f=g}else if(s?.[0]?.value){const d=be(s[0]);f=M(d,t[a],s[1],l.keySeparator,l.keyValueSeparator,a)}const y=he(f);e=e.replace(o,y)}}return e}function ve(e,t,n,r,l){const u=E(e,t);if(u.length===0)return e;for(const i of u){const o=i.value,s=i.arguments;if(s?.length>0){const a=X(r,s[4],l),f=le(s[3]?.properties),y=ie(a,f),d=xe(y,a,n,s,l);e=e.replace(o,d)}}return e}function he(e){return typeof e=="object"?`${ke(e)}`:e}function xe(e,t,n,r,l){let u="";return u+=(o=>{let s="(";for(const a of e){let f=r[1]?.value,y;f&&([f,y]=D(f,l.keyValueSeparator),!y&&/^{.*}$/.test(f)&&(y=f,f=void 0)),f=f?`${f}${l.keySeparator}${a}`:a;const d=y?JSON.parse(y)[a]:void 0;d&&(f=`${f}${l.keyValueSeparator}${d}`);const g=[{type:"Property",key:{type:"Identifier",value:"value"},value:{type:"Expression",value:r[0].value}}];if(r[2]?.properties)for(const $ of r[2].properties)g.push($);const b=g.map($=>`${$.key.value}: ${C($)}`).join(", ");if(a!==e[e.length-1]){const $=r[3]?.properties?.map(S=>`${S.key.value}: ${C(S)}`)?.join(", "),w=Pe(o,r[0].value,a,$);s+=w+` && ${n}(${x(f)}, {${b}}, ${x(o)}) || `}else s+=`${n}(${x(f)}, {${b}}, ${x(o)})`}return s+=")",s})(t),u}function H(e,t){if(e?.[0]?.value){if(e[0].type==="Identifier"||e[0].type==="Literal"&&/\${.*}/.test(e[0].value))return T(t,"key"),!0;if(e[1]?.type==="Identifier"||e[1]?.type==="CallExpression"||e[2]?.type==="Identifier"||e[2]?.type==="CallExpression")return T(t,"params"),!0}return!1}function Z(e,t){return e?.[0]?.value&&(e[1]?.type==="Identifier"||e[1]?.type==="CallExpression"||e[2]?.type==="Identifier"||e[2]?.type==="CallExpression"||e[3]?.type==="Identifier"||e[3]?.type==="CallExpression"||e[4]?.type==="Identifier"||e[4]?.type==="CallExpression")?(T(t,"params"),!0):!1}function X(e,t,n){let r;return t?.type==="Literal"&&(r=n.supportedLangs.find(l=>l===t.value)),r??e}function be(e){return e.value}function we(e){const t=[];if(e.elements)for(const n of e.elements)n.type==="Literal"&&t.push(n.value);return t}const D=(e,t)=>e.split(t);function M(e,t,n,r,l,u){let i;[e,i]=D(e,l);const o=e.split(r).reduce((s,a)=>s&&s[a]!==void 0?s[a]:void 0,t);if(o){if(typeof o=="string")return n?K(o,n):x(o);if(typeof o=="object")return n?_(o,n):o}else u&&Ie(u,e);return i?!/^[[{].*[\]}]$/.test(i)||/^{{/.test(i)?n?K(i,n):x(i):n?_(JSON.parse(i),n):JSON.parse(i):x(A==="dev"?e:"")}function _(e,t){return Object.keys(e).map(n=>{typeof e[n]=="string"&&(e[n]=t?K(e[n],t):x(e[n])),e[n]&&typeof e[n]=="object"&&(e[n]=_(e[n],t))}),e}function K(e,t){if(t.properties)for(const n of t.properties)e=e.replace(/{{\s?([^{}\s]*)\s?}}/g,(r,l)=>l===n.key.value?Se(n):r);return x(e)}function x(e){return/^`.*`$/.test(e)?e:"`"+e+"`"}function Se(e){return e.value.type==="Literal"?e.value.value:"${"+e.value.value+"}"}function C(e){return e.value.type==="Literal"?x(e.value.value):e.value.value}function Pe(e,t,n,r){return r?`new Intl.PluralRules(${x(e)}, {${r}}).select(+${t}) === ${x(n)}`:`new Intl.PluralRules(${x(e)}).select(+${t}) === ${x(n)}`}function ke(e){let t=JSON.stringify(e,qe);return t=t.replace(/("__qsOpenBt)|(__qsCloseBt")/g,"`"),t}function Ie(e,t){const n=oe(e,t);O.includes(n)||O.push(n)}function T(e,t){const n=fe(Ee(e),t);V.includes(n)||V.push(n)}function Ee(e){return e.replace(/\s+/g," ").trim()}function Le(e,t){return e.replace(new RegExp(`\\bconst\\s${t}\\s=\\sinlineTranslate\\(\\);?`,"g"),"")}function je(e,t){return e.replace(new RegExp(`\\bconst\\s${t}\\s=\\sinlinePlural\\(\\);?`,"g"),"")}function qe(e,t){return typeof t=="string"&&/^`.*`$/.test(t)?t.replace(/^`/,"__qsOpenBt").replace(/`$/,"__qsCloseBt"):t}function Oe(e,t){return t!=="production"?e:e.map(r=>({prefix:r.domain?void 0:r.prefix,paths:r.paths,lang:r.prefix,domain:r.domain,withDomain:r.withDomain}))}exports.qwikSpeakInline=ce;exports.toPrefixAsNeeded=Oe;