UNPKG

@voerkai18n/cli

Version:

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

188 lines (151 loc) 6.73 kB
#!/usr/bin/env node /** * 初始化指定项目的语言包 */ const path = require("node:path"); const fs = require("node:fs"); const logsets = require("logsets"); const { getBcp47LanguageApi,addToGitIgnore,getDir } = require("@voerkai18n/utils"); const { getPackageJson } = require("flex-tools/package/getPackageJson"); const { t } = require("../../i18n"); const { copyFiles } = require("flex-tools/fs/copyFiles") const { packageIsInstalled } = require("flex-tools/package/packageIsInstalled") const { installPackage } = require("flex-tools/package/installPackage") function formatLanguages(options){ const osLang = global.OSLanguage || "en-US"; const langApi = getBcp47LanguageApi(osLang) options.languages = langApi .getTags(options.languages) .map(lang=>{ const lng ={ name : lang.tag, title : lang.name, nativeTitle: lang.nativeName } if(lang.tag === options.activeLanguage){ lng.active = true } if(lang.tag === options.defaultLanguage){ lng.default = true } return lng }) } function getDefaultScopeId(){ const pkg = getPackageJson() if(pkg){ return `${pkg.name || 'scope'+ parseInt(Math.random()*10000)}_${pkg.version ? "_"+pkg.version.replaceAll(".","_") : ""}` }else{ return 'scope'+ parseInt(Math.random()*10000) } } function createParagraphsDir(opts){ const { languages,langDir,typescript:isTypeScript,moduleType } = opts const codeFileExtName = isTypeScript ? "ts" : 'js' const paragraphsDir = getDir(path.join(langDir,"paragraphs")) const langEsmImports = languages.reduce((acc,lng)=>{ acc.push(`import ${lng.name.replace("-","")} from './${lng.name}'`) return acc },[]).join("\n") const langCjsImports = languages.reduce((acc,lng)=>{ acc.push(`const ${lng.name.replace("-","")} = require('./${lng.name}')`) return acc },[]).join("\n") const exportDict = languages.map(lang=>(`\t'${lang.name}' : ${lang.name.replace("-","")}`)).join(",\n") const paragraphsCode = isTypeScript || moduleType === 'esm' ? `${langEsmImports}\n\nexport default {\n${exportDict}\n}` : `${langCjsImports}\n\nmodule.exports = {\n${exportDict}\n}` fs.writeFileSync(path.join(paragraphsDir,`index.${codeFileExtName}`),paragraphsCode) languages.forEach(lng=>{ const lngDir = getDir(path.join(paragraphsDir,lng.name)) const paragraphfile = path.join(lngDir,`index.${codeFileExtName}`) if(!fs.existsSync(paragraphfile)){ fs.writeFileSync(paragraphfile,isTypeScript || moduleType === 'esm' ? "export default {}" : "module.exports = {}") } }) return paragraphsDir } function createMessagesDir(opts){ const { moduleType,languages,langDir,typescript:isTypeScript } = opts const codeFileExtName = isTypeScript ? "ts" : 'js' const messagesDir = getDir(path.join(langDir,"messages")) languages.forEach(lng=>{ // 生成信息文件 const msgFile = path.join(messagesDir,`${lng.name}.${codeFileExtName}`) const msgContent = isTypeScript || moduleType === 'esm' ? "export default {}" : "module.exports = {}" if(!fs.existsSync(msgFile)){ fs.writeFileSync(msgFile,msgContent) } }) return messagesDir } async function initializer(opts={}){ formatLanguages(opts) const { langDir,langRelDir,library, settingRelFile, moduleType, typescript:isTypeScript } = opts const tasks = logsets.createTasks([ { title:[t("初始化语言文件夹:{}"),langRelDir], execute:async ()=>{ if(!fs.existsSync(langDir)){ fs.mkdirSync(langDir) } opts.scopeId = getDefaultScopeId() await copyFiles("**/*.*",langDir, { cwd : path.join(__dirname,"templates",isTypeScript ? "ts" : (moduleType=='cjs' ? moduleType : "esm")), vars : opts, overwrite: file=>{ return !file.endsWith(".json") } }) await copyFiles("**/*.*",path.join(langDir,"prompts"), { cwd: path.join(__dirname,"prompts"), overwrite: false }) createParagraphsDir(opts) createMessagesDir(opts) addToGitIgnore([ `${langRelDir}/api.json`, `${langRelDir}/translates/*/*.bak.*.json`, "**/*.wrapped.*", ]) } }, { title: [t("安装{}依赖"),"@voerkai18n/runtime"], execute:async ()=>{ if(await packageIsInstalled("@voerkai18n/runtime")){ return 'skip' }else{ await installPackage.call(this,'@voerkai18n/runtime') } } }, { title: [t("安装{}依赖"),"@voerkai18n/formatters"], end:false, execute:async ()=>{ if(await packageIsInstalled("@voerkai18n/formatters")){ return 'skip' }else{ await installPackage.call(this,'@voerkai18n/formatters') } } } ]) logsets.separator(80) await tasks.run(t("开始初始化")) const summary = logsets.tasklist({grouped:true}) summary.addGroup(t("配置信息:")) summary.addMemo(t("语言配置文件: {}"),settingRelFile) summary.addMemo(t("拟支持的语言: {}"),opts.languages.map(lng=>`${lng.title}(${lng.name})`).join(",")) summary.addMemo(t("已安装运行时: {}"),'@voerkai18n/runtime') summary.addMemo(t("工作模式 : {}"),library ? t("库模式") : t("应用模式")) summary.addGroup(t("下一步:")) summary.addMemo(t("修改{}文件编辑语言参数"),`${langRelDir}/settings.json`) summary.addMemo(t("运行<{}>自动配置React/Vue等框架集成"),"voerkai18n apply") summary.addMemo(t("运行<{}>自动包裹要翻译的文本"),"voerkai18n wrap") summary.addMemo(t("运行<{}>扫描提取要翻译的文本"),"voerkai18n extract") summary.addMemo(t("运行<{}>在线自动翻译"),"voerkai18n translate") summary.addMemo(t("运行<{}>编译语言包"),"voerkai18n compile") summary.done() } module.exports = initializer