chore: turn cn comment to en for common space (#376)
This commit is contained in:
@@ -10,7 +10,7 @@ import { getCommentPatterns } from '../utils/language';
|
||||
import { containsChinese, cleanCommentText } from '../utils/chinese';
|
||||
|
||||
/**
|
||||
* 检查指定位置是否在字符串字面量内部
|
||||
* Checks if the specified location is inside a string literal
|
||||
*/
|
||||
const isInsideStringLiteral = (line: string, position: number): boolean => {
|
||||
let insideDoubleQuote = false;
|
||||
@@ -44,7 +44,7 @@ const isInsideStringLiteral = (line: string, position: number): boolean => {
|
||||
};
|
||||
|
||||
/**
|
||||
* 解析单行注释
|
||||
* Parsing single-line comments
|
||||
*/
|
||||
const parseSingleLineComments = (
|
||||
content: string,
|
||||
@@ -54,34 +54,34 @@ const parseSingleLineComments = (
|
||||
const comments: ParsedComment[] = [];
|
||||
const lines = content.split('\n');
|
||||
|
||||
// 添加安全检查
|
||||
const maxLines = 5000; // 降低到5000行
|
||||
// Add a security check
|
||||
const maxLines = 5000; // Down to 5000 lines
|
||||
if (lines.length > maxLines) {
|
||||
console.warn(`⚠️ 文件行数过多 (${lines.length}行),跳过单行注释解析`);
|
||||
return comments;
|
||||
}
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
pattern.lastIndex = 0; // 重置正则表达式索引
|
||||
pattern.lastIndex = 0; // Reset regular expression index
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
// 查找所有匹配,但只保留不在字符串内的
|
||||
// Find all matches, but keep only those not in the string
|
||||
let matchCount = 0;
|
||||
const maxMatches = 100; // 限制每行最多匹配100次
|
||||
const maxMatches = 100; // Limit each line to a maximum of 100 matches
|
||||
let lastIndex = 0;
|
||||
|
||||
while ((match = pattern.exec(line)) !== null) {
|
||||
// 防止无限循环的多重保护
|
||||
// Multiple protections against infinite loops
|
||||
matchCount++;
|
||||
if (matchCount > maxMatches) {
|
||||
console.warn(`⚠️ 单行匹配次数过多,中断处理: ${line.substring(0, 50)}...`);
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查 lastIndex 是否前进,防止无限循环
|
||||
// Check if lastIndex is advancing to prevent an infinite loop
|
||||
if (pattern.global) {
|
||||
if (pattern.lastIndex <= lastIndex) {
|
||||
// 如果 lastIndex 没有前进,手动前进一位避免无限循环
|
||||
// If lastIndex does not advance, manually advance one bit to avoid infinite loops
|
||||
pattern.lastIndex = lastIndex + 1;
|
||||
if (pattern.lastIndex >= line.length) {
|
||||
break;
|
||||
@@ -93,9 +93,9 @@ const parseSingleLineComments = (
|
||||
if (match[1]) {
|
||||
const commentContent = match[1];
|
||||
let commentStartIndex = match.index!;
|
||||
let commentLength = 2; // 默认为 //
|
||||
let commentLength = 2; // Default is//
|
||||
|
||||
// 根据语言确定注释符号
|
||||
// Determine annotation symbols based on language
|
||||
if (
|
||||
language === 'yaml' ||
|
||||
language === 'toml' ||
|
||||
@@ -104,9 +104,9 @@ const parseSingleLineComments = (
|
||||
language === 'ruby'
|
||||
) {
|
||||
commentStartIndex = line.indexOf('#', match.index!);
|
||||
commentLength = 1; // # 长度为 1
|
||||
commentLength = 1; // #length is 1
|
||||
} else if (language === 'ini') {
|
||||
// INI 文件可能使用 # 或 ;
|
||||
// INI files may use #or;
|
||||
const hashIndex = line.indexOf('#', match.index!);
|
||||
const semicolonIndex = line.indexOf(';', match.index!);
|
||||
if (
|
||||
@@ -120,7 +120,7 @@ const parseSingleLineComments = (
|
||||
commentLength = 1;
|
||||
}
|
||||
} else if (language === 'php') {
|
||||
// PHP 可能使用 // 或 #
|
||||
// PHP may use//or #
|
||||
const slashIndex = line.indexOf('//', match.index!);
|
||||
const hashIndex = line.indexOf('#', match.index!);
|
||||
if (slashIndex >= 0 && (hashIndex < 0 || slashIndex < hashIndex)) {
|
||||
@@ -139,7 +139,7 @@ const parseSingleLineComments = (
|
||||
const startColumn = commentStartIndex;
|
||||
const endColumn = startColumn + commentLength + commentContent.length;
|
||||
|
||||
// 检查注释开始位置是否在字符串内部
|
||||
// Check if the comment starts inside the string
|
||||
if (
|
||||
commentStartIndex >= 0 &&
|
||||
!isInsideStringLiteral(line, commentStartIndex)
|
||||
@@ -155,7 +155,7 @@ const parseSingleLineComments = (
|
||||
}
|
||||
}
|
||||
|
||||
// 防止无限循环
|
||||
// Prevent infinite loops
|
||||
if (!pattern.global) break;
|
||||
}
|
||||
});
|
||||
@@ -164,7 +164,7 @@ const parseSingleLineComments = (
|
||||
};
|
||||
|
||||
/**
|
||||
* 解析多行注释
|
||||
* Parse multiline comments
|
||||
*/
|
||||
const parseMultiLineComments = (
|
||||
content: string,
|
||||
@@ -177,21 +177,21 @@ const parseMultiLineComments = (
|
||||
let commentStart: { line: number; column: number } | null = null;
|
||||
let commentLines: string[] = [];
|
||||
|
||||
// 添加安全检查
|
||||
const maxLines = 5000; // 降低到5000行
|
||||
// Add a security check
|
||||
const maxLines = 5000; // Down to 5000 lines
|
||||
if (lines.length > maxLines) {
|
||||
console.warn(`⚠️ 文件行数过多 (${lines.length}行),跳过多行注释解析`);
|
||||
return comments;
|
||||
}
|
||||
|
||||
// 添加处理计数器,防止无限循环
|
||||
// Add processing counters to prevent infinite loops
|
||||
let processedLines = 0;
|
||||
const maxProcessedLines = 10000;
|
||||
|
||||
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
||||
const line = lines[lineIndex];
|
||||
|
||||
// 防止无限处理
|
||||
// Prevent unlimited processing
|
||||
processedLines++;
|
||||
if (processedLines > maxProcessedLines) {
|
||||
console.warn(`⚠️ 处理行数超限,中断解析`);
|
||||
@@ -206,12 +206,12 @@ const parseMultiLineComments = (
|
||||
inComment = true;
|
||||
commentStart = { line: lineIndex + 1, column: startMatch.index! };
|
||||
|
||||
// 检查是否在同一行结束
|
||||
// Check if they end on the same line
|
||||
endPattern.lastIndex = startMatch.index! + startMatch[0].length;
|
||||
const endMatch = endPattern.exec(line);
|
||||
|
||||
if (endMatch) {
|
||||
// 单行多行注释
|
||||
// single-line multi-line comment
|
||||
const commentContent = line.substring(
|
||||
startMatch.index! + startMatch[0].length,
|
||||
endMatch.index!,
|
||||
@@ -229,7 +229,7 @@ const parseMultiLineComments = (
|
||||
inComment = false;
|
||||
commentStart = null;
|
||||
} else {
|
||||
// 多行注释开始
|
||||
// Start with a multi-line comment
|
||||
const commentContent = line.substring(
|
||||
startMatch.index! + startMatch[0].length,
|
||||
);
|
||||
@@ -237,12 +237,12 @@ const parseMultiLineComments = (
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 在多行注释中
|
||||
// In a multi-line comment
|
||||
endPattern.lastIndex = 0;
|
||||
const endMatch = endPattern.exec(line);
|
||||
|
||||
if (endMatch) {
|
||||
// 多行注释结束
|
||||
// End of multiline comment
|
||||
const commentContent = line.substring(0, endMatch.index!);
|
||||
commentLines.push(commentContent);
|
||||
|
||||
@@ -260,7 +260,7 @@ const parseMultiLineComments = (
|
||||
commentStart = null;
|
||||
commentLines = [];
|
||||
} else {
|
||||
// 继续多行注释
|
||||
// Continue with multi-line comments
|
||||
commentLines.push(line);
|
||||
}
|
||||
}
|
||||
@@ -270,7 +270,7 @@ const parseMultiLineComments = (
|
||||
};
|
||||
|
||||
/**
|
||||
* 解析文件中的所有注释
|
||||
* Parse all comments in the file
|
||||
*/
|
||||
export const parseComments = (file: SourceFile): ParsedComment[] => {
|
||||
const patterns = getCommentPatterns(file.language);
|
||||
@@ -291,7 +291,7 @@ export const parseComments = (file: SourceFile): ParsedComment[] => {
|
||||
};
|
||||
|
||||
/**
|
||||
* 过滤包含中文的注释,对多行注释进行逐行处理
|
||||
* Filter comments containing Chinese and process multi-line comments line by line
|
||||
*/
|
||||
export const filterChineseComments = (
|
||||
comments: ParsedComment[],
|
||||
@@ -301,11 +301,11 @@ export const filterChineseComments = (
|
||||
|
||||
for (const comment of comments) {
|
||||
if (comment.type === 'multi-line' && comment.content.includes('\n')) {
|
||||
// 多行注释:逐行处理
|
||||
// Multi-line comments: line-by-line processing
|
||||
const multiLineResults = processMultiLineCommentForChinese(comment, language);
|
||||
result.push(...multiLineResults);
|
||||
} else if (containsChinese(comment.content)) {
|
||||
// 单行注释或单行多行注释
|
||||
// Single-line comments or single-line multi-line comments
|
||||
result.push({
|
||||
...comment,
|
||||
content: cleanCommentText(
|
||||
@@ -321,7 +321,7 @@ export const filterChineseComments = (
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理多行注释,提取含中文的行作为独立的注释单元
|
||||
* Processing multi-line comments, extracting lines containing Chinese as independent comment units
|
||||
*/
|
||||
const processMultiLineCommentForChinese = (
|
||||
comment: ParsedComment,
|
||||
@@ -334,18 +334,18 @@ const processMultiLineCommentForChinese = (
|
||||
const cleanedLine = cleanCommentText(line, 'multi-line', language);
|
||||
|
||||
if (containsChinese(cleanedLine)) {
|
||||
// 计算这一行在原始文件中的位置
|
||||
// Calculate the position of this line in the original file
|
||||
const actualLineNumber = comment.startLine + lineIndex;
|
||||
|
||||
// 创建一个表示这一行的注释对象
|
||||
// Create a comment object representing this line
|
||||
const lineComment: ChineseComment = {
|
||||
content: cleanedLine,
|
||||
startLine: actualLineNumber,
|
||||
endLine: actualLineNumber,
|
||||
startColumn: 0, // 这个值需要更精确计算,但对于多行注释内的行处理暂时用0
|
||||
startColumn: 0, // This value needs to be calculated more precisely, but for line processing within a multi-line comment, use 0 for the time being.
|
||||
endColumn: line.length,
|
||||
type: 'multi-line',
|
||||
// 添加多行注释的元数据,用于后续处理
|
||||
// Add metadata with multi-line comments for subsequent processing
|
||||
multiLineContext: {
|
||||
isPartOfMultiLine: true,
|
||||
originalComment: comment,
|
||||
@@ -362,11 +362,11 @@ const processMultiLineCommentForChinese = (
|
||||
};
|
||||
|
||||
/**
|
||||
* 检测文件中的中文注释
|
||||
* Detect Chinese comments in files
|
||||
*/
|
||||
export const detectChineseInFile = (file: SourceFile): ChineseComment[] => {
|
||||
try {
|
||||
// 简单防护:跳过大文件
|
||||
// Simple protection: skipping large files
|
||||
if (file.content.length > 500000) {
|
||||
// 500KB
|
||||
console.warn(
|
||||
@@ -375,7 +375,7 @@ export const detectChineseInFile = (file: SourceFile): ChineseComment[] => {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 简单防护:跳过行数过多的文件
|
||||
// Simple protection: skip files with too many lines
|
||||
const lines = file.content.split('\n');
|
||||
if (lines.length > 10000) {
|
||||
console.warn(`⚠️ 跳过多行文件: ${file.path} (${lines.length} 行)`);
|
||||
@@ -391,7 +391,7 @@ export const detectChineseInFile = (file: SourceFile): ChineseComment[] => {
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量检测多个文件中的中文注释
|
||||
* Batch detection of Chinese comments in multiple files
|
||||
*/
|
||||
export const detectChineseInFiles = (files: SourceFile[]): FileWithComments[] => {
|
||||
const results: FileWithComments[] = [];
|
||||
@@ -417,7 +417,7 @@ export const detectChineseInFiles = (files: SourceFile[]): FileWithComments[] =>
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(`❌ 处理文件失败: ${fileName} - ${error}`);
|
||||
// 继续处理其他文件
|
||||
// Continue working on other documents
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -426,7 +426,7 @@ export const detectChineseInFiles = (files: SourceFile[]): FileWithComments[] =>
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取注释统计信息
|
||||
* Get annotation statistics
|
||||
*/
|
||||
export const getCommentStats = (files: SourceFile[]): {
|
||||
totalFiles: number;
|
||||
|
||||
@@ -9,14 +9,14 @@ import { tryCatch } from '../utils/fp';
|
||||
|
||||
|
||||
/**
|
||||
* 检查字符串是否包含中文字符
|
||||
* Check if string contains Chinese characters
|
||||
*/
|
||||
const containsChinese = (text: string): boolean => {
|
||||
return /[\u4e00-\u9fff]/.test(text);
|
||||
};
|
||||
|
||||
/**
|
||||
* 保持注释的原始格式,支持逐行翻译多行注释
|
||||
* Maintain the original format of comments and support line-by-line translation of multi-line comments
|
||||
*/
|
||||
export const preserveCommentFormat = (
|
||||
originalComment: string,
|
||||
@@ -24,7 +24,7 @@ export const preserveCommentFormat = (
|
||||
commentType: 'single-line' | 'multi-line',
|
||||
): string => {
|
||||
if (commentType === 'single-line') {
|
||||
// 保持单行注释的前缀空格和注释符 - 支持多种语言
|
||||
// Keep single-line comments prefixed with spaces and comment characters - supports multiple languages
|
||||
let match = originalComment.match(/^(\s*\/\/\s*)/); // JavaScript/TypeScript style
|
||||
if (match) {
|
||||
return match[1] + translatedComment.trim();
|
||||
@@ -40,13 +40,13 @@ export const preserveCommentFormat = (
|
||||
return match[1] + translatedComment.trim();
|
||||
}
|
||||
|
||||
// 如果无法识别,尝试从原始内容推断
|
||||
// If not recognized, try to infer from the original content
|
||||
if (originalComment.includes('#')) {
|
||||
const hashMatch = originalComment.match(/^(\s*#\s*)/);
|
||||
return (hashMatch ? hashMatch[1] : '# ') + translatedComment.trim();
|
||||
}
|
||||
|
||||
// 默认使用 JavaScript 风格
|
||||
// JavaScript style is used by default
|
||||
return '// ' + translatedComment.trim();
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ export const preserveCommentFormat = (
|
||||
const lines = originalComment.split('\n');
|
||||
|
||||
if (lines.length === 1) {
|
||||
// 单行多行注释 /* ... */ 或 /** ... */
|
||||
// Single-line multi-line comment/*... */or/**... */
|
||||
const startMatch = originalComment.match(/^(\s*\/\*\*?\s*)/);
|
||||
const endMatch = originalComment.match(/(\s*\*\/\s*)$/);
|
||||
|
||||
@@ -71,7 +71,7 @@ export const preserveCommentFormat = (
|
||||
|
||||
return prefix + translatedComment.trim() + suffix;
|
||||
} else {
|
||||
// 多行注释 - 需要逐行处理
|
||||
// Multi-line comments - requires line-by-line processing
|
||||
return processMultiLineComment(originalComment, translatedComment);
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ export const preserveCommentFormat = (
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理多行注释,逐行翻译含中文的行,保持其他行原样
|
||||
* Process multi-line comments, translate lines containing Chinese line by line, and keep other lines as they are
|
||||
*/
|
||||
export const processMultiLineComment = (
|
||||
originalComment: string,
|
||||
@@ -88,54 +88,54 @@ export const processMultiLineComment = (
|
||||
): string => {
|
||||
const originalLines = originalComment.split('\n');
|
||||
|
||||
// 提取每行的注释内容(去除 /** * 等前缀)
|
||||
// Extract comments for each line (remove prefixes such as /** * )other prefixes)
|
||||
const extractedLines = originalLines.map(line => {
|
||||
// 匹配不同类型的注释行
|
||||
Match different types of comment linesifferent types of comment lines
|
||||
if (line.match(/^\s*\/\*\*?\s*/)) {
|
||||
// 开始行: /** 或 /*
|
||||
// Start line:/** or/*
|
||||
return { prefix: line.match(/^\s*\/\*\*?\s*/)![0], content: line.replace(/^\s*\/\*\*?\s*/, '') };
|
||||
} else if (line.match(/^\s*\*\/\s*$/)) {
|
||||
// 结束行: */
|
||||
// End line: */
|
||||
return { prefix: line.match(/^\s*\*\/\s*$/)![0], content: '' };
|
||||
} else if (line.match(/^\s*\*\s*/)) {
|
||||
// 中间行: * content
|
||||
// Middle line: * content
|
||||
const match = line.match(/^(\s*\*\s*)(.*)/);
|
||||
return { prefix: match![1], content: match![2] };
|
||||
} else {
|
||||
// 其他情况
|
||||
// Other situations
|
||||
return { prefix: '', content: line };
|
||||
}
|
||||
});
|
||||
|
||||
// 收集需要翻译的行
|
||||
// Collect lines that need to be translated
|
||||
const linesToTranslate = extractedLines
|
||||
.map((line, index) => ({ index, content: line.content }))
|
||||
.filter(item => containsChinese(item.content));
|
||||
|
||||
// 如果没有中文内容,返回原始注释
|
||||
// If there is no Chinese content, return the original comment
|
||||
if (linesToTranslate.length === 0) {
|
||||
return originalComment;
|
||||
}
|
||||
|
||||
// 解析翻译结果 - 假设翻译服务按顺序返回翻译后的行
|
||||
// Parse translation results - assuming the translation service returns translated rows in order
|
||||
const translatedLines = translatedContent.split('\n');
|
||||
const translations = new Map<number, string>();
|
||||
|
||||
// 将翻译结果映射到对应的行
|
||||
// Map the translation result to the corresponding line
|
||||
linesToTranslate.forEach((item, transIndex) => {
|
||||
if (transIndex < translatedLines.length) {
|
||||
translations.set(item.index, translatedLines[transIndex].trim());
|
||||
}
|
||||
});
|
||||
|
||||
// 重建注释,保持原始结构
|
||||
// Rebuild the annotation, maintaining the original structure
|
||||
return extractedLines
|
||||
.map((line, index) => {
|
||||
if (translations.has(index)) {
|
||||
// 使用翻译内容,保持原始前缀
|
||||
// Use translated content, keeping the original prefix
|
||||
return line.prefix + translations.get(index);
|
||||
} else {
|
||||
// 保持原样
|
||||
// Leave it as it is
|
||||
return originalLines[index];
|
||||
}
|
||||
})
|
||||
@@ -143,7 +143,7 @@ export const processMultiLineComment = (
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建替换操作
|
||||
* Create replacement operation
|
||||
*/
|
||||
export const createReplacements = (
|
||||
file: SourceFile,
|
||||
@@ -157,13 +157,13 @@ export const createReplacements = (
|
||||
if (!translation) return;
|
||||
|
||||
if (comment.multiLineContext?.isPartOfMultiLine) {
|
||||
// 处理多行注释中的单行
|
||||
// Handling single lines in multi-line comments
|
||||
const replacement = createMultiLineReplacement(file, comment, translation);
|
||||
if (replacement) {
|
||||
replacements.push(replacement);
|
||||
}
|
||||
} else {
|
||||
// 处理普通注释(单行注释或整个多行注释)
|
||||
// Processing normal comments (single-line comments or entire multi-line comments)
|
||||
const replacement = createRegularReplacement(file, comment, translation);
|
||||
if (replacement) {
|
||||
replacements.push(replacement);
|
||||
@@ -175,7 +175,7 @@ export const createReplacements = (
|
||||
};
|
||||
|
||||
/**
|
||||
* 为多行注释中的单行创建替换操作
|
||||
* Create a replacement operation for a single line in a multi-line comment
|
||||
*/
|
||||
const createMultiLineReplacement = (
|
||||
file: SourceFile,
|
||||
@@ -189,10 +189,10 @@ const createMultiLineReplacement = (
|
||||
|
||||
const originalLine = lines[lineIndex];
|
||||
|
||||
// 查找这一行中中文内容的位置
|
||||
// Find the location of Chinese content in this line
|
||||
const cleanedContent = comment.content;
|
||||
|
||||
// 更精确地查找中文内容在原始行中的位置
|
||||
// Find the position of Chinese content in the original line more accurately
|
||||
const commentContentRegex = new RegExp(cleanedContent.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
||||
const contentMatch = originalLine.match(commentContentRegex);
|
||||
|
||||
@@ -203,7 +203,7 @@ const createMultiLineReplacement = (
|
||||
const chineseStart = contentMatch.index!;
|
||||
const chineseEnd = chineseStart + contentMatch[0].length;
|
||||
|
||||
// 计算在整个文件中的位置
|
||||
// Calculate the position in the entire file
|
||||
let start = 0;
|
||||
for (let i = 0; i < lineIndex; i++) {
|
||||
start += lines[i].length + 1; // +1 for newline
|
||||
@@ -221,7 +221,7 @@ const createMultiLineReplacement = (
|
||||
};
|
||||
|
||||
/**
|
||||
* 为普通注释创建替换操作
|
||||
* Create a replacement operation for a normal comment
|
||||
*/
|
||||
const createRegularReplacement = (
|
||||
file: SourceFile,
|
||||
@@ -232,7 +232,7 @@ const createRegularReplacement = (
|
||||
const startLineIndex = comment.startLine - 1;
|
||||
const endLineIndex = comment.endLine - 1;
|
||||
|
||||
// 计算原始注释在文件中的精确位置
|
||||
// Calculate the exact location of the original comment in the file
|
||||
let start = 0;
|
||||
for (let i = 0; i < startLineIndex; i++) {
|
||||
start += lines[i].length + 1; // +1 for newline
|
||||
@@ -241,10 +241,10 @@ const createRegularReplacement = (
|
||||
|
||||
let end = start;
|
||||
if (comment.startLine === comment.endLine) {
|
||||
// 同一行
|
||||
// same line
|
||||
end = start + (comment.endColumn - comment.startColumn);
|
||||
} else {
|
||||
// 跨行 - 重新计算end位置
|
||||
// Interline recalculation of end position
|
||||
end = 0;
|
||||
for (let i = 0; i < endLineIndex; i++) {
|
||||
end += lines[i].length + 1; // +1 for newline
|
||||
@@ -252,10 +252,10 @@ const createRegularReplacement = (
|
||||
end += comment.endColumn;
|
||||
}
|
||||
|
||||
// 获取原始注释文本
|
||||
// Get original comment text
|
||||
const originalText = file.content.substring(start, end);
|
||||
|
||||
// 应用格式保持
|
||||
// application format retention
|
||||
const formattedTranslation = preserveCommentFormat(
|
||||
originalText,
|
||||
translation.translated,
|
||||
@@ -271,13 +271,13 @@ const createRegularReplacement = (
|
||||
};
|
||||
|
||||
/**
|
||||
* 应用替换操作到文本内容
|
||||
* Apply a replacement operation to text content
|
||||
*/
|
||||
export const applyReplacements = (
|
||||
content: string,
|
||||
replacements: Replacement[],
|
||||
): string => {
|
||||
// 按位置倒序排列,避免替换后位置偏移
|
||||
// Arrange in reverse order to avoid position shift after replacement
|
||||
const sortedReplacements = [...replacements].sort(
|
||||
(a, b) => b.start - a.start,
|
||||
);
|
||||
@@ -294,7 +294,7 @@ export const applyReplacements = (
|
||||
};
|
||||
|
||||
/**
|
||||
* 替换文件中的注释
|
||||
* Replace comments in the file
|
||||
*/
|
||||
export const replaceCommentsInFile = async (
|
||||
file: SourceFile,
|
||||
@@ -303,13 +303,13 @@ export const replaceCommentsInFile = async (
|
||||
return tryCatch(async () => {
|
||||
const fs = await import('fs/promises');
|
||||
|
||||
// 应用替换
|
||||
// Application Replacement
|
||||
const newContent = applyReplacements(
|
||||
file.content,
|
||||
operation.replacements,
|
||||
);
|
||||
|
||||
// 写入文件
|
||||
// Write file
|
||||
await fs.writeFile(file.path, newContent, 'utf-8');
|
||||
|
||||
return { success: true };
|
||||
@@ -329,7 +329,7 @@ export const replaceCommentsInFile = async (
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量替换多个文件
|
||||
* Batch replacement of multiple files
|
||||
*/
|
||||
export const batchReplaceFiles = async (
|
||||
operations: ReplacementOperation[],
|
||||
@@ -347,7 +347,7 @@ export const batchReplaceFiles = async (
|
||||
const sourceFile: SourceFile = {
|
||||
path: operation.file,
|
||||
content,
|
||||
language: 'other', // 临时值,实际应该检测
|
||||
language: 'other', // Temporary value, which should actually be checked
|
||||
};
|
||||
|
||||
const result = await replaceCommentsInFile(
|
||||
@@ -375,7 +375,7 @@ export const batchReplaceFiles = async (
|
||||
};
|
||||
|
||||
/**
|
||||
* 验证替换操作
|
||||
* Verify replacement operation
|
||||
*/
|
||||
export const validateReplacements = (
|
||||
content: string,
|
||||
@@ -383,7 +383,7 @@ export const validateReplacements = (
|
||||
): { valid: boolean; errors: string[] } => {
|
||||
const errors: string[] = [];
|
||||
|
||||
// 检查位置是否有效
|
||||
// Check if the location is valid
|
||||
replacements.forEach((replacement, index) => {
|
||||
if (replacement.start < 0 || replacement.end > content.length) {
|
||||
errors.push(`Replacement ${index}: Invalid position range`);
|
||||
@@ -395,14 +395,14 @@ export const validateReplacements = (
|
||||
);
|
||||
}
|
||||
|
||||
// 检查原文是否匹配
|
||||
// Check if the original text matches
|
||||
const actualText = content.substring(replacement.start, replacement.end);
|
||||
if (actualText !== replacement.original) {
|
||||
errors.push(`Replacement ${index}: Original text mismatch`);
|
||||
}
|
||||
});
|
||||
|
||||
// 检查是否有重叠
|
||||
// Check for overlap
|
||||
const sortedReplacements = [...replacements].sort(
|
||||
(a, b) => a.start - b.start,
|
||||
);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { getGitTrackedFiles, getAllGitFiles } from '../utils/git';
|
||||
import { tryCatch } from '../utils/fp';
|
||||
|
||||
/**
|
||||
* 读取文件内容并创建SourceFile对象
|
||||
* Read the file contents and create a SourceFile object
|
||||
*/
|
||||
export const readSourceFile = async (filePath: string): Promise<Result<SourceFile>> => {
|
||||
return tryCatch(async () => {
|
||||
@@ -21,7 +21,7 @@ export const readSourceFile = async (filePath: string): Promise<Result<SourceFil
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量读取源文件
|
||||
* Batch reading of source files
|
||||
*/
|
||||
export const readSourceFiles = async (filePaths: string[]): Promise<SourceFile[]> => {
|
||||
const results = await Promise.allSettled(
|
||||
@@ -36,13 +36,13 @@ export const readSourceFiles = async (filePaths: string[]): Promise<SourceFile[]
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取Git仓库中的源码文件
|
||||
* Get the source code file in the Git repository
|
||||
*/
|
||||
export const getSourceFiles = async (config: FileScanConfig): Promise<Result<string[]>> => {
|
||||
const { root, extensions, includeUntracked } = config;
|
||||
|
||||
return tryCatch(async () => {
|
||||
// 获取Git文件列表
|
||||
// Get a list of Git files
|
||||
const gitFilesResult = includeUntracked
|
||||
? await getAllGitFiles(root)
|
||||
: await getGitTrackedFiles(root);
|
||||
@@ -53,10 +53,10 @@ export const getSourceFiles = async (config: FileScanConfig): Promise<Result<str
|
||||
|
||||
let files = gitFilesResult.data;
|
||||
|
||||
// 过滤文本文件
|
||||
// Filter text files
|
||||
files = files.filter(isTextFile);
|
||||
|
||||
// 根据扩展名过滤
|
||||
// Filter by extension
|
||||
files = filterFilesByExtensions(files, extensions);
|
||||
|
||||
return files;
|
||||
@@ -64,7 +64,7 @@ export const getSourceFiles = async (config: FileScanConfig): Promise<Result<str
|
||||
};
|
||||
|
||||
/**
|
||||
* 扫描并读取所有源码文件
|
||||
* Scan and read all source code files
|
||||
*/
|
||||
export const scanSourceFiles = async (config: FileScanConfig): Promise<Result<SourceFile[]>> => {
|
||||
return tryCatch(async () => {
|
||||
@@ -80,7 +80,7 @@ export const scanSourceFiles = async (config: FileScanConfig): Promise<Result<So
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查文件是否存在且可读
|
||||
* Check if the file exists and is readable
|
||||
*/
|
||||
export const isFileAccessible = async (filePath: string): Promise<boolean> => {
|
||||
try {
|
||||
@@ -92,7 +92,7 @@ export const isFileAccessible = async (filePath: string): Promise<boolean> => {
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取文件统计信息
|
||||
* Get file statistics
|
||||
*/
|
||||
export const getFileStats = async (filePaths: string[]): Promise<{
|
||||
total: number;
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
} from '../types/index.js';
|
||||
|
||||
/**
|
||||
* 报告收集器类
|
||||
* report collector class
|
||||
*/
|
||||
export class ReportCollector {
|
||||
private stats: ProcessingStats = {
|
||||
@@ -21,7 +21,7 @@ export class ReportCollector {
|
||||
private fileDetails: Map<string, FileProcessingDetail> = new Map();
|
||||
|
||||
/**
|
||||
* 记录文件处理开始
|
||||
* Record file processing begins
|
||||
*/
|
||||
recordFileStart(filePath: string): void {
|
||||
this.stats.totalFiles++;
|
||||
@@ -34,7 +34,7 @@ export class ReportCollector {
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录文件处理完成
|
||||
* Record file processing completed
|
||||
*/
|
||||
recordFileComplete(filePath: string, commentCount: number): void {
|
||||
const detail = this.fileDetails.get(filePath);
|
||||
@@ -48,7 +48,7 @@ export class ReportCollector {
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录文件跳过
|
||||
* log file skip
|
||||
*/
|
||||
recordFileSkipped(filePath: string, reason?: string): void {
|
||||
const detail = this.fileDetails.get(filePath);
|
||||
@@ -61,7 +61,7 @@ export class ReportCollector {
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录处理错误
|
||||
* Log processing errors
|
||||
*/
|
||||
recordError(filePath: string, error: Error): void {
|
||||
const detail = this.fileDetails.get(filePath);
|
||||
@@ -74,28 +74,28 @@ export class ReportCollector {
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成统计
|
||||
* Complete statistics
|
||||
*/
|
||||
finalize(): void {
|
||||
this.stats.endTime = Date.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计信息
|
||||
* Obtain statistical information
|
||||
*/
|
||||
getStats(): ProcessingStats {
|
||||
return { ...this.stats };
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件详情
|
||||
* Get file details
|
||||
*/
|
||||
getFileDetails(): FileProcessingDetail[] {
|
||||
return Array.from(this.fileDetails.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成完整报告
|
||||
* Generate a full report
|
||||
*/
|
||||
generateReport(): ProcessingReport {
|
||||
this.finalize();
|
||||
@@ -109,7 +109,7 @@ export class ReportCollector {
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置收集器
|
||||
* Reset collector
|
||||
*/
|
||||
reset(): void {
|
||||
this.stats = {
|
||||
@@ -126,7 +126,7 @@ export class ReportCollector {
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成控制台报告
|
||||
* Generate console reports
|
||||
*/
|
||||
export const generateConsoleReport = (report: ProcessingReport): string => {
|
||||
const { stats, duration } = report;
|
||||
@@ -160,7 +160,7 @@ export const generateConsoleReport = (report: ProcessingReport): string => {
|
||||
};
|
||||
|
||||
/**
|
||||
* 生成Markdown报告
|
||||
* Generating Markdown Reports
|
||||
*/
|
||||
export const generateMarkdownReport = (report: ProcessingReport): string => {
|
||||
const { stats, details, duration } = report;
|
||||
@@ -217,14 +217,14 @@ export const generateMarkdownReport = (report: ProcessingReport): string => {
|
||||
};
|
||||
|
||||
/**
|
||||
* 生成JSON报告
|
||||
* Generate JSON reports
|
||||
*/
|
||||
export const generateJsonReport = (report: ProcessingReport): string => {
|
||||
return JSON.stringify(report, null, 2);
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据格式生成报告
|
||||
* Generate reports according to the format
|
||||
*/
|
||||
export const generateReport = (
|
||||
report: ProcessingReport,
|
||||
@@ -242,7 +242,7 @@ export const generateReport = (
|
||||
};
|
||||
|
||||
/**
|
||||
* 保存报告到文件
|
||||
* Save report to file
|
||||
*/
|
||||
export const saveReportToFile = async (
|
||||
report: ProcessingReport,
|
||||
@@ -255,7 +255,7 @@ export const saveReportToFile = async (
|
||||
};
|
||||
|
||||
/**
|
||||
* 在控制台显示实时进度
|
||||
* Display real-time progress on the console
|
||||
*/
|
||||
export class ProgressDisplay {
|
||||
private total: number = 0;
|
||||
@@ -267,7 +267,7 @@ export class ProgressDisplay {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新进度
|
||||
* update progress
|
||||
*/
|
||||
update(current: number, currentFile?: string): void {
|
||||
this.current = current;
|
||||
@@ -286,7 +286,7 @@ export class ProgressDisplay {
|
||||
line += ` | 当前: ${currentFile}`;
|
||||
}
|
||||
|
||||
// 清除当前行并输出新进度
|
||||
// Clear the current line and output the new progress
|
||||
process.stdout.write(
|
||||
'\r' + ' '.repeat(process.stdout.columns || 80) + '\r',
|
||||
);
|
||||
@@ -294,7 +294,7 @@ export class ProgressDisplay {
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成进度显示
|
||||
* completion progress display
|
||||
*/
|
||||
complete(): void {
|
||||
process.stdout.write('\n');
|
||||
|
||||
@@ -10,7 +10,7 @@ import { isValidTranslation } from '../utils/chinese';
|
||||
import { translate as volcTranslate, TranslateConfig as VolcTranslateConfig } from '../volc/translate';
|
||||
|
||||
/**
|
||||
* 翻译服务类
|
||||
* Translation services
|
||||
*/
|
||||
export class TranslationService {
|
||||
private config: TranslationConfig;
|
||||
@@ -21,7 +21,7 @@ export class TranslationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为火山引擎翻译配置
|
||||
* Convert to Volcano Engine Translation Configuration
|
||||
*/
|
||||
private toVolcConfig(): VolcTranslateConfig {
|
||||
return {
|
||||
@@ -34,17 +34,17 @@ export class TranslationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算翻译置信度(简单实现)
|
||||
* Calculate translation confidence level (simple implementation)
|
||||
*/
|
||||
private calculateConfidence(translated: string, original: string): number {
|
||||
// 基于长度比例和有效性的简单置信度计算
|
||||
// Simple confidence level calculation based on length ratio and validity
|
||||
const lengthRatio = translated.length / original.length;
|
||||
|
||||
if (!isValidTranslation(original, translated)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 理想的长度比例在0.8-2.0之间
|
||||
// The ideal length ratio is between 0.8-2
|
||||
let confidence = 0.8;
|
||||
if (lengthRatio >= 0.8 && lengthRatio <= 2.0) {
|
||||
confidence = 0.9;
|
||||
@@ -54,7 +54,7 @@ export class TranslationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用火山引擎API进行翻译
|
||||
* Call Volcano Engine API for translation
|
||||
*/
|
||||
private async callVolcTranslate(texts: string[]): Promise<string[]> {
|
||||
const volcConfig = this.toVolcConfig();
|
||||
@@ -64,13 +64,13 @@ export class TranslationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 翻译单个注释
|
||||
* Translate a single comment
|
||||
*/
|
||||
async translateComment(
|
||||
comment: string,
|
||||
context?: TranslationContext,
|
||||
): Promise<TranslationResult> {
|
||||
// 检查缓存
|
||||
// Check cache
|
||||
const cacheKey = this.getCacheKey(comment, context);
|
||||
const cached = this.cache.get(cacheKey);
|
||||
if (cached) {
|
||||
@@ -95,7 +95,7 @@ export class TranslationService {
|
||||
confidence: this.calculateConfidence(translated, comment),
|
||||
};
|
||||
|
||||
// 缓存结果
|
||||
// cache results
|
||||
this.cache.set(cacheKey, result);
|
||||
|
||||
return result;
|
||||
@@ -108,7 +108,7 @@ export class TranslationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成缓存键
|
||||
* generate cache key
|
||||
*/
|
||||
private getCacheKey(comment: string, context?: TranslationContext): string {
|
||||
const contextStr = context
|
||||
@@ -118,17 +118,17 @@ export class TranslationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量翻译注释
|
||||
* batch translation annotations
|
||||
*/
|
||||
async batchTranslate(
|
||||
comments: ChineseComment[],
|
||||
concurrency: number = this.config.concurrency,
|
||||
): Promise<TranslationResult[]> {
|
||||
// 提取未缓存的注释
|
||||
// Extract uncached comments
|
||||
const uncachedComments: { comment: ChineseComment; index: number }[] = [];
|
||||
const results: TranslationResult[] = new Array(comments.length);
|
||||
|
||||
// 检查缓存
|
||||
// Check cache
|
||||
comments.forEach((comment, index) => {
|
||||
const cacheKey = this.getCacheKey(comment.content);
|
||||
const cached = this.cache.get(cacheKey);
|
||||
@@ -139,12 +139,12 @@ export class TranslationService {
|
||||
}
|
||||
});
|
||||
|
||||
// 如果所有注释都已缓存,直接返回
|
||||
// If all comments are cached, return directly
|
||||
if (uncachedComments.length === 0) {
|
||||
return results;
|
||||
}
|
||||
|
||||
// 分批翻译未缓存的注释
|
||||
// Batch translation of uncached comments
|
||||
const chunks = chunk(uncachedComments, concurrency);
|
||||
|
||||
for (const chunkItems of chunks) {
|
||||
@@ -156,7 +156,7 @@ export class TranslationService {
|
||||
1000,
|
||||
);
|
||||
|
||||
// 处理翻译结果
|
||||
// Processing translation results
|
||||
chunkItems.forEach((item, chunkIndex) => {
|
||||
const translated = translations[chunkIndex];
|
||||
if (translated) {
|
||||
@@ -166,26 +166,26 @@ export class TranslationService {
|
||||
confidence: this.calculateConfidence(translated, item.comment.content),
|
||||
};
|
||||
|
||||
// 缓存结果
|
||||
// cache results
|
||||
const cacheKey = this.getCacheKey(item.comment.content);
|
||||
this.cache.set(cacheKey, result);
|
||||
|
||||
results[item.index] = result;
|
||||
} else {
|
||||
// 如果翻译失败,创建一个错误结果
|
||||
// If the translation fails, an error result is created
|
||||
results[item.index] = {
|
||||
original: item.comment.content,
|
||||
translated: item.comment.content, // 翻译失败时保持原文
|
||||
translated: item.comment.content, // Keep the original text when translation fails
|
||||
confidence: 0,
|
||||
};
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
// 如果整个批次翻译失败,为这个批次的所有注释创建错误结果
|
||||
// If the entire batch translation fails, an error result is created for all comments in that batch
|
||||
chunkItems.forEach(item => {
|
||||
results[item.index] = {
|
||||
original: item.comment.content,
|
||||
translated: item.comment.content, // 翻译失败时保持原文
|
||||
translated: item.comment.content, // Keep the original text when translation fails
|
||||
confidence: 0,
|
||||
};
|
||||
});
|
||||
@@ -198,7 +198,7 @@ export class TranslationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存翻译缓存到文件
|
||||
* Save translation cache to file
|
||||
*/
|
||||
async saveCache(filePath: string): Promise<void> {
|
||||
const cacheData = Object.fromEntries(this.cache);
|
||||
@@ -207,7 +207,7 @@ export class TranslationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文件加载翻译缓存
|
||||
* Load translation cache from file
|
||||
*/
|
||||
async loadCache(filePath: string): Promise<void> {
|
||||
try {
|
||||
@@ -216,24 +216,24 @@ export class TranslationService {
|
||||
const cacheData = JSON.parse(data);
|
||||
this.cache = new Map(Object.entries(cacheData));
|
||||
} catch {
|
||||
// 缓存文件不存在或损坏,忽略
|
||||
// The cache file does not exist or is corrupted, ignore it
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空缓存
|
||||
* clear cache
|
||||
*/
|
||||
clearCache(): void {
|
||||
this.cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存统计
|
||||
* Get cache statistics
|
||||
*/
|
||||
getCacheStats(): { size: number; hitRate: number } {
|
||||
return {
|
||||
size: this.cache.size,
|
||||
hitRate: 0, // 需要实际统计命中率
|
||||
hitRate: 0, // Actual statistical hit rate is required
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user