@koine/i18n 2.0.0-beta.43 → 2.0.0-beta.44
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/i18nCodegen.cjs.js +456 -17
- package/i18nCodegen.esm.js +457 -18
- package/package.json +3 -3
package/i18nCodegen.cjs.js
CHANGED
|
@@ -31,11 +31,11 @@ var t__namespace = /*#__PURE__*/_interopNamespace(t$4);
|
|
|
31
31
|
|
|
32
32
|
const dataFsConfig={cwd:process.cwd(),ignore:[]};let r$4=(e={})=>utils.mergeObjects({...dataFsConfig},e),i$4=e=>{let{cwd:o,ignore:a}=e;return glob.glob.sync("*",{cwd:o,withFileTypes:!0,ignore:[...a,"node_modules/**"]}).filter(e=>e.isDirectory()).map(e=>e.relative()).sort((e,o)=>e.localeCompare(o))};let getDataFs=async a=>{let s=r$4(a),l=i$4(s),n=[];return await Promise.all(l.map(async a=>{let r=await glob.glob("**/*.json",{cwd:node_path.join(s.cwd,a),ignore:s.ignore});await Promise.all(r.map(async t=>{let r=node_path.join(s.cwd,a,t),i=await promises.readFile(r,"utf8");i&&n.push({path:t,data:JSON.parse(i),locale:a});}));})),{localesFolders:l,translationFiles:n}};
|
|
33
33
|
|
|
34
|
-
const dataSourceRoutesConfig={translationJsonFileName:"~.json",tokens:{parentReference:"^",idDelimiter:".",pathnameWildcard:"*"}};let i$3=e=>e.replace(/\.index$/,""),o$4=e=>formatRoutePathname.formatRoutePathname(e.replace(/\*/g,"").replace(/[[{]{1,2}(.*?)[\]}]{1,2}/g,(e,t)=>`[${t.trim()}]`)),l$3=r=>utils.capitalize(utils.changeCaseCamel(r)),m$6=(e,t,r,a)=>{let n=t[a].pathnames[r];if(n.startsWith(`/${e.source.routes.tokens.parentReference}`)){let s=RegExp(`^\\/\\${e.source.routes.tokens.parentReference}`);n=n.replace(s,"");let i=a.split(".").slice(0,-1).join(".");if(i)n=m$6(e,t,r,i)+n;else throw Error("Used a parent route token reference without a matching parent route")}return n},p$
|
|
34
|
+
const dataSourceRoutesConfig={translationJsonFileName:"~.json",tokens:{parentReference:"^",idDelimiter:".",pathnameWildcard:"*"}};let i$3=e=>e.replace(/\.index$/,""),o$4=e=>formatRoutePathname.formatRoutePathname(e.replace(/\*/g,"").replace(/[[{]{1,2}(.*?)[\]}]{1,2}/g,(e,t)=>`[${t.trim()}]`)),l$3=r=>utils.capitalize(utils.changeCaseCamel(r)),m$6=(e,t,r,a)=>{let n=t[a].pathnames[r];if(n.startsWith(`/${e.source.routes.tokens.parentReference}`)){let s=RegExp(`^\\/\\${e.source.routes.tokens.parentReference}`);n=n.replace(s,"");let i=a.split(".").slice(0,-1).join(".");if(i)n=m$6(e,t,r,i)+n;else throw Error("Used a parent route token reference without a matching parent route")}return n},p$4=(e,t)=>{utils.forin(t,(a,n)=>{utils.forin(n.pathnames,r=>{t[a].pathnames[r]=m$6(e,t,r,a);});});},c=e=>{let t=e.match(/\[.*?\]/g);if(t)return t.map(e=>e.slice(1,-1).trim()).reduce((e,t)=>(e[t]="stringOrNumber",e),{})},h$2=(e,t)=>{let{defaultLocale:r,locales:a}=e;for(let e in t){let s=t[e].pathnames,i=s[r],o={};for(let e in s){let t=s[e];t!==i&&(o[e]=t);}Object.keys(o).length===a.length-1||(Object.keys(o).length>=1?(o[r]=i,t[e].optimizedPathnames=utils.objectSortByKeysMatching(o,r)):t[e].optimizedPathnames=i);}};let getDataSourceRoutes=(e,{translationFiles:t})=>{let{defaultLocale:r}=e,s=[],m={};for(let p=0;p<t.length;p++){let{path:h,locale:u,data:d}=t[p];if(h===e.source.routes.translationJsonFileName){let t=utils.objectFlat(d,e.source.routes.tokens.idDelimiter);for(let a in t){let p=t[a],h=i$3(a);if(!m[h]){m[h]=m[h]||{};let t=l$3(h),r=c(h),a=p.includes(e.source.routes.tokens.pathnameWildcard);m[h].id=h,m[h].typeName=t,r&&(m[h].params=r),a&&(m[h].wildcard=!0,s.push(h));}m[h].pathnames=m[h].pathnames||{},m[h].pathnames[u]=o$4(p),m[h].pathnames=utils.objectSortByKeysMatching(m[h].pathnames,r);}}}if(p$4(e,m),h$2(e,m),s.length)for(let e in m)s.some(t=>e.startsWith(t)&&t!==e)&&(m[e].inWildcard=!0);return Object.fromEntries(Object.entries(m).sort())};
|
|
35
35
|
|
|
36
36
|
let s$2=["zero","one","two","few","many","other"],a$4="other";let isPluralSuffix=e=>s$2.includes(e)||utils.isNumericLiteral(e);let removePluralSuffix=e=>{let[l]=utils.splitReverse(e,"_");return l?e.replace(`_${l}`,""):e};let isPluralKey=e=>{let[l]=utils.splitReverse(e,"_");return isPluralSuffix(l)};let i$2=e=>{let l={};return e.forEach(e=>{let[r]=utils.split(e,"_");l[r]=l[r]||[],l[r].push(e);}),l};let transformKeysForPlurals=l=>{let r=l.filter(isPluralKey);if(r.length){let t=[...l];return utils.forin(i$2(r),(e,r)=>{l.includes(e)||t.push(e),r.forEach(e=>{l.includes(e)&&(t=t.filter(l=>l!==e));});}),t}return l};let hasPlurals=e=>Object.keys(e).includes(a$4);let hasOnlyPluralKeys=e=>!!hasPlurals(e)&&0===pickNonPluralKeys(e).length;let pickNonPluralKeys=e=>Object.keys(e).filter(e=>!isPluralSuffix(e));let pickNonPluralValue=e=>hasPlurals(e)?utils.objectPick(e,pickNonPluralKeys(e)):e;
|
|
37
37
|
|
|
38
|
-
const dataSourceTranslationsConfig={dynamicDelimiters:{start:"{{",end:"}}"},fnsAsDataSources:!0,fnsPrefix:"",createArrayIndexBasedFns:!1};let u=RegExp(node_path.sep,"g"),p$
|
|
38
|
+
const dataSourceTranslationsConfig={dynamicDelimiters:{start:"{{",end:"}}"},fnsAsDataSources:!0,fnsPrefix:"",createArrayIndexBasedFns:!1};let u=RegExp(node_path.sep,"g"),p$3=e=>{let t=e.replace(/~/g,"$").replace(/-/g,"_").replace(u,"_").replace(/_+/g,"_").replace(/[^a-zA-Z0-9_$]/gi,"");return /^[0-9]/.test(t)?"$"+t:t},f$1=(e,t)=>{if(utils.isString(t)){let{start:r,end:a}=e.source.translations.dynamicDelimiters,l=RegExp(`${r}(.*?)${a}`,"gm"),s=t.match(l);if(s)return s.map(e=>e.replace(r,"").replace(a,"").trim()).reduce((e,t)=>(e[t]="stringOrNumber",e),{})}},m$5=(e,t)=>(Object.keys(t).filter(isPluralKey).forEach(e=>{let r=removePluralSuffix(e);t[r]&&(t[r].plural=!0),delete t[e];}),t),d$3=(e,t,r,a,l)=>{if(utils.isPrimitive(a)){let s=f$1(e,a);l[t]=l[t]||{},l[t].values=l[t].values||{},l[t].values[r]=a,l[t].typeValue="Primitive",s&&(l[t].params=s);}else {if(e.source.translations.fnsAsDataSources){let e=utils.isArray(a)?"Array":"Object";l[t]=l[t]||{},l[t].values=l[t].values||{},l[t].values[r]=a,l[t].typeValue=e;}if(utils.isArray(a)){if(e.source.translations.createArrayIndexBasedFns)for(let s=0;s<a.length;s++)d$3(e,t+"_"+s,r,a[s],l);}else for(let s in a)d$3(e,t+"_"+p$3(s),r,a[s],l);}return l},g$1=(l,s,n)=>{let{locale:i,path:o}=s,c=node_path.join(node_path.dirname(o),node_path.basename(o,node_path.extname(o)));for(let e in s.data){let t=s.data[e];d$3(l,p$3(c+(e?"_"+e:"")),i,t,n);}return n};let getDataSourceTranslations=(e,{translationFiles:t})=>{let r={};for(let a=0;a<t.length;a++)t[a].path!==e.source.routes.translationJsonFileName&&g$1(e,t[a],r);return Object.fromEntries(Object.entries(r=m$5(e,r)).sort())};
|
|
39
39
|
|
|
40
40
|
const dataSourceConfig={routes:dataSourceRoutesConfig,translations:dataSourceTranslationsConfig};let getDataSource=(t,r)=>({routes:getDataSourceRoutes(t,r),translations:getDataSourceTranslations(t,r)});
|
|
41
41
|
|
|
@@ -192,7 +192,7 @@ export default routesSlim;
|
|
|
192
192
|
|
|
193
193
|
let dataParamsToTsInterfaceBody=e=>Object.keys(e).reduce((r,t)=>{let a=e[t],s="";switch(a){case"number":s="number";break;case"string":s="string";break;default:s="string | number";}return r.push(`${t}: ${s};`),r},[]).join(" ");
|
|
194
194
|
|
|
195
|
-
let i=e=>utils.isString(e)||utils.isNumber(e)?`"${e}"`:utils.isBoolean(e)?`${e}`:utils.isArray(e)?JSON.stringify(e):`(${JSON.stringify(e)})`,p$
|
|
195
|
+
let i=e=>utils.isString(e)||utils.isNumber(e)?`"${e}"`:utils.isBoolean(e)?`${e}`:utils.isArray(e)?JSON.stringify(e):`(${JSON.stringify(e)})`,p$2=(t,r)=>utils.areEqual(t,r),m$3=(e,r)=>{let{defaultLocale:o}=e,l="";return utils.forin(r,(e,t)=>{e===o||p$2(t,r[o])||(l+=`locale === "${e}" ? ${i(t)} : `);}),l+=i(r[o])};var s$1 = (({config:e,data:r})=>{let o=`
|
|
196
196
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
197
197
|
/* eslint-disable prefer-const */
|
|
198
198
|
import type { I18n } from "./types";
|
|
@@ -201,7 +201,7 @@ import { tInterpolateParams } from "./tInterpolateParams";
|
|
|
201
201
|
`;return utils.forin(r.source.translations,(t,{values:r,params:l,plural:s})=>{let p=`${e.source.translations.fnsPrefix}${t}`;l&&s&&(l.count="number");let $=[l?`params: { ${dataParamsToTsInterfaceBody(l)} }`:"","locale?: I18n.Locale"].filter(Boolean).join(", ");o+=`export let ${p} = (${$}) => `;let f="";utils.isPrimitive(r)?f+=i(r):f+=m$3(e,r),f=l?`tInterpolateParams(${f}, params);`:`${f};`,o+=f+`
|
|
202
202
|
`;}),o});
|
|
203
203
|
|
|
204
|
-
let e$3=e=>e.split("").map(e=>`\\${e}`).join("");var f
|
|
204
|
+
let e$3=e=>e.split("").map(e=>`\\${e}`).join("");var f = (({config:a})=>{let{start:t,end:r}=a.source.translations.dynamicDelimiters;return `
|
|
205
205
|
export let tInterpolateParams = (
|
|
206
206
|
value: string,
|
|
207
207
|
params?: object,
|
|
@@ -253,7 +253,7 @@ import type { I18n } from "./types";
|
|
|
253
253
|
`;return utils.forin(a.source.routes,(t,{typeName:a,pathnames:n,params:p})=>{let s=`to_${utils.changeCaseCamel(t)}`,i=`I18n.RouteParams.${a}`,u=[p?`params: ${i}`:"",m?"":"locale?: I18n.Locale"].filter(Boolean).join(", "),c=m?'""':"locale",f=p?", params":"";$+=`export let ${s} = (${u}) => `,utils.isString(n)?$+=`toFormat(${c}, "${n}"${f});`:$+=`toFormat(${c}, ${r$2(l,n)}${f});`,$+=`
|
|
254
254
|
`;}),$});
|
|
255
255
|
|
|
256
|
-
var p = (({config:a})=>`
|
|
256
|
+
var p$1 = (({config:a})=>`
|
|
257
257
|
export function toFormat(
|
|
258
258
|
locale: string | undefined,
|
|
259
259
|
pathname: string,
|
|
@@ -310,33 +310,377 @@ export function toFormat(
|
|
|
310
310
|
export default toFormat;
|
|
311
311
|
`);
|
|
312
312
|
|
|
313
|
-
let
|
|
313
|
+
let p=(t,n)=>{if(!utils.isArray(n)&&utils.isObject(n)){if(hasOnlyPluralKeys(n))return `'${t}': string;`;if(hasPlurals(n))return `'${t}': string | ${d$1(pickNonPluralValue(n))}`}return `'${t}': ${d$1(n)}`},d$1=t=>{let i="",r="";if(utils.isBoolean(t)?r="boolean":utils.isString(t)&&(r="string"),r)i+=r+";";else if(t){if(utils.isArray(t)){let e=t[0];i+=`${d$1(e)}[];`;}else if(utils.isObject(t)){i+="{";let e=transformKeysForPlurals(Object.keys(t));for(let n=0;n<e.length;n++){let s=e[n],a=t[s]||"";i+=p(s,a);}i+="};";}}else i+="";return (i=i.replace(/;\[\];/g,"[];")).replace(/;+/g,";")},h$1=(t,e)=>{let{translationFiles:n}=e,{defaultLocale:s}=t,a=n.filter(t=>t.locale===s),i=`
|
|
314
314
|
export interface Translations {
|
|
315
|
-
`;for(let
|
|
315
|
+
`;for(let t=0;t<a.length;t++){let{path:e,data:n}=a[t],s=e.replace(".json","");i+=`"${s}": ${d$1(n)}
|
|
316
316
|
`;}return i+`
|
|
317
317
|
}
|
|
318
|
-
`},m$2=e=>{let
|
|
319
|
-
`);}),
|
|
318
|
+
`},m$2=e=>{let n="\n";return utils.forin(e,(t,{typeName:e,params:s})=>{s&&(n+=` export interface ${e} { ${dataParamsToTsInterfaceBody(s)} }
|
|
319
|
+
`);}),n},g=(t,e)=>Object.keys(t).filter(n=>e(n,t[n])).sort().map(t=>`"${t}"`).join(" | ");var l$1 = (({config:t,data:e})=>{let n=m$2(e.source.routes),s=g(e.source.routes,(t,e)=>!e.params),a=g(e.source.routes,(t,e)=>!!e.params);return `
|
|
320
320
|
/* eslint-disable @typescript-eslint/no-namespace */
|
|
321
321
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
322
322
|
/* eslint-disable @typescript-eslint/ban-types */
|
|
323
323
|
|
|
324
324
|
export namespace I18n {
|
|
325
|
-
export type Locale = ${
|
|
325
|
+
export type Locale = ${t.locales.map(t=>`"${t}"`).join(" | ")};
|
|
326
326
|
|
|
327
327
|
export type LocalesMap<T = any> = Record<Locale, T>;
|
|
328
328
|
|
|
329
|
-
${
|
|
330
|
-
|
|
329
|
+
${h$1(t,e.fs)}
|
|
330
|
+
|
|
331
|
+
// import type {
|
|
332
|
+
// // Get,
|
|
333
|
+
// Split,
|
|
334
|
+
// } from "@koine/utils";
|
|
335
|
+
|
|
336
|
+
type Split<
|
|
337
|
+
S extends string,
|
|
338
|
+
Delimiter extends string,
|
|
339
|
+
> = S extends \`\${infer Head}\${Delimiter}\${infer Tail}\`
|
|
340
|
+
? [Head, ...Split<Tail, Delimiter>]
|
|
341
|
+
: S extends Delimiter
|
|
342
|
+
? []
|
|
343
|
+
: [S];
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* @file
|
|
347
|
+
*
|
|
348
|
+
* Test this on TSplayground:
|
|
349
|
+
* https://www.typescriptlang.org/play?#code/PTAEFpK6dv4YpSBQJSgJYEYAcA7YAFwE8AHTfAcwGcA6AEzqJrTGQ86+7hRQYCmAYwA2AQwBOA0PjEBbATTJih0gJJ58oAN4oMlIgIkAzFdIAqEsfhriimAPY2dejKHQAiAH4eAXKGsSAG5XAF8+fXxDEzNQS2tbMXsnGgBhJ2NMKh1w8LYIHkKi4sh8rE1ickVmVnQS+obUFFIyaQApB0oAHgBlbAAaUB6AJgA+UABeIexQAQAPQ3wGGlAaIglKKlcAfiHh2YWBJZW1jepXDF2AAwASbT7QujuR0KuL0H8+1398AQA3IwhNAAKmBemBoAAIpghMlZBISKAHMYAiIRKAiAALaTrBJ2Rw2cHAFDzMgOCREDFVOJWGz4lLQ2EEySIqYaAh0eJ0pIEmhA4Cg8GgABy8kUylUJ0xDgAriIGKA5EkhJiMdjQJkREcxSsAO5GHG0xJwlaSaSCTK-BhEklzMkUqmtGl4pICUUKJSxKYAUQWVlhXQA1gISMjndyTYy4SzBqdNqN+YLQBCAErCGUSGiYAGKsRkVoKlo4hwHXGw1HomU0MQAIy1q3Wm1AyixK2MEgccgCGKN9PwQotlEwcKRNYAVsJKQAKKsysRoxHtzvdto9ADywo1mC1AEo6EK1JSq4o1dIrpRjEYrqAPI2hIGPBiS2tyTj1Q5x5OsFoFHJyYjrAVMgpABKIhQAbQvIdDG-NZrHsHknFmCQO0zABdKdMSIIgyBoXwQDg+8HABEwRAcXU6CETtgAAR2AAB2ABWRiAGZsBYgA2DjgGwABOFjcF4+iAAYdxtUlyUpItw2NXkAAUkkxGgulccwUHGKZdAwcCAGlv1AX0yyIIMQzDcxY0bahRjQ3x3nQeZRBlQRZjkMhSFHCdYRoQYBFc9zJCsEhvJctzETjahWDcOJdLQ0sjmWUA0yoiQGC6cKqEGX4SPGAAfGR-iMcDYryjxH12LKjDssApCEDMswBERESVWQqGkD9PJYd5-HMGK4uORLhHJVL0sGGV8EDfByPwcZdneDA8tubQdNedwwCxTAVg2p9QBraRa3rIgS2PU8b3ax8aGlClaqIObQDyjpuh0wYuVklIFNbLoep0tDRlGKqK3I5sNjkYdsxPckAhQsRETDYDMBB+wAUitxut6+ZFgS9K7pkGU5F2iRsZrBwHC1axsYAQShkg0ss7I8vwXH8cJ4nSem0BrjuZa3ii+y5kc5zAnW6hZhEGgBC6-KSJCUJwMM-1jODUMUXMhszioay+oSi8jFANd2d1j5JcBPgBTBZMBtqzMwdzfMBELakw3nStqzraQsZbJSNQ7LssWkXVpQO3tEMJc2GBhaMEToUBD1AY8Vl90Bz3wS8JGvW8NnvR9DobV8Tvar9KEVXz-wCJYgYKsDzcg5PoOkSg4KiTBg+Q1CaAwrCcLwgiiBUQNiKMYwyIoqi5FohjmLYzjuL4gShNE8S7Ukx0LCDk1ybRd7Pc01xwM3Qu5ZUBXTOV1feSjZkEQstXrP8LS3F0-SD4DRWzNPhlw4vkhd7Q-p0pv27eb82kL5UKHlJzBRAf5KmEC-JhVpsjKKL0+w0HPk4Fk380aHH6klIaNM1aZQKhIXKRsJBFWxqVfWFUJAAOqumK2DUmrWDEK1MBXlbrdTfjYVB8Iv7CjQpgjGKwcEpTwZsUa41Jq6jZtsW6UUFp3GFKEXwnMVroHWpteOJZdoBFdttY6CcPBnVWJdIg11ZFuHup0fAXQ9Lo3iicWm+tFqKOUUtFa-hnFKKuM9ThNBN7KSQcHFBH80EIgwd9X6NCAa6iBvDUGSMkQEwCtDJEKI4YIzBgglGMlkHcPQXwgR9jVZNnpozHWeUiYkwEGTPKlNAqiOFqUvG5Sdos2qdIxOCilEqO5lFVaBwgGlxIELbIAhRbiz6YbKhYRZZ+kPiZJWOSgl5LCXwq+8Y0LS1mUZBZr8XSRhCTw9ZVlYp2P6trAmetdh6x+IQxMZsIQAFV8AiEwMGfSVxfgLHALiCMAhrz6gCAwICYgaBZmFjQTs0hgJ2wEJaO2kMqC4yOCwAIkUIQXUktdNsEMR5-i0MdIQoLFC2XNuAROhjxweGvKC7smKroykpMYCGVxtCgCkEQDM+A1yfi8v4dYMppCvCFOSq4pUaWmmMVixlGoWVstMGiGsvd-AUOFcmBe9opLUkCXCHoJjrqTFOlS8hHh7lCgAIqCoRKwqSJYyRkDlK6E6HKuUIt+caBFWMDBGDJPiYWDAkhiCFBDMQSzdX6sZfudV5thRrnMN6fw-sjix3BdkUN9LTEyuUGCpsOqCRrjcrybaVwiBTh3NeLak1KQ0BlPmSSdshTmDXJCNc-LqTVkvGqLau1MRiD+I4DMqSTrrRSoi5FURQBTgcIWlIe4NVL2knmpwlqjCslcHlMag4rTrpxmiHdS78B6ulTdeaLhJngUVv4dKNlimNJxs0gmFS2nWBCFFUIZrzYFqLWGBO7q7DSGMGNJkSEQ1hoJEehlRAo0PJFHGhNoAk0EtTXSiNlJs3IYPQWk0xbS3lqwCsKtqxa2aobebJtLa21Og7W+btAhe39tlATH96oR0KkkEihQE6p0zpsHO5MxIJIOkXZwrDRaJg7s3XCygpHsYHog5mk92M75RRdRIblvKWDbH8JU1mr6+kKpEEq+8Wnb101M0VPTUULRiDlEQEz6VLOgHfSbJMEIdUAaAyOf2MJVTTujAuAIQhVBuW7LID0Eo9ptkwJmSk7Hx0nuBAJxeQntWrwEJ9d04pYhnISu5zLnpVDY0k-ChgGlVL5Yi5rFYeWdQRfeLsGr4WzCpXMBVswf0oocP2QISEcKbMiCIB+tzaWNSeYJMmYEuphzSkZaCGQtWzCDGHNEzRqwxlfkCEOhOTshR9rENufabt4H6SdvNprkpoNJc1cvMNPW+u2cNZ9NMnK1OGr-lOVweEwMpHXiIfx-RXA0RMweldl9XAOGByJnjrAdyTHGOYZ7XKhu3dG-gYDWhQRTaxHNsLWXVBLdi2iciq2xZanLE4RqJ1Tt7YO67IU6VNpaATlQMGWhccFYEJd2013hPdba6oFr-PgFYNy2loXGlQAqQwAjgQL2tBTHSupD7GAvsHr8YpAJviVlf1awt1QP0AcYCB11iMBJQckEN0iSH+z83Q5QLDiY8PEdqeR+51H6PQBkQcGLZegxs7HQp4iQu8MyBak4z3bDWIkgpsUEKBOJbryAbRyOSgYcapEEp1jmblJfh22FhNciWoGAsOY0dtWWAc8CDtui7asocKRvnSlp07mAAyxMfdTGV6sEzgRLfG++-gc3luIcm9etyu3DvxgOZczBgAQoiKi+BQIjg7Iyk8W7QYpEhnXJn6orheDoGOSF+BE-bh3ydMiRKtQ0GANoS-84BChGJObDsDgmUk0EBIKO5hMRbWklIGFMWCdQhREMkHNOsREXHLbdULdBFVfQwAAchr3v1eTFhBSxCgKnArgQ2m1AAYBIDCxhGbEkl5D40S25wXVS26wYBTDr2kCmDV38U+i10OXQW8A8B+mR0eXsFeXcgbgDTIl+Bu2znRnlgrEnSVDmAxF1BLC1AajwIEDckxFhxVG3AYCkC0HgNj3Nij2rR7gpD1FwOZ1Z1M2g0bV-w0Rj0A3RGzlaiknVBrRrC0JWEdi0DzFDxhGbjNDEB8joCoCjlO0cOcODRRFDQDQuiJkkAYFGmQ2Wyz1JRgyuCSLj2pEhFBUxEiJSloLXxWAYLSxoLoLSF-3lA0LXGMC6A8HCIyIcCiI8ATCFCSO5nIMEy1Wb3yOyMMCKLUNKPKNUh6H0NRRywcXwVUiq1M0NXcwKLX3UgmLGMWnMH6MkBYEeDuAuVAAADFos1gVjtA1iehBolg1V9ZNiYtsZFoTjtinh7gDiGAjj-B7JbADBwAw4XYtRwAvkiBwBXkhCAABIsGgIQDYNycARQb4ogYASacAMaY8BgcAP4SQZGcwOYu4BYgYmgHYtYi4ogI43YLE74EhfkdgRoYkkk8AMoHAAgYAOw8wGofIUk+k+oPgFom7AAcVlyRKmClziCFzGMazx2kA3SWCkytENWK2k2tFGC7xQIEHs1pkt3Zwi2ByF3tzh1ADkm9g2nS3cwyz1wEF+mR1BFjXjVBG6hLCVHeX+MBMwBCxkIkEDBkBhDGURGxCkFzHeRrVdJENkDpyriuCkEhREABDaGPwAFkHAGA5R-l25sJcJ8JgBdQEzmAqgASgSM9rB-DyQqBiAASMgsgABif0kmIM0M8MyMsSc2QuUMQdEtHMmufwo-JwU-LULnZkxfNYUAakw1KcMtVU7QUIWHWlNkogcwQkgoBk8c7gckioY8GkzqOoCchcjgJk5LSkQQUQM0d3EcGcstUff9XrUwWzEIZktc8QV0pPD3GcnU87YXQRW7cXKcBUswbqIXHcXc10IXQXXU+oukxc38hAKcykw6Wk+cv80C6AE2MAEPSgp0NlPkjnaI27KYmCUIL2ZcDwOgSoVoGgcACk-AU1PgaSNcF5EgRY+wIQT6MYv+WYoYndRadKR4cCO4eitCK4+i3peRbQeiugRizi2mUINCdixOHi5i1iviwSq4YSvigSnYEhfEkcgi6kIixqSEAg+QGECioY0zCXJEmi09Oivi7ipiqS0StWI4jiriyS0y6SvSyyzYfikyuy8S2y6gfi3pBrfEqhZHH4omFCYnUAcCMQfUSFBQH5EBf9L44cIwecH5ZM6MzuOMlnLEGUGsSiaiKgGbNETAIwYAQKxQKFUK1ycK3gqKkQGKrCgsugiQcAZQKwOQbCmq1Ncs8g6SJ+IgDogQBSWqgJSi2mCXLGTStSS4C2XBEaLS-Eh4sE54jaQ7d49GCK34y01MkEx4qICEhwKEhmNAuEhE0YzSxaNYgAfUWIpBllWOTh1k6vkHsrOpTgGm2Lcp0H8vtMLkuq7DyhfhRFavateuUjTDWBvnGKaSZnCAwHuLAFBKeJeJmo+PmukD+OTKtOBIhtWshOhK2vhMzF2pFxWH2vOoJiOoGNOt2LxrVMkCuusv1jZQvX0lepvSxiBp1hBsNj7KBGZMXQcDdzyL511NSnYO-LZu1QcFIphHasNSUpIoj3UsmPav5pXJu3MAcBUsIKEFFqmHFqVrUvIulroNlp50FsploEmB3XAgVuFpVroLQmNoVo1pBnNrX0GC+roJ+s+kVtUttpls2RnwaIVuvFxwVC0Njh4OHBICjhjhUGC0pAEGmx1nTU2HrDi3DywBRF0PwzpUlqECFADqgNAzFkXzYwkA4xRTVGj29QkF9VdHjhgLdqIM1W-WMDj3VCzrFG-xY2TOgMUGhRIK3w3Js0OiVDIqdiDzxqkCYHBCFG8vJA7F1BWACqCvysMEKtdAiuiGiv+LitjJAESsxGStStHnStlEyuytyuCoEAKtDyXuKqsFKv+KaquyXnPJHEOinDoBfvYy+xNo5rS0GBfs5AcANrblhzvi1EpCkHxBzCmFKj0zbMpHAiIFiimDfqBH0BRCnDfroC1GoCxEmAmCmBYkAfeEwBQbfvAmGDQnwcmVAZ5HAYxFQYLpoHAmwB-kRXodIb3AAPEFUCnA8GBA8EGFKh3EcyZpQrGR90IcnTQYwaoCwZwamGGHIbcEocRnoJoeIcYYEbCAiHZVly5S0bAYEGlggrHLArAoAsIBnIcGAqJOMZMYoIdAfvG3MZ7LvmgYxFFLFnMC4Z8HUYwFUy0GftfrodNP-snyfCnCIG-oCdoHUbyBAusb-PJMKt8hRR1k6LnKsbid-L4BcecMNTvmlAUBVWAF4dcFrDr0KdKcZShJoA8BQGcxQBcYbPwE2K1AUlagAAkoVcnXB7AM8BAVUOmFBmxmEBAam6mGnj9mmOrhnyYiYZVt4MAemtQVUZm68hnWpimMAFAe5b53hcdln8o1gEUtnQ1ccamMBQhLdUCiB-BwJ3hDFfgNm3BbwZCznQAf5XBIESBb4LmPnYEW8Nprn-LLa6mTyNzHzCt2QtA75S7TBCs1cz0nmfBKMBAwxnDHN8m+nl4wxGnJnWmBABn9H3gKnAWixsWJmz88WVnGU9M8hIhohYWV4bcUhRMt8+zanlzrtQUCChBNzxsczWgnHNG1FFBAWZzXBYmmgMAXHKQphtzvH+k3AAA9GRKVlIKSAltxgQDxjwDFjweV9AJVlV0AaVqlmVmPbV4lvVvTA1jAZVoVtaEV-wcx0uQsBwcV9JyV41tVjEdq3I81zxq191qKO11VmwI8NAhWzVhWsta1sAQ1+1jER1js9koNrgVwaV31tMP8GCBB3UfbSkakrho4Xhm8Lx2N4No16VglrNt-ZRwK-N5N4cotvCvh3V-VuN21mRdN712BmtwwYYP3TN4uftv3at4dgQAdjEU1vtid+BgIPN5bdUzsTUugJ2KcW5qKQtjwYtncS3DALd4tvhrxvdxt7Vw9m8Ntk9g9ltm8S13d1wMh8t+N7tsN0zP15TAIflLhjF3wRZkZ+9qKGsflAlrhv9vVk9oQL9jwYl3wY5ugU5gDtwBgflU1rhuDhDk9zFmE6N6D2ZogcD94YwflBwMJ311tqFAjzd-lId7NgQb9ijxDjATEYDqFGd0D4cLUSjtwTAaj8d4YLhmD9DsULj-QYYFDvDmd-jjwK5kTz3ajwoyTgTvD2T9AP47C0kScEE3ygmT5yGQKKUA+hUQjbRY8Q7d4OQcTuvItv5gFlTsANTkEu0TTowVCEKdyfOLyKVOUIzt-HaaQUzn0twCzqdvD6z0KWThwFjhQRT28Dj-9sINFL1sNp9ztvgUIIAA
|
|
350
|
+
*
|
|
351
|
+
* @see
|
|
352
|
+
* - https://stackoverflow.com/q/75531366/1938970: fix for Type instantiation is excessively deep and possibly infinite in Promise.all
|
|
353
|
+
*
|
|
354
|
+
* @notes
|
|
355
|
+
* I might take a better look at how things were done in [i18next](https://github.com/i18next/i18next/blob/master/index.d.ts)
|
|
356
|
+
*/
|
|
357
|
+
|
|
358
|
+
type MergeDictionaries<T, K> = Omit<T, keyof K> & K;
|
|
359
|
+
|
|
360
|
+
type Join<A, Sep extends string = "", R extends string = ""> = A extends [
|
|
361
|
+
infer First,
|
|
362
|
+
...infer Rest,
|
|
363
|
+
]
|
|
364
|
+
? Join<
|
|
365
|
+
Rest,
|
|
366
|
+
Sep,
|
|
367
|
+
R extends "" ? \`\${First & string}\` : \`\${R}\${Sep}\${First & string}\`
|
|
368
|
+
>
|
|
369
|
+
: R;
|
|
370
|
+
|
|
371
|
+
type BuildRecursiveJoin<TList, TSeparator extends string> = Exclude<
|
|
372
|
+
TList extends [...infer ButLast, unknown]
|
|
373
|
+
? Join<ButLast, TSeparator> | BuildRecursiveJoin<ButLast, TSeparator>
|
|
374
|
+
: never,
|
|
375
|
+
""
|
|
376
|
+
>;
|
|
377
|
+
|
|
378
|
+
type JoinObjectPath<S1, S2> = S1 extends string
|
|
379
|
+
? S2 extends string
|
|
380
|
+
? \`\${S1}.\${S2}\`
|
|
381
|
+
: S1
|
|
382
|
+
: never;
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* A very simplified version of \`type-fest\`'s \`Get\` type
|
|
386
|
+
*/
|
|
387
|
+
type GetWithPath<BaseType, Keys extends readonly string[]> = Keys extends []
|
|
388
|
+
? BaseType
|
|
389
|
+
: Keys extends readonly [infer Head, ...infer Tail]
|
|
390
|
+
? GetWithPath<
|
|
391
|
+
Head extends keyof BaseType ? BaseType[Head] : unknown,
|
|
392
|
+
Extract<Tail, string[]>
|
|
393
|
+
>
|
|
394
|
+
: never;
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* A very simplified version of \`type-fest\`'s \`Get\` type, its implementation
|
|
398
|
+
* of square brackets doesn't match our convention as we always keep dots
|
|
399
|
+
* around the brackets and the brackets do not mean dynamic object access but
|
|
400
|
+
* just a dynamic portion of a route.
|
|
401
|
+
*/
|
|
402
|
+
type Get<BaseType, Path extends string | readonly string[]> = GetWithPath<
|
|
403
|
+
BaseType,
|
|
404
|
+
Path extends string ? Split<Path, "."> : Path
|
|
405
|
+
>;
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
*
|
|
409
|
+
*/
|
|
410
|
+
type TranslationsDictionaryDefault = {
|
|
411
|
+
// "~": any;
|
|
412
|
+
"~": {
|
|
413
|
+
test: string;
|
|
414
|
+
static: string;
|
|
415
|
+
dynamic: {
|
|
416
|
+
static: string;
|
|
417
|
+
"[key]": {
|
|
418
|
+
index: string;
|
|
419
|
+
"[id]": string;
|
|
420
|
+
};
|
|
421
|
+
};
|
|
422
|
+
};
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Dictionary of all the translations
|
|
427
|
+
*
|
|
428
|
+
* It must uses \`~\` as namespace for routes defintions to make the \`to\` and \`useTo\`
|
|
429
|
+
* working
|
|
430
|
+
*/
|
|
431
|
+
export type TranslationsDictionary = MergeDictionaries<
|
|
432
|
+
TranslationsDictionaryDefault,
|
|
433
|
+
I18n.Translations
|
|
434
|
+
>;
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Namespaces should match the filenames were translations are defined
|
|
438
|
+
*/
|
|
439
|
+
export type TranslateNamespace = Extract<keyof TranslationsDictionary, string>;
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Translation **value** found at a specific _path_ in the given _namespace_
|
|
443
|
+
*
|
|
444
|
+
* \`TPath\` can be any of all possible paths:
|
|
445
|
+
* - \`plusKey\` sub dictionaries within a namespace
|
|
446
|
+
* - \`plusKey.nested\` whatever nested level of nesting within a namespace
|
|
447
|
+
*/
|
|
448
|
+
export type TranslationAtPathFromNamespace<
|
|
449
|
+
TNamespace extends TranslateNamespace,
|
|
450
|
+
TPath extends TranslationsPaths<TranslationsDictionary[TNamespace]>,
|
|
451
|
+
> = TNamespace extends TranslateNamespace
|
|
452
|
+
? TPath extends string // TranslationsPaths<TranslationsDictionary[TNamespace]>
|
|
453
|
+
? Get<TranslationsDictionary[TNamespace], TPath>
|
|
454
|
+
: TranslationsDictionary[TNamespace]
|
|
455
|
+
: never;
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* The generic type passed and to use with {@link TranslationAtPath} when you
|
|
459
|
+
* want to build a type extending that
|
|
460
|
+
*/
|
|
461
|
+
export type TranslationAtPathGeneric =
|
|
462
|
+
| TranslateNamespace
|
|
463
|
+
| TranslationsAllPaths;
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Translation **value** found at a _path_
|
|
467
|
+
*
|
|
468
|
+
* \`TPath\` can be any of all possible paths begininng with a namespace:
|
|
469
|
+
* - \`namespace\` only a namespace
|
|
470
|
+
* - \`namespace:plusKey\` sub dictionaries within a namespace
|
|
471
|
+
* - \`namespace:plusKey.nested\` whatever nested level of nesting
|
|
472
|
+
*/
|
|
473
|
+
export type TranslationAtPath<TPath extends TranslationAtPathGeneric> =
|
|
474
|
+
TPath extends TranslateNamespace
|
|
475
|
+
? TranslationsDictionary[TPath]
|
|
476
|
+
: TPath extends \`\${infer Namespace}:\${infer Path}\`
|
|
477
|
+
? Namespace extends TranslateNamespace
|
|
478
|
+
? Get<TranslationsDictionary[Namespace], Path>
|
|
479
|
+
: never
|
|
480
|
+
: never;
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* All translations paths from the given _path_
|
|
484
|
+
*
|
|
485
|
+
* \`TPath\` can be any of all possible paths begininng with a namespace:
|
|
486
|
+
* - \`namespace\` only a namespace
|
|
487
|
+
* - \`namespace:plusKey\` sub dictionaries within a namespace
|
|
488
|
+
* - \`namespace:plusKey.nested\` whatever nested level of nesting
|
|
489
|
+
*/
|
|
490
|
+
export type TranslationPathsFrom<TPath extends TranslationAtPathGeneric> =
|
|
491
|
+
TPath extends TranslateNamespace
|
|
492
|
+
? TranslationsPaths<TranslationsDictionary[TPath]>
|
|
493
|
+
: TPath extends \`\${infer Namespace}:\${infer Path}\`
|
|
494
|
+
? Namespace extends TranslateNamespace
|
|
495
|
+
? Get<TranslationsDictionary[Namespace], Path> extends object
|
|
496
|
+
? TranslationsPaths<Get<TranslationsDictionary[Namespace], Path>>
|
|
497
|
+
: TranslationsPaths<TranslationsDictionary[Namespace]>
|
|
498
|
+
: never
|
|
499
|
+
: never;
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* All translations _paths_ of the given one, e.g. if \`TPath\` would be
|
|
503
|
+
* \`"dashboard.users.[id].edit"\` the generated type would be the union
|
|
504
|
+
* \`"dashboard.users.[id]" | "dashboard.users" | "dashboard"\`.
|
|
505
|
+
*/
|
|
506
|
+
export type TranslationsPathsAncestors<
|
|
507
|
+
TPath extends string,
|
|
508
|
+
TSeparator extends string = ".",
|
|
509
|
+
> = BuildRecursiveJoin<Split<TPath, TSeparator>, TSeparator>;
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Recursive mapped type to extract all usable string paths from a translation
|
|
513
|
+
* definition object (usually from a JSON file).
|
|
514
|
+
* It uses the \`infer\` "trick" to store the object in memory and prevent
|
|
515
|
+
* [infinite instantiation errors](https://stackoverflow.com/q/75531366/1938970)
|
|
516
|
+
*/
|
|
517
|
+
export type TranslationsPaths<T, TAsObj extends boolean = true> = {
|
|
518
|
+
[K in Extract<keyof T, string>]: T[K] extends // exclude empty objects, empty arrays, empty strings
|
|
519
|
+
| Record<string, never>
|
|
520
|
+
| never[]
|
|
521
|
+
| ""
|
|
522
|
+
? never
|
|
523
|
+
: // recursively manage objects
|
|
524
|
+
T[K] extends Record<string, unknown>
|
|
525
|
+
?
|
|
526
|
+
| (TAsObj extends true ? \`\${K}\` : never) // this is to be able to use the "obj" shortcut
|
|
527
|
+
| JoinObjectPath<K, TranslationsPaths<T[K], TAsObj>>
|
|
528
|
+
: // allow primitives or array of primitives
|
|
529
|
+
// TODO: support array of objects recursively? For now we just stop at the array name
|
|
530
|
+
T[K] extends
|
|
531
|
+
| string
|
|
532
|
+
| number
|
|
533
|
+
| boolean
|
|
534
|
+
| Array<string | number | boolean | object>
|
|
535
|
+
? \`\${K}\`
|
|
536
|
+
: // exclude anything else
|
|
537
|
+
never;
|
|
538
|
+
}[Extract<keyof T, string>] extends infer O
|
|
539
|
+
? O
|
|
540
|
+
: never;
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Recursive mapped type of all usable string paths from the whole translations
|
|
544
|
+
* dictionary. It uses the \`infer\` "trick" to store the object in memory and prevent
|
|
545
|
+
* [infinite instantiation errors](https://stackoverflow.com/q/75531366/1938970)
|
|
546
|
+
*/
|
|
547
|
+
export type TranslationsAllPaths = {
|
|
548
|
+
[N in Extract<keyof TranslationsDictionary, string>]: {
|
|
549
|
+
[K in Extract<
|
|
550
|
+
keyof TranslationsDictionary[N],
|
|
551
|
+
string
|
|
552
|
+
>]: TranslationsDictionary[N][K] extends // exclude empty objects, empty arrays, empty strings
|
|
553
|
+
| Record<string, never>
|
|
554
|
+
| never[]
|
|
555
|
+
| ""
|
|
556
|
+
? never
|
|
557
|
+
: // recursively manage objects
|
|
558
|
+
TranslationsDictionary[N][K] extends Record<string, unknown>
|
|
559
|
+
?
|
|
560
|
+
| \`\${N}:\${K}\` // this is to be able to use the "obj" shortcut
|
|
561
|
+
| JoinObjectPath<
|
|
562
|
+
K extends string ? \`\${N}:\${K}\` : \`\${N}:\`,
|
|
563
|
+
TranslationsPaths<TranslationsDictionary[N][K]>
|
|
564
|
+
>
|
|
565
|
+
: // allow primitives or array of primitives
|
|
566
|
+
// TODO: support array of objects recursively? For now we just stop at the array name
|
|
567
|
+
TranslationsDictionary[N][K] extends
|
|
568
|
+
| string
|
|
569
|
+
| number
|
|
570
|
+
| boolean
|
|
571
|
+
| Array<string | number | boolean | object>
|
|
572
|
+
? \`\${N}:\${K}\`
|
|
573
|
+
: // exclude anything else
|
|
574
|
+
never;
|
|
575
|
+
}[Extract<keyof TranslationsDictionary[N], string>];
|
|
576
|
+
}[Extract<keyof TranslationsDictionary, string>] extends infer O
|
|
577
|
+
? O
|
|
578
|
+
: never;
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Unlike in \`next-translate\` we allow passing some predefined arguments as
|
|
582
|
+
* shortcuts for common use cases:
|
|
583
|
+
* - \`"obj"\` as a shortcut for \`{ returnObjects: true }\`
|
|
584
|
+
* - \`""\` as a shortcut for \`{ fallback: "" }\`
|
|
585
|
+
*
|
|
586
|
+
*/
|
|
587
|
+
export type TranslationShortcut = "obj" | "";
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Query object to populate the returned translated string interpolating data
|
|
591
|
+
* or a TranslationShortcut.
|
|
592
|
+
*
|
|
593
|
+
* NOTE: when using a shortcut passing TranslationOptions to \`t()\` is not supported
|
|
594
|
+
* TODO: type safe this behaviour of the third argument (options).
|
|
595
|
+
*/
|
|
596
|
+
export type TranslationQuery =
|
|
597
|
+
| undefined
|
|
598
|
+
| null
|
|
599
|
+
| TranslationShortcut
|
|
600
|
+
| {
|
|
601
|
+
[key: string]: string | number | boolean;
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Opions of the translate function or a TranslationShortcut.
|
|
606
|
+
*
|
|
607
|
+
* NOTE: when using a shortcut passing TranslationOptions to \`t()\` is not supported
|
|
608
|
+
* TODO: type safe this behaviour of the third argument (options).
|
|
609
|
+
*/
|
|
610
|
+
export type TranslationOptions =
|
|
611
|
+
| undefined
|
|
612
|
+
| TranslationShortcut
|
|
613
|
+
| {
|
|
614
|
+
returnObjects?: boolean;
|
|
615
|
+
fallback?: string | string[];
|
|
616
|
+
default?: string;
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Translate function which optionally accept a namespace as first argument
|
|
621
|
+
*/
|
|
622
|
+
export type Translate<
|
|
623
|
+
TNamespace extends TranslateNamespace | undefined = TranslateNamespace,
|
|
624
|
+
> = TNamespace extends TranslateNamespace
|
|
625
|
+
? TranslateNamespaced<TNamespace>
|
|
626
|
+
: TranslateDefault;
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Translate function **without** namespace, it allows to select any of the all
|
|
630
|
+
* available strings in _all_ namespaces.
|
|
631
|
+
*/
|
|
632
|
+
export type TranslateDefault = <
|
|
633
|
+
TPath extends TranslationsAllPaths,
|
|
634
|
+
TReturn = TranslationAtPath<TPath>,
|
|
635
|
+
>(
|
|
636
|
+
s: TPath,
|
|
637
|
+
q?: TranslationQuery,
|
|
638
|
+
o?: TranslationOptions,
|
|
639
|
+
) => TReturn;
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* Translate function **with** namespace, it allows to select all available
|
|
643
|
+
* strings _only_ in the given namespace.
|
|
644
|
+
*/
|
|
645
|
+
export type TranslateNamespaced<TNamespace extends TranslateNamespace> = <
|
|
646
|
+
TPath extends TranslationsPaths<TranslationsDictionary[TNamespace]>,
|
|
647
|
+
TReturn = TranslationAtPathFromNamespace<TNamespace, TPath>,
|
|
648
|
+
>(
|
|
649
|
+
s: TPath,
|
|
650
|
+
q?: TranslationQuery,
|
|
651
|
+
o?: TranslationOptions,
|
|
652
|
+
) => TReturn;
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Translate function _loose_ type, to use only in implementations that uses
|
|
656
|
+
* the \`t\` function indirectly without needng knowledge of the string it needs
|
|
657
|
+
* to output.
|
|
658
|
+
*/
|
|
659
|
+
export type TranslateLoose<TReturn = string> = (
|
|
660
|
+
s?: any,
|
|
661
|
+
q?: TranslationQuery,
|
|
662
|
+
o?: TranslationOptions,
|
|
663
|
+
) => TReturn;
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Translate function _loosest_ type it allows to return string or object or array
|
|
667
|
+
* or whatever basically.
|
|
668
|
+
*/
|
|
669
|
+
export type TranslateLoosest<TReturn = any> = (
|
|
670
|
+
s?: any,
|
|
671
|
+
q?: TranslationQuery,
|
|
672
|
+
o?: TranslationOptions,
|
|
673
|
+
) => TReturn;
|
|
674
|
+
|
|
331
675
|
|
|
332
676
|
// export type RouteId = keyof typeof routesSlim;
|
|
333
677
|
export type RouteId = RouteIdStatic | RouteIdDynamic;
|
|
334
678
|
|
|
335
679
|
// export type RouteIdStatic = I18n.Utils.RouteStrictIdStatic<RouteId>;
|
|
336
|
-
export type RouteIdStatic = ${
|
|
680
|
+
export type RouteIdStatic = ${s};
|
|
337
681
|
|
|
338
682
|
// export type RouteIdDynamic = I18n.Utils.RouteStrictIdDynamic<RouteId>;
|
|
339
|
-
export type RouteIdDynamic = ${
|
|
683
|
+
export type RouteIdDynamic = ${a};
|
|
340
684
|
|
|
341
685
|
/**
|
|
342
686
|
* Utility standalone type to extract all children routes that starts with the
|
|
@@ -355,14 +699,109 @@ ${i}
|
|
|
355
699
|
> = T extends \`\${TStarts}.\${infer First}\` ? \`\${TStarts}.\${First}\` : never;
|
|
356
700
|
}
|
|
357
701
|
|
|
358
|
-
export namespace I18n.RouteParams {${
|
|
702
|
+
export namespace I18n.RouteParams {${n}}
|
|
359
703
|
|
|
360
704
|
export namespace I18n.Utils {
|
|
361
|
-
|
|
705
|
+
// import type { Trim } from "@koine/utils";
|
|
706
|
+
type Whitespace = \`\u{20}\`;
|
|
707
|
+
type TrimLeft<V extends string> = V extends \`\${Whitespace}\${infer R}\`
|
|
708
|
+
? TrimLeft<R>
|
|
709
|
+
: V;
|
|
710
|
+
type TrimRight<V extends string> = V extends \`\${infer R}\${Whitespace}\`
|
|
711
|
+
? TrimRight<R>
|
|
712
|
+
: V;
|
|
713
|
+
/** A simplified version of type-fest's Trim which creates too complex types */
|
|
714
|
+
type Trim<V extends string> = TrimLeft<TrimRight<V>>;
|
|
715
|
+
|
|
716
|
+
type WithDynamicPortion<F extends string, D extends GenericDelimiters> =
|
|
717
|
+
| \`\${string}\${F}\${D["start"]}\${string}\${D["end"]}\${F}\${string}\`
|
|
718
|
+
| \`\${string}\${F}\${D["start"]}\${string}\${D["end"]}\`
|
|
719
|
+
| \`\${D["start"]}\${string}\${D["end"]}\${F}\${string}\`
|
|
720
|
+
| \`\${D["start"]}\${string}\${D["end"]}\`;
|
|
721
|
+
|
|
722
|
+
type FilterOnlyStaticRouteId<
|
|
723
|
+
T extends string,
|
|
724
|
+
F extends string,
|
|
725
|
+
D extends GenericDelimiters,
|
|
726
|
+
> = T extends WithDynamicPortion<F, D> ? never : T;
|
|
727
|
+
|
|
728
|
+
type FilterOnlyDynamicRouteId<
|
|
729
|
+
T extends string,
|
|
730
|
+
F extends string,
|
|
731
|
+
D extends GenericDelimiters,
|
|
732
|
+
> = T extends WithDynamicPortion<F, D> ? T : never;
|
|
733
|
+
|
|
734
|
+
type InferredSeparator<T extends string> = T extends \`\${string}.\${string}\`
|
|
735
|
+
? "."
|
|
736
|
+
: T extends \`\${string}/\${string}\`
|
|
737
|
+
? "/"
|
|
738
|
+
: never;
|
|
739
|
+
|
|
740
|
+
type GenericDelimiters = {
|
|
741
|
+
start: string;
|
|
742
|
+
end: string;
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
type WithDelimitedString<Start extends string, End extends string> =
|
|
746
|
+
| \`\${string}\${Start}\${string}\${End}\${string}\`
|
|
747
|
+
| \`\${string}\${Start}\${string}\${End}\`
|
|
748
|
+
| \`\${Start}\${string}\${End}\${string}\`
|
|
749
|
+
| \`\${Start}\${string}\${End}\`;
|
|
750
|
+
|
|
751
|
+
type InferredDelimiters<T extends string> =
|
|
752
|
+
T extends WithDelimitedString<"[", "]">
|
|
753
|
+
? { start: "["; end: "]" }
|
|
754
|
+
: T extends WithDelimitedString<"{{", "}}">
|
|
755
|
+
? { start: "{{"; end: "}}" }
|
|
756
|
+
: T extends WithDelimitedString<"{", "}">
|
|
757
|
+
? { start: "{"; end: "}" }
|
|
758
|
+
: never;
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* @borrows [awesome-template-literal-types](https://github.com/ghoullier/awesome-template-literal-types)
|
|
762
|
+
*/
|
|
763
|
+
// prettier-ignore
|
|
764
|
+
export type DynamicParams<
|
|
765
|
+
T extends string,
|
|
766
|
+
Separator extends string = InferredSeparator<T>,
|
|
767
|
+
Delimiters extends GenericDelimiters = InferredDelimiters<T>,
|
|
768
|
+
> = string extends T
|
|
769
|
+
? Record<string, string>
|
|
770
|
+
: T extends \`\${string}\${Delimiters["start"]}\${infer Param}\${Delimiters["end"]}\${Separator}\${infer Rest}\`
|
|
771
|
+
? {
|
|
772
|
+
[k in Trim<Param> | keyof DynamicParams<Rest>]: string | number;
|
|
773
|
+
}
|
|
774
|
+
: T extends \`\${string}\${Delimiters["start"]}\${infer Param}\${Delimiters["end"]}\`
|
|
775
|
+
? {
|
|
776
|
+
[k in Trim<Param>]: string | number;
|
|
777
|
+
}
|
|
778
|
+
// : T extends \`\${Delimiters["start"]}\${infer Param}\${Delimiters["end"]}\`
|
|
779
|
+
// ? {
|
|
780
|
+
// [k in Trim<Param>]: string | number;
|
|
781
|
+
// }
|
|
782
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
783
|
+
: {};
|
|
784
|
+
|
|
785
|
+
export type RouteStrictIdStatic<T extends string> = FilterOnlyStaticRouteId<
|
|
786
|
+
T,
|
|
787
|
+
InferredSeparator<T>,
|
|
788
|
+
InferredDelimiters<T>
|
|
789
|
+
>;
|
|
790
|
+
|
|
791
|
+
export type RouteStrictIdDynamic<T extends string> = FilterOnlyDynamicRouteId<
|
|
792
|
+
T,
|
|
793
|
+
InferredSeparator<T>,
|
|
794
|
+
InferredDelimiters<T>
|
|
795
|
+
>;
|
|
796
|
+
|
|
797
|
+
export type RouteStrictId<T extends string> =
|
|
798
|
+
| RouteStrictIdStatic<T>
|
|
799
|
+
| RouteStrictIdDynamic<T>;
|
|
800
|
+
|
|
362
801
|
}
|
|
363
802
|
`});
|
|
364
803
|
|
|
365
|
-
var e$2 = (()=>({files:[{name:"config",fn:e$4,ext:"ts",index:!0},{name:"defaultLocale",fn:t$3,ext:"ts",index:!0},{name:"deriveLocalisedPathnames",fn:o$2,ext:"ts",index:!0},{name:"isLocale",fn:n$4,ext:"ts",index:!0},{name:"locales",fn:m$4,ext:"ts",index:!0},{name:"pathnameToRouteId",fn:a$3,ext:"ts",index:!0},{name:"routes",fn:r$3,ext:"ts",index:!0},{name:"routesSlim",fn:i$1,ext:"ts",index:!0},{name:"tFns",fn:s$1,ext:"ts"},{name:"tInterpolateParams",fn:f
|
|
804
|
+
var e$2 = (()=>({files:[{name:"config",fn:e$4,ext:"ts",index:!0},{name:"defaultLocale",fn:t$3,ext:"ts",index:!0},{name:"deriveLocalisedPathnames",fn:o$2,ext:"ts",index:!0},{name:"isLocale",fn:n$4,ext:"ts",index:!0},{name:"locales",fn:m$4,ext:"ts",index:!0},{name:"pathnameToRouteId",fn:a$3,ext:"ts",index:!0},{name:"routes",fn:r$3,ext:"ts",index:!0},{name:"routesSlim",fn:i$1,ext:"ts",index:!0},{name:"tFns",fn:s$1,ext:"ts"},{name:"tInterpolateParams",fn:f,ext:"ts",index:!1},{name:"to",fn:x$1,ext:"ts",index:!0},{name:"toFns",fn:d$2,ext:"ts",index:!0},{name:"toFormat",fn:p$1,ext:"ts",index:!0},{name:"types",fn:l$1,ext:"ts",index:!0}]}));
|
|
366
805
|
|
|
367
806
|
var e$1 = (()=>`
|
|
368
807
|
"use client";
|
package/i18nCodegen.esm.js
CHANGED
|
@@ -4,16 +4,16 @@ import { join, dirname, basename, extname, sep } from 'node:path';
|
|
|
4
4
|
import { glob } from 'glob';
|
|
5
5
|
import { f as formatRoutePathname } from './formatRoutePathname.esm.js';
|
|
6
6
|
import { fsWrite } from '@koine/node';
|
|
7
|
-
import {
|
|
7
|
+
import { rmSync } from 'node:fs';
|
|
8
8
|
import * as t$4 from 'typescript';
|
|
9
9
|
|
|
10
10
|
const dataFsConfig={cwd:process.cwd(),ignore:[]};let r$4=(e={})=>mergeObjects({...dataFsConfig},e),i$4=e=>{let{cwd:o,ignore:a}=e;return glob.sync("*",{cwd:o,withFileTypes:!0,ignore:[...a,"node_modules/**"]}).filter(e=>e.isDirectory()).map(e=>e.relative()).sort((e,o)=>e.localeCompare(o))};let getDataFs=async a=>{let s=r$4(a),l=i$4(s),n=[];return await Promise.all(l.map(async a=>{let r=await glob("**/*.json",{cwd:join(s.cwd,a),ignore:s.ignore});await Promise.all(r.map(async t=>{let r=join(s.cwd,a,t),i=await readFile(r,"utf8");i&&n.push({path:t,data:JSON.parse(i),locale:a});}));})),{localesFolders:l,translationFiles:n}};
|
|
11
11
|
|
|
12
|
-
const dataSourceRoutesConfig={translationJsonFileName:"~.json",tokens:{parentReference:"^",idDelimiter:".",pathnameWildcard:"*"}};let i$3=e=>e.replace(/\.index$/,""),o$4=e=>formatRoutePathname(e.replace(/\*/g,"").replace(/[[{]{1,2}(.*?)[\]}]{1,2}/g,(e,t)=>`[${t.trim()}]`)),l$3=r=>capitalize(changeCaseCamel(r)),m$6=(e,t,r,a)=>{let n=t[a].pathnames[r];if(n.startsWith(`/${e.source.routes.tokens.parentReference}`)){let s=RegExp(`^\\/\\${e.source.routes.tokens.parentReference}`);n=n.replace(s,"");let i=a.split(".").slice(0,-1).join(".");if(i)n=m$6(e,t,r,i)+n;else throw Error("Used a parent route token reference without a matching parent route")}return n},p$
|
|
12
|
+
const dataSourceRoutesConfig={translationJsonFileName:"~.json",tokens:{parentReference:"^",idDelimiter:".",pathnameWildcard:"*"}};let i$3=e=>e.replace(/\.index$/,""),o$4=e=>formatRoutePathname(e.replace(/\*/g,"").replace(/[[{]{1,2}(.*?)[\]}]{1,2}/g,(e,t)=>`[${t.trim()}]`)),l$3=r=>capitalize(changeCaseCamel(r)),m$6=(e,t,r,a)=>{let n=t[a].pathnames[r];if(n.startsWith(`/${e.source.routes.tokens.parentReference}`)){let s=RegExp(`^\\/\\${e.source.routes.tokens.parentReference}`);n=n.replace(s,"");let i=a.split(".").slice(0,-1).join(".");if(i)n=m$6(e,t,r,i)+n;else throw Error("Used a parent route token reference without a matching parent route")}return n},p$4=(e,t)=>{forin(t,(a,n)=>{forin(n.pathnames,r=>{t[a].pathnames[r]=m$6(e,t,r,a);});});},c=e=>{let t=e.match(/\[.*?\]/g);if(t)return t.map(e=>e.slice(1,-1).trim()).reduce((e,t)=>(e[t]="stringOrNumber",e),{})},h$2=(e,t)=>{let{defaultLocale:r,locales:a}=e;for(let e in t){let s=t[e].pathnames,i=s[r],o={};for(let e in s){let t=s[e];t!==i&&(o[e]=t);}Object.keys(o).length===a.length-1||(Object.keys(o).length>=1?(o[r]=i,t[e].optimizedPathnames=objectSortByKeysMatching(o,r)):t[e].optimizedPathnames=i);}};let getDataSourceRoutes=(e,{translationFiles:t})=>{let{defaultLocale:r}=e,s=[],m={};for(let p=0;p<t.length;p++){let{path:h,locale:u,data:d}=t[p];if(h===e.source.routes.translationJsonFileName){let t=objectFlat(d,e.source.routes.tokens.idDelimiter);for(let a in t){let p=t[a],h=i$3(a);if(!m[h]){m[h]=m[h]||{};let t=l$3(h),r=c(h),a=p.includes(e.source.routes.tokens.pathnameWildcard);m[h].id=h,m[h].typeName=t,r&&(m[h].params=r),a&&(m[h].wildcard=!0,s.push(h));}m[h].pathnames=m[h].pathnames||{},m[h].pathnames[u]=o$4(p),m[h].pathnames=objectSortByKeysMatching(m[h].pathnames,r);}}}if(p$4(e,m),h$2(e,m),s.length)for(let e in m)s.some(t=>e.startsWith(t)&&t!==e)&&(m[e].inWildcard=!0);return Object.fromEntries(Object.entries(m).sort())};
|
|
13
13
|
|
|
14
14
|
let s$2=["zero","one","two","few","many","other"],a$4="other";let isPluralSuffix=e=>s$2.includes(e)||isNumericLiteral(e);let removePluralSuffix=e=>{let[l]=splitReverse(e,"_");return l?e.replace(`_${l}`,""):e};let isPluralKey=e=>{let[l]=splitReverse(e,"_");return isPluralSuffix(l)};let i$2=e=>{let l={};return e.forEach(e=>{let[r]=split(e,"_");l[r]=l[r]||[],l[r].push(e);}),l};let transformKeysForPlurals=l=>{let r=l.filter(isPluralKey);if(r.length){let t=[...l];return forin(i$2(r),(e,r)=>{l.includes(e)||t.push(e),r.forEach(e=>{l.includes(e)&&(t=t.filter(l=>l!==e));});}),t}return l};let hasPlurals=e=>Object.keys(e).includes(a$4);let hasOnlyPluralKeys=e=>!!hasPlurals(e)&&0===pickNonPluralKeys(e).length;let pickNonPluralKeys=e=>Object.keys(e).filter(e=>!isPluralSuffix(e));let pickNonPluralValue=e=>hasPlurals(e)?objectPick(e,pickNonPluralKeys(e)):e;
|
|
15
15
|
|
|
16
|
-
const dataSourceTranslationsConfig={dynamicDelimiters:{start:"{{",end:"}}"},fnsAsDataSources:!0,fnsPrefix:"",createArrayIndexBasedFns:!1};let u=RegExp(sep,"g"),p$
|
|
16
|
+
const dataSourceTranslationsConfig={dynamicDelimiters:{start:"{{",end:"}}"},fnsAsDataSources:!0,fnsPrefix:"",createArrayIndexBasedFns:!1};let u=RegExp(sep,"g"),p$3=e=>{let t=e.replace(/~/g,"$").replace(/-/g,"_").replace(u,"_").replace(/_+/g,"_").replace(/[^a-zA-Z0-9_$]/gi,"");return /^[0-9]/.test(t)?"$"+t:t},f$1=(e,t)=>{if(isString(t)){let{start:r,end:a}=e.source.translations.dynamicDelimiters,l=RegExp(`${r}(.*?)${a}`,"gm"),s=t.match(l);if(s)return s.map(e=>e.replace(r,"").replace(a,"").trim()).reduce((e,t)=>(e[t]="stringOrNumber",e),{})}},m$5=(e,t)=>(Object.keys(t).filter(isPluralKey).forEach(e=>{let r=removePluralSuffix(e);t[r]&&(t[r].plural=!0),delete t[e];}),t),d$3=(e,t,r,a,l)=>{if(isPrimitive(a)){let s=f$1(e,a);l[t]=l[t]||{},l[t].values=l[t].values||{},l[t].values[r]=a,l[t].typeValue="Primitive",s&&(l[t].params=s);}else {if(e.source.translations.fnsAsDataSources){let e=isArray(a)?"Array":"Object";l[t]=l[t]||{},l[t].values=l[t].values||{},l[t].values[r]=a,l[t].typeValue=e;}if(isArray(a)){if(e.source.translations.createArrayIndexBasedFns)for(let s=0;s<a.length;s++)d$3(e,t+"_"+s,r,a[s],l);}else for(let s in a)d$3(e,t+"_"+p$3(s),r,a[s],l);}return l},g$1=(l,s,n)=>{let{locale:i,path:o}=s,c=join(dirname(o),basename(o,extname(o)));for(let e in s.data){let t=s.data[e];d$3(l,p$3(c+(e?"_"+e:"")),i,t,n);}return n};let getDataSourceTranslations=(e,{translationFiles:t})=>{let r={};for(let a=0;a<t.length;a++)t[a].path!==e.source.routes.translationJsonFileName&&g$1(e,t[a],r);return Object.fromEntries(Object.entries(r=m$5(e,r)).sort())};
|
|
17
17
|
|
|
18
18
|
const dataSourceConfig={routes:dataSourceRoutesConfig,translations:dataSourceTranslationsConfig};let getDataSource=(t,r)=>({routes:getDataSourceRoutes(t,r),translations:getDataSourceTranslations(t,r)});
|
|
19
19
|
|
|
@@ -170,7 +170,7 @@ export default routesSlim;
|
|
|
170
170
|
|
|
171
171
|
let dataParamsToTsInterfaceBody=e=>Object.keys(e).reduce((r,t)=>{let a=e[t],s="";switch(a){case"number":s="number";break;case"string":s="string";break;default:s="string | number";}return r.push(`${t}: ${s};`),r},[]).join(" ");
|
|
172
172
|
|
|
173
|
-
let i=e=>isString(e)||isNumber(e)?`"${e}"`:isBoolean(e)?`${e}`:isArray(e)?JSON.stringify(e):`(${JSON.stringify(e)})`,p$
|
|
173
|
+
let i=e=>isString(e)||isNumber(e)?`"${e}"`:isBoolean(e)?`${e}`:isArray(e)?JSON.stringify(e):`(${JSON.stringify(e)})`,p$2=(t,r)=>areEqual(t,r),m$3=(e,r)=>{let{defaultLocale:o}=e,l="";return forin(r,(e,t)=>{e===o||p$2(t,r[o])||(l+=`locale === "${e}" ? ${i(t)} : `);}),l+=i(r[o])};var s$1 = (({config:e,data:r})=>{let o=`
|
|
174
174
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
175
175
|
/* eslint-disable prefer-const */
|
|
176
176
|
import type { I18n } from "./types";
|
|
@@ -179,7 +179,7 @@ import { tInterpolateParams } from "./tInterpolateParams";
|
|
|
179
179
|
`;return forin(r.source.translations,(t,{values:r,params:l,plural:s})=>{let p=`${e.source.translations.fnsPrefix}${t}`;l&&s&&(l.count="number");let $=[l?`params: { ${dataParamsToTsInterfaceBody(l)} }`:"","locale?: I18n.Locale"].filter(Boolean).join(", ");o+=`export let ${p} = (${$}) => `;let f="";isPrimitive(r)?f+=i(r):f+=m$3(e,r),f=l?`tInterpolateParams(${f}, params);`:`${f};`,o+=f+`
|
|
180
180
|
`;}),o});
|
|
181
181
|
|
|
182
|
-
let e$3=e=>e.split("").map(e=>`\\${e}`).join("");var f
|
|
182
|
+
let e$3=e=>e.split("").map(e=>`\\${e}`).join("");var f = (({config:a})=>{let{start:t,end:r}=a.source.translations.dynamicDelimiters;return `
|
|
183
183
|
export let tInterpolateParams = (
|
|
184
184
|
value: string,
|
|
185
185
|
params?: object,
|
|
@@ -231,7 +231,7 @@ import type { I18n } from "./types";
|
|
|
231
231
|
`;return forin(a.source.routes,(t,{typeName:a,pathnames:n,params:p})=>{let s=`to_${changeCaseCamel(t)}`,i=`I18n.RouteParams.${a}`,u=[p?`params: ${i}`:"",m?"":"locale?: I18n.Locale"].filter(Boolean).join(", "),c=m?'""':"locale",f=p?", params":"";$+=`export let ${s} = (${u}) => `,isString(n)?$+=`toFormat(${c}, "${n}"${f});`:$+=`toFormat(${c}, ${r$2(l,n)}${f});`,$+=`
|
|
232
232
|
`;}),$});
|
|
233
233
|
|
|
234
|
-
var p = (({config:a})=>`
|
|
234
|
+
var p$1 = (({config:a})=>`
|
|
235
235
|
export function toFormat(
|
|
236
236
|
locale: string | undefined,
|
|
237
237
|
pathname: string,
|
|
@@ -288,33 +288,377 @@ export function toFormat(
|
|
|
288
288
|
export default toFormat;
|
|
289
289
|
`);
|
|
290
290
|
|
|
291
|
-
let
|
|
291
|
+
let p=(t,n)=>{if(!isArray(n)&&isObject(n)){if(hasOnlyPluralKeys(n))return `'${t}': string;`;if(hasPlurals(n))return `'${t}': string | ${d$1(pickNonPluralValue(n))}`}return `'${t}': ${d$1(n)}`},d$1=t=>{let i="",r="";if(isBoolean(t)?r="boolean":isString(t)&&(r="string"),r)i+=r+";";else if(t){if(isArray(t)){let e=t[0];i+=`${d$1(e)}[];`;}else if(isObject(t)){i+="{";let e=transformKeysForPlurals(Object.keys(t));for(let n=0;n<e.length;n++){let s=e[n],a=t[s]||"";i+=p(s,a);}i+="};";}}else i+="";return (i=i.replace(/;\[\];/g,"[];")).replace(/;+/g,";")},h$1=(t,e)=>{let{translationFiles:n}=e,{defaultLocale:s}=t,a=n.filter(t=>t.locale===s),i=`
|
|
292
292
|
export interface Translations {
|
|
293
|
-
`;for(let
|
|
293
|
+
`;for(let t=0;t<a.length;t++){let{path:e,data:n}=a[t],s=e.replace(".json","");i+=`"${s}": ${d$1(n)}
|
|
294
294
|
`;}return i+`
|
|
295
295
|
}
|
|
296
|
-
`},m$2=e=>{let
|
|
297
|
-
`);}),
|
|
296
|
+
`},m$2=e=>{let n="\n";return forin(e,(t,{typeName:e,params:s})=>{s&&(n+=` export interface ${e} { ${dataParamsToTsInterfaceBody(s)} }
|
|
297
|
+
`);}),n},g=(t,e)=>Object.keys(t).filter(n=>e(n,t[n])).sort().map(t=>`"${t}"`).join(" | ");var l$1 = (({config:t,data:e})=>{let n=m$2(e.source.routes),s=g(e.source.routes,(t,e)=>!e.params),a=g(e.source.routes,(t,e)=>!!e.params);return `
|
|
298
298
|
/* eslint-disable @typescript-eslint/no-namespace */
|
|
299
299
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
300
300
|
/* eslint-disable @typescript-eslint/ban-types */
|
|
301
301
|
|
|
302
302
|
export namespace I18n {
|
|
303
|
-
export type Locale = ${
|
|
303
|
+
export type Locale = ${t.locales.map(t=>`"${t}"`).join(" | ")};
|
|
304
304
|
|
|
305
305
|
export type LocalesMap<T = any> = Record<Locale, T>;
|
|
306
306
|
|
|
307
|
-
${
|
|
308
|
-
|
|
307
|
+
${h$1(t,e.fs)}
|
|
308
|
+
|
|
309
|
+
// import type {
|
|
310
|
+
// // Get,
|
|
311
|
+
// Split,
|
|
312
|
+
// } from "@koine/utils";
|
|
313
|
+
|
|
314
|
+
type Split<
|
|
315
|
+
S extends string,
|
|
316
|
+
Delimiter extends string,
|
|
317
|
+
> = S extends \`\${infer Head}\${Delimiter}\${infer Tail}\`
|
|
318
|
+
? [Head, ...Split<Tail, Delimiter>]
|
|
319
|
+
: S extends Delimiter
|
|
320
|
+
? []
|
|
321
|
+
: [S];
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* @file
|
|
325
|
+
*
|
|
326
|
+
* Test this on TSplayground:
|
|
327
|
+
* https://www.typescriptlang.org/play?#code/PTAEFpK6dv4YpSBQJSgJYEYAcA7YAFwE8AHTfAcwGcA6AEzqJrTGQ86+7hRQYCmAYwA2AQwBOA0PjEBbATTJih0gJJ58oAN4oMlIgIkAzFdIAqEsfhriimAPY2dejKHQAiAH4eAXKGsSAG5XAF8+fXxDEzNQS2tbMXsnGgBhJ2NMKh1w8LYIHkKi4sh8rE1ickVmVnQS+obUFFIyaQApB0oAHgBlbAAaUB6AJgA+UABeIexQAQAPQ3wGGlAaIglKKlcAfiHh2YWBJZW1jepXDF2AAwASbT7QujuR0KuL0H8+1398AQA3IwhNAAKmBemBoAAIpghMlZBISKAHMYAiIRKAiAALaTrBJ2Rw2cHAFDzMgOCREDFVOJWGz4lLQ2EEySIqYaAh0eJ0pIEmhA4Cg8GgABy8kUylUJ0xDgAriIGKA5EkhJiMdjQJkREcxSsAO5GHG0xJwlaSaSCTK-BhEklzMkUqmtGl4pICUUKJSxKYAUQWVlhXQA1gISMjndyTYy4SzBqdNqN+YLQBCAErCGUSGiYAGKsRkVoKlo4hwHXGw1HomU0MQAIy1q3Wm1AyixK2MEgccgCGKN9PwQotlEwcKRNYAVsJKQAKKsysRoxHtzvdto9ADywo1mC1AEo6EK1JSq4o1dIrpRjEYrqAPI2hIGPBiS2tyTj1Q5x5OsFoFHJyYjrAVMgpABKIhQAbQvIdDG-NZrHsHknFmCQO0zABdKdMSIIgyBoXwQDg+8HABEwRAcXU6CETtgAAR2AAB2ABWRiAGZsBYgA2DjgGwABOFjcF4+iAAYdxtUlyUpItw2NXkAAUkkxGgulccwUHGKZdAwcCAGlv1AX0yyIIMQzDcxY0bahRjQ3x3nQeZRBlQRZjkMhSFHCdYRoQYBFc9zJCsEhvJctzETjahWDcOJdLQ0sjmWUA0yoiQGC6cKqEGX4SPGAAfGR-iMcDYryjxH12LKjDssApCEDMswBERESVWQqGkD9PJYd5-HMGK4uORLhHJVL0sGGV8EDfByPwcZdneDA8tubQdNedwwCxTAVg2p9QBraRa3rIgS2PU8b3ax8aGlClaqIObQDyjpuh0wYuVklIFNbLoep0tDRlGKqK3I5sNjkYdsxPckAhQsRETDYDMBB+wAUitxut6+ZFgS9K7pkGU5F2iRsZrBwHC1axsYAQShkg0ss7I8vwXH8cJ4nSem0BrjuZa3ii+y5kc5zAnW6hZhEGgBC6-KSJCUJwMM-1jODUMUXMhszioay+oSi8jFANd2d1j5JcBPgBTBZMBtqzMwdzfMBELakw3nStqzraQsZbJSNQ7LssWkXVpQO3tEMJc2GBhaMEToUBD1AY8Vl90Bz3wS8JGvW8NnvR9DobV8Tvar9KEVXz-wCJYgYKsDzcg5PoOkSg4KiTBg+Q1CaAwrCcLwgiiBUQNiKMYwyIoqi5FohjmLYzjuL4gShNE8S7Ukx0LCDk1ybRd7Pc01xwM3Qu5ZUBXTOV1feSjZkEQstXrP8LS3F0-SD4DRWzNPhlw4vkhd7Q-p0pv27eb82kL5UKHlJzBRAf5KmEC-JhVpsjKKL0+w0HPk4Fk380aHH6klIaNM1aZQKhIXKRsJBFWxqVfWFUJAAOqumK2DUmrWDEK1MBXlbrdTfjYVB8Iv7CjQpgjGKwcEpTwZsUa41Jq6jZtsW6UUFp3GFKEXwnMVroHWpteOJZdoBFdttY6CcPBnVWJdIg11ZFuHup0fAXQ9Lo3iicWm+tFqKOUUtFa-hnFKKuM9ThNBN7KSQcHFBH80EIgwd9X6NCAa6iBvDUGSMkQEwCtDJEKI4YIzBgglGMlkHcPQXwgR9jVZNnpozHWeUiYkwEGTPKlNAqiOFqUvG5Sdos2qdIxOCilEqO5lFVaBwgGlxIELbIAhRbiz6YbKhYRZZ+kPiZJWOSgl5LCXwq+8Y0LS1mUZBZr8XSRhCTw9ZVlYp2P6trAmetdh6x+IQxMZsIQAFV8AiEwMGfSVxfgLHALiCMAhrz6gCAwICYgaBZmFjQTs0hgJ2wEJaO2kMqC4yOCwAIkUIQXUktdNsEMR5-i0MdIQoLFC2XNuAROhjxweGvKC7smKroykpMYCGVxtCgCkEQDM+A1yfi8v4dYMppCvCFOSq4pUaWmmMVixlGoWVstMGiGsvd-AUOFcmBe9opLUkCXCHoJjrqTFOlS8hHh7lCgAIqCoRKwqSJYyRkDlK6E6HKuUIt+caBFWMDBGDJPiYWDAkhiCFBDMQSzdX6sZfudV5thRrnMN6fw-sjix3BdkUN9LTEyuUGCpsOqCRrjcrybaVwiBTh3NeLak1KQ0BlPmSSdshTmDXJCNc-LqTVkvGqLau1MRiD+I4DMqSTrrRSoi5FURQBTgcIWlIe4NVL2knmpwlqjCslcHlMag4rTrpxmiHdS78B6ulTdeaLhJngUVv4dKNlimNJxs0gmFS2nWBCFFUIZrzYFqLWGBO7q7DSGMGNJkSEQ1hoJEehlRAo0PJFHGhNoAk0EtTXSiNlJs3IYPQWk0xbS3lqwCsKtqxa2aobebJtLa21Og7W+btAhe39tlATH96oR0KkkEihQE6p0zpsHO5MxIJIOkXZwrDRaJg7s3XCygpHsYHog5mk92M75RRdRIblvKWDbH8JU1mr6+kKpEEq+8Wnb101M0VPTUULRiDlEQEz6VLOgHfSbJMEIdUAaAyOf2MJVTTujAuAIQhVBuW7LID0Eo9ptkwJmSk7Hx0nuBAJxeQntWrwEJ9d04pYhnISu5zLnpVDY0k-ChgGlVL5Yi5rFYeWdQRfeLsGr4WzCpXMBVswf0oocP2QISEcKbMiCIB+tzaWNSeYJMmYEuphzSkZaCGQtWzCDGHNEzRqwxlfkCEOhOTshR9rENufabt4H6SdvNprkpoNJc1cvMNPW+u2cNZ9NMnK1OGr-lOVweEwMpHXiIfx-RXA0RMweldl9XAOGByJnjrAdyTHGOYZ7XKhu3dG-gYDWhQRTaxHNsLWXVBLdi2iciq2xZanLE4RqJ1Tt7YO67IU6VNpaATlQMGWhccFYEJd2013hPdba6oFr-PgFYNy2loXGlQAqQwAjgQL2tBTHSupD7GAvsHr8YpAJviVlf1awt1QP0AcYCB11iMBJQckEN0iSH+z83Q5QLDiY8PEdqeR+51H6PQBkQcGLZegxs7HQp4iQu8MyBak4z3bDWIkgpsUEKBOJbryAbRyOSgYcapEEp1jmblJfh22FhNciWoGAsOY0dtWWAc8CDtui7asocKRvnSlp07mAAyxMfdTGV6sEzgRLfG++-gc3luIcm9etyu3DvxgOZczBgAQoiKi+BQIjg7Iyk8W7QYpEhnXJn6orheDoGOSF+BE-bh3ydMiRKtQ0GANoS-84BChGJObDsDgmUk0EBIKO5hMRbWklIGFMWCdQhREMkHNOsREXHLbdULdBFVfQwAAchr3v1eTFhBSxCgKnArgQ2m1AAYBIDCxhGbEkl5D40S25wXVS26wYBTDr2kCmDV38U+i10OXQW8A8B+mR0eXsFeXcgbgDTIl+Bu2znRnlgrEnSVDmAxF1BLC1AajwIEDckxFhxVG3AYCkC0HgNj3Nij2rR7gpD1FwOZ1Z1M2g0bV-w0Rj0A3RGzlaiknVBrRrC0JWEdi0DzFDxhGbjNDEB8joCoCjlO0cOcODRRFDQDQuiJkkAYFGmQ2Wyz1JRgyuCSLj2pEhFBUxEiJSloLXxWAYLSxoLoLSF-3lA0LXGMC6A8HCIyIcCiI8ATCFCSO5nIMEy1Wb3yOyMMCKLUNKPKNUh6H0NRRywcXwVUiq1M0NXcwKLX3UgmLGMWnMH6MkBYEeDuAuVAAADFos1gVjtA1iehBolg1V9ZNiYtsZFoTjtinh7gDiGAjj-B7JbADBwAw4XYtRwAvkiBwBXkhCAABIsGgIQDYNycARQb4ogYASacAMaY8BgcAP4SQZGcwOYu4BYgYmgHYtYi4ogI43YLE74EhfkdgRoYkkk8AMoHAAgYAOw8wGofIUk+k+oPgFom7AAcVlyRKmClziCFzGMazx2kA3SWCkytENWK2k2tFGC7xQIEHs1pkt3Zwi2ByF3tzh1ADkm9g2nS3cwyz1wEF+mR1BFjXjVBG6hLCVHeX+MBMwBCxkIkEDBkBhDGURGxCkFzHeRrVdJENkDpyriuCkEhREABDaGPwAFkHAGA5R-l25sJcJ8JgBdQEzmAqgASgSM9rB-DyQqBiAASMgsgABif0kmIM0M8MyMsSc2QuUMQdEtHMmufwo-JwU-LULnZkxfNYUAakw1KcMtVU7QUIWHWlNkogcwQkgoBk8c7gckioY8GkzqOoCchcjgJk5LSkQQUQM0d3EcGcstUff9XrUwWzEIZktc8QV0pPD3GcnU87YXQRW7cXKcBUswbqIXHcXc10IXQXXU+oukxc38hAKcykw6Wk+cv80C6AE2MAEPSgp0NlPkjnaI27KYmCUIL2ZcDwOgSoVoGgcACk-AU1PgaSNcF5EgRY+wIQT6MYv+WYoYndRadKR4cCO4eitCK4+i3peRbQeiugRizi2mUINCdixOHi5i1iviwSq4YSvigSnYEhfEkcgi6kIixqSEAg+QGECioY0zCXJEmi09Oivi7ipiqS0StWI4jiriyS0y6SvSyyzYfikyuy8S2y6gfi3pBrfEqhZHH4omFCYnUAcCMQfUSFBQH5EBf9L44cIwecH5ZM6MzuOMlnLEGUGsSiaiKgGbNETAIwYAQKxQKFUK1ycK3gqKkQGKrCgsugiQcAZQKwOQbCmq1Ncs8g6SJ+IgDogQBSWqgJSi2mCXLGTStSS4C2XBEaLS-Eh4sE54jaQ7d49GCK34y01MkEx4qICEhwKEhmNAuEhE0YzSxaNYgAfUWIpBllWOTh1k6vkHsrOpTgGm2Lcp0H8vtMLkuq7DyhfhRFavateuUjTDWBvnGKaSZnCAwHuLAFBKeJeJmo+PmukD+OTKtOBIhtWshOhK2vhMzF2pFxWH2vOoJiOoGNOt2LxrVMkCuusv1jZQvX0lepvSxiBp1hBsNj7KBGZMXQcDdzyL511NSnYO-LZu1QcFIphHasNSUpIoj3UsmPav5pXJu3MAcBUsIKEFFqmHFqVrUvIulroNlp50FsploEmB3XAgVuFpVroLQmNoVo1pBnNrX0GC+roJ+s+kVtUttpls2RnwaIVuvFxwVC0Njh4OHBICjhjhUGC0pAEGmx1nTU2HrDi3DywBRF0PwzpUlqECFADqgNAzFkXzYwkA4xRTVGj29QkF9VdHjhgLdqIM1W-WMDj3VCzrFG-xY2TOgMUGhRIK3w3Js0OiVDIqdiDzxqkCYHBCFG8vJA7F1BWACqCvysMEKtdAiuiGiv+LitjJAESsxGStStHnStlEyuytyuCoEAKtDyXuKqsFKv+KaquyXnPJHEOinDoBfvYy+xNo5rS0GBfs5AcANrblhzvi1EpCkHxBzCmFKj0zbMpHAiIFiimDfqBH0BRCnDfroC1GoCxEmAmCmBYkAfeEwBQbfvAmGDQnwcmVAZ5HAYxFQYLpoHAmwB-kRXodIb3AAPEFUCnA8GBA8EGFKh3EcyZpQrGR90IcnTQYwaoCwZwamGGHIbcEocRnoJoeIcYYEbCAiHZVly5S0bAYEGlggrHLArAoAsIBnIcGAqJOMZMYoIdAfvG3MZ7LvmgYxFFLFnMC4Z8HUYwFUy0GftfrodNP-snyfCnCIG-oCdoHUbyBAusb-PJMKt8hRR1k6LnKsbid-L4BcecMNTvmlAUBVWAF4dcFrDr0KdKcZShJoA8BQGcxQBcYbPwE2K1AUlagAAkoVcnXB7AM8BAVUOmFBmxmEBAam6mGnj9mmOrhnyYiYZVt4MAemtQVUZm68hnWpimMAFAe5b53hcdln8o1gEUtnQ1ccamMBQhLdUCiB-BwJ3hDFfgNm3BbwZCznQAf5XBIESBb4LmPnYEW8Nprn-LLa6mTyNzHzCt2QtA75S7TBCs1cz0nmfBKMBAwxnDHN8m+nl4wxGnJnWmBABn9H3gKnAWixsWJmz88WVnGU9M8hIhohYWV4bcUhRMt8+zanlzrtQUCChBNzxsczWgnHNG1FFBAWZzXBYmmgMAXHKQphtzvH+k3AAA9GRKVlIKSAltxgQDxjwDFjweV9AJVlV0AaVqlmVmPbV4lvVvTA1jAZVoVtaEV-wcx0uQsBwcV9JyV41tVjEdq3I81zxq191qKO11VmwI8NAhWzVhWsta1sAQ1+1jER1js9koNrgVwaV31tMP8GCBB3UfbSkakrho4Xhm8Lx2N4No16VglrNt-ZRwK-N5N4cotvCvh3V-VuN21mRdN712BmtwwYYP3TN4uftv3at4dgQAdjEU1vtid+BgIPN5bdUzsTUugJ2KcW5qKQtjwYtncS3DALd4tvhrxvdxt7Vw9m8Ntk9g9ltm8S13d1wMh8t+N7tsN0zP15TAIflLhjF3wRZkZ+9qKGsflAlrhv9vVk9oQL9jwYl3wY5ugU5gDtwBgflU1rhuDhDk9zFmE6N6D2ZogcD94YwflBwMJ311tqFAjzd-lId7NgQb9ijxDjATEYDqFGd0D4cLUSjtwTAaj8d4YLhmD9DsULj-QYYFDvDmd-jjwK5kTz3ajwoyTgTvD2T9AP47C0kScEE3ygmT5yGQKKUA+hUQjbRY8Q7d4OQcTuvItv5gFlTsANTkEu0TTowVCEKdyfOLyKVOUIzt-HaaQUzn0twCzqdvD6z0KWThwFjhQRT28Dj-9sINFL1sNp9ztvgUIIAA
|
|
328
|
+
*
|
|
329
|
+
* @see
|
|
330
|
+
* - https://stackoverflow.com/q/75531366/1938970: fix for Type instantiation is excessively deep and possibly infinite in Promise.all
|
|
331
|
+
*
|
|
332
|
+
* @notes
|
|
333
|
+
* I might take a better look at how things were done in [i18next](https://github.com/i18next/i18next/blob/master/index.d.ts)
|
|
334
|
+
*/
|
|
335
|
+
|
|
336
|
+
type MergeDictionaries<T, K> = Omit<T, keyof K> & K;
|
|
337
|
+
|
|
338
|
+
type Join<A, Sep extends string = "", R extends string = ""> = A extends [
|
|
339
|
+
infer First,
|
|
340
|
+
...infer Rest,
|
|
341
|
+
]
|
|
342
|
+
? Join<
|
|
343
|
+
Rest,
|
|
344
|
+
Sep,
|
|
345
|
+
R extends "" ? \`\${First & string}\` : \`\${R}\${Sep}\${First & string}\`
|
|
346
|
+
>
|
|
347
|
+
: R;
|
|
348
|
+
|
|
349
|
+
type BuildRecursiveJoin<TList, TSeparator extends string> = Exclude<
|
|
350
|
+
TList extends [...infer ButLast, unknown]
|
|
351
|
+
? Join<ButLast, TSeparator> | BuildRecursiveJoin<ButLast, TSeparator>
|
|
352
|
+
: never,
|
|
353
|
+
""
|
|
354
|
+
>;
|
|
355
|
+
|
|
356
|
+
type JoinObjectPath<S1, S2> = S1 extends string
|
|
357
|
+
? S2 extends string
|
|
358
|
+
? \`\${S1}.\${S2}\`
|
|
359
|
+
: S1
|
|
360
|
+
: never;
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* A very simplified version of \`type-fest\`'s \`Get\` type
|
|
364
|
+
*/
|
|
365
|
+
type GetWithPath<BaseType, Keys extends readonly string[]> = Keys extends []
|
|
366
|
+
? BaseType
|
|
367
|
+
: Keys extends readonly [infer Head, ...infer Tail]
|
|
368
|
+
? GetWithPath<
|
|
369
|
+
Head extends keyof BaseType ? BaseType[Head] : unknown,
|
|
370
|
+
Extract<Tail, string[]>
|
|
371
|
+
>
|
|
372
|
+
: never;
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* A very simplified version of \`type-fest\`'s \`Get\` type, its implementation
|
|
376
|
+
* of square brackets doesn't match our convention as we always keep dots
|
|
377
|
+
* around the brackets and the brackets do not mean dynamic object access but
|
|
378
|
+
* just a dynamic portion of a route.
|
|
379
|
+
*/
|
|
380
|
+
type Get<BaseType, Path extends string | readonly string[]> = GetWithPath<
|
|
381
|
+
BaseType,
|
|
382
|
+
Path extends string ? Split<Path, "."> : Path
|
|
383
|
+
>;
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
*
|
|
387
|
+
*/
|
|
388
|
+
type TranslationsDictionaryDefault = {
|
|
389
|
+
// "~": any;
|
|
390
|
+
"~": {
|
|
391
|
+
test: string;
|
|
392
|
+
static: string;
|
|
393
|
+
dynamic: {
|
|
394
|
+
static: string;
|
|
395
|
+
"[key]": {
|
|
396
|
+
index: string;
|
|
397
|
+
"[id]": string;
|
|
398
|
+
};
|
|
399
|
+
};
|
|
400
|
+
};
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Dictionary of all the translations
|
|
405
|
+
*
|
|
406
|
+
* It must uses \`~\` as namespace for routes defintions to make the \`to\` and \`useTo\`
|
|
407
|
+
* working
|
|
408
|
+
*/
|
|
409
|
+
export type TranslationsDictionary = MergeDictionaries<
|
|
410
|
+
TranslationsDictionaryDefault,
|
|
411
|
+
I18n.Translations
|
|
412
|
+
>;
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Namespaces should match the filenames were translations are defined
|
|
416
|
+
*/
|
|
417
|
+
export type TranslateNamespace = Extract<keyof TranslationsDictionary, string>;
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Translation **value** found at a specific _path_ in the given _namespace_
|
|
421
|
+
*
|
|
422
|
+
* \`TPath\` can be any of all possible paths:
|
|
423
|
+
* - \`plusKey\` sub dictionaries within a namespace
|
|
424
|
+
* - \`plusKey.nested\` whatever nested level of nesting within a namespace
|
|
425
|
+
*/
|
|
426
|
+
export type TranslationAtPathFromNamespace<
|
|
427
|
+
TNamespace extends TranslateNamespace,
|
|
428
|
+
TPath extends TranslationsPaths<TranslationsDictionary[TNamespace]>,
|
|
429
|
+
> = TNamespace extends TranslateNamespace
|
|
430
|
+
? TPath extends string // TranslationsPaths<TranslationsDictionary[TNamespace]>
|
|
431
|
+
? Get<TranslationsDictionary[TNamespace], TPath>
|
|
432
|
+
: TranslationsDictionary[TNamespace]
|
|
433
|
+
: never;
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* The generic type passed and to use with {@link TranslationAtPath} when you
|
|
437
|
+
* want to build a type extending that
|
|
438
|
+
*/
|
|
439
|
+
export type TranslationAtPathGeneric =
|
|
440
|
+
| TranslateNamespace
|
|
441
|
+
| TranslationsAllPaths;
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Translation **value** found at a _path_
|
|
445
|
+
*
|
|
446
|
+
* \`TPath\` can be any of all possible paths begininng with a namespace:
|
|
447
|
+
* - \`namespace\` only a namespace
|
|
448
|
+
* - \`namespace:plusKey\` sub dictionaries within a namespace
|
|
449
|
+
* - \`namespace:plusKey.nested\` whatever nested level of nesting
|
|
450
|
+
*/
|
|
451
|
+
export type TranslationAtPath<TPath extends TranslationAtPathGeneric> =
|
|
452
|
+
TPath extends TranslateNamespace
|
|
453
|
+
? TranslationsDictionary[TPath]
|
|
454
|
+
: TPath extends \`\${infer Namespace}:\${infer Path}\`
|
|
455
|
+
? Namespace extends TranslateNamespace
|
|
456
|
+
? Get<TranslationsDictionary[Namespace], Path>
|
|
457
|
+
: never
|
|
458
|
+
: never;
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* All translations paths from the given _path_
|
|
462
|
+
*
|
|
463
|
+
* \`TPath\` can be any of all possible paths begininng with a namespace:
|
|
464
|
+
* - \`namespace\` only a namespace
|
|
465
|
+
* - \`namespace:plusKey\` sub dictionaries within a namespace
|
|
466
|
+
* - \`namespace:plusKey.nested\` whatever nested level of nesting
|
|
467
|
+
*/
|
|
468
|
+
export type TranslationPathsFrom<TPath extends TranslationAtPathGeneric> =
|
|
469
|
+
TPath extends TranslateNamespace
|
|
470
|
+
? TranslationsPaths<TranslationsDictionary[TPath]>
|
|
471
|
+
: TPath extends \`\${infer Namespace}:\${infer Path}\`
|
|
472
|
+
? Namespace extends TranslateNamespace
|
|
473
|
+
? Get<TranslationsDictionary[Namespace], Path> extends object
|
|
474
|
+
? TranslationsPaths<Get<TranslationsDictionary[Namespace], Path>>
|
|
475
|
+
: TranslationsPaths<TranslationsDictionary[Namespace]>
|
|
476
|
+
: never
|
|
477
|
+
: never;
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* All translations _paths_ of the given one, e.g. if \`TPath\` would be
|
|
481
|
+
* \`"dashboard.users.[id].edit"\` the generated type would be the union
|
|
482
|
+
* \`"dashboard.users.[id]" | "dashboard.users" | "dashboard"\`.
|
|
483
|
+
*/
|
|
484
|
+
export type TranslationsPathsAncestors<
|
|
485
|
+
TPath extends string,
|
|
486
|
+
TSeparator extends string = ".",
|
|
487
|
+
> = BuildRecursiveJoin<Split<TPath, TSeparator>, TSeparator>;
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Recursive mapped type to extract all usable string paths from a translation
|
|
491
|
+
* definition object (usually from a JSON file).
|
|
492
|
+
* It uses the \`infer\` "trick" to store the object in memory and prevent
|
|
493
|
+
* [infinite instantiation errors](https://stackoverflow.com/q/75531366/1938970)
|
|
494
|
+
*/
|
|
495
|
+
export type TranslationsPaths<T, TAsObj extends boolean = true> = {
|
|
496
|
+
[K in Extract<keyof T, string>]: T[K] extends // exclude empty objects, empty arrays, empty strings
|
|
497
|
+
| Record<string, never>
|
|
498
|
+
| never[]
|
|
499
|
+
| ""
|
|
500
|
+
? never
|
|
501
|
+
: // recursively manage objects
|
|
502
|
+
T[K] extends Record<string, unknown>
|
|
503
|
+
?
|
|
504
|
+
| (TAsObj extends true ? \`\${K}\` : never) // this is to be able to use the "obj" shortcut
|
|
505
|
+
| JoinObjectPath<K, TranslationsPaths<T[K], TAsObj>>
|
|
506
|
+
: // allow primitives or array of primitives
|
|
507
|
+
// TODO: support array of objects recursively? For now we just stop at the array name
|
|
508
|
+
T[K] extends
|
|
509
|
+
| string
|
|
510
|
+
| number
|
|
511
|
+
| boolean
|
|
512
|
+
| Array<string | number | boolean | object>
|
|
513
|
+
? \`\${K}\`
|
|
514
|
+
: // exclude anything else
|
|
515
|
+
never;
|
|
516
|
+
}[Extract<keyof T, string>] extends infer O
|
|
517
|
+
? O
|
|
518
|
+
: never;
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Recursive mapped type of all usable string paths from the whole translations
|
|
522
|
+
* dictionary. It uses the \`infer\` "trick" to store the object in memory and prevent
|
|
523
|
+
* [infinite instantiation errors](https://stackoverflow.com/q/75531366/1938970)
|
|
524
|
+
*/
|
|
525
|
+
export type TranslationsAllPaths = {
|
|
526
|
+
[N in Extract<keyof TranslationsDictionary, string>]: {
|
|
527
|
+
[K in Extract<
|
|
528
|
+
keyof TranslationsDictionary[N],
|
|
529
|
+
string
|
|
530
|
+
>]: TranslationsDictionary[N][K] extends // exclude empty objects, empty arrays, empty strings
|
|
531
|
+
| Record<string, never>
|
|
532
|
+
| never[]
|
|
533
|
+
| ""
|
|
534
|
+
? never
|
|
535
|
+
: // recursively manage objects
|
|
536
|
+
TranslationsDictionary[N][K] extends Record<string, unknown>
|
|
537
|
+
?
|
|
538
|
+
| \`\${N}:\${K}\` // this is to be able to use the "obj" shortcut
|
|
539
|
+
| JoinObjectPath<
|
|
540
|
+
K extends string ? \`\${N}:\${K}\` : \`\${N}:\`,
|
|
541
|
+
TranslationsPaths<TranslationsDictionary[N][K]>
|
|
542
|
+
>
|
|
543
|
+
: // allow primitives or array of primitives
|
|
544
|
+
// TODO: support array of objects recursively? For now we just stop at the array name
|
|
545
|
+
TranslationsDictionary[N][K] extends
|
|
546
|
+
| string
|
|
547
|
+
| number
|
|
548
|
+
| boolean
|
|
549
|
+
| Array<string | number | boolean | object>
|
|
550
|
+
? \`\${N}:\${K}\`
|
|
551
|
+
: // exclude anything else
|
|
552
|
+
never;
|
|
553
|
+
}[Extract<keyof TranslationsDictionary[N], string>];
|
|
554
|
+
}[Extract<keyof TranslationsDictionary, string>] extends infer O
|
|
555
|
+
? O
|
|
556
|
+
: never;
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Unlike in \`next-translate\` we allow passing some predefined arguments as
|
|
560
|
+
* shortcuts for common use cases:
|
|
561
|
+
* - \`"obj"\` as a shortcut for \`{ returnObjects: true }\`
|
|
562
|
+
* - \`""\` as a shortcut for \`{ fallback: "" }\`
|
|
563
|
+
*
|
|
564
|
+
*/
|
|
565
|
+
export type TranslationShortcut = "obj" | "";
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Query object to populate the returned translated string interpolating data
|
|
569
|
+
* or a TranslationShortcut.
|
|
570
|
+
*
|
|
571
|
+
* NOTE: when using a shortcut passing TranslationOptions to \`t()\` is not supported
|
|
572
|
+
* TODO: type safe this behaviour of the third argument (options).
|
|
573
|
+
*/
|
|
574
|
+
export type TranslationQuery =
|
|
575
|
+
| undefined
|
|
576
|
+
| null
|
|
577
|
+
| TranslationShortcut
|
|
578
|
+
| {
|
|
579
|
+
[key: string]: string | number | boolean;
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Opions of the translate function or a TranslationShortcut.
|
|
584
|
+
*
|
|
585
|
+
* NOTE: when using a shortcut passing TranslationOptions to \`t()\` is not supported
|
|
586
|
+
* TODO: type safe this behaviour of the third argument (options).
|
|
587
|
+
*/
|
|
588
|
+
export type TranslationOptions =
|
|
589
|
+
| undefined
|
|
590
|
+
| TranslationShortcut
|
|
591
|
+
| {
|
|
592
|
+
returnObjects?: boolean;
|
|
593
|
+
fallback?: string | string[];
|
|
594
|
+
default?: string;
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Translate function which optionally accept a namespace as first argument
|
|
599
|
+
*/
|
|
600
|
+
export type Translate<
|
|
601
|
+
TNamespace extends TranslateNamespace | undefined = TranslateNamespace,
|
|
602
|
+
> = TNamespace extends TranslateNamespace
|
|
603
|
+
? TranslateNamespaced<TNamespace>
|
|
604
|
+
: TranslateDefault;
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Translate function **without** namespace, it allows to select any of the all
|
|
608
|
+
* available strings in _all_ namespaces.
|
|
609
|
+
*/
|
|
610
|
+
export type TranslateDefault = <
|
|
611
|
+
TPath extends TranslationsAllPaths,
|
|
612
|
+
TReturn = TranslationAtPath<TPath>,
|
|
613
|
+
>(
|
|
614
|
+
s: TPath,
|
|
615
|
+
q?: TranslationQuery,
|
|
616
|
+
o?: TranslationOptions,
|
|
617
|
+
) => TReturn;
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Translate function **with** namespace, it allows to select all available
|
|
621
|
+
* strings _only_ in the given namespace.
|
|
622
|
+
*/
|
|
623
|
+
export type TranslateNamespaced<TNamespace extends TranslateNamespace> = <
|
|
624
|
+
TPath extends TranslationsPaths<TranslationsDictionary[TNamespace]>,
|
|
625
|
+
TReturn = TranslationAtPathFromNamespace<TNamespace, TPath>,
|
|
626
|
+
>(
|
|
627
|
+
s: TPath,
|
|
628
|
+
q?: TranslationQuery,
|
|
629
|
+
o?: TranslationOptions,
|
|
630
|
+
) => TReturn;
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Translate function _loose_ type, to use only in implementations that uses
|
|
634
|
+
* the \`t\` function indirectly without needng knowledge of the string it needs
|
|
635
|
+
* to output.
|
|
636
|
+
*/
|
|
637
|
+
export type TranslateLoose<TReturn = string> = (
|
|
638
|
+
s?: any,
|
|
639
|
+
q?: TranslationQuery,
|
|
640
|
+
o?: TranslationOptions,
|
|
641
|
+
) => TReturn;
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Translate function _loosest_ type it allows to return string or object or array
|
|
645
|
+
* or whatever basically.
|
|
646
|
+
*/
|
|
647
|
+
export type TranslateLoosest<TReturn = any> = (
|
|
648
|
+
s?: any,
|
|
649
|
+
q?: TranslationQuery,
|
|
650
|
+
o?: TranslationOptions,
|
|
651
|
+
) => TReturn;
|
|
652
|
+
|
|
309
653
|
|
|
310
654
|
// export type RouteId = keyof typeof routesSlim;
|
|
311
655
|
export type RouteId = RouteIdStatic | RouteIdDynamic;
|
|
312
656
|
|
|
313
657
|
// export type RouteIdStatic = I18n.Utils.RouteStrictIdStatic<RouteId>;
|
|
314
|
-
export type RouteIdStatic = ${
|
|
658
|
+
export type RouteIdStatic = ${s};
|
|
315
659
|
|
|
316
660
|
// export type RouteIdDynamic = I18n.Utils.RouteStrictIdDynamic<RouteId>;
|
|
317
|
-
export type RouteIdDynamic = ${
|
|
661
|
+
export type RouteIdDynamic = ${a};
|
|
318
662
|
|
|
319
663
|
/**
|
|
320
664
|
* Utility standalone type to extract all children routes that starts with the
|
|
@@ -333,14 +677,109 @@ ${i}
|
|
|
333
677
|
> = T extends \`\${TStarts}.\${infer First}\` ? \`\${TStarts}.\${First}\` : never;
|
|
334
678
|
}
|
|
335
679
|
|
|
336
|
-
export namespace I18n.RouteParams {${
|
|
680
|
+
export namespace I18n.RouteParams {${n}}
|
|
337
681
|
|
|
338
682
|
export namespace I18n.Utils {
|
|
339
|
-
|
|
683
|
+
// import type { Trim } from "@koine/utils";
|
|
684
|
+
type Whitespace = \`\u{20}\`;
|
|
685
|
+
type TrimLeft<V extends string> = V extends \`\${Whitespace}\${infer R}\`
|
|
686
|
+
? TrimLeft<R>
|
|
687
|
+
: V;
|
|
688
|
+
type TrimRight<V extends string> = V extends \`\${infer R}\${Whitespace}\`
|
|
689
|
+
? TrimRight<R>
|
|
690
|
+
: V;
|
|
691
|
+
/** A simplified version of type-fest's Trim which creates too complex types */
|
|
692
|
+
type Trim<V extends string> = TrimLeft<TrimRight<V>>;
|
|
693
|
+
|
|
694
|
+
type WithDynamicPortion<F extends string, D extends GenericDelimiters> =
|
|
695
|
+
| \`\${string}\${F}\${D["start"]}\${string}\${D["end"]}\${F}\${string}\`
|
|
696
|
+
| \`\${string}\${F}\${D["start"]}\${string}\${D["end"]}\`
|
|
697
|
+
| \`\${D["start"]}\${string}\${D["end"]}\${F}\${string}\`
|
|
698
|
+
| \`\${D["start"]}\${string}\${D["end"]}\`;
|
|
699
|
+
|
|
700
|
+
type FilterOnlyStaticRouteId<
|
|
701
|
+
T extends string,
|
|
702
|
+
F extends string,
|
|
703
|
+
D extends GenericDelimiters,
|
|
704
|
+
> = T extends WithDynamicPortion<F, D> ? never : T;
|
|
705
|
+
|
|
706
|
+
type FilterOnlyDynamicRouteId<
|
|
707
|
+
T extends string,
|
|
708
|
+
F extends string,
|
|
709
|
+
D extends GenericDelimiters,
|
|
710
|
+
> = T extends WithDynamicPortion<F, D> ? T : never;
|
|
711
|
+
|
|
712
|
+
type InferredSeparator<T extends string> = T extends \`\${string}.\${string}\`
|
|
713
|
+
? "."
|
|
714
|
+
: T extends \`\${string}/\${string}\`
|
|
715
|
+
? "/"
|
|
716
|
+
: never;
|
|
717
|
+
|
|
718
|
+
type GenericDelimiters = {
|
|
719
|
+
start: string;
|
|
720
|
+
end: string;
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
type WithDelimitedString<Start extends string, End extends string> =
|
|
724
|
+
| \`\${string}\${Start}\${string}\${End}\${string}\`
|
|
725
|
+
| \`\${string}\${Start}\${string}\${End}\`
|
|
726
|
+
| \`\${Start}\${string}\${End}\${string}\`
|
|
727
|
+
| \`\${Start}\${string}\${End}\`;
|
|
728
|
+
|
|
729
|
+
type InferredDelimiters<T extends string> =
|
|
730
|
+
T extends WithDelimitedString<"[", "]">
|
|
731
|
+
? { start: "["; end: "]" }
|
|
732
|
+
: T extends WithDelimitedString<"{{", "}}">
|
|
733
|
+
? { start: "{{"; end: "}}" }
|
|
734
|
+
: T extends WithDelimitedString<"{", "}">
|
|
735
|
+
? { start: "{"; end: "}" }
|
|
736
|
+
: never;
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* @borrows [awesome-template-literal-types](https://github.com/ghoullier/awesome-template-literal-types)
|
|
740
|
+
*/
|
|
741
|
+
// prettier-ignore
|
|
742
|
+
export type DynamicParams<
|
|
743
|
+
T extends string,
|
|
744
|
+
Separator extends string = InferredSeparator<T>,
|
|
745
|
+
Delimiters extends GenericDelimiters = InferredDelimiters<T>,
|
|
746
|
+
> = string extends T
|
|
747
|
+
? Record<string, string>
|
|
748
|
+
: T extends \`\${string}\${Delimiters["start"]}\${infer Param}\${Delimiters["end"]}\${Separator}\${infer Rest}\`
|
|
749
|
+
? {
|
|
750
|
+
[k in Trim<Param> | keyof DynamicParams<Rest>]: string | number;
|
|
751
|
+
}
|
|
752
|
+
: T extends \`\${string}\${Delimiters["start"]}\${infer Param}\${Delimiters["end"]}\`
|
|
753
|
+
? {
|
|
754
|
+
[k in Trim<Param>]: string | number;
|
|
755
|
+
}
|
|
756
|
+
// : T extends \`\${Delimiters["start"]}\${infer Param}\${Delimiters["end"]}\`
|
|
757
|
+
// ? {
|
|
758
|
+
// [k in Trim<Param>]: string | number;
|
|
759
|
+
// }
|
|
760
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
761
|
+
: {};
|
|
762
|
+
|
|
763
|
+
export type RouteStrictIdStatic<T extends string> = FilterOnlyStaticRouteId<
|
|
764
|
+
T,
|
|
765
|
+
InferredSeparator<T>,
|
|
766
|
+
InferredDelimiters<T>
|
|
767
|
+
>;
|
|
768
|
+
|
|
769
|
+
export type RouteStrictIdDynamic<T extends string> = FilterOnlyDynamicRouteId<
|
|
770
|
+
T,
|
|
771
|
+
InferredSeparator<T>,
|
|
772
|
+
InferredDelimiters<T>
|
|
773
|
+
>;
|
|
774
|
+
|
|
775
|
+
export type RouteStrictId<T extends string> =
|
|
776
|
+
| RouteStrictIdStatic<T>
|
|
777
|
+
| RouteStrictIdDynamic<T>;
|
|
778
|
+
|
|
340
779
|
}
|
|
341
780
|
`});
|
|
342
781
|
|
|
343
|
-
var e$2 = (()=>({files:[{name:"config",fn:e$4,ext:"ts",index:!0},{name:"defaultLocale",fn:t$3,ext:"ts",index:!0},{name:"deriveLocalisedPathnames",fn:o$2,ext:"ts",index:!0},{name:"isLocale",fn:n$4,ext:"ts",index:!0},{name:"locales",fn:m$4,ext:"ts",index:!0},{name:"pathnameToRouteId",fn:a$3,ext:"ts",index:!0},{name:"routes",fn:r$3,ext:"ts",index:!0},{name:"routesSlim",fn:i$1,ext:"ts",index:!0},{name:"tFns",fn:s$1,ext:"ts"},{name:"tInterpolateParams",fn:f
|
|
782
|
+
var e$2 = (()=>({files:[{name:"config",fn:e$4,ext:"ts",index:!0},{name:"defaultLocale",fn:t$3,ext:"ts",index:!0},{name:"deriveLocalisedPathnames",fn:o$2,ext:"ts",index:!0},{name:"isLocale",fn:n$4,ext:"ts",index:!0},{name:"locales",fn:m$4,ext:"ts",index:!0},{name:"pathnameToRouteId",fn:a$3,ext:"ts",index:!0},{name:"routes",fn:r$3,ext:"ts",index:!0},{name:"routesSlim",fn:i$1,ext:"ts",index:!0},{name:"tFns",fn:s$1,ext:"ts"},{name:"tInterpolateParams",fn:f,ext:"ts",index:!1},{name:"to",fn:x$1,ext:"ts",index:!0},{name:"toFns",fn:d$2,ext:"ts",index:!0},{name:"toFormat",fn:p$1,ext:"ts",index:!0},{name:"types",fn:l$1,ext:"ts",index:!0}]}));
|
|
344
783
|
|
|
345
784
|
var e$1 = (()=>`
|
|
346
785
|
"use client";
|
package/package.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"name": "@koine/i18n",
|
|
3
3
|
"sideEffects": false,
|
|
4
4
|
"dependencies": {
|
|
5
|
-
"@koine/node": "2.0.0-beta.
|
|
6
|
-
"@koine/utils": "2.0.0-beta.
|
|
5
|
+
"@koine/node": "2.0.0-beta.44",
|
|
6
|
+
"@koine/utils": "2.0.0-beta.44"
|
|
7
7
|
},
|
|
8
8
|
"peerDependencies": {
|
|
9
9
|
"glob": "^10.3.10",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
},
|
|
48
48
|
"module": "./index.esm.js",
|
|
49
49
|
"main": "./index.cjs.js",
|
|
50
|
-
"version": "2.0.0-beta.
|
|
50
|
+
"version": "2.0.0-beta.44"
|
|
51
51
|
}
|