编辑
2025-04-29
工程化
00

现在越来越多的公司在做出海项目,出海项目首先要解决的就是语言国际化的问题,有很多如l18n、l10n的工具可以用,这些工具可以提供解决方案,但是不能约束开发者的开发行为。开发者仍然可能在代码中存留没有做过国际化处理的部分,假设后续 MR 的Code Review也没有查出来,这就是很大的隐患了,甚至会有监管风险,因为很多项目不想让别人知道是中国团队做的,所以要严格禁止控制台输出中文日志。

我最近也是接到一个这样的需求,本来需求是让我人肉检查一下项目中有没有输出中文日志的情况。人肉是不可能人肉的,我觉得这个可以通过写脚本来实现检查,因为核心要素其实就两个点:

  1. 需要检查中文
  2. 需要全局检查所有文件

这些要素都可以通过 Node.js 脚本来实现。

这个脚本会实现以下能力:

  1. 读取当前项目下所有目录、所有文件
  2. 能有效检查文件中是否包含中文字符
  3. 可以提前声明要忽略的文件夹/文件
  4. 主动忽略所有注释,包含///* ... */{/* ... */}
  5. 输出详细的检查结果日志,包含 文件路径、文件行数、相关代码,并且高亮检查出来的中文的部分

image.png

在项目根目录新建一个文件,如check-chinese.js。写入以下内容:

js
const fs = require('fs'); const path = require('path'); // 中文字符的正则表达式 const chineseRegex = /[\u4e00-\u9fa5]/; // 要忽略的文件或目录 const ignorePatterns = [ 'node_modules', '.git', '.next', 'public', 'locales', 'dist', 'build', 'check-chinese' ]; // 要检查的文件扩展名 const extensions = ['.ts', '.tsx', '.js', '.jsx']; // 控制台颜色 const colors = { reset: '\x1b[0m', bright: '\x1b[1m', dim: '\x1b[2m', underscore: '\x1b[4m', blink: '\x1b[5m', reverse: '\x1b[7m', hidden: '\x1b[8m', black: '\x1b[30m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', magenta: '\x1b[35m', cyan: '\x1b[36m', white: '\x1b[37m', bgBlack: '\x1b[40m', bgRed: '\x1b[41m', bgGreen: '\x1b[42m', bgYellow: '\x1b[43m', bgBlue: '\x1b[44m', bgMagenta: '\x1b[45m', bgCyan: '\x1b[46m', bgWhite: '\x1b[47m' }; // 使用第三方库来解析代码和注释 function parseFileContent(content, filePath) { // 首先通过简单的方式移除所有注释 let processedContent = content; // 1. 移除多行注释 /* ... */ processedContent = processedContent.replace(/\/\*[\s\S]*?\*\//g, match => { // 保留换行符以保持行号 return match.replace(/[^\n\r]/g, ' '); }); // 2. 移除单行注释 // ... processedContent = processedContent.replace(/\/\/.*$/gm, match => { // 保留相同长度的空格 return ' '.repeat(match.length); }); // 3. 移除JSX注释 {/* ... */} processedContent = processedContent.replace(/\{\/\*[\s\S]*?\*\/\}/g, match => { // 保留换行符以保持行号 return match.replace(/[^\n\r]/g, ' '); }); return processedContent; } // 检查文件中的中文字符 function checkFileForChinese(filePath) { try { const content = fs.readFileSync(filePath, 'utf8'); // 处理文件内容,移除注释 const processedContent = parseFileContent(content, filePath); // 按行检查处理后的内容 const lines = processedContent.split('\n'); const originalLines = content.split('\n'); const results = []; lines.forEach((line, index) => { // 检查行中是否包含中文字符 if (chineseRegex.test(line)) { results.push({ file: filePath, line: index + 1, content: originalLines[index].trim() }); } }); return results; } catch (error) { console.error(`${colors.red}无法读取文件 ${filePath}: ${error.message}${colors.reset}`); return []; } } // 递归遍历目录 function traverseDirectory(dir) { const results = []; try { const files = fs.readdirSync(dir, { withFileTypes: true }); for (const file of files) { const fullPath = path.join(dir, file.name); // 检查是否应该忽略此路径 if (ignorePatterns.some(pattern => fullPath.includes(pattern))) { continue; } if (file.isDirectory()) { results.push(...traverseDirectory(fullPath)); } else if (file.isFile() && extensions.includes(path.extname(file.name))) { results.push(...checkFileForChinese(fullPath)); } } } catch (error) { console.error(`${colors.red}无法读取目录 ${dir}: ${error.message}${colors.reset}`); } return results; } // 高亮显示中文字符 function highlightChinese(text) { return text.replace(/([\u4e00-\u9fa5]+)/g, `${colors.bgYellow}${colors.black}$1${colors.reset}`); } // 主函数 function main() { console.log(`${colors.cyan}${colors.bright}=== 开始扫描中文字符... ===${colors.reset}`); const results = traverseDirectory('.'); if (results.length === 0) { console.log(`${colors.green}${colors.bright}✓ 没有找到非注释中的中文字符!${colors.reset}`); } else { console.log(`${colors.yellow}${colors.bright}! 找到 ${results.length} 处可能需要国际化的中文字符:${colors.reset}\n`); // 按文件分组 const fileGroups = {}; results.forEach(result => { if (!fileGroups[result.file]) { fileGroups[result.file] = []; } fileGroups[result.file].push(result); }); // 输出分组结果 Object.keys(fileGroups).forEach(file => { console.log(`${colors.blue}${colors.bright}文件: ${file}${colors.reset}`); fileGroups[file].forEach(result => { console.log(` ${colors.magenta}${result.line}:${colors.reset} ${highlightChinese(result.content)}`); }); console.log(''); // 空行分隔不同文件 }); console.log(`${colors.yellow}${colors.bright}请检查上述中文字符,并考虑使用国际化方案替换它们。${colors.reset}`); } } // 执行主函数 main();

然后通过node ./check-chinese.js来执行脚本

也可以在package.json中新增一个scripts

json
{ ... "scripts": { ... "check-chinese": "node ./check-chinese.js" }, }

然后通过npm run check-chinese来执行脚本

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:CreatorRay

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!