UNPKG

i18n-helper-babel

Version:

i18n 命令行工具。一键包裹,提取,翻译,统计。支持网页截图,翻译词条检测

264 lines (220 loc) 7.29 kB
/* eslint-disable @typescript-eslint/no-var-requires */ import fs from 'fs'; import path from 'path'; import fse from 'fs-extra'; import inquirer from 'inquirer'; import glob from 'glob'; import minimatch from 'minimatch'; import shell from 'shelljs'; import _ from 'lodash'; import prettier from 'prettier'; import Logger from './logger'; import { I18N_CONFIGURATION_FILE_NAME } from '../config/const'; import questions from '../config/questionList'; import { formatJSON } from './helper'; import { iI18nConf } from '../types'; const i18nDefaultConfiguration = require('../config/i18n.default.config'); /** * 生成i18n配置文件 * @param configuration i18n配置 */ const doGenerateConfiguration = (configuration: any) => { const configurationStr = formatJSON(configuration); fs.writeFileSync(I18N_CONFIGURATION_FILE_NAME, configurationStr, 'utf8'); // Logger.success(t('i18n.config.json 生成成功')); Logger.success('i18n.config.json is generated successfully'); }; /** * 生成配置文件 * @param useDefaultConfig 是否用默认配置生成 */ const generateConfiguration = (useDefaultConfig: boolean): void => { if (useDefaultConfig) { doGenerateConfiguration(i18nDefaultConfiguration); } else { inquirer.prompt(questions).then((answers) => { doGenerateConfiguration(answers); }); } }; /** * 根据 exclude 中的路径或文件过滤 * @param parsedExclude * @param changedFiles * @returns 排除后的文件列表 */ const FilterFilesByExclude = ( parsedExclude: string[] | undefined, changedFiles: string[], ): string[] => { const fileArr: string[] = []; const dirArr: string[] = []; let excludeTmpFiles: string[] = []; let excludeTmpDirs: string[] = []; parsedExclude?.map((item) => { if (item.includes('.')) { fileArr.push(item); } else { dirArr.push(item); } }); if (fileArr.length > 0) { const filePattern = fileArr.length === 1 ? `**/${fileArr.join(',')}` : `**/{${fileArr.join(',')}}`; excludeTmpFiles = minimatch.match(changedFiles, filePattern); } if (dirArr.length > 0) { const dirPattern = dirArr.length === 1 ? `**/${dirArr.join(',')}/**` : `**/{${dirArr.join(',')}}/**`; excludeTmpDirs = minimatch.match(changedFiles, dirPattern); } const excludeFiles = Array.from( new Set([...excludeTmpFiles, ...excludeTmpDirs]), ); changedFiles = _.difference(changedFiles, excludeFiles); return changedFiles; }; /** * 获取符合规则文件列表 - 指定路径srcPath下,符合fileExt后缀文件,过滤exclude路径或文件 * @param i18nConf i18n配置 * @returns 符合条件文件列表 */ const getMatchedFilesByPath = (i18nConf: iI18nConf): string[] => { let files: string[] = []; const filePath = i18nConf.parsedPath as string; const { fileExt } = i18nConf; const stat = fs.statSync(filePath); if (stat.isFile() && fileExt.includes(path.extname(filePath).substr(1))) { files.push(filePath); } else if (stat.isDirectory()) { const ext = fileExt.includes(',') ? `{${fileExt}}` : fileExt; const pattern = `${filePath}/**/*.${ext}`; // TODO: Exclude 为空时还需要处理 const ignorePath = i18nConf.parsedExclude?.map((item) => { return item.includes('.') ? `${filePath}/**/${item}` : `${filePath}/**/${item}/**`; }); const option = { ignore: ignorePath, }; files = glob.sync(pattern, option); } return files; }; /** * 获取符合规则文件列表 - git中修改或者新增的文件,同时符合i18n配置fileExt后缀文件,过滤exclude路径或文件 * @param i18nConf i18n配置 * @returns 符合条件文件列表 */ const getMatchedFilesByGit = (i18nConf: iI18nConf): string[] => { const { fileExt, parsedExclude, srcPath } = i18nConf; // TODO: 晚点看看 // 新增一个文件夹,再往里面加文件(e.g. src下新建文件夹test,文件夹中新建文件a.js),此时无法把a.js扫出,反而会扫出test/, // 如果是一个已在git仓库中的文件夹里加一个文件则会被扫描出来,同git status const gitCommand = `git status --porcelain | awk '!match($1, "D"){print $2}'`; // git 非 delete 文件列表 let changedFiles = shell .exec(gitCommand, { silent: true, }) .stdout.split('\n'); // 最后一个为空,所以弹出 changedFiles.pop(); const fileExtPatten = `**/*.{${fileExt}}`; // 按文件后缀过滤 changedFiles = minimatch.match(changedFiles, fileExtPatten); // 按exclude过滤 changedFiles = FilterFilesByExclude(parsedExclude, changedFiles); return changedFiles; }; /** * 获取指定路径下匹配的文件 * @param i18nConf i18n配置 * @returns 指定路径下符匹配的文件列表 */ const getMatchedFiles = (i18nConf: iI18nConf): string[] => { let files: string[] = []; const { gitModel } = i18nConf; if (gitModel) { const isGitInstalled = !!shell.which('git'); if (isGitInstalled) { files = getMatchedFilesByGit(i18nConf); } else { Logger.error('未安装git,只能试用文件路径形式,请将gitMode设为false'); } } else { files = getMatchedFilesByPath(i18nConf); } return files; }; /** * i18n配置文件是否存在 * @returns i18n配置文件是否存在 */ const isI18nConfExited = (): boolean => { const configFileName = path.resolve(I18N_CONFIGURATION_FILE_NAME); return fs.existsSync(configFileName); }; const getPrettierConfig = () => { let prettierConfig = null; const pattern = `*prettier*`; const option = { ignore: '*prettierignore', dot: true, }; const files = glob.sync(pattern, option); if (files.length > 0) { prettierConfig = prettier.resolveConfig.sync(files[0]); } return prettierConfig; }; /** * 读取 i18n 配置文件 * @returns i18n 配置对象 */ const parseI18nConf = ( filePath?: string | undefined, language?: string | undefined, needPrint = true, ): iI18nConf | null => { const configFileName = path.resolve(I18N_CONFIGURATION_FILE_NAME); if (isI18nConfExited()) { const i18nConf: iI18nConf = fse.readJSONSync(configFileName); const importArray = i18nConf.importStr.split(' '); const specifiedPath = filePath || i18nConf.srcPath; const specifiedLanguage = language || i18nConf.languages; i18nConf.parsedExclude = i18nConf.exclude.split(','); i18nConf.parsedLanguages = specifiedLanguage.split(','); i18nConf.parsedPath = specifiedPath; i18nConf.parsedImportKey = importArray[importArray.length - 1].replace( /(\n|;)/g, '', ); i18nConf.parsedExcludeWrapperFuncNameRegex = new RegExp( i18nConf.excludeWrapperFuncName.split(',').join('|'), ); if (i18nConf.format.toLowerCase() !== 'eslint') { i18nConf.parsedPrettierConfig = getPrettierConfig(); } return i18nConf; } if (needPrint) { // Logger.error(t('【配置错误】请先运行 i18n-helper init 生成配置文件')); Logger.error( 'Missing configuration file, please Run "i18n-helper init" to generate it', ); } return null; }; export { generateConfiguration, getMatchedFiles, isI18nConfExited, parseI18nConf, FilterFilesByExclude, };