通过脚本自动检查项目中全局的中文

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

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

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

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

公众号:Code程序人生,个人网站:https://creatorblog.cn

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

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

image.png

在项目根目录新建一个文件,如check-chinese.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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/80927.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件分析师-第三遍-章节导图-13/14

系统设计,按步骤分:概要设计、详细设计。另一种分类方式:按设计内容和设计方法分。设计内容:处理流程、输入/输出原型、人机交互。设计方法:结构化、面向对象、设计模式。 软件实现&测试,分为实现、测…

通过全局交叉注意力机制和距离感知训练从多模态数据中识别桥本氏甲状腺炎|文献速递-深度学习医疗AI最新文献

Title 题目 Hashimoto’s thyroiditis recognition from multi-modal data via globalcross-attention and distance-aware training 通过全局交叉注意力机制和距离感知训练从多模态数据中识别桥本氏甲状腺炎 01 文献速递介绍 桥本氏甲状腺炎(HT)&a…

刀客doc:小红书商业技术负责人苍响离职

根据大厂日爆的爆料,小红书商业化再度迎来高层人事变动,原商业平台技术负责人苍响(薯名),职级L2,已于本月正式离职,其下属团队现由电商业务负责人接管。 根据刀客doc获得的资料,苍响…

Manus AI多语言手写识别技术全解析:从模型架构到实战部署

简介 Manus AI作为当前多语言手写识别领域的领军技术,其核心创新在于融合三维卷积网络、动态特征融合引擎和混合解码系统,实现了对112种语言的98.7%识别准确率和8ms延迟的实时处理能力。本文将深入探讨Manus AI的架构设计、特征提取方法、数据预处理策略…

华为云Astro大屏从iotda影子设备抽取数据做设备运行状态的大屏实施步骤

目录 背景与意义 1. 准备阶段 2. IoTDA 开放影子查询API 3. Astro轻应用创建连接器 4. Astro大屏设计界面 5. 数据绑定与交互逻辑 6. 发布与测试 小结(流程复盘) 背景与意义 随着物联网技术的快速发展,越来越多的设备接入云端&#x…

为什么要学习《易经》?

《易经》精华解读:变易之道与人生智慧 《易经》(《周易》)是中国最古老的经典之一,被誉为“群经之首,大道之源”。它不仅是占卜之书,更是一部哲学经典,揭示了宇宙运行的规律和人生处世的智慧。…

逆传播AIGEO营销:破局生成式搜索时代,让AI成为品牌代言人!

当GS(Generative Search生成式搜索)成为用户的新“搜索入口”,你的品牌还在进行传统软文发布吗? Gartner分析师预测"到2026年70%企业将把生成式AI整合进核心营销系统",传统SEO的正被AI搜索彻底重构。用户的搜索行为发生史诗级转变&#xff0…

WPF(Windows Presentation Foundation)的内容模型

WPF(Windows Presentation Foundation)的内容模型(Content Model)是其核心架构之一,定义了UI元素如何组织和呈现内容。以下是WPF内容模型的系统化解析: 1. 内容模型基础概念 WPF通过逻辑树和可视化树管理内…

52.[前端开发-JS实战框架应用]Day03-AJAX-插件开发-备课项目实战-Lodash

常用JavaScript库 1 认识前端工具库 前端工具类库 2 Lodash vs underscore underscore库 VS Lodash库 Lodash库 的安装 手写精简版的Lodash ;(function(g) {function Lodash() {}// 添加类方法Lodash.VERSION 1.0.0Lodash.join function(arr, separater) {// todo ......…

前端Ui设计工具

PS 稿、蓝湖、Sketch 和 Figma 前端 UI 设计工具的对比分析 PS 稿(Adobe Photoshop) 提供精准设计细节:PS 稿能让前端更精准地理解页面布局、元素尺寸、颜色等,通过精确测量和查看信息面板,把握设计元素的空间关系、…

映射关系5

明白!🚀 你要我 继续扩展,在这套 C98 代码里加一个功能: 根据完整的5位ID,反查出对应的路径。 OK,我直接接着上面那版来,给你补充 getPathFromId 方法,并且保持整体风格统一&#…

编译原理:由浅入深从语法树到文法类型

文法与语言基础:从语法树到文法类型 文法(Grammar)和语言(Language)是计算机科学和语言学中解析和理解语言结构的核心概念。无论是编程语言的编译器设计,还是自然语言处理(NLP)中的…

第十三步:vue

Vue 1、上手 1、安装 使用命令:npm create vuelatestvue文件后缀为.vueconst app createApp(App):初始化根组件app.mount("#app"):挂载根组件到页面 2、文件 script标签:编写jstemplate标签:编写htmls…

Pytest-mark使用详解(跳过、标记、参数 化)

1.前言 在工作中我们经常使用pytest.mark.XXXX进行装饰器修饰,后面的XXX的不同,在pytest中有不同的作 用,其整体使用相对复杂,我们单独将其抽取出来做详细的讲解。 2.pytest.mark.skip()/skipif()跳过用例 import pytest #无条…

基于 Spring Boot 的井字棋游戏开发与实现

目录 引言 项目概述 项目搭建 1. 环境准备 2. 创建 Spring Boot 项目 3. 项目结构 代码实现 1. DemoApplication.java 2. TicTacToeController.java 3. pom.xml 电脑落子策略 - Minimax 算法 findBestMove 方法 minimax 方法 运行游戏 总结 引言 在软件开发领域&…

【算法笔记】贪心算法

一、什么是贪心算法? 贪心算法是一种在每一步选择中都采取当前看起来最优(最“贪心”)的策略,从而希望得到全局最优解的算法设计思想。 核心思想:每一步都做出局部最优选择,不回退。适用场景:…

现代c++获取linux所有的网络接口名称

现代c获取linux所有的网络接口名称 前言一、在linux中查看网络接口名称二、使用c代码获取三、验证四、完整代码如下五、总结 前言 本文介绍一种使用c获取本地所有网络接口名称的方法。 一、在linux中查看网络接口名称 在linux系统中可以使用ifconfig -a命令列举出本机所有网络…

打印及判断回文数组、打印N阶数组、蛇形矩阵

打印回文数组 1 1 1 1 1 1 2 2 2 1 1 2 3 2 1 1 2 2 2 1 1 1 1 1 1方法1: 对角线对称 左上和右下是对称的。 所以先考虑左上打印, m i n ( i 1 , j 1 ) \text min(i1,j1) min(i1,j1),打印出来: 1 1 1 1 1 2 2 2 1 2 3 3 1 2 …

详解UnityWebRequest类

什么是UnityWebRequest类 UnityWebRequest 是 Unity 引擎中用于处理网络请求的一个强大类,它可以让你在 Unity 项目里方便地与网络资源进行交互,像发送 HTTP 请求、下载文件等操作都能实现。下面会详细介绍 UnityWebRequest 的相关内容。 UnityWebRequ…

UE5 在旋转A的基础上执行旋转B

用径向slider实现模型旋转时,得到的结果与ue编辑器里面的结果有很大出入。 问题应该是 两个FRotator(0,10,0)和(10,20,30), 两个FRotator的加法结果为&…