@voerkai18n/cli
Version:
命令行工具,用来初始化/提取/编译/自动翻译等工具链
118 lines (102 loc) • 4.11 kB
JavaScript
const { aiQuestion } = require('@voerkai18n/utils');
const { t } = require("../../i18n");
const glob = require("fast-glob");
const logsets = require("logsets");
const path = require("node:path");
const fs = require("node:fs");
const { readFile, writeFile, rm:deleteFile } = require('flex-tools/fs/nodefs');
function hasImportTranslteFunc(code) {
return /import\s+\{.*\bt\b.*\}\s+from\s+(['"])[^'"]+\1/gm.test(code) || /const\s+\{.*\bt\b.*\}\s*=\s*require\(['"][^'"]+['"]\)/gm.test(code);
}
/**
* 将代码中的字符串字面量用i18n翻译函数包裹
* @param {import('@voerkai18n/utils').VoerkaI18nProjectContext} ctx
*/
async function wrap(ctx){
const { patterns } = ctx
const { key:apiKey,model ,url:apiUrl } = ctx.api
const tasks = logsets.tasklist({ width:80,grouped:true })
const promptTemplate = await ctx.getPrompt(ctx.prompt)
if(!promptTemplate){
logsets.log(t("未找到提示模板{}"),ctx.prompt)
return
}
tasks.addGroup(t("开始自动应用翻译{}函数"),'t')
tasks.addMemo(t("应用范围: {}"),patterns.join(", "))
const files = await glob(patterns,{
absolute: true
})
tasks.addGroup(t("共处理{}个文件"),files.length)
for(let file of files){
try{
const relFile= path.relative(process.cwd(),file)
const wrappedFile = file.replace(path.extname(file),".wrapped"+path.extname(file))
tasks.add(t("处理{}"),relFile)
if(fs.existsSync(wrappedFile)){
tasks.skip()
}else{
const code = await readFile(file,{ encoding: "utf-8" })
ctx.file = path.normalize(file)
ctx.code = code
ctx.importPath = path.relative(path.dirname(file),path.join(ctx.langDir,"index")).replaceAll("\\","/").slice(0,-6)
if(!ctx.importPath.startsWith(".")) ctx.importPath="./"+ctx.importPath
const prompt = promptTemplate.params(ctx)
const result = await aiQuestion(prompt,{
apiUrl,
apiKey,
model
})
if(result.trim()==='' || !hasImportTranslteFunc(result)){
tasks.skip()
}else{
await writeFile(wrappedFile,result,{ encoding: "utf-8" })
tasks.complete()
}
}
}catch(e){
tasks.error(e)
}
}
tasks.addGroup(t("注意:"));
tasks.addMemo(t("保存结果到同名的{}文件,不会修改原文件"),".wrapped.*");
tasks.addMemo(t("接下来可以使用{}命令更新到原文件"),"voerkai18n wrap --apply");
tasks.done()
}
async function applyWrap(ctx){
const patterns = ctx.patterns.filter( pattern => {
return pattern.startsWith("!") && pattern!=="!**/*.wrapped.*"
});
patterns.push("**/*.wrapped.*")
const files = await glob(patterns,{
absolute: true
})
if(files.length===0){
logsets.log(t("未找到任何{}文件"),".wrapped.*")
return
}else{
const tasks = logsets.tasklist()
tasks.addGroup(t("开始应用{}修改,共应用{}个文件"),'Wrap',files.length)
for(let wrappedFile of files){
try{
const relFile= path.relative(process.cwd(),wrappedFile)
tasks.add(t("应用{}"),relFile)
const code = await readFile(wrappedFile,{ encoding: "utf-8" })
const outfile = wrappedFile.replace(".wrapped","")
try{
await writeFile(outfile,code,{ encoding: "utf-8" })
await deleteFile(wrappedFile)
tasks.complete()
}catch(e){
throw e
}
}catch(e){
tasks.error(e)
}
}
tasks.done()
}
}
module.exports = {
wrap,
applyWrap
}