事情的经过是这样的,公司内部的各大项目需要做AI相关模块迁移,国际化词条也成为了十分重要的部分。如果全量迁移词条,会造成很大的词条冗余,于是领导给了我3天时间,让我梳理出所有AI模块的词条,并以增量的形式给到项目中。
工作任务和目标
此次工作任务是那种难度不大,但重复繁琐的过程。需要在标准产品的所有工程中,寻找ai文件目录下的所有词条,将其梳理出来作为增量。因为ai文件目录下的组件和js文件非常多,深度和广度皆为感人,领导也只给了3天的时间进行词条整理。
目标和受众是项目中心的前端开发工程师,帮助他们简化工作。当然我自己也是一名前端开发,知晓他们工作几乎所有细节,既然要做何不送佛送到西,与其梳理成excel表格,不如直接梳理成js文件,以便直接导入,避免二次格式化。
方案和灵感
领导给到的方案是,梳理成一个个的表格,表格中存在各种字段,如终端、词条包、词条、词条值,示例如下:
领导认为时间紧任务重,这么多文件只给3天时间可要加把劲了,搞不完就加加班吧。也确实,这么多文件机械性重复寻找既枯燥也可能走神遗漏。想到重复性、机械性的工作,岂不是AI最擅长的嘛。那我可不可以借住AI的能力去帮我完成这个工作呢?
既然是要把所有ai目录下的词条找到,使用nodejs搜索/ai目录下的所有文件,用正则匹配类似“zxy.xxx”这种字符串,匹配到了就存到数组中,岂不快哉。所有终端都做一遍这个工作,再结合标准产品的词条库进行条件过滤,最终将词条库的副本进行过滤处理,那其实只需要执行两个脚本代码就可以了!
结合DeepSeek
按照以上方案,我需要让DeepSeek帮我编写第一个脚本,这个脚本的目的是搜索所有/ai目录下的文件收集词条。给到提示词如下。
使用nodejs写一个脚本,要求扫描某一路径下所有目录的所有文件,将代码中具有'zxy.xxx'的字符串输出到i18nKey.js文件下。其中'zxy.xxx'例如'zxy.123456789',输出的i18nKey.js文件的所有匹配到的字符串以数组方式存储。
const fs = require('fs'); const path = require('path'); // 配置参数 const targetDirectory = './'; // 要扫描的目录,默认为当前目录 const outputFile = 'i18nKey.js'; // 输出文件名 const pattern = /zxy\.\d+/g; // 匹配 zxy.后面跟着数字的模式 // 存储找到的所有匹配项 const foundKeys = new Set(); // 递归扫描目录 function scanDirectory(directory) { const files = fs.readdirSync(directory); files.forEach(file => { const fullPath = path.join(directory, file); const stat = fs.statSync(fullPath); if (stat.isDirectory()) { // 如果是目录,递归扫描 scanDirectory(fullPath); } else if (stat.isFile()) { // 如果是文件,检查文件内容 scanFile(fullPath); } }); } // 扫描文件内容查找匹配项 function scanFile(filePath) { try { const content = fs.readFileSync(filePath, 'utf8'); const matches = content.match(pattern); if (matches) { matches.forEach(match => { foundKeys.add(match); console.log(`Found in ${filePath}: ${match}`); }); } } catch (err) { console.error(`Error reading file ${filePath}:`, err); } } // 将结果写入输出文件 function writeOutputFile() { const outputContent = `// Auto-generated i18n keys list // Generated at: ${new Date().toISOString()} // Total keys found: ${foundKeys.size} module.exports = [ ${Array.from(foundKeys).map(key => `'${key}'`).join(',\n ')} ];`; fs.writeFileSync(outputFile, outputContent, 'utf8'); console.log(`\nSuccessfully wrote ${foundKeys.size} keys to ${outputFile}`); } // 主函数 function main() { console.log(`Starting scan in directory: ${targetDirectory}`); console.log(`Looking for pattern: ${pattern}`); scanDirectory(targetDirectory); writeOutputFile(); } // 执行主函数 main();
复制DeepSeek给到的代码,在本地ai目录的同级目录下新建一个js文件,将脚本代码引入,使用node命令执行,果然得到的i18nKey文件正确。
初见成效,执行所有端的脚本获得的词条文件修改成admin.js、student.js、engine.js以及mobile.js放入自己新建工程的data文件夹下,再将标品词条库的js文件放在target文件下。我需要让DeepSeek帮我写第二个脚本,这个脚本就是让data和target比对,在target的基础上做副本过滤,提示词如下。
使用nodejs写一个脚本,要求扫描当前目录下的target文件夹中的所有js文件,这些js文件中都使用export default导出一个对象;再根据每一项去比对当前目录下的data文件夹中所有js文件,这些js文件中都使用module.exports导出一个数组。如果该项能够匹配上data中数组的项,就保留,否则移除,最终在output文件夹输出过滤后的所有文件。
const fs = require('fs'); const path = require('path'); // 配置路径 const TARGET_DIR = path.join(__dirname, 'target'); const DATA_DIR = path.join(__dirname, 'data'); const OUTPUT_DIR = path.join(__dirname, 'output'); // 确保输出目录存在 if (!fs.existsSync(OUTPUT_DIR)) { fs.mkdirSync(OUTPUT_DIR, { recursive: true }); } // 1. 读取所有 data 文件并收集所有有效项 function collectDataItems() { const dataItems = new Set(); const dataFiles = fs.readdirSync(DATA_DIR).filter(file => file.endsWith('.js') && !file.startsWith('.') ); dataFiles.forEach(file => { const filePath = path.join(DATA_DIR, file); try { const dataModule = require(filePath); if (Array.isArray(dataModule)) { dataModule.forEach(item => { if (typeof item === 'string' || typeof item === 'number') { dataItems.add(item.toString()); } }); } } catch (err) { console.error(`Error processing data file ${file}:`, err); } }); return dataItems; } // 2. 处理 target 文件 function processTargetFiles(dataItems) { const targetFiles = fs.readdirSync(TARGET_DIR).filter(file => file.endsWith('.js') && !file.startsWith('.') ); targetFiles.forEach(file => { const filePath = path.join(TARGET_DIR, file); const outputPath = path.join(OUTPUT_DIR, file); try { // 读取文件内容 let content = fs.readFileSync(filePath, 'utf8'); // 提取 export default 对象 const exportDefaultRegex = /export\s+default\s*({[\s\S]*?});?\s*$/; const match = content.match(exportDefaultRegex); if (match) { let exportedObj; try { // 使用 eval 来解析 export default 对象(注意安全风险) exportedObj = eval(`(${match[1]})`); } catch (e) { console.error(`Error parsing export default in ${file}:`, e); return; } // 过滤对象 const filteredObj = {}; for (const key in exportedObj) { if (dataItems.has(key) || dataItems.has(exportedObj[key])) { filteredObj[key] = exportedObj[key]; } } // 重新生成文件内容 const newExport = `export default ${JSON.stringify(filteredObj, null, 2)};`; content = content.replace(exportDefaultRegex, newExport); // 写入输出文件 fs.writeFileSync(outputPath, content, 'utf8'); console.log(`Processed and filtered ${file}`); } else { console.warn(`No export default found in ${file}, skipping`); } } catch (err) { console.error(`Error processing target file ${file}:`, err); } }); } // 主函数 function main() { console.log('Starting filtering process...'); // 1. 收集所有 data 项 console.log('Collecting data items from data folder...'); const dataItems = collectDataItems(); console.log(`Found ${dataItems.size} unique data items`); // 2. 处理 target 文件 console.log('Processing target files...'); processTargetFiles(dataItems); console.log('Filtering process completed!'); console.log(`Check the ${OUTPUT_DIR} folder for results`); } // 执行主函数 main();
再将得到的代码复制到自己新建工程的main.js中,文件目录如下。 使用node main命令执行过滤脚本,得到的最终结果经过验证后正确。
满足领导需求
输出的词条文件的工作已经完成,来来回回也就十几二十分钟,虽然对开发更友好,但和领导的期望有所出入,此时还有最后一步,就是输出一个excel文档,满足领导的需求,同样可以借助DeepSeek来快速实现。
使用nodejs写一个脚本,要求扫描当前目录下output文件夹中的所有js文件,这些js文件都使用export default导出,其中文件名PC_MANAGE开头的对应名称为“管理端”,PC_STUDENT开头的对应名称为“学员端”,APP_STUDENT开头的对应名称为“移动端”;每个js文件都是一个词条包,里边每个key作为词条,对应的value为词条值,最终生成一个excel文档,字段分别有“终端”、"词条包"、"词条"、“词条值”。
const fs = require('fs'); const path = require('path'); const XLSX = require('xlsx'); // 配置路径 const OUTPUT_DIR = path.join(__dirname, 'output'); const EXCEL_FILE = path.join(__dirname, 'i18n_terms.xlsx'); // 终端类型映射 const PLATFORM_MAPPING = { 'PC_MANAGE': '管理端', 'PC_STUDENT': '学员端', 'APP_STUDENT': '移动端' }; // 获取终端类型名称 function getPlatformName(filename) { for (const [prefix, name] of Object.entries(PLATFORM_MAPPING)) { if (filename.startsWith(prefix)) { return name; } } return '未知终端'; } // 读取 JS 文件内容并提取 export default 对象 function extractExportedObject(filePath) { const content = fs.readFileSync(filePath, 'utf8'); // 使用正则表达式匹配 export default 对象 const exportDefaultRegex = /export\s+default\s*({[\s\S]*?})\s*;?\s*$/; const match = content.match(exportDefaultRegex); if (!match) { throw new Error('No export default found in file'); } // 安全地评估对象 try { return new Function(`return ${match[1]}`)(); } catch (e) { throw new Error(`Failed to parse export default object: ${e.message}`); } } // 读取 output 目录下的所有 JS 文件 function readJsFiles() { const files = fs.readdirSync(OUTPUT_DIR) .filter(file => file.endsWith('.js') && !file.startsWith('.')); const allTerms = []; files.forEach(file => { const filePath = path.join(OUTPUT_DIR, file); const platform = getPlatformName(file); const packageName = path.basename(file, '.js'); try { const termObj = extractExportedObject(filePath); // 转换为 Excel 行数据 for (const [key, value] of Object.entries(termObj)) { allTerms.push({ '终端': platform, '词条包': packageName, '词条': key, '词条值': value }); } console.log(`成功处理文件: ${file}`); } catch (err) { console.error(`处理文件 ${file} 时出错:`, err.message); } }); return allTerms; } // 生成 Excel 文件 function generateExcel(terms) { // 创建工作簿 const wb = XLSX.utils.book_new(); // 创建工作表数据 const ws = XLSX.utils.json_to_sheet(terms); // 设置列宽 ws['!cols'] = [ { wch: 10 }, // 终端 { wch: 20 }, // 词条包 { wch: 30 }, // 词条 { wch: 50 } // 词条值 ]; // 将工作表添加到工作簿 XLSX.utils.book_append_sheet(wb, ws, '词条列表'); // 写入文件 XLSX.writeFile(wb, EXCEL_FILE); console.log(`Excel 文件已生成: ${EXCEL_FILE}`); console.log(`共导出词条数: ${terms.length}`); } // 主函数 function main() { console.log('开始导出流程...'); try { // 1. 检查 output 目录是否存在 if (!fs.existsSync(OUTPUT_DIR)) { throw new Error(`output 目录不存在: ${OUTPUT_DIR}`); } // 2. 读取所有 JS 文件并提取词条 console.log('正在从 output 文件夹读取 JS 文件...'); const terms = readJsFiles(); if (terms.length === 0) { throw new Error('未找到任何可导出的词条'); } // 3. 生成 Excel 文件 console.log('正在生成 Excel 文件...'); generateExcel(terms); console.log('导出流程完成!'); } catch (err) { console.error('处理过程中出错:', err.message); process.exit(1); } } // 执行主函数 main();
在根目录下创建excel.js,复制代码执行node excel,可以看到输出了一个xlsx文件,这里也需要提前安装一下xlsx依赖npm i xlsx。
打开xlsx文件,验证一下,确实是我想要的,这下既可以给开发使用也可以给领导交差了,可谓一举两得,而且仅用了20分钟就完成了3天的工作量。
使用AI工具提升工作效率成为了当下热门旋律。以上案例只是抛砖引玉,在工作中很多地方都可以使用AI工具,尤其是那些大量重复的工作,提示词的需求逻辑描述清楚后,AI给到的结果大概率会帮助到你!