现在越来越多的公司在做出海项目,出海项目首先要解决的就是语言国际化的问题,有很多如l18n、l10n的工具可以用,这些工具可以提供解决方案,但是不能约束开发者的开发行为。开发者仍然可能在代码中存留没有做过国际化处理的部分,假设后续 MR 的Code Review也没有查出来,这就是很大的隐患了,甚至会有监管风险,因为很多项目不想让别人知道是中国团队做的,所以要严格禁止控制台输出中文日志。
我最近也是接到一个这样的需求,本来需求是让我人肉检查一下项目中有没有输出中文日志的情况。人肉是不可能人肉的,我觉得这个可以通过写脚本来实现检查,因为核心要素其实就两个点:
这些要素都可以通过 Node.js
脚本来实现。
这个脚本会实现以下能力:
//
、/* ... */
、{/* ... */}
在项目根目录新建一个文件,如check-chinese.js
。写入以下内容:
jsconst 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
来执行脚本
本文作者:CreatorRay
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!