import * as fs from "fs"; import { glob } from "glob"; export class TableScanner { parseTrStrFields(content: string) { let m = content.match(/\/\/ NeedTranslateFields\: \[([a-zA-Z_,\s0-9]*)\]$/m); if (m != null) { let wordsContent = m[1]; let words = wordsContent.split(", "); return words; } else { return []; } } scanJsonWords(jsonContent: string, fields: string[], literals: string[]) { try { let arr = JSON.parse(jsonContent); for (const jsonRow of arr) { for (const key of fields) { let value = jsonRow[key]; if (typeof (value) == "string") { literals.push(value); } else if (Array.isArray(value)) { literals.push(...value); } } } } catch (error) { console.error(`解析JSON失败: ${error}`); } } async scanTableLiterals(csFullPath: string, literals: string[], verbose: boolean) { // csFullPath = "E:/DATA/Projects/ZhiYou/ProjectFClient/GameClient/Assets/Bundles/GameConfigs/Main/RefinerTable-RefinerEventTable.cs"; let jsonFullPath = csFullPath.replace("/Main/", "/Auto/").replace(/\.cs$/, ".json"); try { const [csExists, jsonExists] = await Promise.all([ fs.promises.access(csFullPath).then(() => true).catch(() => false), fs.promises.access(jsonFullPath).then(() => true).catch(() => false) ]); if (jsonExists && csExists) { const [csContent, jsonContent] = await Promise.all([ fs.promises.readFile(csFullPath, "utf-8"), fs.promises.readFile(jsonFullPath, "utf-8") ]); let trstrFields = this.parseTrStrFields(csContent); if (trstrFields.length > 0) { if (verbose) { console.log(`扫描表格: ${csFullPath} , 需要翻译字段: ${trstrFields}`); } this.scanJsonWords(jsonContent, trstrFields, literals); } else { if (verbose) { console.log(`跳过表格: ${csFullPath}`); } } } else { if (verbose) { if (!csExists) { console.warn(`表格 CS 文件不存在: ${jsonFullPath}`); } if (!jsonExists) { console.warn(`表格 JSON 文件不存在: ${csFullPath}`); } } } } catch (error) { console.error(`处理表格文件失败: ${csFullPath}`, error); } } /** * 扫描 */ async scanTablesLiterals(folder: string, literals: string[], verbose: boolean) { let dir = folder; let files = glob.sync("*.cs", { cwd: dir }); // 限制并行处理的文件数量,避免内存占用过高 const batchSize = 10; for (let i = 0; i < files.length; i += batchSize) { const batchFiles = files.slice(i, i + batchSize).reverse(); const batchPromises = batchFiles.map(async (filePath) => { let csFullPath = folder + filePath; await this.scanTableLiterals(csFullPath, literals, verbose); }); await Promise.all(batchPromises); } } }