UNPKG

@voerkai18n/cli

Version:

命令行工具,用来初始化/提取/编译/自动翻译等工具链

170 lines (150 loc) 5.87 kB
const fs = require("node:fs") const path = require("node:path") const { deepMerge } = require("flex-tools/object/deepmerge") const { delay } = require("flex-tools/async/delay") const { t } = require("../../i18n"); function getTranslateProvider(){ const { provider } = this; const providerFile = path.join(__dirname,`${provider}.provider.js`) try{ if(fs.existsSync(providerFile)){ return require(providerFile)(this.api) }else{ return require(provider)(this) } }catch(e){ throw new Error(t("加载翻译提供者{}失败: {}").params([provider,e.message])) } } async function sendToTranslate(messages={},from,to,options){ let { qps=0 } = this const { strictLine = true } = Object.assign({},options) const texts = Object.keys(messages) const lineCount = texts.length if(lineCount===0) return; const provider = getTranslateProvider.call(this) if(qps>0) await delay(1000/qps) let translatedMessages try{ translatedMessages = await provider.translate.call(this,texts,from,to,this) if(strictLine && lineCount!==translatedMessages.length){ console.log("\n--------------------") const lines = texts.length>translatedMessages.length ? texts : translatedMessages console.log(lines.map((text,i)=>text + " -> " + translatedMessages[i]).join("\n")) console.log("--------------------") throw new Error(t("翻译后的内容与原始内容行数不一致,建议更换翻译提供者或优化提示词")) } }catch(e){ throw new Error(e.message) } Object.keys(messages).forEach((key,index)=>{ messages[key][to] = translatedMessages[index] }) return messages } function getTranslateOptions(options){ return Object.assign({ strictLine: true, prompt: undefined },options) } /** * 翻译多条单行文本 * @param {*} to * @param {*} messages 保存要翻译的内容 * @param {*} options * @returns */ async function translateSingleLineMessage(messages={},from="zh",to="en"){ const translatedMessages = await sendToTranslate.call(this,messages,from,to) Object.keys(messages).forEach((key)=>{ messages[key][to] = translatedMessages[key][to] }) return messages } /** * 翻译多行文本 * @param {*} messages * @param {*} from * @param {*} to * @param {Object} options { * strictLine: false, // 严格按行翻译 * qps: 0, // 每秒请求次数 * } * @returns */ async function translateMultiLineMessage(messages={},from,to,options){ const translatedMessages = await sendToTranslate.call(this,messages,from,to,getTranslateOptions(options)) return translatedMessages.join("\n") } async function translateParagraph(paragraph, from,to,options){ const provider = getTranslateProvider.call(this) let translatedParagraphs = [paragraph] try{ translatedParagraphs = await provider.translate.call(this,[paragraph],from,to,this) }catch(e){ throw new Error(e.message) } return translatedParagraphs.join("\n") } /** * 判断是否翻译内容已经变化 */ function isMessageUpdated(message,lngMessage){ return typeof(lngMessage)==="string" && (lngMessage!=message && lngMessage.trim()!="") } /** * 翻译指定的语言 * @param {*} messages * @param {*} from * @param {*} to * @param {*} options * @returns */ async function startTranslate(messages,from,to){ const { maxPackageSize,mode,task } = this; const result = messages // 保存翻译结果 const msgCount = Object.keys(messages).length const items = Object.entries(messages) let translatedMessages = {} // 保存已经翻译的内容 let packageSize = 0 let translatedCount = 0 for(let i=0;i<msgCount;i++){ const [message,lngs ] = items[i] const langMessage = lngs[to] const hasUpdated = isMessageUpdated(message,langMessage) const needTranslate = mode=='full' || (mode=='auto' && !hasUpdated) if(needTranslate) translatedCount++ task.note(`${translatedCount}/${msgCount}`) if(Array.isArray(langMessage)){// 由于复数需要手动配置,不进行翻译 result[message][to] = langMessage if(i<msgCount-1) continue }else if(mode == "auto" && hasUpdated){ result[message][to] = langMessage if(i<msgCount-1) continue }else{ if(!(message in result)) result[message] = {} // 由于百度翻译按\n来分行翻译,如果有\n则会出现多行翻译的情况。因此,如果有\n则就不将多条文件合并翻译 if(message.includes("\n") && needTranslate){ result[message][to] = await translateMultiLineMessage.call(this,message.split("\n"),from,to) }else if(needTranslate){ translatedMessages[message]={[to]:langMessage} packageSize += message.length } } // 多个信息合并进行翻译,减少请求次数 if(packageSize>=maxPackageSize || i==msgCount-1){ await translateSingleLineMessage.call(this,translatedMessages,from,to) deepMerge(result,translatedMessages) packageSize = 0 translatedMessages = {} } } return [result,translatedCount] } module.exports = { startTranslate, translateMultiLineMessage, translateSingleLineMessage, translateParagraph }