@intlayer/cli 8.4.2 → 8.4.3
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/cjs/auth/login.cjs +2 -2
- package/dist/cjs/auth/login.cjs.map +1 -1
- package/dist/cjs/extract.cjs +1 -1
- package/dist/cjs/extract.cjs.map +1 -1
- package/dist/cjs/fill/fill.cjs +1 -1
- package/dist/cjs/fill/fill.cjs.map +1 -1
- package/dist/cjs/fill/listTranslationsTasks.cjs +1 -1
- package/dist/cjs/fill/listTranslationsTasks.cjs.map +1 -1
- package/dist/cjs/fill/translateDictionary.cjs +1 -1
- package/dist/cjs/fill/translateDictionary.cjs.map +1 -1
- package/dist/cjs/pull.cjs +1 -1
- package/dist/cjs/pull.cjs.map +1 -1
- package/dist/cjs/push/pullLog.cjs +3 -3
- package/dist/cjs/push/pullLog.cjs.map +1 -1
- package/dist/cjs/push/push.cjs +1 -1
- package/dist/cjs/push/push.cjs.map +1 -1
- package/dist/cjs/pushLog.cjs +3 -3
- package/dist/cjs/pushLog.cjs.map +1 -1
- package/dist/cjs/reviewDoc/reviewDoc.cjs +1 -1
- package/dist/cjs/reviewDoc/reviewDoc.cjs.map +1 -1
- package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs +1 -1
- package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs.map +1 -1
- package/dist/cjs/test/test.cjs +1 -1
- package/dist/cjs/test/test.cjs.map +1 -1
- package/dist/cjs/translateDoc/translateDoc.cjs +1 -1
- package/dist/cjs/translateDoc/translateDoc.cjs.map +1 -1
- package/dist/cjs/translateDoc/translateFile.cjs +2 -2
- package/dist/cjs/translateDoc/translateFile.cjs.map +1 -1
- package/dist/cjs/utils/checkAccess.cjs +1 -1
- package/dist/cjs/utils/checkAccess.cjs.map +1 -1
- package/dist/cjs/utils/setupAI.cjs +1 -1
- package/dist/cjs/utils/setupAI.cjs.map +1 -1
- package/dist/esm/auth/login.mjs +1 -1
- package/dist/esm/auth/login.mjs.map +1 -1
- package/dist/esm/extract.mjs +1 -1
- package/dist/esm/extract.mjs.map +1 -1
- package/dist/esm/fill/fill.mjs +1 -1
- package/dist/esm/fill/fill.mjs.map +1 -1
- package/dist/esm/fill/listTranslationsTasks.mjs +1 -1
- package/dist/esm/fill/listTranslationsTasks.mjs.map +1 -1
- package/dist/esm/fill/translateDictionary.mjs +1 -1
- package/dist/esm/fill/translateDictionary.mjs.map +1 -1
- package/dist/esm/pull.mjs +1 -1
- package/dist/esm/pull.mjs.map +1 -1
- package/dist/esm/push/pullLog.mjs +1 -1
- package/dist/esm/push/pullLog.mjs.map +1 -1
- package/dist/esm/push/push.mjs +1 -1
- package/dist/esm/push/push.mjs.map +1 -1
- package/dist/esm/pushLog.mjs +1 -1
- package/dist/esm/pushLog.mjs.map +1 -1
- package/dist/esm/reviewDoc/reviewDoc.mjs +1 -1
- package/dist/esm/reviewDoc/reviewDoc.mjs.map +1 -1
- package/dist/esm/reviewDoc/reviewDocBlockAware.mjs +1 -1
- package/dist/esm/reviewDoc/reviewDocBlockAware.mjs.map +1 -1
- package/dist/esm/test/test.mjs +1 -1
- package/dist/esm/test/test.mjs.map +1 -1
- package/dist/esm/translateDoc/translateDoc.mjs +1 -1
- package/dist/esm/translateDoc/translateDoc.mjs.map +1 -1
- package/dist/esm/translateDoc/translateFile.mjs +1 -1
- package/dist/esm/translateDoc/translateFile.mjs.map +1 -1
- package/dist/esm/utils/checkAccess.mjs +1 -1
- package/dist/esm/utils/checkAccess.mjs.map +1 -1
- package/dist/esm/utils/setupAI.mjs +1 -1
- package/dist/esm/utils/setupAI.mjs.map +1 -1
- package/dist/types/auth/login.d.ts.map +1 -1
- package/dist/types/extract.d.ts.map +1 -1
- package/dist/types/pull.d.ts.map +1 -1
- package/dist/types/push/pullLog.d.ts.map +1 -1
- package/dist/types/push/push.d.ts.map +1 -1
- package/dist/types/setupAI-Bosjx7ah.d.ts.map +1 -1
- package/dist/types/utils/checkAccess.d.ts.map +1 -1
- package/package.json +12 -12
package/dist/cjs/auth/login.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../chunk-Bmb41Sf3.cjs`),t=require(`../utils/openBrowser.cjs`);let n=require(`@intlayer/chokidar/cli`),r=require(`@intlayer/config/logger`),
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../chunk-Bmb41Sf3.cjs`),t=require(`../utils/openBrowser.cjs`);let n=require(`@intlayer/chokidar/cli`),r=require(`@intlayer/config/colors`);r=e.t(r);let i=require(`@intlayer/config/logger`),a=require(`@intlayer/config/node`),o=require(`node:http`);o=e.t(o);let s=require(`node:url`);const c=async e=>{let c=(0,a.getConfiguration)(e.configOptions);(0,n.logConfigDetails)(e?.configOptions);let l=(0,i.getAppLogger)(c),u=e.cmsUrl??c.editor.cmsURL;return new Promise(e=>{let n=o.default.createServer((t,a)=>{let o=new s.URL(t.url??``,`http://${t.headers.host}`);if(a.setHeader(`Access-Control-Allow-Origin`,`*`),a.setHeader(`Access-Control-Allow-Methods`,`GET, OPTIONS`),a.setHeader(`Access-Control-Allow-Headers`,`Content-Type`),t.method===`OPTIONS`){a.writeHead(204),a.end();return}if(o.pathname===`/callback`){let t=o.searchParams.get(`clientId`),s=o.searchParams.get(`clientSecret`);t&&s?(l(``),l(`Log in successful. Client ID and Client Secret received.`),l(``),l([`1. Insert the Client ID and Client Secret in your`,(0,i.colorizePath)(`.env`),`file:`]),l((0,i.colorize)(`--------------------------------`,r.GREY_DARK)),l([(0,i.colorize)(`INTLAYER_CLIENT_ID=`,r.GREY_LIGHT),(0,i.colorize)(t,r.BLUE)].join(``)),l([(0,i.colorize)(`INTLAYER_CLIENT_SECRET=`,r.GREY_LIGHT),(0,i.colorize)(s,r.BLUE)].join(``)),l((0,i.colorize)(`--------------------------------`,r.GREY_DARK)),l(``),l(`2. Insert in your Intlayer configuration file:`),l((0,i.colorize)(`--------------------------------`,r.GREY_DARK)),[`${r.GREY_LIGHT}{`,` editor: {`,` cmsURL: '${(0,i.colorizePath)(u,void 0,r.GREY_LIGHT)}',`,` clientId: '${(0,i.colorize)(`process.env.INTLAYER_CLIENT_ID`,r.BLUE,r.GREY_LIGHT)}',`,` clientSecret: '${(0,i.colorize)(`process.env.INTLAYER_CLIENT_SECRET`,r.BLUE,r.GREY_LIGHT)}',`,` },`,`}`].forEach(e=>{l(e)}),l((0,i.colorize)(`--------------------------------`,r.GREY_DARK)),a.writeHead(200,{"Content-Type":`text/html`}),a.end(`
|
|
2
2
|
<!DOCTYPE html>
|
|
3
3
|
<html lang="en" data-theme="dark">
|
|
4
4
|
<head>
|
|
@@ -70,5 +70,5 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
70
70
|
<\/script>
|
|
71
71
|
</body>
|
|
72
72
|
</html>
|
|
73
|
-
`),n.close(()=>{e(),process.exit(0)})):(
|
|
73
|
+
`),n.close(()=>{e(),process.exit(0)})):(a.writeHead(400,{"Content-Type":`text/plain`}),a.end(`Missing parameters`))}else a.writeHead(404,{"Content-Type":`text/plain`}),a.end(`Not found`)});n.listen(0,()=>{let e=n.address(),r=typeof e==`object`&&e?e.port:0,a=Math.random().toString(36).substring(7),o=`${u??process.env.INTLAYER_SITE_URL??`http://localhost:3000`}/en/auth/cli-login?port=${r}&state=${a}`;l(`Opening browser for login...`),l(`If browser does not open, visit: ${(0,i.colorizePath)(o)}`),t.openBrowser(o)})})};exports.login=c;
|
|
74
74
|
//# sourceMappingURL=login.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.cjs","names":["http","URL","ANSIColors"],"sources":["../../../src/auth/login.ts"],"sourcesContent":["import http from 'node:http';\nimport { URL } from 'node:url';\nimport { logConfigDetails } from '@intlayer/chokidar/cli';\nimport {
|
|
1
|
+
{"version":3,"file":"login.cjs","names":["http","URL","ANSIColors"],"sources":["../../../src/auth/login.ts"],"sourcesContent":["import http from 'node:http';\nimport { URL } from 'node:url';\nimport { logConfigDetails } from '@intlayer/chokidar/cli';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { openBrowser } from '../utils/openBrowser';\n\ntype LoginOptions = {\n cmsUrl?: string;\n configOptions?: GetConfigurationOptions;\n};\n\nexport const login = async (options: LoginOptions) => {\n const configuration = getConfiguration(options.configOptions);\n logConfigDetails(options?.configOptions);\n\n const logger = getAppLogger(configuration);\n\n const cmsUrl = options.cmsUrl ?? configuration.editor.cmsURL;\n\n return new Promise<void>((resolve) => {\n const server = http.createServer((req, res) => {\n const url = new URL(req.url ?? '', `http://${req.headers.host}`);\n\n // Set CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n if (url.pathname === '/callback') {\n const clientId = url.searchParams.get('clientId');\n const clientSecret = url.searchParams.get('clientSecret');\n\n if (clientId && clientSecret) {\n logger('');\n logger('Log in successful. Client ID and Client Secret received.');\n\n logger('');\n logger([\n '1. Insert the Client ID and Client Secret in your',\n colorizePath('.env'),\n 'file:',\n ]);\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n logger(\n [\n colorize('INTLAYER_CLIENT_ID=', ANSIColors.GREY_LIGHT),\n colorize(clientId, ANSIColors.BLUE),\n ].join('')\n );\n logger(\n [\n colorize('INTLAYER_CLIENT_SECRET=', ANSIColors.GREY_LIGHT),\n colorize(clientSecret, ANSIColors.BLUE),\n ].join('')\n );\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n logger('');\n logger('2. Insert in your Intlayer configuration file:');\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n [\n `${ANSIColors.GREY_LIGHT}{`,\n ` editor: {`,\n ` cmsURL: '${colorizePath(cmsUrl, undefined, ANSIColors.GREY_LIGHT)}',`,\n ` clientId: '${colorize('process.env.INTLAYER_CLIENT_ID', ANSIColors.BLUE, ANSIColors.GREY_LIGHT)}',`,\n ` clientSecret: '${colorize('process.env.INTLAYER_CLIENT_SECRET', ANSIColors.BLUE, ANSIColors.GREY_LIGHT)}',`,\n ` },`,\n `}`,\n ].forEach((line) => {\n logger(line);\n });\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(`\n <!DOCTYPE html>\n <html lang=\"en\" data-theme=\"dark\">\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Intlayer CLI Login</title>\n <style>\n :root {\n --color-background: rgba(23, 23, 23);\n --color-card: rgba(39, 39, 39);\n --color-text: rgba(255, 245, 237);\n --color-neutral: rgba(93, 93, 93);\n --font-sans: \"Inter\", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;\n }\n \n * {\n box-sizing: border-box;\n }\n \n body {\n font-family: var(--font-sans);\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n margin: 0;\n padding: 1rem;\n background-color: var(--color-background);\n color: var(--color-text);\n }\n \n .container {\n text-align: center;\n padding: 2rem;\n border-radius: 1rem;\n background-color: var(--color-card);\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n max-width: 400px;\n width: 100%;\n }\n \n h1 {\n margin: 0 0 1rem 0;\n font-size: 1.5rem;\n font-weight: 700;\n color: var(--color-text);\n }\n \n p {\n color: var(--color-neutral);\n margin: 0 0 1.5rem 0;\n line-height: 1.5;\n }\n </style>\n </head>\n <body>\n <div class=\"container\">\n <h1>Login Successful</h1>\n <p>You have successfully logged in to Intlayer CLI. You can now close this tab and return to your terminal.</p>\n </div>\n <script>\n // Attempt to close the window\n window.close();\n \n // Fallback: if window.close() doesn't work, show a message\n setTimeout(() => {\n window.close();\n }, 1000);\n </script>\n </body>\n </html>\n `);\n\n server.close(() => {\n resolve();\n process.exit(0);\n });\n } else {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end('Missing parameters');\n }\n } else {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not found');\n }\n });\n\n server.listen(0, () => {\n const address = server.address();\n const port = typeof address === 'object' && address ? address.port : 0;\n const state = Math.random().toString(36).substring(7);\n\n const websiteUrl =\n cmsUrl ?? process.env.INTLAYER_SITE_URL ?? 'http://localhost:3000';\n const loginUrl = `${websiteUrl}/en/auth/cli-login?port=${port}&state=${state}`;\n\n logger('Opening browser for login...');\n logger(`If browser does not open, visit: ${colorizePath(loginUrl)}`);\n\n openBrowser(loginUrl);\n });\n });\n};\n"],"mappings":"8WAgBA,MAAa,EAAQ,KAAO,IAA0B,CACpD,IAAM,GAAA,EAAA,EAAA,kBAAiC,EAAQ,cAAc,EAC7D,EAAA,EAAA,kBAAiB,GAAS,cAAc,CAExC,IAAM,GAAA,EAAA,EAAA,cAAsB,EAAc,CAEpC,EAAS,EAAQ,QAAU,EAAc,OAAO,OAEtD,OAAO,IAAI,QAAe,GAAY,CACpC,IAAM,EAASA,EAAAA,QAAK,cAAc,EAAK,IAAQ,CAC7C,IAAM,EAAM,IAAIC,EAAAA,IAAI,EAAI,KAAO,GAAI,UAAU,EAAI,QAAQ,OAAO,CAOhE,GAJA,EAAI,UAAU,8BAA+B,IAAI,CACjD,EAAI,UAAU,+BAAgC,eAAe,CAC7D,EAAI,UAAU,+BAAgC,eAAe,CAEzD,EAAI,SAAW,UAAW,CAC5B,EAAI,UAAU,IAAI,CAClB,EAAI,KAAK,CACT,OAGF,GAAI,EAAI,WAAa,YAAa,CAChC,IAAM,EAAW,EAAI,aAAa,IAAI,WAAW,CAC3C,EAAe,EAAI,aAAa,IAAI,eAAe,CAErD,GAAY,GACd,EAAO,GAAG,CACV,EAAO,2DAA2D,CAElE,EAAO,GAAG,CACV,EAAO,CACL,uEACa,OAAO,CACpB,QACD,CAAC,CACF,GAAA,EAAA,EAAA,UACW,mCAAoCC,EAAW,UAAU,CACnE,CACD,EACE,EAAA,EAAA,EAAA,UACW,sBAAuBA,EAAW,WAAW,EAAA,EAAA,EAAA,UAC7C,EAAUA,EAAW,KAAK,CACpC,CAAC,KAAK,GAAG,CACX,CACD,EACE,EAAA,EAAA,EAAA,UACW,0BAA2BA,EAAW,WAAW,EAAA,EAAA,EAAA,UACjD,EAAcA,EAAW,KAAK,CACxC,CAAC,KAAK,GAAG,CACX,CACD,GAAA,EAAA,EAAA,UACW,mCAAoCA,EAAW,UAAU,CACnE,CACD,EAAO,GAAG,CACV,EAAO,iDAAiD,CACxD,GAAA,EAAA,EAAA,UACW,mCAAoCA,EAAW,UAAU,CACnE,CACD,CACE,GAAGA,EAAW,WAAW,GACzB,cACA,kBAAA,EAAA,EAAA,cAA8B,EAAQ,IAAA,GAAWA,EAAW,WAAW,CAAC,IACxE,oBAAA,EAAA,EAAA,UAA4B,iCAAkCA,EAAW,KAAMA,EAAW,WAAW,CAAC,IACtG,wBAAA,EAAA,EAAA,UAAgC,qCAAsCA,EAAW,KAAMA,EAAW,WAAW,CAAC,IAC9G,OACA,IACD,CAAC,QAAS,GAAS,CAClB,EAAO,EAAK,EACZ,CACF,GAAA,EAAA,EAAA,UACW,mCAAoCA,EAAW,UAAU,CACnE,CAED,EAAI,UAAU,IAAK,CAAE,eAAgB,YAAa,CAAC,CACnD,EAAI,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAwEN,CAEF,EAAO,UAAY,CACjB,GAAS,CACT,QAAQ,KAAK,EAAE,EACf,GAEF,EAAI,UAAU,IAAK,CAAE,eAAgB,aAAc,CAAC,CACpD,EAAI,IAAI,qBAAqB,OAG/B,EAAI,UAAU,IAAK,CAAE,eAAgB,aAAc,CAAC,CACpD,EAAI,IAAI,YAAY,EAEtB,CAEF,EAAO,OAAO,MAAS,CACrB,IAAM,EAAU,EAAO,SAAS,CAC1B,EAAO,OAAO,GAAY,UAAY,EAAU,EAAQ,KAAO,EAC/D,EAAQ,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,UAAU,EAAE,CAI/C,EAAW,GADf,GAAU,QAAQ,IAAI,mBAAqB,wBACd,0BAA0B,EAAK,SAAS,IAEvE,EAAO,+BAA+B,CACtC,EAAO,qCAAA,EAAA,EAAA,cAAiD,EAAS,GAAG,CAEpE,EAAA,YAAY,EAAS,EACrB,EACF"}
|
package/dist/cjs/extract.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./chunk-Bmb41Sf3.cjs`);let t=require(`node:fs`),n=require(`node:path`),r=require(`@intlayer/babel`),i=require(`@intlayer/chokidar/build`),a=require(`@intlayer/chokidar/cli`),o=require(`@intlayer/chokidar/utils`),s=require(`@intlayer/config/logger`),
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./chunk-Bmb41Sf3.cjs`);let t=require(`node:fs`),n=require(`node:path`),r=require(`@intlayer/babel`),i=require(`@intlayer/chokidar/build`),a=require(`@intlayer/chokidar/cli`),o=require(`@intlayer/chokidar/utils`),s=require(`@intlayer/config/colors`);s=e.t(s);let c=require(`@intlayer/config/logger`),l=require(`@intlayer/config/node`),u=require(`@intlayer/unmerged-dictionaries-entry`),d=require(`enquirer`);d=e.t(d);const f=async e=>{let f=(0,l.getConfiguration)(e.configOptions);(0,a.logConfigDetails)(e?.configOptions);let p=(0,c.getAppLogger)(f),{baseDir:m}=f.system,{output:h}=f.compiler;if(!h){p(`${c.x} No output configuration found. Add a ${(0,c.colorize)(`compiler.output`,s.BLUE)} in your configuration.`,{level:`error`});return}let g=(0,r.detectPackageName)(m),_=e.files??[];if(_.length===0){let e=(0,o.buildComponentFilesList)(f).map(e=>({value:e,label:(0,n.relative)(m,e)}));if(e.length===0){p(`No extractable files found in the project.`);return}let t=`__select_all__`,r;try{let n=Math.max((process.stdout.columns||80)-15,20),i=e=>e.length>n?`...${e.slice(-(n-3))}`:e,{files:a}=await d.default.prompt({type:`autocomplete`,name:`files`,message:`Select files to extract (Type to search):`,multiple:!0,limit:40,choices:[{name:t,message:`────── Select all ──────`},...e.map(e=>({name:e.value,message:i(e.label)}))],async toggle(e,n){if(!(!e||e.disabled))return e.enabled=n??!e.enabled,e.name===t&&this.choices.filter(e=>e.name!==t).forEach(t=>{t.enabled=e.enabled}),this.render()},format(){return this.state?.submitted&&this.options?.multiple?`${this.selected.filter(e=>e.name!==t).length} file(s) selected`:this.input??``}});r=a.filter(e=>e!==t)}catch{r=Symbol(`cancel`)}typeof r==`symbol`&&process.exit(0),_=r}if(_.length===0){p(`No files selected for extraction.`);return}let v=_.map(e=>(0,n.resolve)(m,e)).filter(e=>(0,t.existsSync)(e)?!0:(p(`File not found: ${(0,o.formatPath)(e)}`),!1));if(v.length===0)return;let y=(0,u.getUnmergedDictionaries)(f);await Promise.all(v.map(async t=>{try{await(0,r.extractContent)(t,g,{unmergedDictionaries:y,configuration:f,codeOnly:e.codeOnly,declarationOnly:e.declarationOnly})}catch(e){p(`Failed to transform ${t}: ${e.message}`)}})),await(0,i.prepareIntlayer)(f)};exports.extract=f;
|
|
2
2
|
//# sourceMappingURL=extract.cjs.map
|
package/dist/cjs/extract.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract.cjs","names":["x","ANSIColors"],"sources":["../../src/extract.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { relative, resolve } from 'node:path';\nimport {\n detectPackageName,\n extractContent,\n type PackageName,\n} from '@intlayer/babel';\nimport { prepareIntlayer } from '@intlayer/chokidar/build';\nimport { logConfigDetails } from '@intlayer/chokidar/cli';\nimport { buildComponentFilesList, formatPath } from '@intlayer/chokidar/utils';\nimport
|
|
1
|
+
{"version":3,"file":"extract.cjs","names":["x","ANSIColors"],"sources":["../../src/extract.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { relative, resolve } from 'node:path';\nimport {\n detectPackageName,\n extractContent,\n type PackageName,\n} from '@intlayer/babel';\nimport { prepareIntlayer } from '@intlayer/chokidar/build';\nimport { logConfigDetails } from '@intlayer/chokidar/cli';\nimport { buildComponentFilesList, formatPath } from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger, x } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { FilePathPattern } from '@intlayer/types/filePathPattern';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport enquirer from 'enquirer';\n\ntype ExtractOptions = {\n files?: string[];\n output?: FilePathPattern;\n configOptions?: GetConfigurationOptions;\n codeOnly?: boolean;\n declarationOnly?: boolean;\n};\n\nexport const extract = async (options: ExtractOptions) => {\n const configuration = getConfiguration(options.configOptions);\n\n logConfigDetails(options?.configOptions);\n\n const appLogger = getAppLogger(configuration);\n\n const { baseDir } = configuration.system;\n const { output } = configuration.compiler;\n\n if (!output) {\n appLogger(\n `${x} No output configuration found. Add a ${colorize('compiler.output', ANSIColors.BLUE)} in your configuration.`,\n {\n level: 'error',\n }\n );\n return;\n }\n\n // Detect package\n const packageName: PackageName = detectPackageName(baseDir);\n\n let filesToExtract = options.files ?? [];\n\n if (filesToExtract.length === 0) {\n // Await all promises simultaneously\n const fileList = buildComponentFilesList(configuration);\n\n // Flatten the nested arrays and remove duplicates\n // Relative paths for selection\n const choices = fileList.map((file) => {\n const relPath = relative(baseDir, file);\n\n return {\n value: file,\n label: relPath,\n };\n });\n\n if (choices.length === 0) {\n appLogger('No extractable files found in the project.');\n return;\n }\n\n const SELECT_ALL = '__select_all__';\n\n type PromptChoice = {\n name: string;\n enabled: boolean;\n disabled?: boolean | string;\n };\n\n type PromptContext = {\n choices: PromptChoice[];\n render(): void | Promise<void>;\n state: { submitted: boolean };\n selected: PromptChoice[];\n input: string;\n options: { multiple?: boolean };\n };\n\n let selectedFiles: string[] | symbol;\n try {\n const maxLen = Math.max((process.stdout.columns || 80) - 15, 20);\n const truncatePath = (path: string) =>\n path.length > maxLen ? `...${path.slice(-(maxLen - 3))}` : path;\n\n const { files: enquirerSelectedFiles } = await enquirer.prompt<{\n files: string[];\n }>({\n type: 'autocomplete',\n name: 'files',\n message: 'Select files to extract (Type to search):',\n multiple: true,\n // @ts-ignore limit exist but is not typed\n limit: 40,\n choices: [\n { name: SELECT_ALL, message: '────── Select all ──────' },\n ...choices.map((choice) => ({\n name: choice.value,\n message: truncatePath(choice.label),\n })),\n ],\n async toggle(\n this: PromptContext,\n choice: PromptChoice,\n enabled?: boolean\n ) {\n if (!choice || choice.disabled) return;\n choice.enabled = enabled == null ? !choice.enabled : enabled;\n\n if (choice.name === SELECT_ALL) {\n this.choices\n .filter((choiceEl) => choiceEl.name !== SELECT_ALL)\n .forEach((choiceEl) => {\n choiceEl.enabled = choice.enabled;\n });\n }\n\n return this.render();\n },\n format(this: PromptContext) {\n if (this.state?.submitted && this.options?.multiple) {\n return `${this.selected.filter((s) => s.name !== SELECT_ALL).length} file(s) selected`;\n }\n return this.input ?? '';\n },\n });\n\n selectedFiles = enquirerSelectedFiles.filter((f) => f !== SELECT_ALL);\n } catch {\n selectedFiles = Symbol('cancel');\n }\n\n if (typeof selectedFiles === 'symbol') {\n // User cancelled\n process.exit(0);\n }\n\n filesToExtract = selectedFiles as string[];\n }\n\n if (filesToExtract.length === 0) {\n appLogger('No files selected for extraction.');\n return;\n }\n\n const absoluteFiles = filesToExtract\n .map((file) => resolve(baseDir, file))\n .filter((file) => {\n if (!existsSync(file)) {\n appLogger(`File not found: ${formatPath(file)}`);\n return false;\n }\n return true;\n });\n\n if (absoluteFiles.length === 0) {\n return;\n }\n\n const unmergedDictionaries = getUnmergedDictionaries(configuration);\n\n await Promise.all(\n absoluteFiles.map(async (filePath) => {\n try {\n await extractContent(filePath, packageName, {\n unmergedDictionaries,\n configuration,\n codeOnly: options.codeOnly,\n declarationOnly: options.declarationOnly,\n });\n } catch (error) {\n appLogger(\n `Failed to transform ${filePath}: ${(error as Error).message}`\n );\n }\n })\n );\n\n await prepareIntlayer(configuration); // Prepare Intlayer to apply the changes\n};\n"],"mappings":"ofA4BA,MAAa,EAAU,KAAO,IAA4B,CACxD,IAAM,GAAA,EAAA,EAAA,kBAAiC,EAAQ,cAAc,EAE7D,EAAA,EAAA,kBAAiB,GAAS,cAAc,CAExC,IAAM,GAAA,EAAA,EAAA,cAAyB,EAAc,CAEvC,CAAE,WAAY,EAAc,OAC5B,CAAE,UAAW,EAAc,SAEjC,GAAI,CAAC,EAAQ,CACX,EACE,GAAGA,EAAAA,EAAE,yCAAA,EAAA,EAAA,UAAiD,kBAAmBC,EAAW,KAAK,CAAC,yBAC1F,CACE,MAAO,QACR,CACF,CACD,OAIF,IAAM,GAAA,EAAA,EAAA,mBAA6C,EAAQ,CAEvD,EAAiB,EAAQ,OAAS,EAAE,CAExC,GAAI,EAAe,SAAW,EAAG,CAM/B,IAAM,GAAA,EAAA,EAAA,yBAJmC,EAAc,CAI9B,IAAK,IAGrB,CACL,MAAO,EACP,OAAA,EAAA,EAAA,UAJuB,EAAS,EAAK,CAKtC,EACD,CAEF,GAAI,EAAQ,SAAW,EAAG,CACxB,EAAU,6CAA6C,CACvD,OAGF,IAAM,EAAa,iBAiBf,EACJ,GAAI,CACF,IAAM,EAAS,KAAK,KAAK,QAAQ,OAAO,SAAW,IAAM,GAAI,GAAG,CAC1D,EAAgB,GACpB,EAAK,OAAS,EAAS,MAAM,EAAK,MAAM,EAAE,EAAS,GAAG,GAAK,EAEvD,CAAE,MAAO,GAA0B,MAAM,EAAA,QAAS,OAErD,CACD,KAAM,eACN,KAAM,QACN,QAAS,4CACT,SAAU,GAEV,MAAO,GACP,QAAS,CACP,CAAE,KAAM,EAAY,QAAS,2BAA4B,CACzD,GAAG,EAAQ,IAAK,IAAY,CAC1B,KAAM,EAAO,MACb,QAAS,EAAa,EAAO,MAAM,CACpC,EAAE,CACJ,CACD,MAAM,OAEJ,EACA,EACA,CACI,MAAC,GAAU,EAAO,UAWtB,MAVA,GAAO,QAAU,GAAkB,CAAC,EAAO,QAEvC,EAAO,OAAS,GAClB,KAAK,QACF,OAAQ,GAAa,EAAS,OAAS,EAAW,CAClD,QAAS,GAAa,CACrB,EAAS,QAAU,EAAO,SAC1B,CAGC,KAAK,QAAQ,EAEtB,QAA4B,CAI1B,OAHI,KAAK,OAAO,WAAa,KAAK,SAAS,SAClC,GAAG,KAAK,SAAS,OAAQ,GAAM,EAAE,OAAS,EAAW,CAAC,OAAO,mBAE/D,KAAK,OAAS,IAExB,CAAC,CAEF,EAAgB,EAAsB,OAAQ,GAAM,IAAM,EAAW,MAC/D,CACN,EAAgB,OAAO,SAAS,CAG9B,OAAO,GAAkB,UAE3B,QAAQ,KAAK,EAAE,CAGjB,EAAiB,EAGnB,GAAI,EAAe,SAAW,EAAG,CAC/B,EAAU,oCAAoC,CAC9C,OAGF,IAAM,EAAgB,EACnB,IAAK,IAAA,EAAA,EAAA,SAAiB,EAAS,EAAK,CAAC,CACrC,OAAQ,IACH,EAAA,EAAA,YAAY,EAAK,CAId,IAHL,EAAU,oBAAA,EAAA,EAAA,YAA8B,EAAK,GAAG,CACzC,IAGT,CAEJ,GAAI,EAAc,SAAW,EAC3B,OAGF,IAAM,GAAA,EAAA,EAAA,yBAA+C,EAAc,CAEnE,MAAM,QAAQ,IACZ,EAAc,IAAI,KAAO,IAAa,CACpC,GAAI,CACF,MAAA,EAAA,EAAA,gBAAqB,EAAU,EAAa,CAC1C,uBACA,gBACA,SAAU,EAAQ,SAClB,gBAAiB,EAAQ,gBAC1B,CAAC,OACK,EAAO,CACd,EACE,uBAAuB,EAAS,IAAK,EAAgB,UACtD,GAEH,CACH,CAED,MAAA,EAAA,EAAA,iBAAsB,EAAc"}
|
package/dist/cjs/fill/fill.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`})
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../chunk-Bmb41Sf3.cjs`),t=require(`../getTargetDictionary.cjs`),n=require(`../utils/setupAI.cjs`),r=require(`./listTranslationsTasks.cjs`),i=require(`./translateDictionary.cjs`),a=require(`./writeFill.cjs`);let o=require(`node:path`),s=require(`@intlayer/chokidar/build`),c=require(`@intlayer/chokidar/cli`),l=require(`@intlayer/chokidar/utils`),u=require(`@intlayer/config/colors`);u=e.t(u);let d=require(`@intlayer/config/logger`),f=require(`@intlayer/config/node`);const p=async e=>{let p=(0,f.getConfiguration)(e?.configOptions);(0,c.logConfigDetails)(e?.configOptions);let m=(0,d.getAppLogger)(p);e?.build===!0?await(0,s.prepareIntlayer)(p,{forceRun:!0}):e?.build===void 0&&await(0,s.prepareIntlayer)(p);let{defaultLocale:h,locales:g}=p.internationalization,_=e?.mode??`complete`,v=e?.sourceLocale??h,y=e?.outputLocales?t.ensureArray(e.outputLocales):g,b=await n.setupAI(p,e?.aiOptions);if(!b?.hasAIAccess)return;let{aiClient:x,aiConfig:S}=b,C=await t.getTargetUnmergedDictionaries(e),w=new Set;C.forEach(e=>{w.add(e.key)});let T=Array.from(w);if(m([`Affected dictionary keys for processing:`,T.length>0?T.map(e=>(0,d.colorizeKey)(e)).join(`, `):(0,d.colorize)(`No keys found`,u.YELLOW)]),T.length===0)return;let E=r.listTranslationsTasks(C.map(e=>e.localId),y,_,v,p),D=e?.nbConcurrentTranslations??7,O=(0,l.getGlobalLimiter)(D),k=(0,l.getTaskLimiter)(Math.max(1,Math.min(e?.nbConcurrentTasks??D,E.length))),A=E.map(t=>k(async()=>{let n=(0,o.relative)(p?.content?.baseDir??process.cwd(),t?.dictionaryFilePath??``);m(`${t.dictionaryPreset} Processing ${(0,d.colorizePath)((0,o.basename)(n))}`,{level:`info`});let r=await i.translateDictionary(t,p,{mode:_,aiOptions:e?.aiOptions,fillMetadata:!e?.skipMetadata,onHandle:O,aiClient:x,aiConfig:S});if(!r?.dictionaryOutput)return;let{dictionaryOutput:c,sourceLocale:u}=r,f=typeof c.fill==`string`||typeof c.fill==`object`,h=typeof c.locale==`string`,g=f?c.fill:h?p.dictionary?.fill??!0:!1;typeof g==`string`||typeof g==`object`?await a.writeFill({...c,fill:g},y,[u],p):(await(0,s.writeContentDeclaration)(c,p),c.filePath&&m(`${t.dictionaryPreset} Content declaration written to ${(0,l.formatPath)((0,o.basename)(c.filePath))}`,{level:`info`}))}));await Promise.all(A),await O.onIdle()};exports.fill=p;
|
|
2
2
|
//# sourceMappingURL=fill.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fill.cjs","names":["ensureArray","setupAI","getTargetUnmergedDictionaries","ANSIColors","listTranslationsTasks","translateDictionary","writeFill"],"sources":["../../../src/fill/fill.ts"],"sourcesContent":["import { basename, relative } from 'node:path';\nimport type { AIOptions } from '@intlayer/api';\nimport {\n prepareIntlayer,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport {\n type ListGitFilesOptions,\n logConfigDetails,\n} from '@intlayer/chokidar/cli';\nimport {\n formatPath,\n getGlobalLimiter,\n getTaskLimiter,\n} from '@intlayer/chokidar/utils';\nimport {\n
|
|
1
|
+
{"version":3,"file":"fill.cjs","names":["ensureArray","setupAI","getTargetUnmergedDictionaries","ANSIColors","listTranslationsTasks","translateDictionary","writeFill"],"sources":["../../../src/fill/fill.ts"],"sourcesContent":["import { basename, relative } from 'node:path';\nimport type { AIOptions } from '@intlayer/api';\nimport {\n prepareIntlayer,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport {\n type ListGitFilesOptions,\n logConfigDetails,\n} from '@intlayer/chokidar/cli';\nimport {\n formatPath,\n getGlobalLimiter,\n getTaskLimiter,\n} from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colorize,\n colorizeKey,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport {\n ensureArray,\n type GetTargetDictionaryOptions,\n getTargetUnmergedDictionaries,\n} from '../getTargetDictionary';\nimport { setupAI } from '../utils/setupAI';\nimport {\n listTranslationsTasks,\n type TranslationTask,\n} from './listTranslationsTasks';\nimport { translateDictionary } from './translateDictionary';\nimport { writeFill } from './writeFill';\n\nconst NB_CONCURRENT_TRANSLATIONS = 7;\n\n// Arguments for the fill function\nexport type FillOptions = {\n sourceLocale?: Locale;\n outputLocales?: Locale | Locale[];\n mode?: 'complete' | 'review';\n gitOptions?: ListGitFilesOptions;\n aiOptions?: AIOptions; // Added aiOptions to be passed to translateJSON\n verbose?: boolean;\n nbConcurrentTranslations?: number;\n nbConcurrentTasks?: number; // NEW: number of tasks that may run at once\n build?: boolean;\n skipMetadata?: boolean;\n} & GetTargetDictionaryOptions;\n\n/**\n * Fill translations based on the provided options.\n */\nexport const fill = async (options?: FillOptions): Promise<void> => {\n const configuration = getConfiguration(options?.configOptions);\n logConfigDetails(options?.configOptions);\n\n const appLogger = getAppLogger(configuration);\n\n if (options?.build === true) {\n await prepareIntlayer(configuration, { forceRun: true });\n } else if (typeof options?.build === 'undefined') {\n await prepareIntlayer(configuration);\n }\n\n const { defaultLocale, locales } = configuration.internationalization;\n const mode = options?.mode ?? 'complete';\n const baseLocale = options?.sourceLocale ?? defaultLocale;\n\n const outputLocales = options?.outputLocales\n ? ensureArray(options.outputLocales)\n : locales;\n\n const aiResult = await setupAI(configuration, options?.aiOptions);\n\n if (!aiResult?.hasAIAccess) return;\n\n const { aiClient, aiConfig } = aiResult;\n\n const targetUnmergedDictionaries =\n await getTargetUnmergedDictionaries(options);\n\n const affectedDictionaryKeys = new Set<string>();\n targetUnmergedDictionaries.forEach((dict) => {\n affectedDictionaryKeys.add(dict.key);\n });\n\n const keysToProcess = Array.from(affectedDictionaryKeys);\n\n appLogger([\n 'Affected dictionary keys for processing:',\n keysToProcess.length > 0\n ? keysToProcess.map((key) => colorizeKey(key)).join(', ')\n : colorize('No keys found', ANSIColors.YELLOW),\n ]);\n\n if (keysToProcess.length === 0) return;\n\n /**\n * List the translations tasks\n *\n * Create a list of per-locale dictionaries to translate\n *\n * In 'complete' mode, filter only the missing locales to translate\n */\n const translationTasks: TranslationTask[] = listTranslationsTasks(\n targetUnmergedDictionaries.map((dictionary) => dictionary.localId!),\n outputLocales,\n mode,\n baseLocale,\n configuration\n );\n\n // AI calls in flight at once (translateJSON + metadata audit)\n const nbConcurrentTranslations =\n options?.nbConcurrentTranslations ?? NB_CONCURRENT_TRANSLATIONS;\n const globalLimiter = getGlobalLimiter(nbConcurrentTranslations);\n\n // NEW: number of *tasks* that may run at once (start/prepare/log/write)\n const nbConcurrentTasks = Math.max(\n 1,\n Math.min(\n options?.nbConcurrentTasks ?? nbConcurrentTranslations,\n translationTasks.length\n )\n );\n\n const taskLimiter = getTaskLimiter(nbConcurrentTasks);\n\n const runners = translationTasks.map((task) =>\n taskLimiter(async () => {\n const relativePath = relative(\n configuration?.content?.baseDir ?? process.cwd(),\n task?.dictionaryFilePath ?? ''\n );\n\n // log AFTER acquiring a task slot\n appLogger(\n `${task.dictionaryPreset} Processing ${colorizePath(basename(relativePath))}`,\n { level: 'info' }\n );\n\n const translationTaskResult = await translateDictionary(\n task,\n configuration,\n {\n mode,\n aiOptions: options?.aiOptions,\n fillMetadata: !options?.skipMetadata,\n onHandle: globalLimiter, // <= AI calls go through here\n aiClient,\n aiConfig,\n }\n );\n\n if (!translationTaskResult?.dictionaryOutput) return;\n\n const { dictionaryOutput, sourceLocale } = translationTaskResult;\n\n // Determine if we should write to separate files\n // - If dictionary has explicit fill setting (string or object), use it\n // - If dictionary is per-locale AND has no explicit fill=false, use global fill config\n // - If dictionary is multilingual (no locale property), always write to same file\n const hasDictionaryLevelFill =\n typeof dictionaryOutput.fill === 'string' ||\n typeof dictionaryOutput.fill === 'object';\n\n const isPerLocale = typeof dictionaryOutput.locale === 'string';\n\n const effectiveFill = hasDictionaryLevelFill\n ? dictionaryOutput.fill\n : isPerLocale\n ? (configuration.dictionary?.fill ?? true)\n : false; // Multilingual dictionaries don't use fill by default\n\n const isFillOtherFile =\n typeof effectiveFill === 'string' || typeof effectiveFill === 'object';\n\n if (isFillOtherFile) {\n await writeFill(\n {\n ...dictionaryOutput,\n // Ensure fill is set on the dictionary for writeFill to use\n fill: effectiveFill,\n },\n outputLocales,\n [sourceLocale],\n configuration\n );\n } else {\n await writeContentDeclaration(dictionaryOutput, configuration);\n\n if (dictionaryOutput.filePath) {\n appLogger(\n `${task.dictionaryPreset} Content declaration written to ${formatPath(basename(dictionaryOutput.filePath))}`,\n { level: 'info' }\n );\n }\n }\n })\n );\n\n await Promise.all(runners);\n await (globalLimiter as any).onIdle();\n};\n"],"mappings":"wiBAqCA,MAmBa,EAAO,KAAO,IAAyC,CAClE,IAAM,GAAA,EAAA,EAAA,kBAAiC,GAAS,cAAc,EAC9D,EAAA,EAAA,kBAAiB,GAAS,cAAc,CAExC,IAAM,GAAA,EAAA,EAAA,cAAyB,EAAc,CAEzC,GAAS,QAAU,GACrB,MAAA,EAAA,EAAA,iBAAsB,EAAe,CAAE,SAAU,GAAM,CAAC,CACxC,GAAS,QAAU,QACnC,MAAA,EAAA,EAAA,iBAAsB,EAAc,CAGtC,GAAM,CAAE,gBAAe,WAAY,EAAc,qBAC3C,EAAO,GAAS,MAAQ,WACxB,EAAa,GAAS,cAAgB,EAEtC,EAAgB,GAAS,cAC3BA,EAAAA,YAAY,EAAQ,cAAc,CAClC,EAEE,EAAW,MAAMC,EAAAA,QAAQ,EAAe,GAAS,UAAU,CAEjE,GAAI,CAAC,GAAU,YAAa,OAE5B,GAAM,CAAE,WAAU,YAAa,EAEzB,EACJ,MAAMC,EAAAA,8BAA8B,EAAQ,CAExC,EAAyB,IAAI,IACnC,EAA2B,QAAS,GAAS,CAC3C,EAAuB,IAAI,EAAK,IAAI,EACpC,CAEF,IAAM,EAAgB,MAAM,KAAK,EAAuB,CASxD,GAPA,EAAU,CACR,2CACA,EAAc,OAAS,EACnB,EAAc,IAAK,IAAA,EAAA,EAAA,aAAoB,EAAI,CAAC,CAAC,KAAK,KAAK,EAAA,EAAA,EAAA,UAC9C,gBAAiBC,EAAW,OAAO,CACjD,CAAC,CAEE,EAAc,SAAW,EAAG,OAShC,IAAM,EAAsCC,EAAAA,sBAC1C,EAA2B,IAAK,GAAe,EAAW,QAAS,CACnE,EACA,EACA,EACA,EACD,CAGK,EACJ,GAAS,0BAA4B,EACjC,GAAA,EAAA,EAAA,kBAAiC,EAAyB,CAW1D,GAAA,EAAA,EAAA,gBARoB,KAAK,IAC7B,EACA,KAAK,IACH,GAAS,mBAAqB,EAC9B,EAAiB,OAClB,CACF,CAEoD,CAE/C,EAAU,EAAiB,IAAK,GACpC,EAAY,SAAY,CACtB,IAAM,GAAA,EAAA,EAAA,UACJ,GAAe,SAAS,SAAW,QAAQ,KAAK,CAChD,GAAM,oBAAsB,GAC7B,CAGD,EACE,GAAG,EAAK,iBAAiB,eAAA,EAAA,EAAA,eAAA,EAAA,EAAA,UAAoC,EAAa,CAAC,GAC3E,CAAE,MAAO,OAAQ,CAClB,CAED,IAAM,EAAwB,MAAMC,EAAAA,oBAClC,EACA,EACA,CACE,OACA,UAAW,GAAS,UACpB,aAAc,CAAC,GAAS,aACxB,SAAU,EACV,WACA,WACD,CACF,CAED,GAAI,CAAC,GAAuB,iBAAkB,OAE9C,GAAM,CAAE,mBAAkB,gBAAiB,EAMrC,EACJ,OAAO,EAAiB,MAAS,UACjC,OAAO,EAAiB,MAAS,SAE7B,EAAc,OAAO,EAAiB,QAAW,SAEjD,EAAgB,EAClB,EAAiB,KACjB,EACG,EAAc,YAAY,MAAQ,GACnC,GAGJ,OAAO,GAAkB,UAAY,OAAO,GAAkB,SAG9D,MAAMC,EAAAA,UACJ,CACE,GAAG,EAEH,KAAM,EACP,CACD,EACA,CAAC,EAAa,CACd,EACD,EAED,MAAA,EAAA,EAAA,yBAA8B,EAAkB,EAAc,CAE1D,EAAiB,UACnB,EACE,GAAG,EAAK,iBAAiB,mCAAA,EAAA,EAAA,aAAA,EAAA,EAAA,UAAsD,EAAiB,SAAS,CAAC,GAC1G,CAAE,MAAO,OAAQ,CAClB,GAGL,CACH,CAED,MAAM,QAAQ,IAAI,EAAQ,CAC1B,MAAO,EAAsB,QAAQ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`})
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../chunk-Bmb41Sf3.cjs`),t=require(`../test/listMissingTranslations.cjs`);let n=require(`node:path`),r=require(`@intlayer/chokidar/utils`),i=require(`@intlayer/config/colors`);i=e.t(i);let a=require(`@intlayer/config/logger`),o=require(`@intlayer/unmerged-dictionaries-entry`),s=require(`@intlayer/core/plugins`),c=require(`@intlayer/dictionaries-entry`);const l=(e,l,u,d,f)=>{let p=(0,a.getAppLogger)(f),m=(0,c.getDictionaries)(f),h=(0,o.getUnmergedDictionaries)(f),g=Object.values(h).flat().filter(t=>e.includes(t.localId)),{missingTranslations:_}=t.listMissingTranslationsWithConfig(f),v=Math.max(...g.map(e=>e.key.length)),y=[];for(let e of g){let t=(0,a.colon)([` - `,(0,a.colorize)(`[`,i.GREY_DARK),(0,a.colorizeKey)(e.key),(0,a.colorize)(`]`,i.GREY_DARK)].join(``),{colSize:v+6}),o=e.key,c=e.localId,h=m[o];if((e.filled??!1)===!0||(e.fill??f.dictionary?.fill??!1)===!1)continue;let g=e.locale??d;if(!h){p(`${t} Dictionary not found in dictionariesRecord. Skipping.`,{level:`warn`});continue}if(!e.filePath){p(`${t} Dictionary has no file path. Skipping.`,{level:`warn`});continue}let b=(0,s.getFilterTranslationsOnlyDictionary)(h,g);if(Object.keys(b).length===0){p(`${t} No content found for dictionary in source locale ${(0,r.formatLocale)(g)}. Skipping translation for this dictionary.`,{level:`warn`});continue}let x=l;if(u===`complete`&&(x=_.find(e=>e.key===o)?.locales.filter(e=>l.includes(e))??[]),x.length===0){p(`${t} ${(0,a.colorize)(`No locales to fill, Skipping`,i.GREY_DARK)} ${(0,a.colorizePath)((0,n.basename)(e.filePath))}`,{level:`warn`});continue}y.push({dictionaryKey:o,dictionaryLocalId:c,sourceLocale:g,targetLocales:x,dictionaryPreset:t,dictionaryFilePath:e.filePath})}return y};exports.listTranslationsTasks=l;
|
|
2
2
|
//# sourceMappingURL=listTranslationsTasks.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listTranslationsTasks.cjs","names":["listMissingTranslationsWithConfig","ANSIColors"],"sources":["../../../src/fill/listTranslationsTasks.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport { formatLocale } from '@intlayer/chokidar/utils';\nimport {\n
|
|
1
|
+
{"version":3,"file":"listTranslationsTasks.cjs","names":["listMissingTranslationsWithConfig","ANSIColors"],"sources":["../../../src/fill/listTranslationsTasks.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport { formatLocale } from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeKey,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport { getFilterTranslationsOnlyDictionary } from '@intlayer/core/plugins';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary, LocalDictionaryId } from '@intlayer/types/dictionary';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { listMissingTranslationsWithConfig } from '../test';\n\nexport type TranslationTask = {\n dictionaryKey: string;\n dictionaryLocalId: LocalDictionaryId;\n sourceLocale: Locale;\n targetLocales: Locale[];\n dictionaryPreset: string;\n dictionaryFilePath: string;\n};\n\nexport const listTranslationsTasks = (\n localIds: LocalDictionaryId[],\n outputLocales: Locale[],\n mode: 'complete' | 'review',\n baseLocale: Locale,\n configuration: IntlayerConfig\n): TranslationTask[] => {\n const appLogger = getAppLogger(configuration);\n\n const mergedDictionariesRecord = getDictionaries(configuration);\n const unmergedDictionariesRecord = getUnmergedDictionaries(configuration);\n\n const allFlatDictionaries = Object.values(unmergedDictionariesRecord).flat();\n const dictionariesToProcess = allFlatDictionaries.filter((dictionary) =>\n localIds.includes(dictionary.localId!)\n );\n\n const { missingTranslations } =\n listMissingTranslationsWithConfig(configuration);\n\n const maxKeyLength = Math.max(\n ...dictionariesToProcess.map((dictionary) => dictionary.key.length)\n );\n\n const translationTasks: TranslationTask[] = [];\n\n for (const targetUnmergedDictionary of dictionariesToProcess) {\n const dictionaryPreset = colon(\n [\n ' - ',\n colorize('[', ANSIColors.GREY_DARK),\n colorizeKey(targetUnmergedDictionary.key),\n colorize(']', ANSIColors.GREY_DARK),\n ].join(''),\n { colSize: maxKeyLength + 6 }\n );\n\n const dictionaryKey = targetUnmergedDictionary.key;\n const dictionaryLocalId = targetUnmergedDictionary.localId!;\n const mainDictionaryToProcess: Dictionary =\n mergedDictionariesRecord[dictionaryKey];\n const dictionaryFilled = targetUnmergedDictionary.filled ?? false;\n\n if (dictionaryFilled === true) {\n continue;\n }\n\n const dictionaryFill =\n targetUnmergedDictionary.fill ?? configuration.dictionary?.fill ?? false;\n\n if (dictionaryFill === false) continue;\n\n const sourceLocale: Locale = (targetUnmergedDictionary.locale ??\n baseLocale) as Locale;\n\n if (!mainDictionaryToProcess) {\n appLogger(\n `${dictionaryPreset} Dictionary not found in dictionariesRecord. Skipping.`,\n {\n level: 'warn',\n }\n );\n continue;\n }\n\n if (!targetUnmergedDictionary.filePath) {\n appLogger(`${dictionaryPreset} Dictionary has no file path. Skipping.`, {\n level: 'warn',\n });\n continue;\n }\n\n const sourceLocaleContent = getFilterTranslationsOnlyDictionary(\n mainDictionaryToProcess,\n sourceLocale\n );\n\n if (\n Object.keys(sourceLocaleContent as Record<string, unknown>).length === 0\n ) {\n appLogger(\n `${dictionaryPreset} No content found for dictionary in source locale ${formatLocale(sourceLocale)}. Skipping translation for this dictionary.`,\n {\n level: 'warn',\n }\n );\n continue;\n }\n\n /**\n * In 'complete' mode, filter only the missing locales to translate\n *\n * Skip the dictionary if there are no missing locales to translate\n */\n let outputLocalesList: Locale[] = outputLocales as Locale[];\n\n if (mode === 'complete') {\n outputLocalesList =\n missingTranslations\n .find(\n (missingTranslation) => missingTranslation.key === dictionaryKey\n )\n ?.locales.filter((locale) => outputLocales.includes(locale)) ?? [];\n }\n\n if (outputLocalesList.length === 0) {\n appLogger(\n `${dictionaryPreset} ${colorize('No locales to fill, Skipping', ANSIColors.GREY_DARK)} ${colorizePath(basename(targetUnmergedDictionary.filePath))}`,\n {\n level: 'warn',\n }\n );\n continue;\n }\n\n translationTasks.push({\n dictionaryKey,\n dictionaryLocalId,\n sourceLocale,\n targetLocales: outputLocalesList,\n dictionaryPreset,\n dictionaryFilePath: targetUnmergedDictionary.filePath,\n });\n }\n\n // Return the list of tasks to execute\n return translationTasks;\n};\n"],"mappings":"sbA2BA,MAAa,GACX,EACA,EACA,EACA,EACA,IACsB,CACtB,IAAM,GAAA,EAAA,EAAA,cAAyB,EAAc,CAEvC,GAAA,EAAA,EAAA,iBAA2C,EAAc,CACzD,GAAA,EAAA,EAAA,yBAAqD,EAAc,CAGnE,EADsB,OAAO,OAAO,EAA2B,CAAC,MAAM,CAC1B,OAAQ,GACxD,EAAS,SAAS,EAAW,QAAS,CACvC,CAEK,CAAE,uBACNA,EAAAA,kCAAkC,EAAc,CAE5C,EAAe,KAAK,IACxB,GAAG,EAAsB,IAAK,GAAe,EAAW,IAAI,OAAO,CACpE,CAEK,EAAsC,EAAE,CAE9C,IAAK,IAAM,KAA4B,EAAuB,CAC5D,IAAM,GAAA,EAAA,EAAA,OACJ,CACE,qBACS,IAAKC,EAAW,UAAU,mBACvB,EAAyB,IAAI,gBAChC,IAAKA,EAAW,UAAU,CACpC,CAAC,KAAK,GAAG,CACV,CAAE,QAAS,EAAe,EAAG,CAC9B,CAEK,EAAgB,EAAyB,IACzC,EAAoB,EAAyB,QAC7C,EACJ,EAAyB,GAU3B,IATyB,EAAyB,QAAU,MAEnC,KAKvB,EAAyB,MAAQ,EAAc,YAAY,MAAQ,MAE9C,GAAO,SAE9B,IAAM,EAAwB,EAAyB,QACrD,EAEF,GAAI,CAAC,EAAyB,CAC5B,EACE,GAAG,EAAiB,wDACpB,CACE,MAAO,OACR,CACF,CACD,SAGF,GAAI,CAAC,EAAyB,SAAU,CACtC,EAAU,GAAG,EAAiB,yCAA0C,CACtE,MAAO,OACR,CAAC,CACF,SAGF,IAAM,GAAA,EAAA,EAAA,qCACJ,EACA,EACD,CAED,GACE,OAAO,KAAK,EAA+C,CAAC,SAAW,EACvE,CACA,EACE,GAAG,EAAiB,qDAAA,EAAA,EAAA,cAAiE,EAAa,CAAC,6CACnG,CACE,MAAO,OACR,CACF,CACD,SAQF,IAAI,EAA8B,EAWlC,GATI,IAAS,aACX,EACE,EACG,KACE,GAAuB,EAAmB,MAAQ,EACpD,EACC,QAAQ,OAAQ,GAAW,EAAc,SAAS,EAAO,CAAC,EAAI,EAAE,EAGpE,EAAkB,SAAW,EAAG,CAClC,EACE,GAAG,EAAiB,IAAA,EAAA,EAAA,UAAY,+BAAgCA,EAAW,UAAU,CAAC,IAAA,EAAA,EAAA,eAAA,EAAA,EAAA,UAAyB,EAAyB,SAAS,CAAC,GAClJ,CACE,MAAO,OACR,CACF,CACD,SAGF,EAAiB,KAAK,CACpB,gBACA,oBACA,eACA,cAAe,EACf,mBACA,mBAAoB,EAAyB,SAC9C,CAAC,CAIJ,OAAO"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`})
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../chunk-Bmb41Sf3.cjs`),t=require(`./deepMergeContent.cjs`),n=require(`./getFilterMissingContentPerLocale.cjs`);let r=require(`node:path`),i=require(`@intlayer/chokidar/utils`),a=require(`@intlayer/config/colors`);a=e.t(a);let o=require(`@intlayer/config/logger`),s=require(`@intlayer/unmerged-dictionaries-entry`),c=require(`@intlayer/core/plugins`),l=require(`@intlayer/api`),u=require(`@intlayer/config/utils`);const d=e=>!e.description||!e.title||!e.tags,f=e=>{if(typeof e!=`object`||!e||Array.isArray(e))return{content:e,nulls:void 0,hasNulls:!1};let t={},n={},r=!1;for(let[i,a]of Object.entries(e))if(a===null)n[i]=null,r=!0;else{let e=f(a);t[i]=e.content,e.hasNulls&&(n[i]=e.nulls,r=!0)}return{content:t,nulls:r?n:void 0,hasNulls:r}},p=1e3*10;let m=0;const h=async(e,h,g)=>{let _=(0,o.getAppLogger)(h),v=(0,l.getIntlayerAPIProxy)(void 0,h),{mode:y,aiOptions:b,fillMetadata:x,aiClient:S,aiConfig:C}={mode:`complete`,fillMetadata:!0,...g},w=()=>{m=0,g?.onSuccess?.()};return await(0,u.retryManager)(async()=>{let l=(0,s.getUnmergedDictionaries)(h),T=l[e.dictionaryKey].find(t=>t.localId===e.dictionaryLocalId);if(!T)return _(`${e.dictionaryPreset}Dictionary not found in unmergedDictionariesRecord. Skipping.`,{level:`warn`}),{...e,dictionaryOutput:null};let E;if(x&&(d(T)||y===`review`)){let t=(0,c.getPerLocaleDictionary)(T,h.internationalization.defaultLocale);_(`${e.dictionaryPreset} Filling missing metadata for ${(0,o.colorizePath)((0,r.basename)(T.filePath))}`,{level:`info`});let n=async()=>S&&C?{data:await S.auditDictionaryMetadata({fileContent:JSON.stringify(t),aiConfig:C})}:await v.ai.auditContentDeclarationMetadata({fileContent:JSON.stringify(t),aiOptions:b});E=(g?.onHandle?await g.onHandle(n):await n()).data?.fileContent}let D=await Promise.all(e.targetLocales.map(async s=>{let d=structuredClone(T),h;if(typeof T.locale==`string`){let t=T.filePath?.replace(RegExp(`/${e.sourceLocale}/`,`g`),`/${s}/`),r=t?l[e.dictionaryKey]?.find(e=>e.filePath===t&&e.locale===s):void 0;h=r??{key:T.key,content:{},filePath:t,locale:s},y===`complete`&&(d=n.getFilterMissingContentPerLocale(d,r))}else y===`complete`&&(d=(0,c.getFilterMissingTranslationsDictionary)(d,s)),d=(0,c.getPerLocaleDictionary)(d,e.sourceLocale),h=(0,c.getPerLocaleDictionary)(T,s);let x=(0,o.colon)([(0,o.colorize)(`[`,a.GREY_DARK),(0,i.formatLocale)(s),(0,o.colorize)(`]`,a.GREY_DARK)].join(``),{colSize:18}),D=(e,t)=>t<=1?``:(0,o.colon)([(0,o.colorize)(`[`,a.GREY_DARK),(0,o.colorizeNumber)(e+1),(0,o.colorize)(`/${t}`,a.GREY_DARK),(0,o.colorize)(`]`,a.GREY_DARK)].join(``),{colSize:5});_(`${e.dictionaryPreset}${x} Preparing ${(0,o.colorizePath)((0,r.basename)(h.filePath))}`,{level:`info`});let O=typeof d.content==`object`&&d.content!==null||Array.isArray(d.content),{content:k,nulls:A}=f(O?d.content:{__INTLAYER_ROOT_PRIMITIVE_CONTENT__:d.content}),j=(0,i.chunkJSON)(k,7e3),M=j.length;M>1&&_(`${e.dictionaryPreset}${x} Split into ${(0,o.colorizeNumber)(M)} chunks for translation`,{level:`info`});let N=[],P=j.map(t=>{let n=D(t.index,t.total);M>1&&_(`${e.dictionaryPreset}${x}${n} Translating chunk`,{level:`info`});let r=(0,i.reconstructFromSingleChunk)(t),c=(0,i.reduceObjectFormat)(O?h.content:{__INTLAYER_ROOT_PRIMITIVE_CONTENT__:h.content},r),l=async()=>await(0,u.retryManager)(async()=>{let t;if(t=S&&C?await S.translateJSON({entryFileContent:r,presetOutputContent:c,dictionaryDescription:d.description??E?.description??``,entryLocale:e.sourceLocale,outputLocale:s,mode:y,aiConfig:C}):await v.ai.translateJSON({entryFileContent:r,presetOutputContent:c,dictionaryDescription:d.description??E?.description??``,entryLocale:e.sourceLocale,outputLocale:s,mode:y,aiOptions:b}).then(e=>e.data),!t?.fileContent)throw Error(`No content result`);let{isIdentic:n}=(0,i.verifyIdenticObjectFormat)(t.fileContent,r);if(!n)throw Error(`Translation result does not match expected format`);return w(),t.fileContent},{maxRetry:3,delay:p,onError:({error:n,attempt:r,maxRetry:i})=>{let s=D(t.index,t.total);_(`${e.dictionaryPreset}${x}${s} ${(0,o.colorize)(`Error filling:`,a.RED)} ${(0,o.colorize)(typeof n==`string`?n:JSON.stringify(n),a.GREY_DARK)} - Attempt ${(0,o.colorizeNumber)(r+1)} of ${(0,o.colorizeNumber)(i)}`,{level:`error`}),m+=1,m>=10&&(_(`There is something wrong.`,{level:`error`}),process.exit(1))}})();return(g?.onHandle?g.onHandle(l):l()).then(e=>({chunk:t,result:e}))});(await Promise.all(P)).sort((e,t)=>e.chunk.index-t.chunk.index).forEach(({result:e})=>{N.push(e)});let F=(0,i.mergeChunks)(N);A&&(F=t.deepMergeContent(F,A));let I={...d,content:F}.content;return O||(I=I?.__INTLAYER_ROOT_PRIMITIVE_CONTENT__),typeof T.locale==`string`&&(I=t.deepMergeContent(h.content??{},I)),[s,I]})),O=Object.fromEntries(D),k={...(0,c.getMultilingualDictionary)(T.locale?{...T,key:T.key,content:{}}:T),locale:void 0,...E};for(let t of e.targetLocales)O[t]&&(k=(0,c.insertContentInDictionary)(k,O[t],t));if(_(`${e.dictionaryPreset} ${(0,o.colorize)(`Translation completed successfully`,a.GREEN)} for ${(0,o.colorizePath)((0,r.basename)(k.filePath))}`,{level:`info`}),T.locale&&(T.fill===!0||T.fill===void 0)&&T.location===`local`){let t=T.filePath.split(`.`).slice(0,-1),n=t[t.length-1];return JSON.parse(JSON.stringify({...e,dictionaryOutput:{...k,fill:void 0,filled:!0}}).replaceAll(RegExp(`\\.${n}\\.[a-zA-Z0-9]+`,`g`),`.filled.${n}.json`))}return{...e,dictionaryOutput:k}},{maxRetry:2,delay:p,onError:({error:t,attempt:n,maxRetry:r})=>_(`${e.dictionaryPreset} ${(0,o.colorize)(`Error:`,a.RED)} ${(0,o.colorize)(typeof t==`string`?t:JSON.stringify(t),a.GREY_DARK)} - Attempt ${(0,o.colorizeNumber)(n+1)} of ${(0,o.colorizeNumber)(r)}`,{level:`error`}),onMaxTryReached:({error:t})=>_(`${e.dictionaryPreset} ${(0,o.colorize)(`Maximum number of retries reached:`,a.RED)} ${(0,o.colorize)(typeof t==`string`?t:JSON.stringify(t),a.GREY_DARK)}`,{level:`error`})})()};exports.translateDictionary=h;
|
|
2
2
|
//# sourceMappingURL=translateDictionary.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translateDictionary.cjs","names":["getFilterMissingContentPerLocale","ANSIColors","deepMergeContent"],"sources":["../../../src/fill/translateDictionary.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport type { AIConfig } from '@intlayer/ai';\nimport { type AIOptions, getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n chunkJSON,\n formatLocale,\n type JsonChunk,\n mergeChunks,\n reconstructFromSingleChunk,\n reduceObjectFormat,\n verifyIdenticObjectFormat,\n} from '@intlayer/chokidar/utils';\nimport {\n ANSIColors,\n colon,\n colorize,\n colorizeNumber,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport { retryManager } from '@intlayer/config/utils';\nimport {\n getFilterMissingTranslationsDictionary,\n getMultilingualDictionary,\n getPerLocaleDictionary,\n insertContentInDictionary,\n} from '@intlayer/core/plugins';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport type { AIClient } from '../utils/setupAI';\nimport { deepMergeContent } from './deepMergeContent';\nimport { getFilterMissingContentPerLocale } from './getFilterMissingContentPerLocale';\nimport type { TranslationTask } from './listTranslationsTasks';\n\ntype TranslateDictionaryResult = TranslationTask & {\n dictionaryOutput: Dictionary | null;\n};\n\ntype TranslateDictionaryOptions = {\n mode: 'complete' | 'review';\n aiOptions?: AIOptions;\n fillMetadata?: boolean;\n onHandle?: ReturnType<\n typeof import('@intlayer/chokidar/utils').getGlobalLimiter\n >;\n onSuccess?: () => void;\n onError?: (error: unknown) => void;\n getAbortError?: () => Error | null;\n aiClient?: AIClient;\n aiConfig?: AIConfig;\n};\n\nconst hasMissingMetadata = (dictionary: Dictionary) =>\n !dictionary.description || !dictionary.title || !dictionary.tags;\n\n/**\n * Recursively strips null values from an object, returning the cleaned content\n * and a separate object containing only the null-valued paths so they can be\n * re-injected after AI translation (nulls don't need translation).\n */\nconst stripNullValues = (\n obj: any\n): { content: any; nulls: any; hasNulls: boolean } => {\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return { content: obj, nulls: undefined, hasNulls: false };\n }\n\n const content: any = {};\n const nulls: any = {};\n let hasNulls = false;\n\n for (const [key, value] of Object.entries(obj)) {\n if (value === null) {\n nulls[key] = null;\n hasNulls = true;\n } else {\n const child = stripNullValues(value);\n content[key] = child.content;\n if (child.hasNulls) {\n nulls[key] = child.nulls;\n hasNulls = true;\n }\n }\n }\n\n return { content, nulls: hasNulls ? nulls : undefined, hasNulls };\n};\n\nconst CHUNK_SIZE = 7000; // GPT-5 Mini safe input size\nconst GROUP_MAX_RETRY = 2;\nconst MAX_RETRY = 3;\nconst RETRY_DELAY = 1000 * 10; // 10 seconds\n\nconst MAX_FOLLOWING_ERRORS = 10; // 10 errors in a row, hard exit the process\nlet followingErrors = 0;\n\nexport const translateDictionary = async (\n task: TranslationTask,\n configuration: IntlayerConfig,\n options?: TranslateDictionaryOptions\n): Promise<TranslateDictionaryResult> => {\n const appLogger = getAppLogger(configuration);\n const intlayerAPI = getIntlayerAPIProxy(undefined, configuration);\n\n const { mode, aiOptions, fillMetadata, aiClient, aiConfig } = {\n mode: 'complete',\n fillMetadata: true,\n ...options,\n } as const;\n\n const notifySuccess = () => {\n followingErrors = 0;\n options?.onSuccess?.();\n };\n\n const result = await retryManager(\n async () => {\n const unmergedDictionariesRecord = getUnmergedDictionaries(configuration);\n\n const baseUnmergedDictionary: Dictionary | undefined =\n unmergedDictionariesRecord[task.dictionaryKey].find(\n (dict) => dict.localId === task.dictionaryLocalId\n );\n\n if (!baseUnmergedDictionary) {\n appLogger(\n `${task.dictionaryPreset}Dictionary not found in unmergedDictionariesRecord. Skipping.`,\n {\n level: 'warn',\n }\n );\n return { ...task, dictionaryOutput: null };\n }\n\n let metadata:\n | Pick<Dictionary, 'description' | 'title' | 'tags'>\n | undefined;\n\n if (\n fillMetadata &&\n (hasMissingMetadata(baseUnmergedDictionary) || mode === 'review')\n ) {\n const defaultLocaleDictionary = getPerLocaleDictionary(\n baseUnmergedDictionary,\n configuration.internationalization.defaultLocale\n );\n\n appLogger(\n `${task.dictionaryPreset} Filling missing metadata for ${colorizePath(basename(baseUnmergedDictionary.filePath!))}`,\n {\n level: 'info',\n }\n );\n\n const runAudit = async () => {\n if (aiClient && aiConfig) {\n const result = await aiClient.auditDictionaryMetadata({\n fileContent: JSON.stringify(defaultLocaleDictionary),\n aiConfig,\n });\n\n return {\n data: result,\n };\n }\n\n return await intlayerAPI.ai.auditContentDeclarationMetadata({\n fileContent: JSON.stringify(defaultLocaleDictionary),\n aiOptions,\n });\n };\n\n const metadataResult = options?.onHandle\n ? await options.onHandle(runAudit)\n : await runAudit();\n\n metadata = metadataResult.data?.fileContent;\n }\n\n const translatedContentResults = await Promise.all(\n task.targetLocales.map(async (targetLocale) => {\n /**\n * In complete mode, for large dictionaries, we want to filter all content that is already translated\n *\n * targetLocale: fr\n *\n * { test1: t({ ar: 'Hello', en: 'Hello', fr: 'Bonjour' } }) -> {}\n * { test2: t({ ar: 'Hello', en: 'Hello' }) } -> { test2: t({ ar: 'Hello', en: 'Hello' }) }\n *\n */\n // Reset to base dictionary for each locale to ensure we filter from the original\n let dictionaryToProcess = structuredClone(baseUnmergedDictionary);\n\n let targetLocaleDictionary: Dictionary;\n\n if (typeof baseUnmergedDictionary.locale === 'string') {\n // For per-locale files, the content is already in simple JSON format (not translation nodes)\n // The base dictionary is already the source locale content\n\n // Load the existing target locale dictionary\n const targetLocaleFilePath =\n baseUnmergedDictionary.filePath?.replace(\n new RegExp(`/${task.sourceLocale}/`, 'g'),\n `/${targetLocale}/`\n );\n\n // Find the target locale dictionary in unmerged dictionaries\n const targetUnmergedDictionary = targetLocaleFilePath\n ? unmergedDictionariesRecord[task.dictionaryKey]?.find(\n (dict) =>\n dict.filePath === targetLocaleFilePath &&\n dict.locale === targetLocale\n )\n : undefined;\n\n targetLocaleDictionary = targetUnmergedDictionary ?? {\n key: baseUnmergedDictionary.key,\n content: {},\n filePath: targetLocaleFilePath,\n locale: targetLocale,\n };\n\n // In complete mode, filter out already translated content\n if (mode === 'complete') {\n dictionaryToProcess = getFilterMissingContentPerLocale(\n dictionaryToProcess,\n targetUnmergedDictionary\n );\n }\n } else {\n // For multilingual dictionaries\n if (mode === 'complete') {\n // Remove all nodes that don't have any content to translate\n dictionaryToProcess = getFilterMissingTranslationsDictionary(\n dictionaryToProcess,\n targetLocale\n );\n }\n\n dictionaryToProcess = getPerLocaleDictionary(\n dictionaryToProcess,\n task.sourceLocale\n );\n\n targetLocaleDictionary = getPerLocaleDictionary(\n baseUnmergedDictionary,\n targetLocale\n );\n }\n\n const localePreset = colon(\n [\n colorize('[', ANSIColors.GREY_DARK),\n formatLocale(targetLocale),\n colorize(']', ANSIColors.GREY_DARK),\n ].join(''),\n { colSize: 18 }\n );\n\n const createChunkPreset = (\n chunkIndex: number,\n totalChunks: number\n ) => {\n if (totalChunks <= 1) return '';\n return colon(\n [\n colorize('[', ANSIColors.GREY_DARK),\n colorizeNumber(chunkIndex + 1),\n colorize(`/${totalChunks}`, ANSIColors.GREY_DARK),\n colorize(']', ANSIColors.GREY_DARK),\n ].join(''),\n { colSize: 5 }\n );\n };\n\n appLogger(\n `${task.dictionaryPreset}${localePreset} Preparing ${colorizePath(basename(targetLocaleDictionary.filePath!))}`,\n {\n level: 'info',\n }\n );\n\n const isContentStructured =\n (typeof dictionaryToProcess.content === 'object' &&\n dictionaryToProcess.content !== null) ||\n Array.isArray(dictionaryToProcess.content);\n\n const rawContentToProcess = isContentStructured\n ? dictionaryToProcess.content\n : {\n __INTLAYER_ROOT_PRIMITIVE_CONTENT__:\n dictionaryToProcess.content,\n };\n\n // Strip null values before sending to AI — nulls need no translation\n // and confuse the model. They will be re-injected after merging.\n const { content: contentToProcess, nulls: strippedNullValues } =\n stripNullValues(rawContentToProcess);\n\n const chunkedJsonContent: JsonChunk[] = chunkJSON(\n contentToProcess as unknown as Record<string, any>,\n CHUNK_SIZE\n );\n\n const nbOfChunks = chunkedJsonContent.length;\n\n if (nbOfChunks > 1) {\n appLogger(\n `${task.dictionaryPreset}${localePreset} Split into ${colorizeNumber(nbOfChunks)} chunks for translation`,\n {\n level: 'info',\n }\n );\n }\n\n const chunkResult: JsonChunk[] = [];\n\n // Process chunks in parallel (globally throttled) to allow concurrent translation\n const chunkPromises = chunkedJsonContent.map((chunk) => {\n const chunkPreset = createChunkPreset(chunk.index, chunk.total);\n\n if (nbOfChunks > 1) {\n appLogger(\n `${task.dictionaryPreset}${localePreset}${chunkPreset} Translating chunk`,\n {\n level: 'info',\n }\n );\n }\n\n // Reconstruct partial JSON content from this chunk's patches\n const chunkContent = reconstructFromSingleChunk(chunk);\n const presetOutputContent = reduceObjectFormat(\n isContentStructured\n ? targetLocaleDictionary.content\n : {\n __INTLAYER_ROOT_PRIMITIVE_CONTENT__:\n targetLocaleDictionary.content,\n },\n chunkContent\n ) as unknown as JSON;\n\n const executeTranslation = async () => {\n return await retryManager(\n async () => {\n let translationResult: any;\n\n if (aiClient && aiConfig) {\n translationResult = await aiClient.translateJSON({\n entryFileContent: chunkContent as unknown as JSON,\n presetOutputContent,\n dictionaryDescription:\n dictionaryToProcess.description ??\n metadata?.description ??\n '',\n entryLocale: task.sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiConfig,\n });\n } else {\n translationResult = await intlayerAPI.ai\n .translateJSON({\n entryFileContent: chunkContent as unknown as JSON,\n presetOutputContent,\n dictionaryDescription:\n dictionaryToProcess.description ??\n metadata?.description ??\n '',\n entryLocale: task.sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiOptions,\n })\n .then((result) => result.data);\n }\n\n if (!translationResult?.fileContent) {\n throw new Error('No content result');\n }\n\n const { isIdentic } = verifyIdenticObjectFormat(\n translationResult.fileContent,\n chunkContent\n );\n\n if (!isIdentic) {\n throw new Error(\n 'Translation result does not match expected format'\n );\n }\n\n notifySuccess();\n return translationResult.fileContent;\n },\n {\n maxRetry: MAX_RETRY,\n delay: RETRY_DELAY,\n onError: ({ error, attempt, maxRetry }) => {\n const chunkPreset = createChunkPreset(\n chunk.index,\n chunk.total\n );\n appLogger(\n `${task.dictionaryPreset}${localePreset}${chunkPreset} ${colorize('Error filling:', ANSIColors.RED)} ${colorize(typeof error === 'string' ? error : JSON.stringify(error), ANSIColors.GREY_DARK)} - Attempt ${colorizeNumber(attempt + 1)} of ${colorizeNumber(maxRetry)}`,\n {\n level: 'error',\n }\n );\n\n followingErrors += 1;\n\n if (followingErrors >= MAX_FOLLOWING_ERRORS) {\n appLogger(`There is something wrong.`, {\n level: 'error',\n });\n process.exit(1); // 1 for error\n }\n },\n }\n )();\n };\n\n const wrapped = options?.onHandle\n ? options.onHandle(executeTranslation) // queued in global limiter\n : executeTranslation(); // no global limiter\n\n return wrapped.then((result) => ({ chunk, result }));\n });\n\n // Wait for all chunks for this locale in parallel (still capped by global limiter)\n const chunkResults = await Promise.all(chunkPromises);\n\n // Maintain order\n chunkResults\n .sort((chunkA, chunkB) => chunkA.chunk.index - chunkB.chunk.index)\n .forEach(({ result }) => {\n chunkResult.push(result);\n });\n\n // Merge partial JSON objects produced from each chunk into a single object\n let mergedContent = mergeChunks(chunkResult);\n\n // Re-inject null values that were stripped before AI translation\n if (strippedNullValues) {\n mergedContent = deepMergeContent(mergedContent, strippedNullValues);\n }\n\n const merged = {\n ...dictionaryToProcess,\n content: mergedContent,\n };\n\n // For per-locale files, merge the newly translated content with existing target content\n let finalContent = merged.content;\n\n if (!isContentStructured) {\n finalContent = (finalContent as any)\n ?.__INTLAYER_ROOT_PRIMITIVE_CONTENT__;\n }\n\n if (typeof baseUnmergedDictionary.locale === 'string') {\n // Deep merge: existing content + newly translated content\n finalContent = deepMergeContent(\n targetLocaleDictionary.content ?? {},\n finalContent\n );\n }\n\n return [targetLocale, finalContent] as const;\n })\n );\n\n const translatedContent: Partial<Record<Locale, Dictionary['content']>> =\n Object.fromEntries(translatedContentResults);\n\n const baseDictionary = baseUnmergedDictionary.locale\n ? {\n ...baseUnmergedDictionary,\n key: baseUnmergedDictionary.key!,\n content: {},\n }\n : baseUnmergedDictionary;\n\n let dictionaryOutput: Dictionary = {\n ...getMultilingualDictionary(baseDictionary),\n locale: undefined, // Ensure the dictionary is multilingual\n ...metadata,\n };\n\n for (const targetLocale of task.targetLocales) {\n if (translatedContent[targetLocale]) {\n dictionaryOutput = insertContentInDictionary(\n dictionaryOutput,\n translatedContent[targetLocale],\n targetLocale\n );\n }\n }\n\n appLogger(\n `${task.dictionaryPreset} ${colorize('Translation completed successfully', ANSIColors.GREEN)} for ${colorizePath(basename(dictionaryOutput.filePath!))}`,\n {\n level: 'info',\n }\n );\n\n if (\n baseUnmergedDictionary.locale &&\n (baseUnmergedDictionary.fill === true ||\n baseUnmergedDictionary.fill === undefined) &&\n baseUnmergedDictionary.location === 'local'\n ) {\n const dictionaryFilePath = baseUnmergedDictionary\n .filePath!.split('.')\n .slice(0, -1);\n\n const contentIndex = dictionaryFilePath[dictionaryFilePath.length - 1];\n\n return JSON.parse(\n JSON.stringify({\n ...task,\n dictionaryOutput: {\n ...dictionaryOutput,\n fill: undefined,\n filled: true,\n },\n }).replaceAll(\n new RegExp(`\\\\.${contentIndex}\\\\.[a-zA-Z0-9]+`, 'g'),\n `.filled.${contentIndex}.json`\n )\n );\n }\n\n return {\n ...task,\n dictionaryOutput,\n };\n },\n {\n maxRetry: GROUP_MAX_RETRY,\n delay: RETRY_DELAY,\n onError: ({ error, attempt, maxRetry }) =>\n appLogger(\n `${task.dictionaryPreset} ${colorize('Error:', ANSIColors.RED)} ${colorize(typeof error === 'string' ? error : JSON.stringify(error), ANSIColors.GREY_DARK)} - Attempt ${colorizeNumber(attempt + 1)} of ${colorizeNumber(maxRetry)}`,\n {\n level: 'error',\n }\n ),\n onMaxTryReached: ({ error }) =>\n appLogger(\n `${task.dictionaryPreset} ${colorize('Maximum number of retries reached:', ANSIColors.RED)} ${colorize(typeof error === 'string' ? error : JSON.stringify(error), ANSIColors.GREY_DARK)}`,\n {\n level: 'error',\n }\n ),\n }\n )();\n\n return result as TranslateDictionaryResult;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"translateDictionary.cjs","names":["getFilterMissingContentPerLocale","ANSIColors","deepMergeContent"],"sources":["../../../src/fill/translateDictionary.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport type { AIConfig } from '@intlayer/ai';\nimport { type AIOptions, getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n chunkJSON,\n formatLocale,\n type JsonChunk,\n mergeChunks,\n reconstructFromSingleChunk,\n reduceObjectFormat,\n verifyIdenticObjectFormat,\n} from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeNumber,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport { retryManager } from '@intlayer/config/utils';\nimport {\n getFilterMissingTranslationsDictionary,\n getMultilingualDictionary,\n getPerLocaleDictionary,\n insertContentInDictionary,\n} from '@intlayer/core/plugins';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport type { AIClient } from '../utils/setupAI';\nimport { deepMergeContent } from './deepMergeContent';\nimport { getFilterMissingContentPerLocale } from './getFilterMissingContentPerLocale';\nimport type { TranslationTask } from './listTranslationsTasks';\n\ntype TranslateDictionaryResult = TranslationTask & {\n dictionaryOutput: Dictionary | null;\n};\n\ntype TranslateDictionaryOptions = {\n mode: 'complete' | 'review';\n aiOptions?: AIOptions;\n fillMetadata?: boolean;\n onHandle?: ReturnType<\n typeof import('@intlayer/chokidar/utils').getGlobalLimiter\n >;\n onSuccess?: () => void;\n onError?: (error: unknown) => void;\n getAbortError?: () => Error | null;\n aiClient?: AIClient;\n aiConfig?: AIConfig;\n};\n\nconst hasMissingMetadata = (dictionary: Dictionary) =>\n !dictionary.description || !dictionary.title || !dictionary.tags;\n\n/**\n * Recursively strips null values from an object, returning the cleaned content\n * and a separate object containing only the null-valued paths so they can be\n * re-injected after AI translation (nulls don't need translation).\n */\nconst stripNullValues = (\n obj: any\n): { content: any; nulls: any; hasNulls: boolean } => {\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return { content: obj, nulls: undefined, hasNulls: false };\n }\n\n const content: any = {};\n const nulls: any = {};\n let hasNulls = false;\n\n for (const [key, value] of Object.entries(obj)) {\n if (value === null) {\n nulls[key] = null;\n hasNulls = true;\n } else {\n const child = stripNullValues(value);\n content[key] = child.content;\n if (child.hasNulls) {\n nulls[key] = child.nulls;\n hasNulls = true;\n }\n }\n }\n\n return { content, nulls: hasNulls ? nulls : undefined, hasNulls };\n};\n\nconst CHUNK_SIZE = 7000; // GPT-5 Mini safe input size\nconst GROUP_MAX_RETRY = 2;\nconst MAX_RETRY = 3;\nconst RETRY_DELAY = 1000 * 10; // 10 seconds\n\nconst MAX_FOLLOWING_ERRORS = 10; // 10 errors in a row, hard exit the process\nlet followingErrors = 0;\n\nexport const translateDictionary = async (\n task: TranslationTask,\n configuration: IntlayerConfig,\n options?: TranslateDictionaryOptions\n): Promise<TranslateDictionaryResult> => {\n const appLogger = getAppLogger(configuration);\n const intlayerAPI = getIntlayerAPIProxy(undefined, configuration);\n\n const { mode, aiOptions, fillMetadata, aiClient, aiConfig } = {\n mode: 'complete',\n fillMetadata: true,\n ...options,\n } as const;\n\n const notifySuccess = () => {\n followingErrors = 0;\n options?.onSuccess?.();\n };\n\n const result = await retryManager(\n async () => {\n const unmergedDictionariesRecord = getUnmergedDictionaries(configuration);\n\n const baseUnmergedDictionary: Dictionary | undefined =\n unmergedDictionariesRecord[task.dictionaryKey].find(\n (dict) => dict.localId === task.dictionaryLocalId\n );\n\n if (!baseUnmergedDictionary) {\n appLogger(\n `${task.dictionaryPreset}Dictionary not found in unmergedDictionariesRecord. Skipping.`,\n {\n level: 'warn',\n }\n );\n return { ...task, dictionaryOutput: null };\n }\n\n let metadata:\n | Pick<Dictionary, 'description' | 'title' | 'tags'>\n | undefined;\n\n if (\n fillMetadata &&\n (hasMissingMetadata(baseUnmergedDictionary) || mode === 'review')\n ) {\n const defaultLocaleDictionary = getPerLocaleDictionary(\n baseUnmergedDictionary,\n configuration.internationalization.defaultLocale\n );\n\n appLogger(\n `${task.dictionaryPreset} Filling missing metadata for ${colorizePath(basename(baseUnmergedDictionary.filePath!))}`,\n {\n level: 'info',\n }\n );\n\n const runAudit = async () => {\n if (aiClient && aiConfig) {\n const result = await aiClient.auditDictionaryMetadata({\n fileContent: JSON.stringify(defaultLocaleDictionary),\n aiConfig,\n });\n\n return {\n data: result,\n };\n }\n\n return await intlayerAPI.ai.auditContentDeclarationMetadata({\n fileContent: JSON.stringify(defaultLocaleDictionary),\n aiOptions,\n });\n };\n\n const metadataResult = options?.onHandle\n ? await options.onHandle(runAudit)\n : await runAudit();\n\n metadata = metadataResult.data?.fileContent;\n }\n\n const translatedContentResults = await Promise.all(\n task.targetLocales.map(async (targetLocale) => {\n /**\n * In complete mode, for large dictionaries, we want to filter all content that is already translated\n *\n * targetLocale: fr\n *\n * { test1: t({ ar: 'Hello', en: 'Hello', fr: 'Bonjour' } }) -> {}\n * { test2: t({ ar: 'Hello', en: 'Hello' }) } -> { test2: t({ ar: 'Hello', en: 'Hello' }) }\n *\n */\n // Reset to base dictionary for each locale to ensure we filter from the original\n let dictionaryToProcess = structuredClone(baseUnmergedDictionary);\n\n let targetLocaleDictionary: Dictionary;\n\n if (typeof baseUnmergedDictionary.locale === 'string') {\n // For per-locale files, the content is already in simple JSON format (not translation nodes)\n // The base dictionary is already the source locale content\n\n // Load the existing target locale dictionary\n const targetLocaleFilePath =\n baseUnmergedDictionary.filePath?.replace(\n new RegExp(`/${task.sourceLocale}/`, 'g'),\n `/${targetLocale}/`\n );\n\n // Find the target locale dictionary in unmerged dictionaries\n const targetUnmergedDictionary = targetLocaleFilePath\n ? unmergedDictionariesRecord[task.dictionaryKey]?.find(\n (dict) =>\n dict.filePath === targetLocaleFilePath &&\n dict.locale === targetLocale\n )\n : undefined;\n\n targetLocaleDictionary = targetUnmergedDictionary ?? {\n key: baseUnmergedDictionary.key,\n content: {},\n filePath: targetLocaleFilePath,\n locale: targetLocale,\n };\n\n // In complete mode, filter out already translated content\n if (mode === 'complete') {\n dictionaryToProcess = getFilterMissingContentPerLocale(\n dictionaryToProcess,\n targetUnmergedDictionary\n );\n }\n } else {\n // For multilingual dictionaries\n if (mode === 'complete') {\n // Remove all nodes that don't have any content to translate\n dictionaryToProcess = getFilterMissingTranslationsDictionary(\n dictionaryToProcess,\n targetLocale\n );\n }\n\n dictionaryToProcess = getPerLocaleDictionary(\n dictionaryToProcess,\n task.sourceLocale\n );\n\n targetLocaleDictionary = getPerLocaleDictionary(\n baseUnmergedDictionary,\n targetLocale\n );\n }\n\n const localePreset = colon(\n [\n colorize('[', ANSIColors.GREY_DARK),\n formatLocale(targetLocale),\n colorize(']', ANSIColors.GREY_DARK),\n ].join(''),\n { colSize: 18 }\n );\n\n const createChunkPreset = (\n chunkIndex: number,\n totalChunks: number\n ) => {\n if (totalChunks <= 1) return '';\n return colon(\n [\n colorize('[', ANSIColors.GREY_DARK),\n colorizeNumber(chunkIndex + 1),\n colorize(`/${totalChunks}`, ANSIColors.GREY_DARK),\n colorize(']', ANSIColors.GREY_DARK),\n ].join(''),\n { colSize: 5 }\n );\n };\n\n appLogger(\n `${task.dictionaryPreset}${localePreset} Preparing ${colorizePath(basename(targetLocaleDictionary.filePath!))}`,\n {\n level: 'info',\n }\n );\n\n const isContentStructured =\n (typeof dictionaryToProcess.content === 'object' &&\n dictionaryToProcess.content !== null) ||\n Array.isArray(dictionaryToProcess.content);\n\n const rawContentToProcess = isContentStructured\n ? dictionaryToProcess.content\n : {\n __INTLAYER_ROOT_PRIMITIVE_CONTENT__:\n dictionaryToProcess.content,\n };\n\n // Strip null values before sending to AI — nulls need no translation\n // and confuse the model. They will be re-injected after merging.\n const { content: contentToProcess, nulls: strippedNullValues } =\n stripNullValues(rawContentToProcess);\n\n const chunkedJsonContent: JsonChunk[] = chunkJSON(\n contentToProcess as unknown as Record<string, any>,\n CHUNK_SIZE\n );\n\n const nbOfChunks = chunkedJsonContent.length;\n\n if (nbOfChunks > 1) {\n appLogger(\n `${task.dictionaryPreset}${localePreset} Split into ${colorizeNumber(nbOfChunks)} chunks for translation`,\n {\n level: 'info',\n }\n );\n }\n\n const chunkResult: JsonChunk[] = [];\n\n // Process chunks in parallel (globally throttled) to allow concurrent translation\n const chunkPromises = chunkedJsonContent.map((chunk) => {\n const chunkPreset = createChunkPreset(chunk.index, chunk.total);\n\n if (nbOfChunks > 1) {\n appLogger(\n `${task.dictionaryPreset}${localePreset}${chunkPreset} Translating chunk`,\n {\n level: 'info',\n }\n );\n }\n\n // Reconstruct partial JSON content from this chunk's patches\n const chunkContent = reconstructFromSingleChunk(chunk);\n const presetOutputContent = reduceObjectFormat(\n isContentStructured\n ? targetLocaleDictionary.content\n : {\n __INTLAYER_ROOT_PRIMITIVE_CONTENT__:\n targetLocaleDictionary.content,\n },\n chunkContent\n ) as unknown as JSON;\n\n const executeTranslation = async () => {\n return await retryManager(\n async () => {\n let translationResult: any;\n\n if (aiClient && aiConfig) {\n translationResult = await aiClient.translateJSON({\n entryFileContent: chunkContent as unknown as JSON,\n presetOutputContent,\n dictionaryDescription:\n dictionaryToProcess.description ??\n metadata?.description ??\n '',\n entryLocale: task.sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiConfig,\n });\n } else {\n translationResult = await intlayerAPI.ai\n .translateJSON({\n entryFileContent: chunkContent as unknown as JSON,\n presetOutputContent,\n dictionaryDescription:\n dictionaryToProcess.description ??\n metadata?.description ??\n '',\n entryLocale: task.sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiOptions,\n })\n .then((result) => result.data);\n }\n\n if (!translationResult?.fileContent) {\n throw new Error('No content result');\n }\n\n const { isIdentic } = verifyIdenticObjectFormat(\n translationResult.fileContent,\n chunkContent\n );\n\n if (!isIdentic) {\n throw new Error(\n 'Translation result does not match expected format'\n );\n }\n\n notifySuccess();\n return translationResult.fileContent;\n },\n {\n maxRetry: MAX_RETRY,\n delay: RETRY_DELAY,\n onError: ({ error, attempt, maxRetry }) => {\n const chunkPreset = createChunkPreset(\n chunk.index,\n chunk.total\n );\n appLogger(\n `${task.dictionaryPreset}${localePreset}${chunkPreset} ${colorize('Error filling:', ANSIColors.RED)} ${colorize(typeof error === 'string' ? error : JSON.stringify(error), ANSIColors.GREY_DARK)} - Attempt ${colorizeNumber(attempt + 1)} of ${colorizeNumber(maxRetry)}`,\n {\n level: 'error',\n }\n );\n\n followingErrors += 1;\n\n if (followingErrors >= MAX_FOLLOWING_ERRORS) {\n appLogger(`There is something wrong.`, {\n level: 'error',\n });\n process.exit(1); // 1 for error\n }\n },\n }\n )();\n };\n\n const wrapped = options?.onHandle\n ? options.onHandle(executeTranslation) // queued in global limiter\n : executeTranslation(); // no global limiter\n\n return wrapped.then((result) => ({ chunk, result }));\n });\n\n // Wait for all chunks for this locale in parallel (still capped by global limiter)\n const chunkResults = await Promise.all(chunkPromises);\n\n // Maintain order\n chunkResults\n .sort((chunkA, chunkB) => chunkA.chunk.index - chunkB.chunk.index)\n .forEach(({ result }) => {\n chunkResult.push(result);\n });\n\n // Merge partial JSON objects produced from each chunk into a single object\n let mergedContent = mergeChunks(chunkResult);\n\n // Re-inject null values that were stripped before AI translation\n if (strippedNullValues) {\n mergedContent = deepMergeContent(mergedContent, strippedNullValues);\n }\n\n const merged = {\n ...dictionaryToProcess,\n content: mergedContent,\n };\n\n // For per-locale files, merge the newly translated content with existing target content\n let finalContent = merged.content;\n\n if (!isContentStructured) {\n finalContent = (finalContent as any)\n ?.__INTLAYER_ROOT_PRIMITIVE_CONTENT__;\n }\n\n if (typeof baseUnmergedDictionary.locale === 'string') {\n // Deep merge: existing content + newly translated content\n finalContent = deepMergeContent(\n targetLocaleDictionary.content ?? {},\n finalContent\n );\n }\n\n return [targetLocale, finalContent] as const;\n })\n );\n\n const translatedContent: Partial<Record<Locale, Dictionary['content']>> =\n Object.fromEntries(translatedContentResults);\n\n const baseDictionary = baseUnmergedDictionary.locale\n ? {\n ...baseUnmergedDictionary,\n key: baseUnmergedDictionary.key!,\n content: {},\n }\n : baseUnmergedDictionary;\n\n let dictionaryOutput: Dictionary = {\n ...getMultilingualDictionary(baseDictionary),\n locale: undefined, // Ensure the dictionary is multilingual\n ...metadata,\n };\n\n for (const targetLocale of task.targetLocales) {\n if (translatedContent[targetLocale]) {\n dictionaryOutput = insertContentInDictionary(\n dictionaryOutput,\n translatedContent[targetLocale],\n targetLocale\n );\n }\n }\n\n appLogger(\n `${task.dictionaryPreset} ${colorize('Translation completed successfully', ANSIColors.GREEN)} for ${colorizePath(basename(dictionaryOutput.filePath!))}`,\n {\n level: 'info',\n }\n );\n\n if (\n baseUnmergedDictionary.locale &&\n (baseUnmergedDictionary.fill === true ||\n baseUnmergedDictionary.fill === undefined) &&\n baseUnmergedDictionary.location === 'local'\n ) {\n const dictionaryFilePath = baseUnmergedDictionary\n .filePath!.split('.')\n .slice(0, -1);\n\n const contentIndex = dictionaryFilePath[dictionaryFilePath.length - 1];\n\n return JSON.parse(\n JSON.stringify({\n ...task,\n dictionaryOutput: {\n ...dictionaryOutput,\n fill: undefined,\n filled: true,\n },\n }).replaceAll(\n new RegExp(`\\\\.${contentIndex}\\\\.[a-zA-Z0-9]+`, 'g'),\n `.filled.${contentIndex}.json`\n )\n );\n }\n\n return {\n ...task,\n dictionaryOutput,\n };\n },\n {\n maxRetry: GROUP_MAX_RETRY,\n delay: RETRY_DELAY,\n onError: ({ error, attempt, maxRetry }) =>\n appLogger(\n `${task.dictionaryPreset} ${colorize('Error:', ANSIColors.RED)} ${colorize(typeof error === 'string' ? error : JSON.stringify(error), ANSIColors.GREY_DARK)} - Attempt ${colorizeNumber(attempt + 1)} of ${colorizeNumber(maxRetry)}`,\n {\n level: 'error',\n }\n ),\n onMaxTryReached: ({ error }) =>\n appLogger(\n `${task.dictionaryPreset} ${colorize('Maximum number of retries reached:', ANSIColors.RED)} ${colorize(typeof error === 'string' ? error : JSON.stringify(error), ANSIColors.GREY_DARK)}`,\n {\n level: 'error',\n }\n ),\n }\n )();\n\n return result as TranslateDictionaryResult;\n};\n"],"mappings":"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"}
|
package/dist/cjs/pull.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`})
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./chunk-Bmb41Sf3.cjs`),t=require(`./utils/checkAccess.cjs`),n=require(`./push/pullLog.cjs`);let r=require(`node:fs`),i=require(`node:path`),a=require(`@intlayer/chokidar/build`),o=require(`@intlayer/chokidar/cli`),s=require(`@intlayer/chokidar/utils`),c=require(`@intlayer/config/colors`);c=e.t(c);let l=require(`@intlayer/config/logger`),u=require(`@intlayer/config/node`),d=require(`@intlayer/unmerged-dictionaries-entry`),f=require(`@intlayer/api`),p=require(`@intlayer/config/utils`);const m=async e=>{let m=(0,l.getAppLogger)(e?.configOptions?.override);try{let l=(0,u.getConfiguration)(e?.configOptions);if((0,o.logConfigDetails)(e?.configOptions),!await t.checkCMSAuth(l))return;let h=(0,f.getIntlayerAPIProxy)(void 0,l),g=(0,d.getUnmergedDictionaries)(l),_=await h.dictionary.getDictionariesUpdateTimestamp();if(!_.data)throw Error(`No distant dictionaries found`);let v=_.data;e?.dictionaries&&(v=Object.fromEntries(Object.entries(v).filter(([t])=>e.dictionaries?.includes(t)))),v=Object.fromEntries(Object.entries(v).filter(([e])=>{let t=g[e]?.[0]?.location??l.dictionary?.location??`remote`;return t===`remote`||t===`hybrid`}));let y=(0,i.join)(l.system.mainDir,`remote_dictionaries.cjs`),b=l.build?.require??(0,p.getProjectRequire)(),x=(0,r.existsSync)(y)?b(y):{},S=Object.entries(v),C=S.filter(([e,t])=>{if(!t)return!0;let n=typeof t==`object`?t.updatedAt:t,r=x[e];if(!r)return!0;let i=r?.updatedAt,a=typeof i==`number`?i:i?new Date(i).getTime():void 0;return typeof a==`number`?n>a:!0}).map(([e])=>e),w=S.filter(([e,t])=>{let n=typeof t==`object`?t.updatedAt:t,r=x[e]?.updatedAt,i=typeof r==`number`?r:r?new Date(r).getTime():void 0;return typeof i==`number`&&typeof n==`number`&&i>=n}).map(([e])=>e);if(S.length===0){m(`No dictionaries to fetch`,{level:`error`});return}m(`Fetching dictionaries:`);let T=[...w.map(e=>({dictionaryKey:e,status:`imported`})),...C.map(e=>({dictionaryKey:e,status:`pending`}))],E=new n.PullLogger;E.update(T.map(e=>({dictionaryKey:e.dictionaryKey,status:e.status})));let D=[];await(0,s.parallelize)(T,async t=>{let n=t.status===`imported`||t.status===`up-to-date`;n||(t.status=`fetching`,E.update([{dictionaryKey:t.dictionaryKey,status:`fetching`}]));try{let r;if(n&&(r=x[t.dictionaryKey]),r||=(await h.dictionary.getDictionary(t.dictionaryKey)).data,!r)throw Error(`Dictionary ${t.dictionaryKey} not found on remote`);let i=g[t.dictionaryKey]?.find(e=>e.location===`hybrid`);i&&(r={...r,location:`hybrid`,filePath:i.filePath,localId:i.localId});let{status:o}=await(0,a.writeContentDeclaration)(r,l,e);t.status=o,E.update([{dictionaryKey:t.dictionaryKey,status:o}]),D.push(r)}catch(e){t.status=`error`,t.error=e,t.errorMessage=`Error fetching dictionary ${t.dictionaryKey}: ${e}`,E.update([{dictionaryKey:t.dictionaryKey,status:`error`}])}},5),E.finish();let O=e=>{switch(e){case`fetched`:case`imported`:case`updated`:case`up-to-date`:case`reimported in JSON`:case`new content file`:return`✔`;case`error`:return`✖`;default:return`⏲`}},k=e=>{switch(e){case`fetched`:case`imported`:case`updated`:case`up-to-date`:return c.GREEN;case`reimported in JSON`:case`new content file`:return c.YELLOW;case`error`:return c.RED;default:return c.BLUE}};for(let e of T){let t=O(e.status),n=k(e.status);m(` - ${e.dictionaryKey} ${c.GREY}[${n}${t} ${e.status}${c.GREY}]${c.RESET}`)}for(let e of T)e.errorMessage&&m(e.errorMessage,{level:`error`})}catch(e){m(e,{level:`error`})}};exports.pull=m;
|
|
2
2
|
//# sourceMappingURL=pull.cjs.map
|
package/dist/cjs/pull.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pull.cjs","names":["checkCMSAuth","PullLogger","ANSIColors"],"sources":["../../src/pull.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n type DictionaryStatus,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { logConfigDetails } from '@intlayer/chokidar/cli';\nimport { parallelize } from '@intlayer/chokidar/utils';\nimport { ANSIColors, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { getProjectRequire } from '@intlayer/config/utils';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { PullLogger, type PullStatus } from './push/pullLog';\nimport { checkCMSAuth } from './utils/checkAccess';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n configOptions?: GetConfigurationOptions;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status: DictionaryStatus | 'pending' | 'fetching' | 'error';\n error?: Error;\n errorMessage?: string;\n};\n\n/**\n * Fetch distant dictionaries and write them locally,\n * with progress indicators and concurrency control.\n */\nexport const pull = async (options?: PullOptions): Promise<void> => {\n const appLogger = getAppLogger(options?.configOptions?.override);\n\n try {\n const config = getConfiguration(options?.configOptions);\n logConfigDetails(options?.configOptions);\n\n const hasCMSAuth = await checkCMSAuth(config);\n\n if (!hasCMSAuth) return;\n\n const intlayerAPI = getIntlayerAPIProxy(undefined, config);\n\n const unmergedDictionariesRecord = getUnmergedDictionaries(config);\n\n // Get remote update timestamps map\n const getDictionariesUpdateTimestampResult =\n await intlayerAPI.dictionary.getDictionariesUpdateTimestamp();\n\n if (!getDictionariesUpdateTimestampResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesUpdateTimeStamp: Record<string, any> =\n getDictionariesUpdateTimestampResult.data;\n\n // Optional filtering by requested dictionaries\n if (options?.dictionaries) {\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) =>\n options.dictionaries?.includes(key)\n )\n );\n }\n\n // Filter by location\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) => {\n const localDictionaries = unmergedDictionariesRecord[key];\n const location =\n localDictionaries?.[0]?.location ??\n config.dictionary?.location ??\n 'remote';\n\n return location === 'remote' || location === 'hybrid';\n })\n );\n\n // Load local cached remote dictionaries (if any)\n const remoteDictionariesPath = join(\n config.system.mainDir,\n 'remote_dictionaries.cjs'\n );\n const requireFunction = config.build?.require ?? getProjectRequire();\n const remoteDictionariesRecord: Record<string, any> = existsSync(\n remoteDictionariesPath\n )\n ? (requireFunction(remoteDictionariesPath) as any)\n : {};\n\n // Determine which keys need fetching by comparing updatedAt with local cache\n const entries = Object.entries(distantDictionariesUpdateTimeStamp);\n const keysToFetch = entries\n .filter(([key, remoteUpdatedAtValue]) => {\n if (!remoteUpdatedAtValue) return true;\n\n const remoteUpdatedAt =\n typeof remoteUpdatedAtValue === 'object'\n ? (remoteUpdatedAtValue as any).updatedAt\n : remoteUpdatedAtValue;\n\n const local = (remoteDictionariesRecord as any)[key];\n if (!local) return true;\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n if (typeof localUpdatedAt !== 'number') return true;\n return remoteUpdatedAt > localUpdatedAt;\n })\n .map(([key]) => key);\n\n const cachedKeys = entries\n .filter(([key, remoteUpdatedAtValue]) => {\n const remoteUpdatedAt =\n typeof remoteUpdatedAtValue === 'object'\n ? (remoteUpdatedAtValue as any).updatedAt\n : remoteUpdatedAtValue;\n\n const local = (remoteDictionariesRecord as any)[key];\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n return (\n typeof localUpdatedAt === 'number' &&\n typeof remoteUpdatedAt === 'number' &&\n localUpdatedAt >= remoteUpdatedAt\n );\n })\n .map(([key]) => key);\n\n // Check if dictionaries list is empty\n if (entries.length === 0) {\n appLogger('No dictionaries to fetch', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = [\n ...cachedKeys.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'imported' as DictionaryStatus,\n })),\n ...keysToFetch.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'pending' as const,\n })),\n ];\n\n // Initialize aggregated logger\n const logger = new PullLogger();\n logger.update(\n dictionariesStatuses.map<PullStatus>((s) => ({\n dictionaryKey: s.dictionaryKey,\n status: s.status,\n }))\n );\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n const isCached =\n statusObj.status === 'imported' || statusObj.status === 'up-to-date';\n\n if (!isCached) {\n statusObj.status = 'fetching';\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'fetching' },\n ]);\n }\n\n try {\n let sourceDictionary: Dictionary | undefined;\n\n if (isCached) {\n sourceDictionary = remoteDictionariesRecord[\n statusObj.dictionaryKey\n ] as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n // Fetch the dictionary\n const getDictionaryResult =\n await intlayerAPI.dictionary.getDictionary(statusObj.dictionaryKey);\n\n sourceDictionary = getDictionaryResult.data as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Check if there is a local version of this dictionary that is hybrid\n const localDictionaries =\n unmergedDictionariesRecord[statusObj.dictionaryKey];\n const localAndRemoteDictionary = localDictionaries?.find(\n (d) => d.location === 'hybrid'\n );\n\n if (localAndRemoteDictionary) {\n // We want to preserve the local properties but use the remote content\n sourceDictionary = {\n ...sourceDictionary,\n location: 'hybrid',\n filePath: localAndRemoteDictionary.filePath,\n localId: localAndRemoteDictionary.localId,\n };\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n sourceDictionary,\n config,\n options\n );\n\n statusObj.status = status;\n logger.update([{ dictionaryKey: statusObj.dictionaryKey, status }]);\n\n successfullyFetchedDictionaries.push(sourceDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'error' },\n ]);\n }\n };\n\n // Process dictionaries in parallel with concurrency limit\n await parallelize(dictionariesStatuses, processDictionary, 5);\n\n // Stop the logger and render final state\n logger.finish();\n\n // Per-dictionary summary\n const iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n case 'reimported in JSON':\n case 'new content file':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n };\n\n const colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n return ANSIColors.GREEN;\n case 'reimported in JSON':\n case 'new content file':\n return ANSIColors.YELLOW;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n };\n\n for (const s of dictionariesStatuses) {\n const icon = iconFor(s.status);\n const color = colorFor(s.status);\n appLogger(\n ` - ${s.dictionaryKey} ${ANSIColors.GREY}[${color}${icon} ${s.status}${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n appLogger(statusObj.errorMessage, {\n level: 'error',\n });\n }\n }\n } catch (error) {\n appLogger(error, {\n level: 'error',\n });\n }\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pull.cjs","names":["checkCMSAuth","PullLogger","ANSIColors"],"sources":["../../src/pull.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n type DictionaryStatus,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { logConfigDetails } from '@intlayer/chokidar/cli';\nimport { parallelize } from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { getProjectRequire } from '@intlayer/config/utils';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { PullLogger, type PullStatus } from './push/pullLog';\nimport { checkCMSAuth } from './utils/checkAccess';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n configOptions?: GetConfigurationOptions;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status: DictionaryStatus | 'pending' | 'fetching' | 'error';\n error?: Error;\n errorMessage?: string;\n};\n\n/**\n * Fetch distant dictionaries and write them locally,\n * with progress indicators and concurrency control.\n */\nexport const pull = async (options?: PullOptions): Promise<void> => {\n const appLogger = getAppLogger(options?.configOptions?.override);\n\n try {\n const config = getConfiguration(options?.configOptions);\n logConfigDetails(options?.configOptions);\n\n const hasCMSAuth = await checkCMSAuth(config);\n\n if (!hasCMSAuth) return;\n\n const intlayerAPI = getIntlayerAPIProxy(undefined, config);\n\n const unmergedDictionariesRecord = getUnmergedDictionaries(config);\n\n // Get remote update timestamps map\n const getDictionariesUpdateTimestampResult =\n await intlayerAPI.dictionary.getDictionariesUpdateTimestamp();\n\n if (!getDictionariesUpdateTimestampResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesUpdateTimeStamp: Record<string, any> =\n getDictionariesUpdateTimestampResult.data;\n\n // Optional filtering by requested dictionaries\n if (options?.dictionaries) {\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) =>\n options.dictionaries?.includes(key)\n )\n );\n }\n\n // Filter by location\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) => {\n const localDictionaries = unmergedDictionariesRecord[key];\n const location =\n localDictionaries?.[0]?.location ??\n config.dictionary?.location ??\n 'remote';\n\n return location === 'remote' || location === 'hybrid';\n })\n );\n\n // Load local cached remote dictionaries (if any)\n const remoteDictionariesPath = join(\n config.system.mainDir,\n 'remote_dictionaries.cjs'\n );\n const requireFunction = config.build?.require ?? getProjectRequire();\n const remoteDictionariesRecord: Record<string, any> = existsSync(\n remoteDictionariesPath\n )\n ? (requireFunction(remoteDictionariesPath) as any)\n : {};\n\n // Determine which keys need fetching by comparing updatedAt with local cache\n const entries = Object.entries(distantDictionariesUpdateTimeStamp);\n const keysToFetch = entries\n .filter(([key, remoteUpdatedAtValue]) => {\n if (!remoteUpdatedAtValue) return true;\n\n const remoteUpdatedAt =\n typeof remoteUpdatedAtValue === 'object'\n ? (remoteUpdatedAtValue as any).updatedAt\n : remoteUpdatedAtValue;\n\n const local = (remoteDictionariesRecord as any)[key];\n if (!local) return true;\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n if (typeof localUpdatedAt !== 'number') return true;\n return remoteUpdatedAt > localUpdatedAt;\n })\n .map(([key]) => key);\n\n const cachedKeys = entries\n .filter(([key, remoteUpdatedAtValue]) => {\n const remoteUpdatedAt =\n typeof remoteUpdatedAtValue === 'object'\n ? (remoteUpdatedAtValue as any).updatedAt\n : remoteUpdatedAtValue;\n\n const local = (remoteDictionariesRecord as any)[key];\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n return (\n typeof localUpdatedAt === 'number' &&\n typeof remoteUpdatedAt === 'number' &&\n localUpdatedAt >= remoteUpdatedAt\n );\n })\n .map(([key]) => key);\n\n // Check if dictionaries list is empty\n if (entries.length === 0) {\n appLogger('No dictionaries to fetch', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = [\n ...cachedKeys.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'imported' as DictionaryStatus,\n })),\n ...keysToFetch.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'pending' as const,\n })),\n ];\n\n // Initialize aggregated logger\n const logger = new PullLogger();\n logger.update(\n dictionariesStatuses.map<PullStatus>((s) => ({\n dictionaryKey: s.dictionaryKey,\n status: s.status,\n }))\n );\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n const isCached =\n statusObj.status === 'imported' || statusObj.status === 'up-to-date';\n\n if (!isCached) {\n statusObj.status = 'fetching';\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'fetching' },\n ]);\n }\n\n try {\n let sourceDictionary: Dictionary | undefined;\n\n if (isCached) {\n sourceDictionary = remoteDictionariesRecord[\n statusObj.dictionaryKey\n ] as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n // Fetch the dictionary\n const getDictionaryResult =\n await intlayerAPI.dictionary.getDictionary(statusObj.dictionaryKey);\n\n sourceDictionary = getDictionaryResult.data as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Check if there is a local version of this dictionary that is hybrid\n const localDictionaries =\n unmergedDictionariesRecord[statusObj.dictionaryKey];\n const localAndRemoteDictionary = localDictionaries?.find(\n (d) => d.location === 'hybrid'\n );\n\n if (localAndRemoteDictionary) {\n // We want to preserve the local properties but use the remote content\n sourceDictionary = {\n ...sourceDictionary,\n location: 'hybrid',\n filePath: localAndRemoteDictionary.filePath,\n localId: localAndRemoteDictionary.localId,\n };\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n sourceDictionary,\n config,\n options\n );\n\n statusObj.status = status;\n logger.update([{ dictionaryKey: statusObj.dictionaryKey, status }]);\n\n successfullyFetchedDictionaries.push(sourceDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'error' },\n ]);\n }\n };\n\n // Process dictionaries in parallel with concurrency limit\n await parallelize(dictionariesStatuses, processDictionary, 5);\n\n // Stop the logger and render final state\n logger.finish();\n\n // Per-dictionary summary\n const iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n case 'reimported in JSON':\n case 'new content file':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n };\n\n const colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n return ANSIColors.GREEN;\n case 'reimported in JSON':\n case 'new content file':\n return ANSIColors.YELLOW;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n };\n\n for (const s of dictionariesStatuses) {\n const icon = iconFor(s.status);\n const color = colorFor(s.status);\n appLogger(\n ` - ${s.dictionaryKey} ${ANSIColors.GREY}[${color}${icon} ${s.status}${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n appLogger(statusObj.errorMessage, {\n level: 'error',\n });\n }\n }\n } catch (error) {\n appLogger(error, {\n level: 'error',\n });\n }\n};\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`})
|
|
2
|
-
`);if(
|
|
3
|
-
`)}this.renderedLines=
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../chunk-Bmb41Sf3.cjs`);let t=require(`@intlayer/config/colors`);t=e.t(t);let n=require(`@intlayer/config/logger`),r=require(`@intlayer/config/node`);var i=class{statuses=[];spinnerTimer=null;spinnerIndex=0;renderedLines=0;spinnerFrames=n.spinnerFrames;isFinished=!1;prefix;lastRenderedState=``;constructor(){this.prefix=(0,r.getConfiguration)().log.prefix}update(e){if(!this.isFinished){for(let t of e){let e=this.statuses.findIndex(e=>e.dictionaryKey===t.dictionaryKey);e>=0?this.statuses[e]=t:this.statuses.push(t)}this.startSpinner(),this.render()}}finish(){this.isFinished=!0,this.stopSpinner(),this.render()}startSpinner(){this.spinnerTimer||this.isFinished||(this.spinnerTimer=setInterval(()=>{this.spinnerIndex=(this.spinnerIndex+1)%this.spinnerFrames.length,this.render()},100))}stopSpinner(){this.spinnerTimer&&=(clearInterval(this.spinnerTimer),null)}render(){let{total:e,done:r,success:i,errors:a}=this.computeProgress(),o=this.spinnerFrames[this.spinnerIndex],s=[],c=r===e,l=`dictionaries: ${r}/${e}`,u=[];i>0&&u.push(`ok: ${i}`),a>0&&u.push((0,n.colorize)(`errors: ${a}`,t.RED));let d=u.length>0?` (${u.join(`, `)})`:``;c?s.push(`${this.prefix} ${(0,n.colorize)(`✔`,t.GREEN)} fetched ${l}${d}`):s.push(`${this.prefix} ${(0,n.colorize)(o,t.BLUE)} fetching ${l}${d}`);let f=s.join(`
|
|
2
|
+
`);if(f===this.lastRenderedState)return;this.lastRenderedState=f,this.renderedLines>0&&process.stdout.write(`\x1b[${this.renderedLines}F`);let p=Math.max(this.renderedLines,s.length);for(let e=0;e<p;e++){process.stdout.write(`\x1B[2K`);let t=s[e];t!==void 0&&process.stdout.write(t),process.stdout.write(`
|
|
3
|
+
`)}this.renderedLines=s.length}computeProgress(){let e=new Set(this.statuses.map(e=>e.dictionaryKey)),t=new Set([`fetched`,`imported`,`updated`,`up-to-date`,`reimported in JSON`,`new content file`,`error`]),n=new Set([`fetched`,`imported`,`updated`,`up-to-date`,`reimported in JSON`,`new content file`]),r=this.statuses.filter(e=>t.has(e.status)).length,i=this.statuses.filter(e=>n.has(e.status)).length,a=this.statuses.filter(e=>e.status===`error`).length;return{total:e.size,done:r,success:i,errors:a}}};exports.PullLogger=i;
|
|
4
4
|
//# sourceMappingURL=pullLog.cjs.map
|