chore: turn cn comment to en for common space (#376)

This commit is contained in:
tecvan 2025-07-31 12:42:03 +08:00 committed by GitHub
parent f7d73cd391
commit a1f3a9aead
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 390 additions and 390 deletions

View File

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# 设置默认值 # Set default value
TARGET_BRANCH=${targetBranch} TARGET_BRANCH=${targetBranch}
CI_MODE=${CI:-false} CI_MODE=${CI:-false}
@ -36,11 +36,11 @@ else
files=$(git diff --name-only --diff-filter=AM --cached $EXCLUDE_STRING) files=$(git diff --name-only --diff-filter=AM --cached $EXCLUDE_STRING)
fi fi
# 体积限制为512KB # The volume limit is 512KB.
size_limit=$((512)) size_limit=$((512))
large_files_info="" large_files_info=""
IFS=$'\n' # 处理文件名存在空格情况 IFS=$'\n' # Handling the existence of spaces in the file name
for file in $files; do for file in $files; do
file_size=$(wc -c <"$file" 2>/dev/null) file_size=$(wc -c <"$file" 2>/dev/null)
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then

View File

@ -37,10 +37,10 @@ jobs:
- name: Process changed files - name: Process changed files
id: process-files id: process-files
run: | run: |
# 获取所有变更文件 # Get all change files
all_files="${{ steps.changed-files.outputs.all_changed_files }}" all_files="${{ steps.changed-files.outputs.all_changed_files }}"
# 过滤掉 common/changes 目录下的文件 # Filter out files in the common/changes directory
filtered_files="" filtered_files=""
for file in $all_files; do for file in $all_files; do
if [[ ! "$file" =~ ^common/changes/.* ]]; then if [[ ! "$file" =~ ^common/changes/.* ]]; then
@ -52,10 +52,10 @@ jobs:
fi fi
done done
# 创建 JSON 格式的缓存文件 # Create cached files in JSON format
echo "[$( echo "$filtered_files" | sed 's/ /", "/g' | sed 's/^/"/' | sed 's/$/"/' )]" > changed-files-cache.json echo "[$( echo "$filtered_files" | sed 's/ /", "/g' | sed 's/^/"/' | sed 's/$/"/' )]" > changed-files-cache.json
# 输出缓存文件路径供后续步骤使用 # Output cache file path for subsequent steps
echo "cache_file=changed-files-cache.json" >> $GITHUB_OUTPUT echo "cache_file=changed-files-cache.json" >> $GITHUB_OUTPUT
echo "过滤前文件数量: $(echo $all_files | wc -w)" echo "过滤前文件数量: $(echo $all_files | wc -w)"

View File

@ -33,7 +33,7 @@ export default class SelectTeamPlugin implements IPlugin {
apply(hooks: IHooks): void { apply(hooks: IHooks): void {
hooks.prompts.tap("SelectTeamPlugin", (prompts: IPromptsHookParams) => { hooks.prompts.tap("SelectTeamPlugin", (prompts: IPromptsHookParams) => {
// 只留下以team-为前缀的 // Leave only the prefix team-
const teamNamePrefix = /^team-/; const teamNamePrefix = /^team-/;
const choices = rushJson.allowedProjectTags.filter( const choices = rushJson.allowedProjectTags.filter(
teamName => teamNamePrefix.test(teamName) teamName => teamNamePrefix.test(teamName)
@ -41,20 +41,20 @@ export default class SelectTeamPlugin implements IPlugin {
teamName => teamName.replace(teamNamePrefix, '') teamName => teamName.replace(teamNamePrefix, '')
); );
// unshift一个问题使得用户选择完模版后展示该问题。 // Unshift an issue, causing the user to display the issue after selecting a template.
prompts.promptQueue.unshift({ prompts.promptQueue.unshift({
type: "list", type: "list",
name: "team", name: "team",
message: "Select your team", message: "Select your team",
choices, choices,
default: 0, // 默认选择choices[0] default: 0, // Default choices [0]
}); });
const projectFolderPrompt = prompts.promptQueue.find( const projectFolderPrompt = prompts.promptQueue.find(
item => item.name === 'projectFolder' item => item.name === 'projectFolder'
); );
projectFolderPrompt.default = (answers) => { projectFolderPrompt.default = (answers) => {
// 文件夹名去除scope如 @coze-arch/foo -> foo // Remove the scope from the folder name, such as @code-arch/foo - > foo
const folderDir = answers.packageName.split('/').slice(-1)[0]; const folderDir = answers.packageName.split('/').slice(-1)[0];
return `frontend/packages/${answers.team}/${folderDir}`; return `frontend/packages/${answers.team}/${folderDir}`;
} }

View File

@ -20,9 +20,9 @@ import type {
IPromptsHookParams, IPromptsHookParams,
} from 'rush-init-project-plugin'; } from 'rush-init-project-plugin';
// FIXME: // FIXME:
// 按照 https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md // According to https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md
// 一文的指引,无法正确 resolve 到对应模块,暂时没找到解决方案,故此处先用相对路径引用 // The guidelines of this article cannot be correctly resolved to the corresponding module, and a solution has not been found for the time being, so the relative path reference is used here first
// 未来需要调整为正常的 node_modules 引用方式 // Future needs to be adjusted to normal node_modules citation
import { createLog } from '../../autoinstallers/plugins/node_modules/rush-init-project-plugin'; import { createLog } from '../../autoinstallers/plugins/node_modules/rush-init-project-plugin';
import { exec } from './utils'; import { exec } from './utils';

View File

@ -21,9 +21,9 @@ import type {
IPromptsHookParams, IPromptsHookParams,
} from 'rush-init-project-plugin'; } from 'rush-init-project-plugin';
// FIXME: // FIXME:
// 按照 https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md // According to https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md
// 一文的指引,无法正确 resolve 到对应模块,暂时没找到解决方案,故此处先用相对路径引用 // The guidelines of this article cannot be correctly resolved to the corresponding module, and a solution has not been found for the time being, so the relative path reference is used here first
// 未来需要调整为正常的 node_modules 引用方式 // Future needs to be adjusted to normal node_modules citation
import { import {
getTemplatesFolder, getTemplatesFolder,
getTemplateNameList, getTemplateNameList,

View File

@ -21,18 +21,18 @@ export function parseCommandLineArguments() {
const args = process.argv.slice(2); const args = process.argv.slice(2);
const result: Record<string, string> = {}; const result: Record<string, string> = {};
// 循环遍历所有参数 // Loop through all parameters
for (let i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
// 检查当前参数是否是一个选项(以 "--" 开头) // Check if the current argument is an option (starting with "--").
if (args[i].startsWith('--')) { if (args[i].startsWith('--')) {
const key = args[i].substring(2); // 移除 "--" 前缀 const key = args[i].substring(2); // Remove the "--" prefix
// 检查下一个参数是否存在,且不是另一个选项 // Check if the next argument exists and is not another option
if (i + 1 < args.length && !args[i + 1].startsWith('--')) { if (i + 1 < args.length && !args[i + 1].startsWith('--')) {
result[key] = args[i + 1]; // 将下一个参数作为当前选项的值 result[key] = args[i + 1]; // Set the next argument as the value of the current option
i++; // 跳过下一个参数,因为它已经被处理为当前选项的值 i++; // Skip the next argument because it has already been processed to the value of the current option
} else { } else {
result[key] = ''; // 如果没有值,只设置选项的键 result[key] = ''; // If there is no value, only set the key of the option
} }
} }
} }

View File

@ -27,8 +27,8 @@ export function DemoComponent(props: { name: string }): JSX.Element {
const [foo] = useState('hello world'); const [foo] = useState('hello world');
const { name } = props; const { name } = props;
return ( return (
// font-bold 来自 taiwindcss // Font-bold from taiwindcss
// 建议优先使用 taiwindcss // It is recommended to use taiwindcss first.
<div className={classNames(s.foo, 'font-bold')}> <div className={classNames(s.foo, 'font-bold')}>
{foo} {name}! {foo} {name}!
<div> <div>

View File

@ -16,8 +16,8 @@
const { NODE_ENV } = process.env; const { NODE_ENV } = process.env;
const IS_DEV_MODE = NODE_ENV === 'development'; // 本地环境 const IS_DEV_MODE = NODE_ENV === 'development'; // local environment
const IS_PRODUCT_MODE = NODE_ENV === 'production'; // 生产环境 const IS_PRODUCT_MODE = NODE_ENV === 'production'; // production environment
const IS_CI = process.env.CI === 'true'; const IS_CI = process.env.CI === 'true';

View File

@ -41,7 +41,7 @@ export const updateDTS = (
) => { ) => {
const start = Date.now(); const start = Date.now();
// 初始化一个 ts-morph 项目 // Initialize a ts-morph project
const project = new Project({ const project = new Project({
compilerOptions: { compilerOptions: {
incremental: true, incremental: true,
@ -51,19 +51,19 @@ export const updateDTS = (
noEmitOnError: true, noEmitOnError: true,
}, },
}); });
// 添加想要解析的文件 // Add the file you want to parse
const file = project.addSourceFileAtPath(inputFileName); const file = project.addSourceFileAtPath(inputFileName);
// 获取你想要解析的变量 // Get the variable you want to parse
const envs = file.getVariableDeclarationOrThrow(envVarName); const envs = file.getVariableDeclarationOrThrow(envVarName);
// 获取 envs 变量的初始值 // Get the initial value of the envs variable
const initializer = envs.getInitializerIfKindOrThrow( const initializer = envs.getInitializerIfKindOrThrow(
SyntaxKind.ObjectLiteralExpression, SyntaxKind.ObjectLiteralExpression,
); );
// 获取 envs 对象的属性 // Get the properties of the envs object
const properties = initializer.getProperties(); const properties = initializer.getProperties();
// 创建一个新的文件,用来保存生成的类型定义 // Create a new file to hold the generated type definition
const typeDefs = project.createSourceFile( const typeDefs = project.createSourceFile(
outputFileName, outputFileName,
`// 基于${inputFileName}自动生成,请勿手动修改`, `// 基于${inputFileName}自动生成,请勿手动修改`,
@ -81,7 +81,7 @@ export const updateDTS = (
}); });
}; };
// 遍历每一个属性 // Iterate through each attribute
properties.forEach(property => { properties.forEach(property => {
if ( if (
property instanceof PropertyAssignment || property instanceof PropertyAssignment ||
@ -93,9 +93,9 @@ export const updateDTS = (
const type = expression.getType(); const type = expression.getType();
if (type.isObject()) { if (type.isObject()) {
// 如果类型是一个对象类型,获取其属性 // If the type is an object type, obtain its properties
const spreadProperties = type.getProperties(); const spreadProperties = type.getProperties();
// 遍历属性 // traversal properties
for (const spreadProperty of spreadProperties) { for (const spreadProperty of spreadProperties) {
const declaration = spreadProperty.getDeclarations()?.[0]; const declaration = spreadProperty.getDeclarations()?.[0];
if (declaration) { if (declaration) {
@ -113,7 +113,7 @@ export const updateDTS = (
} }
} }
}); });
// 保存文件 // Save file
typeDefs.addVariableStatements( typeDefs.addVariableStatements(
declarations declarations
.sort((a, b) => (a.name > b.name ? 1 : -1)) .sort((a, b) => (a.name > b.name ? 1 : -1))

View File

@ -17,7 +17,7 @@
import { RouterProvider } from 'react-router-dom'; import { RouterProvider } from 'react-router-dom';
import { createRoot } from 'react-dom/client'; import { createRoot } from 'react-dom/client';
import browserClient from '@slardar/web'; // 默认引入的是CN地区的 import browserClient from '@slardar/web'; // The default introduction is the CN region
import { reporter } from '@coze-arch/logger'; import { reporter } from '@coze-arch/logger';
import { router } from '@/router'; import { router } from '@/router';

View File

@ -29,6 +29,6 @@ export const createUserInfoSlice: StateCreator<
> = set => ({ > = set => ({
userInfo: '', userInfo: '',
iniUserInfo: () => { iniUserInfo: () => {
// TODO: 用户信息相关方法获取 // TODO: User information related methods
}, },
}); });

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
// 基于env/index.ts自动生成请勿手动修改 // Automatically generated based on env/index.ts, do not modify manually
declare const IS_CI: boolean; declare const IS_CI: boolean;
declare const IS_DEV_MODE: boolean; declare const IS_DEV_MODE: boolean;
declare const IS_PRODUCT_MODE: boolean; declare const IS_PRODUCT_MODE: boolean;

View File

@ -27,8 +27,8 @@ export function DemoComponent(props: { name: string }): JSX.Element {
const [foo] = useState('hello world'); const [foo] = useState('hello world');
const { name } = props; const { name } = props;
return ( return (
// font-bold 来自 taiwindcss // Font-bold from taiwindcss
// 建议优先使用 taiwindcss // It is recommended to use taiwindcss first.
<div className={classNames(s.foo, 'font-bold')}> <div className={classNames(s.foo, 'font-bold')}>
{foo} {name}! {foo} {name}!
<div> <div>

View File

@ -2,7 +2,7 @@ import { Command } from 'commander';
import { CliOptions } from '../types/config'; import { CliOptions } from '../types/config';
/** /**
* * Create a command line program
*/ */
export const createProgram = (): Command => { export const createProgram = (): Command => {
const program = new Command(); const program = new Command();
@ -32,7 +32,7 @@ export const createProgram = (): Command => {
}; };
/** /**
* * Parse command line options
*/ */
export const parseOptions = (program: Command): CliOptions => { export const parseOptions = (program: Command): CliOptions => {
const options = program.opts(); const options = program.opts();
@ -53,7 +53,7 @@ export const parseOptions = (program: Command): CliOptions => {
}; };
/** /**
* * Display help information
*/ */
export const showHelp = (): void => { export const showHelp = (): void => {
console.log(` console.log(`
@ -101,7 +101,7 @@ export const showHelp = (): void => {
}; };
/** /**
* * Show version information
*/ */
export const showVersion = (): void => { export const showVersion = (): void => {
console.log('ai-translate version 1.0.0'); console.log('ai-translate version 1.0.0');

View File

@ -2,7 +2,7 @@ import { AppConfig, CliOptions, TranslationConfig, ProcessingConfig } from '../t
import { deepMerge } from '../utils/fp'; import { deepMerge } from '../utils/fp';
/** /**
* * default configuration
*/ */
const DEFAULT_CONFIG: AppConfig = { const DEFAULT_CONFIG: AppConfig = {
translation: { translation: {
@ -32,7 +32,7 @@ const DEFAULT_CONFIG: AppConfig = {
}; };
/** /**
* * Load configuration from file
*/ */
export const loadConfigFromFile = async (configPath: string): Promise<Partial<AppConfig>> => { export const loadConfigFromFile = async (configPath: string): Promise<Partial<AppConfig>> => {
try { try {
@ -46,12 +46,12 @@ export const loadConfigFromFile = async (configPath: string): Promise<Partial<Ap
}; };
/** /**
* * Create configuration from command line options
*/ */
export const createConfigFromOptions = (options: CliOptions): Partial<AppConfig> => { export const createConfigFromOptions = (options: CliOptions): Partial<AppConfig> => {
const config: Partial<AppConfig> = {}; const config: Partial<AppConfig> = {};
// 翻译配置 // translation configuration
if (options.accessKeyId || options.secretAccessKey || options.region || options.sourceLanguage || options.targetLanguage) { if (options.accessKeyId || options.secretAccessKey || options.region || options.sourceLanguage || options.targetLanguage) {
config.translation = {} as Partial<TranslationConfig>; config.translation = {} as Partial<TranslationConfig>;
if (options.accessKeyId) { if (options.accessKeyId) {
@ -71,10 +71,10 @@ export const createConfigFromOptions = (options: CliOptions): Partial<AppConfig>
} }
} }
// 处理配置 // handle configuration
if (options.output) { if (options.output) {
config.processing = {} as Partial<ProcessingConfig>; config.processing = {} as Partial<ProcessingConfig>;
// 根据输出文件扩展名推断格式 // Infer format based on output file extension
const ext = options.output.toLowerCase().split('.').pop(); const ext = options.output.toLowerCase().split('.').pop();
if (ext === 'json') { if (ext === 'json') {
config.processing!.outputFormat = 'json'; config.processing!.outputFormat = 'json';
@ -87,7 +87,7 @@ export const createConfigFromOptions = (options: CliOptions): Partial<AppConfig>
}; };
/** /**
* * merge configuration
*/ */
export const mergeConfigs = (...configs: Partial<AppConfig>[]): AppConfig => { export const mergeConfigs = (...configs: Partial<AppConfig>[]): AppConfig => {
return configs.reduce( return configs.reduce(
@ -97,18 +97,18 @@ export const mergeConfigs = (...configs: Partial<AppConfig>[]): AppConfig => {
}; };
/** /**
* * Load full configuration
*/ */
export const loadConfig = async (options: CliOptions): Promise<AppConfig> => { export const loadConfig = async (options: CliOptions): Promise<AppConfig> => {
const configs: Partial<AppConfig>[] = [DEFAULT_CONFIG]; const configs: Partial<AppConfig>[] = [DEFAULT_CONFIG];
// 加载配置文件 // Load configuration file
if (options.config) { if (options.config) {
const fileConfig = await loadConfigFromFile(options.config); const fileConfig = await loadConfigFromFile(options.config);
configs.push(fileConfig); configs.push(fileConfig);
} }
// 加载命令行选项配置 // Load command line options configuration
const optionsConfig = createConfigFromOptions(options); const optionsConfig = createConfigFromOptions(options);
configs.push(optionsConfig); configs.push(optionsConfig);
@ -116,28 +116,28 @@ export const loadConfig = async (options: CliOptions): Promise<AppConfig> => {
}; };
/** /**
* * verify configuration
*/ */
export const validateConfig = (config: AppConfig): { valid: boolean; errors: string[] } => { export const validateConfig = (config: AppConfig): { valid: boolean; errors: string[] } => {
const errors: string[] = []; const errors: string[] = [];
// 验证火山引擎 Access Key ID // Verify Volcano Engine Access Key ID
if (!config.translation.accessKeyId) { if (!config.translation.accessKeyId) {
errors.push('火山引擎 Access Key ID 未设置请通过环境变量VOLC_ACCESS_KEY_ID或--access-key-id参数提供'); errors.push('火山引擎 Access Key ID 未设置请通过环境变量VOLC_ACCESS_KEY_ID或--access-key-id参数提供');
} }
// 验证火山引擎 Secret Access Key // Verify Volcano Engine Secret Access Key
if (!config.translation.secretAccessKey) { if (!config.translation.secretAccessKey) {
errors.push('火山引擎 Secret Access Key 未设置请通过环境变量VOLC_SECRET_ACCESS_KEY或--secret-access-key参数提供'); errors.push('火山引擎 Secret Access Key 未设置请通过环境变量VOLC_SECRET_ACCESS_KEY或--secret-access-key参数提供');
} }
// 验证区域 // validation area
const validRegions = ['cn-beijing', 'ap-southeast-1', 'us-east-1']; const validRegions = ['cn-beijing', 'ap-southeast-1', 'us-east-1'];
if (!validRegions.includes(config.translation.region)) { if (!validRegions.includes(config.translation.region)) {
console.warn(`未知的区域: ${config.translation.region},建议使用: ${validRegions.join(', ')}`); console.warn(`未知的区域: ${config.translation.region},建议使用: ${validRegions.join(', ')}`);
} }
// 验证语言代码 // Verify language code
const validLanguages = ['zh', 'en', 'ja', 'ko', 'fr', 'de', 'es', 'pt', 'ru']; const validLanguages = ['zh', 'en', 'ja', 'ko', 'fr', 'de', 'es', 'pt', 'ru'];
if (!validLanguages.includes(config.translation.sourceLanguage)) { if (!validLanguages.includes(config.translation.sourceLanguage)) {
console.warn(`未知的源语言: ${config.translation.sourceLanguage},建议使用: ${validLanguages.join(', ')}`); console.warn(`未知的源语言: ${config.translation.sourceLanguage},建议使用: ${validLanguages.join(', ')}`);
@ -146,12 +146,12 @@ export const validateConfig = (config: AppConfig): { valid: boolean; errors: str
console.warn(`未知的目标语言: ${config.translation.targetLanguage},建议使用: ${validLanguages.join(', ')}`); console.warn(`未知的目标语言: ${config.translation.targetLanguage},建议使用: ${validLanguages.join(', ')}`);
} }
// 验证并发数 // validation concurrency
if (config.translation.concurrency < 1 || config.translation.concurrency > 10) { if (config.translation.concurrency < 1 || config.translation.concurrency > 10) {
errors.push('并发数应该在1-10之间'); errors.push('并发数应该在1-10之间');
} }
// 验证超时时间 // verification timeout
if (config.translation.timeout < 1000 || config.translation.timeout > 300000) { if (config.translation.timeout < 1000 || config.translation.timeout > 300000) {
errors.push('超时时间应该在1000-300000毫秒之间'); errors.push('超时时间应该在1000-300000毫秒之间');
} }
@ -160,7 +160,7 @@ export const validateConfig = (config: AppConfig): { valid: boolean; errors: str
}; };
/** /**
* * Print configuration information
*/ */
export const printConfigInfo = (config: AppConfig, verbose: boolean = false): void => { export const printConfigInfo = (config: AppConfig, verbose: boolean = false): void => {
console.log('🔧 当前配置:'); console.log('🔧 当前配置:');

View File

@ -18,7 +18,7 @@ import {
import { FileScanConfig } from './types/index'; import { FileScanConfig } from './types/index';
/** /**
* * main processing function
*/ */
async function processRepository( async function processRepository(
rootPath: string, rootPath: string,
@ -36,7 +36,7 @@ async function processRepository(
printConfigInfo(config, true); printConfigInfo(config, true);
} }
// 1. 扫描源文件 // 1. Scan source files
console.log('\n📁 扫描源文件...'); console.log('\n📁 扫描源文件...');
const scanConfig: FileScanConfig = { const scanConfig: FileScanConfig = {
root: rootPath, root: rootPath,
@ -58,7 +58,7 @@ async function processRepository(
return; return;
} }
// 2. 检测中文注释 // 2. Detect Chinese annotations
console.log('\n🔍 检测中文注释...'); console.log('\n🔍 检测中文注释...');
const filesWithComments = detectChineseInFiles(sourceFiles); const filesWithComments = detectChineseInFiles(sourceFiles);
@ -76,11 +76,11 @@ async function processRepository(
return; return;
} }
// 3. 初始化翻译服务 // 3. Initialize the translation service
console.log('\n🤖 初始化翻译服务...'); console.log('\n🤖 初始化翻译服务...');
const translationService = new TranslationService(config.translation); const translationService = new TranslationService(config.translation);
// 4. 处理文件 // 4. Processing documents
console.log('\n🔄 开始翻译处理...'); console.log('\n🔄 开始翻译处理...');
const progressDisplay = new ProgressDisplay(filesWithComments.length); const progressDisplay = new ProgressDisplay(filesWithComments.length);
@ -92,7 +92,7 @@ async function processRepository(
reportCollector.recordFileStart(file.path); reportCollector.recordFileStart(file.path);
try { try {
// 翻译注释 // Translation annotations
const translations = await translationService.batchTranslate( const translations = await translationService.batchTranslate(
chineseComments, chineseComments,
config.translation.concurrency, config.translation.concurrency,
@ -107,7 +107,7 @@ async function processRepository(
}); });
} }
// 如果不是干运行模式,则替换文件内容 // If not in dry running mode, replace the file content
if (!dryRun) { if (!dryRun) {
const replacements = createReplacements( const replacements = createReplacements(
file, file,
@ -140,7 +140,7 @@ async function processRepository(
progressDisplay.complete(); progressDisplay.complete();
// 5. 生成报告 // 5. Generate reports
console.log('\n📊 生成处理报告...'); console.log('\n📊 生成处理报告...');
const report = reportCollector.generateReport(); const report = reportCollector.generateReport();
@ -148,11 +148,11 @@ async function processRepository(
console.log('\n🔍 预览模式 - 未实际修改文件'); console.log('\n🔍 预览模式 - 未实际修改文件');
} }
// 显示报告 // Show report
const reportText = generateReport(report, 'console'); const reportText = generateReport(report, 'console');
console.log(reportText); console.log(reportText);
// 保存报告到文件(如果指定了输出路径) // Save the report to a file (if output path is specified)
if (config.outputFile) { if (config.outputFile) {
await saveReportToFile( await saveReportToFile(
report, report,
@ -168,20 +168,20 @@ async function processRepository(
} }
/** /**
* * main function
*/ */
async function main(): Promise<void> { async function main(): Promise<void> {
try { try {
const program = createProgram(); const program = createProgram();
// 解析命令行参数 // Parsing command line arguments
program.parse(); program.parse();
const options = parseOptions(program); const options = parseOptions(program);
// 加载配置 // load configuration
const config = await loadConfig(options); const config = await loadConfig(options);
// 验证配置 // verify configuration
const validation = validateConfig(config); const validation = validateConfig(config);
if (!validation.valid) { if (!validation.valid) {
console.error('❌ 配置验证失败:'); console.error('❌ 配置验证失败:');
@ -190,18 +190,18 @@ async function main(): Promise<void> {
process.exit(1); process.exit(1);
} }
// 解析文件扩展名 // Parse file extension
const extensions = options.exts const extensions = options.exts
? options.exts.split(',').map(ext => ext.trim()) ? options.exts.split(',').map(ext => ext.trim())
: config.processing.defaultExtensions; : config.processing.defaultExtensions;
// 添加输出文件配置 // Add output file configuration
const fullConfig = { const fullConfig = {
...config, ...config,
outputFile: options.output, outputFile: options.output,
}; };
// 执行处理 // execution processing
await processRepository( await processRepository(
options.root, options.root,
extensions, extensions,
@ -215,7 +215,7 @@ async function main(): Promise<void> {
} }
} }
// 处理未捕获的异常 // Handling uncaught exceptions
process.on('unhandledRejection', (reason, promise) => { process.on('unhandledRejection', (reason, promise) => {
console.error('未处理的Promise拒绝:', reason); console.error('未处理的Promise拒绝:', reason);
process.exit(1); process.exit(1);
@ -226,7 +226,7 @@ process.on('uncaughtException', error => {
process.exit(1); process.exit(1);
}); });
// 运行主函数 // Run the main function
if (import.meta.url === `file://${process.argv[1]}`) { if (import.meta.url === `file://${process.argv[1]}`) {
main(); main();
} }

View File

@ -10,7 +10,7 @@ import { getCommentPatterns } from '../utils/language';
import { containsChinese, cleanCommentText } from '../utils/chinese'; import { containsChinese, cleanCommentText } from '../utils/chinese';
/** /**
* * Checks if the specified location is inside a string literal
*/ */
const isInsideStringLiteral = (line: string, position: number): boolean => { const isInsideStringLiteral = (line: string, position: number): boolean => {
let insideDoubleQuote = false; let insideDoubleQuote = false;
@ -44,7 +44,7 @@ const isInsideStringLiteral = (line: string, position: number): boolean => {
}; };
/** /**
* * Parsing single-line comments
*/ */
const parseSingleLineComments = ( const parseSingleLineComments = (
content: string, content: string,
@ -54,34 +54,34 @@ const parseSingleLineComments = (
const comments: ParsedComment[] = []; const comments: ParsedComment[] = [];
const lines = content.split('\n'); const lines = content.split('\n');
// 添加安全检查 // Add a security check
const maxLines = 5000; // 降低到5000行 const maxLines = 5000; // Down to 5000 lines
if (lines.length > maxLines) { if (lines.length > maxLines) {
console.warn(`⚠️ 文件行数过多 (${lines.length}行),跳过单行注释解析`); console.warn(`⚠️ 文件行数过多 (${lines.length}行),跳过单行注释解析`);
return comments; return comments;
} }
lines.forEach((line, index) => { lines.forEach((line, index) => {
pattern.lastIndex = 0; // 重置正则表达式索引 pattern.lastIndex = 0; // Reset regular expression index
let match: RegExpExecArray | null; let match: RegExpExecArray | null;
// 查找所有匹配,但只保留不在字符串内的 // Find all matches, but keep only those not in the string
let matchCount = 0; let matchCount = 0;
const maxMatches = 100; // 限制每行最多匹配100次 const maxMatches = 100; // Limit each line to a maximum of 100 matches
let lastIndex = 0; let lastIndex = 0;
while ((match = pattern.exec(line)) !== null) { while ((match = pattern.exec(line)) !== null) {
// 防止无限循环的多重保护 // Multiple protections against infinite loops
matchCount++; matchCount++;
if (matchCount > maxMatches) { if (matchCount > maxMatches) {
console.warn(`⚠️ 单行匹配次数过多,中断处理: ${line.substring(0, 50)}...`); console.warn(`⚠️ 单行匹配次数过多,中断处理: ${line.substring(0, 50)}...`);
break; break;
} }
// 检查 lastIndex 是否前进,防止无限循环 // Check if lastIndex is advancing to prevent an infinite loop
if (pattern.global) { if (pattern.global) {
if (pattern.lastIndex <= lastIndex) { if (pattern.lastIndex <= lastIndex) {
// 如果 lastIndex 没有前进,手动前进一位避免无限循环 // If lastIndex does not advance, manually advance one bit to avoid infinite loops
pattern.lastIndex = lastIndex + 1; pattern.lastIndex = lastIndex + 1;
if (pattern.lastIndex >= line.length) { if (pattern.lastIndex >= line.length) {
break; break;
@ -93,9 +93,9 @@ const parseSingleLineComments = (
if (match[1]) { if (match[1]) {
const commentContent = match[1]; const commentContent = match[1];
let commentStartIndex = match.index!; let commentStartIndex = match.index!;
let commentLength = 2; // 默认为 // let commentLength = 2; // Default is//
// 根据语言确定注释符号 // Determine annotation symbols based on language
if ( if (
language === 'yaml' || language === 'yaml' ||
language === 'toml' || language === 'toml' ||
@ -104,9 +104,9 @@ const parseSingleLineComments = (
language === 'ruby' language === 'ruby'
) { ) {
commentStartIndex = line.indexOf('#', match.index!); commentStartIndex = line.indexOf('#', match.index!);
commentLength = 1; // # 长度为 1 commentLength = 1; // #length is 1
} else if (language === 'ini') { } else if (language === 'ini') {
// INI 文件可能使用 # 或 ; // INI files may use #or;
const hashIndex = line.indexOf('#', match.index!); const hashIndex = line.indexOf('#', match.index!);
const semicolonIndex = line.indexOf(';', match.index!); const semicolonIndex = line.indexOf(';', match.index!);
if ( if (
@ -120,7 +120,7 @@ const parseSingleLineComments = (
commentLength = 1; commentLength = 1;
} }
} else if (language === 'php') { } else if (language === 'php') {
// PHP 可能使用 // 或 # // PHP may use//or #
const slashIndex = line.indexOf('//', match.index!); const slashIndex = line.indexOf('//', match.index!);
const hashIndex = line.indexOf('#', match.index!); const hashIndex = line.indexOf('#', match.index!);
if (slashIndex >= 0 && (hashIndex < 0 || slashIndex < hashIndex)) { if (slashIndex >= 0 && (hashIndex < 0 || slashIndex < hashIndex)) {
@ -139,7 +139,7 @@ const parseSingleLineComments = (
const startColumn = commentStartIndex; const startColumn = commentStartIndex;
const endColumn = startColumn + commentLength + commentContent.length; const endColumn = startColumn + commentLength + commentContent.length;
// 检查注释开始位置是否在字符串内部 // Check if the comment starts inside the string
if ( if (
commentStartIndex >= 0 && commentStartIndex >= 0 &&
!isInsideStringLiteral(line, commentStartIndex) !isInsideStringLiteral(line, commentStartIndex)
@ -155,7 +155,7 @@ const parseSingleLineComments = (
} }
} }
// 防止无限循环 // Prevent infinite loops
if (!pattern.global) break; if (!pattern.global) break;
} }
}); });
@ -164,7 +164,7 @@ const parseSingleLineComments = (
}; };
/** /**
* * Parse multiline comments
*/ */
const parseMultiLineComments = ( const parseMultiLineComments = (
content: string, content: string,
@ -177,21 +177,21 @@ const parseMultiLineComments = (
let commentStart: { line: number; column: number } | null = null; let commentStart: { line: number; column: number } | null = null;
let commentLines: string[] = []; let commentLines: string[] = [];
// 添加安全检查 // Add a security check
const maxLines = 5000; // 降低到5000行 const maxLines = 5000; // Down to 5000 lines
if (lines.length > maxLines) { if (lines.length > maxLines) {
console.warn(`⚠️ 文件行数过多 (${lines.length}行),跳过多行注释解析`); console.warn(`⚠️ 文件行数过多 (${lines.length}行),跳过多行注释解析`);
return comments; return comments;
} }
// 添加处理计数器,防止无限循环 // Add processing counters to prevent infinite loops
let processedLines = 0; let processedLines = 0;
const maxProcessedLines = 10000; const maxProcessedLines = 10000;
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) { for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
const line = lines[lineIndex]; const line = lines[lineIndex];
// 防止无限处理 // Prevent unlimited processing
processedLines++; processedLines++;
if (processedLines > maxProcessedLines) { if (processedLines > maxProcessedLines) {
console.warn(`⚠️ 处理行数超限,中断解析`); console.warn(`⚠️ 处理行数超限,中断解析`);
@ -206,12 +206,12 @@ const parseMultiLineComments = (
inComment = true; inComment = true;
commentStart = { line: lineIndex + 1, column: startMatch.index! }; commentStart = { line: lineIndex + 1, column: startMatch.index! };
// 检查是否在同一行结束 // Check if they end on the same line
endPattern.lastIndex = startMatch.index! + startMatch[0].length; endPattern.lastIndex = startMatch.index! + startMatch[0].length;
const endMatch = endPattern.exec(line); const endMatch = endPattern.exec(line);
if (endMatch) { if (endMatch) {
// 单行多行注释 // single-line multi-line comment
const commentContent = line.substring( const commentContent = line.substring(
startMatch.index! + startMatch[0].length, startMatch.index! + startMatch[0].length,
endMatch.index!, endMatch.index!,
@ -229,7 +229,7 @@ const parseMultiLineComments = (
inComment = false; inComment = false;
commentStart = null; commentStart = null;
} else { } else {
// 多行注释开始 // Start with a multi-line comment
const commentContent = line.substring( const commentContent = line.substring(
startMatch.index! + startMatch[0].length, startMatch.index! + startMatch[0].length,
); );
@ -237,12 +237,12 @@ const parseMultiLineComments = (
} }
} }
} else { } else {
// 在多行注释中 // In a multi-line comment
endPattern.lastIndex = 0; endPattern.lastIndex = 0;
const endMatch = endPattern.exec(line); const endMatch = endPattern.exec(line);
if (endMatch) { if (endMatch) {
// 多行注释结束 // End of multiline comment
const commentContent = line.substring(0, endMatch.index!); const commentContent = line.substring(0, endMatch.index!);
commentLines.push(commentContent); commentLines.push(commentContent);
@ -260,7 +260,7 @@ const parseMultiLineComments = (
commentStart = null; commentStart = null;
commentLines = []; commentLines = [];
} else { } else {
// 继续多行注释 // Continue with multi-line comments
commentLines.push(line); commentLines.push(line);
} }
} }
@ -270,7 +270,7 @@ const parseMultiLineComments = (
}; };
/** /**
* * Parse all comments in the file
*/ */
export const parseComments = (file: SourceFile): ParsedComment[] => { export const parseComments = (file: SourceFile): ParsedComment[] => {
const patterns = getCommentPatterns(file.language); 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 = ( export const filterChineseComments = (
comments: ParsedComment[], comments: ParsedComment[],
@ -301,11 +301,11 @@ export const filterChineseComments = (
for (const comment of comments) { for (const comment of comments) {
if (comment.type === 'multi-line' && comment.content.includes('\n')) { if (comment.type === 'multi-line' && comment.content.includes('\n')) {
// 多行注释:逐行处理 // Multi-line comments: line-by-line processing
const multiLineResults = processMultiLineCommentForChinese(comment, language); const multiLineResults = processMultiLineCommentForChinese(comment, language);
result.push(...multiLineResults); result.push(...multiLineResults);
} else if (containsChinese(comment.content)) { } else if (containsChinese(comment.content)) {
// 单行注释或单行多行注释 // Single-line comments or single-line multi-line comments
result.push({ result.push({
...comment, ...comment,
content: cleanCommentText( content: cleanCommentText(
@ -321,7 +321,7 @@ export const filterChineseComments = (
}; };
/** /**
* * Processing multi-line comments, extracting lines containing Chinese as independent comment units
*/ */
const processMultiLineCommentForChinese = ( const processMultiLineCommentForChinese = (
comment: ParsedComment, comment: ParsedComment,
@ -334,18 +334,18 @@ const processMultiLineCommentForChinese = (
const cleanedLine = cleanCommentText(line, 'multi-line', language); const cleanedLine = cleanCommentText(line, 'multi-line', language);
if (containsChinese(cleanedLine)) { if (containsChinese(cleanedLine)) {
// 计算这一行在原始文件中的位置 // Calculate the position of this line in the original file
const actualLineNumber = comment.startLine + lineIndex; const actualLineNumber = comment.startLine + lineIndex;
// 创建一个表示这一行的注释对象 // Create a comment object representing this line
const lineComment: ChineseComment = { const lineComment: ChineseComment = {
content: cleanedLine, content: cleanedLine,
startLine: actualLineNumber, startLine: actualLineNumber,
endLine: 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, endColumn: line.length,
type: 'multi-line', type: 'multi-line',
// 添加多行注释的元数据,用于后续处理 // Add metadata with multi-line comments for subsequent processing
multiLineContext: { multiLineContext: {
isPartOfMultiLine: true, isPartOfMultiLine: true,
originalComment: comment, originalComment: comment,
@ -362,11 +362,11 @@ const processMultiLineCommentForChinese = (
}; };
/** /**
* * Detect Chinese comments in files
*/ */
export const detectChineseInFile = (file: SourceFile): ChineseComment[] => { export const detectChineseInFile = (file: SourceFile): ChineseComment[] => {
try { try {
// 简单防护:跳过大文件 // Simple protection: skipping large files
if (file.content.length > 500000) { if (file.content.length > 500000) {
// 500KB // 500KB
console.warn( console.warn(
@ -375,7 +375,7 @@ export const detectChineseInFile = (file: SourceFile): ChineseComment[] => {
return []; return [];
} }
// 简单防护:跳过行数过多的文件 // Simple protection: skip files with too many lines
const lines = file.content.split('\n'); const lines = file.content.split('\n');
if (lines.length > 10000) { if (lines.length > 10000) {
console.warn(`⚠️ 跳过多行文件: ${file.path} (${lines.length} 行)`); 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[] => { export const detectChineseInFiles = (files: SourceFile[]): FileWithComments[] => {
const results: FileWithComments[] = []; const results: FileWithComments[] = [];
@ -417,7 +417,7 @@ export const detectChineseInFiles = (files: SourceFile[]): FileWithComments[] =>
); );
} catch (error) { } catch (error) {
console.error(`❌ 处理文件失败: ${fileName} - ${error}`); console.error(`❌ 处理文件失败: ${fileName} - ${error}`);
// 继续处理其他文件 // Continue working on other documents
continue; continue;
} }
} }
@ -426,7 +426,7 @@ export const detectChineseInFiles = (files: SourceFile[]): FileWithComments[] =>
}; };
/** /**
* * Get annotation statistics
*/ */
export const getCommentStats = (files: SourceFile[]): { export const getCommentStats = (files: SourceFile[]): {
totalFiles: number; totalFiles: number;

View File

@ -9,14 +9,14 @@ import { tryCatch } from '../utils/fp';
/** /**
* * Check if string contains Chinese characters
*/ */
const containsChinese = (text: string): boolean => { const containsChinese = (text: string): boolean => {
return /[\u4e00-\u9fff]/.test(text); return /[\u4e00-\u9fff]/.test(text);
}; };
/** /**
* * Maintain the original format of comments and support line-by-line translation of multi-line comments
*/ */
export const preserveCommentFormat = ( export const preserveCommentFormat = (
originalComment: string, originalComment: string,
@ -24,7 +24,7 @@ export const preserveCommentFormat = (
commentType: 'single-line' | 'multi-line', commentType: 'single-line' | 'multi-line',
): string => { ): string => {
if (commentType === 'single-line') { 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 let match = originalComment.match(/^(\s*\/\/\s*)/); // JavaScript/TypeScript style
if (match) { if (match) {
return match[1] + translatedComment.trim(); return match[1] + translatedComment.trim();
@ -40,13 +40,13 @@ export const preserveCommentFormat = (
return match[1] + translatedComment.trim(); return match[1] + translatedComment.trim();
} }
// 如果无法识别,尝试从原始内容推断 // If not recognized, try to infer from the original content
if (originalComment.includes('#')) { if (originalComment.includes('#')) {
const hashMatch = originalComment.match(/^(\s*#\s*)/); const hashMatch = originalComment.match(/^(\s*#\s*)/);
return (hashMatch ? hashMatch[1] : '# ') + translatedComment.trim(); return (hashMatch ? hashMatch[1] : '# ') + translatedComment.trim();
} }
// 默认使用 JavaScript 风格 // JavaScript style is used by default
return '// ' + translatedComment.trim(); return '// ' + translatedComment.trim();
} }
@ -54,7 +54,7 @@ export const preserveCommentFormat = (
const lines = originalComment.split('\n'); const lines = originalComment.split('\n');
if (lines.length === 1) { if (lines.length === 1) {
// 单行多行注释 /* ... */ 或 /** ... */ // Single-line multi-line comment/*... */or/**... */
const startMatch = originalComment.match(/^(\s*\/\*\*?\s*)/); const startMatch = originalComment.match(/^(\s*\/\*\*?\s*)/);
const endMatch = originalComment.match(/(\s*\*\/\s*)$/); const endMatch = originalComment.match(/(\s*\*\/\s*)$/);
@ -71,7 +71,7 @@ export const preserveCommentFormat = (
return prefix + translatedComment.trim() + suffix; return prefix + translatedComment.trim() + suffix;
} else { } else {
// 多行注释 - 需要逐行处理 // Multi-line comments - requires line-by-line processing
return processMultiLineComment(originalComment, translatedComment); 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 = ( export const processMultiLineComment = (
originalComment: string, originalComment: string,
@ -88,54 +88,54 @@ export const processMultiLineComment = (
): string => { ): string => {
const originalLines = originalComment.split('\n'); const originalLines = originalComment.split('\n');
// 提取每行的注释内容(去除 /** * 等前缀) // Extract comments for each line (remove prefixes such as /** * )other prefixes)
const extractedLines = originalLines.map(line => { const extractedLines = originalLines.map(line => {
// 匹配不同类型的注释行 Match different types of comment linesifferent types of comment lines
if (line.match(/^\s*\/\*\*?\s*/)) { if (line.match(/^\s*\/\*\*?\s*/)) {
// 开始行: /** 或 /* // Start line:/** or/*
return { prefix: line.match(/^\s*\/\*\*?\s*/)![0], content: line.replace(/^\s*\/\*\*?\s*/, '') }; return { prefix: line.match(/^\s*\/\*\*?\s*/)![0], content: line.replace(/^\s*\/\*\*?\s*/, '') };
} else if (line.match(/^\s*\*\/\s*$/)) { } else if (line.match(/^\s*\*\/\s*$/)) {
// 结束行: */ // End line: */
return { prefix: line.match(/^\s*\*\/\s*$/)![0], content: '' }; return { prefix: line.match(/^\s*\*\/\s*$/)![0], content: '' };
} else if (line.match(/^\s*\*\s*/)) { } else if (line.match(/^\s*\*\s*/)) {
// 中间行: * content // Middle line: * content
const match = line.match(/^(\s*\*\s*)(.*)/); const match = line.match(/^(\s*\*\s*)(.*)/);
return { prefix: match![1], content: match![2] }; return { prefix: match![1], content: match![2] };
} else { } else {
// 其他情况 // Other situations
return { prefix: '', content: line }; return { prefix: '', content: line };
} }
}); });
// 收集需要翻译的行 // Collect lines that need to be translated
const linesToTranslate = extractedLines const linesToTranslate = extractedLines
.map((line, index) => ({ index, content: line.content })) .map((line, index) => ({ index, content: line.content }))
.filter(item => containsChinese(item.content)); .filter(item => containsChinese(item.content));
// 如果没有中文内容,返回原始注释 // If there is no Chinese content, return the original comment
if (linesToTranslate.length === 0) { if (linesToTranslate.length === 0) {
return originalComment; return originalComment;
} }
// 解析翻译结果 - 假设翻译服务按顺序返回翻译后的行 // Parse translation results - assuming the translation service returns translated rows in order
const translatedLines = translatedContent.split('\n'); const translatedLines = translatedContent.split('\n');
const translations = new Map<number, string>(); const translations = new Map<number, string>();
// 将翻译结果映射到对应的行 // Map the translation result to the corresponding line
linesToTranslate.forEach((item, transIndex) => { linesToTranslate.forEach((item, transIndex) => {
if (transIndex < translatedLines.length) { if (transIndex < translatedLines.length) {
translations.set(item.index, translatedLines[transIndex].trim()); translations.set(item.index, translatedLines[transIndex].trim());
} }
}); });
// 重建注释,保持原始结构 // Rebuild the annotation, maintaining the original structure
return extractedLines return extractedLines
.map((line, index) => { .map((line, index) => {
if (translations.has(index)) { if (translations.has(index)) {
// 使用翻译内容,保持原始前缀 // Use translated content, keeping the original prefix
return line.prefix + translations.get(index); return line.prefix + translations.get(index);
} else { } else {
// 保持原样 // Leave it as it is
return originalLines[index]; return originalLines[index];
} }
}) })
@ -143,7 +143,7 @@ export const processMultiLineComment = (
}; };
/** /**
* * Create replacement operation
*/ */
export const createReplacements = ( export const createReplacements = (
file: SourceFile, file: SourceFile,
@ -157,13 +157,13 @@ export const createReplacements = (
if (!translation) return; if (!translation) return;
if (comment.multiLineContext?.isPartOfMultiLine) { if (comment.multiLineContext?.isPartOfMultiLine) {
// 处理多行注释中的单行 // Handling single lines in multi-line comments
const replacement = createMultiLineReplacement(file, comment, translation); const replacement = createMultiLineReplacement(file, comment, translation);
if (replacement) { if (replacement) {
replacements.push(replacement); replacements.push(replacement);
} }
} else { } else {
// 处理普通注释(单行注释或整个多行注释) // Processing normal comments (single-line comments or entire multi-line comments)
const replacement = createRegularReplacement(file, comment, translation); const replacement = createRegularReplacement(file, comment, translation);
if (replacement) { if (replacement) {
replacements.push(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 = ( const createMultiLineReplacement = (
file: SourceFile, file: SourceFile,
@ -189,10 +189,10 @@ const createMultiLineReplacement = (
const originalLine = lines[lineIndex]; const originalLine = lines[lineIndex];
// 查找这一行中中文内容的位置 // Find the location of Chinese content in this line
const cleanedContent = comment.content; const cleanedContent = comment.content;
// 更精确地查找中文内容在原始行中的位置 // Find the position of Chinese content in the original line more accurately
const commentContentRegex = new RegExp(cleanedContent.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); const commentContentRegex = new RegExp(cleanedContent.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
const contentMatch = originalLine.match(commentContentRegex); const contentMatch = originalLine.match(commentContentRegex);
@ -203,7 +203,7 @@ const createMultiLineReplacement = (
const chineseStart = contentMatch.index!; const chineseStart = contentMatch.index!;
const chineseEnd = chineseStart + contentMatch[0].length; const chineseEnd = chineseStart + contentMatch[0].length;
// 计算在整个文件中的位置 // Calculate the position in the entire file
let start = 0; let start = 0;
for (let i = 0; i < lineIndex; i++) { for (let i = 0; i < lineIndex; i++) {
start += lines[i].length + 1; // +1 for newline start += lines[i].length + 1; // +1 for newline
@ -221,7 +221,7 @@ const createMultiLineReplacement = (
}; };
/** /**
* * Create a replacement operation for a normal comment
*/ */
const createRegularReplacement = ( const createRegularReplacement = (
file: SourceFile, file: SourceFile,
@ -232,7 +232,7 @@ const createRegularReplacement = (
const startLineIndex = comment.startLine - 1; const startLineIndex = comment.startLine - 1;
const endLineIndex = comment.endLine - 1; const endLineIndex = comment.endLine - 1;
// 计算原始注释在文件中的精确位置 // Calculate the exact location of the original comment in the file
let start = 0; let start = 0;
for (let i = 0; i < startLineIndex; i++) { for (let i = 0; i < startLineIndex; i++) {
start += lines[i].length + 1; // +1 for newline start += lines[i].length + 1; // +1 for newline
@ -241,10 +241,10 @@ const createRegularReplacement = (
let end = start; let end = start;
if (comment.startLine === comment.endLine) { if (comment.startLine === comment.endLine) {
// 同一行 // same line
end = start + (comment.endColumn - comment.startColumn); end = start + (comment.endColumn - comment.startColumn);
} else { } else {
// 跨行 - 重新计算end位置 // Interline recalculation of end position
end = 0; end = 0;
for (let i = 0; i < endLineIndex; i++) { for (let i = 0; i < endLineIndex; i++) {
end += lines[i].length + 1; // +1 for newline end += lines[i].length + 1; // +1 for newline
@ -252,10 +252,10 @@ const createRegularReplacement = (
end += comment.endColumn; end += comment.endColumn;
} }
// 获取原始注释文本 // Get original comment text
const originalText = file.content.substring(start, end); const originalText = file.content.substring(start, end);
// 应用格式保持 // application format retention
const formattedTranslation = preserveCommentFormat( const formattedTranslation = preserveCommentFormat(
originalText, originalText,
translation.translated, translation.translated,
@ -271,13 +271,13 @@ const createRegularReplacement = (
}; };
/** /**
* * Apply a replacement operation to text content
*/ */
export const applyReplacements = ( export const applyReplacements = (
content: string, content: string,
replacements: Replacement[], replacements: Replacement[],
): string => { ): string => {
// 按位置倒序排列,避免替换后位置偏移 // Arrange in reverse order to avoid position shift after replacement
const sortedReplacements = [...replacements].sort( const sortedReplacements = [...replacements].sort(
(a, b) => b.start - a.start, (a, b) => b.start - a.start,
); );
@ -294,7 +294,7 @@ export const applyReplacements = (
}; };
/** /**
* * Replace comments in the file
*/ */
export const replaceCommentsInFile = async ( export const replaceCommentsInFile = async (
file: SourceFile, file: SourceFile,
@ -303,13 +303,13 @@ export const replaceCommentsInFile = async (
return tryCatch(async () => { return tryCatch(async () => {
const fs = await import('fs/promises'); const fs = await import('fs/promises');
// 应用替换 // Application Replacement
const newContent = applyReplacements( const newContent = applyReplacements(
file.content, file.content,
operation.replacements, operation.replacements,
); );
// 写入文件 // Write file
await fs.writeFile(file.path, newContent, 'utf-8'); await fs.writeFile(file.path, newContent, 'utf-8');
return { success: true }; return { success: true };
@ -329,7 +329,7 @@ export const replaceCommentsInFile = async (
}; };
/** /**
* * Batch replacement of multiple files
*/ */
export const batchReplaceFiles = async ( export const batchReplaceFiles = async (
operations: ReplacementOperation[], operations: ReplacementOperation[],
@ -347,7 +347,7 @@ export const batchReplaceFiles = async (
const sourceFile: SourceFile = { const sourceFile: SourceFile = {
path: operation.file, path: operation.file,
content, content,
language: 'other', // 临时值,实际应该检测 language: 'other', // Temporary value, which should actually be checked
}; };
const result = await replaceCommentsInFile( const result = await replaceCommentsInFile(
@ -375,7 +375,7 @@ export const batchReplaceFiles = async (
}; };
/** /**
* * Verify replacement operation
*/ */
export const validateReplacements = ( export const validateReplacements = (
content: string, content: string,
@ -383,7 +383,7 @@ export const validateReplacements = (
): { valid: boolean; errors: string[] } => { ): { valid: boolean; errors: string[] } => {
const errors: string[] = []; const errors: string[] = [];
// 检查位置是否有效 // Check if the location is valid
replacements.forEach((replacement, index) => { replacements.forEach((replacement, index) => {
if (replacement.start < 0 || replacement.end > content.length) { if (replacement.start < 0 || replacement.end > content.length) {
errors.push(`Replacement ${index}: Invalid position range`); 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); const actualText = content.substring(replacement.start, replacement.end);
if (actualText !== replacement.original) { if (actualText !== replacement.original) {
errors.push(`Replacement ${index}: Original text mismatch`); errors.push(`Replacement ${index}: Original text mismatch`);
} }
}); });
// 检查是否有重叠 // Check for overlap
const sortedReplacements = [...replacements].sort( const sortedReplacements = [...replacements].sort(
(a, b) => a.start - b.start, (a, b) => a.start - b.start,
); );

View File

@ -5,7 +5,7 @@ import { getGitTrackedFiles, getAllGitFiles } from '../utils/git';
import { tryCatch } from '../utils/fp'; import { tryCatch } from '../utils/fp';
/** /**
* SourceFile对象 * Read the file contents and create a SourceFile object
*/ */
export const readSourceFile = async (filePath: string): Promise<Result<SourceFile>> => { export const readSourceFile = async (filePath: string): Promise<Result<SourceFile>> => {
return tryCatch(async () => { 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[]> => { export const readSourceFiles = async (filePaths: string[]): Promise<SourceFile[]> => {
const results = await Promise.allSettled( 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[]>> => { export const getSourceFiles = async (config: FileScanConfig): Promise<Result<string[]>> => {
const { root, extensions, includeUntracked } = config; const { root, extensions, includeUntracked } = config;
return tryCatch(async () => { return tryCatch(async () => {
// 获取Git文件列表 // Get a list of Git files
const gitFilesResult = includeUntracked const gitFilesResult = includeUntracked
? await getAllGitFiles(root) ? await getAllGitFiles(root)
: await getGitTrackedFiles(root); : await getGitTrackedFiles(root);
@ -53,10 +53,10 @@ export const getSourceFiles = async (config: FileScanConfig): Promise<Result<str
let files = gitFilesResult.data; let files = gitFilesResult.data;
// 过滤文本文件 // Filter text files
files = files.filter(isTextFile); files = files.filter(isTextFile);
// 根据扩展名过滤 // Filter by extension
files = filterFilesByExtensions(files, extensions); files = filterFilesByExtensions(files, extensions);
return files; 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[]>> => { export const scanSourceFiles = async (config: FileScanConfig): Promise<Result<SourceFile[]>> => {
return tryCatch(async () => { 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> => { export const isFileAccessible = async (filePath: string): Promise<boolean> => {
try { try {
@ -92,7 +92,7 @@ export const isFileAccessible = async (filePath: string): Promise<boolean> => {
}; };
/** /**
* * Get file statistics
*/ */
export const getFileStats = async (filePaths: string[]): Promise<{ export const getFileStats = async (filePaths: string[]): Promise<{
total: number; total: number;

View File

@ -5,7 +5,7 @@ import {
} from '../types/index.js'; } from '../types/index.js';
/** /**
* * report collector class
*/ */
export class ReportCollector { export class ReportCollector {
private stats: ProcessingStats = { private stats: ProcessingStats = {
@ -21,7 +21,7 @@ export class ReportCollector {
private fileDetails: Map<string, FileProcessingDetail> = new Map(); private fileDetails: Map<string, FileProcessingDetail> = new Map();
/** /**
* * Record file processing begins
*/ */
recordFileStart(filePath: string): void { recordFileStart(filePath: string): void {
this.stats.totalFiles++; this.stats.totalFiles++;
@ -34,7 +34,7 @@ export class ReportCollector {
} }
/** /**
* * Record file processing completed
*/ */
recordFileComplete(filePath: string, commentCount: number): void { recordFileComplete(filePath: string, commentCount: number): void {
const detail = this.fileDetails.get(filePath); const detail = this.fileDetails.get(filePath);
@ -48,7 +48,7 @@ export class ReportCollector {
} }
/** /**
* * log file skip
*/ */
recordFileSkipped(filePath: string, reason?: string): void { recordFileSkipped(filePath: string, reason?: string): void {
const detail = this.fileDetails.get(filePath); const detail = this.fileDetails.get(filePath);
@ -61,7 +61,7 @@ export class ReportCollector {
} }
/** /**
* * Log processing errors
*/ */
recordError(filePath: string, error: Error): void { recordError(filePath: string, error: Error): void {
const detail = this.fileDetails.get(filePath); const detail = this.fileDetails.get(filePath);
@ -74,28 +74,28 @@ export class ReportCollector {
} }
/** /**
* * Complete statistics
*/ */
finalize(): void { finalize(): void {
this.stats.endTime = Date.now(); this.stats.endTime = Date.now();
} }
/** /**
* * Obtain statistical information
*/ */
getStats(): ProcessingStats { getStats(): ProcessingStats {
return { ...this.stats }; return { ...this.stats };
} }
/** /**
* * Get file details
*/ */
getFileDetails(): FileProcessingDetail[] { getFileDetails(): FileProcessingDetail[] {
return Array.from(this.fileDetails.values()); return Array.from(this.fileDetails.values());
} }
/** /**
* * Generate a full report
*/ */
generateReport(): ProcessingReport { generateReport(): ProcessingReport {
this.finalize(); this.finalize();
@ -109,7 +109,7 @@ export class ReportCollector {
} }
/** /**
* * Reset collector
*/ */
reset(): void { reset(): void {
this.stats = { this.stats = {
@ -126,7 +126,7 @@ export class ReportCollector {
} }
/** /**
* * Generate console reports
*/ */
export const generateConsoleReport = (report: ProcessingReport): string => { export const generateConsoleReport = (report: ProcessingReport): string => {
const { stats, duration } = report; const { stats, duration } = report;
@ -160,7 +160,7 @@ export const generateConsoleReport = (report: ProcessingReport): string => {
}; };
/** /**
* Markdown报告 * Generating Markdown Reports
*/ */
export const generateMarkdownReport = (report: ProcessingReport): string => { export const generateMarkdownReport = (report: ProcessingReport): string => {
const { stats, details, duration } = report; 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 => { export const generateJsonReport = (report: ProcessingReport): string => {
return JSON.stringify(report, null, 2); return JSON.stringify(report, null, 2);
}; };
/** /**
* * Generate reports according to the format
*/ */
export const generateReport = ( export const generateReport = (
report: ProcessingReport, report: ProcessingReport,
@ -242,7 +242,7 @@ export const generateReport = (
}; };
/** /**
* * Save report to file
*/ */
export const saveReportToFile = async ( export const saveReportToFile = async (
report: ProcessingReport, report: ProcessingReport,
@ -255,7 +255,7 @@ export const saveReportToFile = async (
}; };
/** /**
* * Display real-time progress on the console
*/ */
export class ProgressDisplay { export class ProgressDisplay {
private total: number = 0; private total: number = 0;
@ -267,7 +267,7 @@ export class ProgressDisplay {
} }
/** /**
* * update progress
*/ */
update(current: number, currentFile?: string): void { update(current: number, currentFile?: string): void {
this.current = current; this.current = current;
@ -286,7 +286,7 @@ export class ProgressDisplay {
line += ` | 当前: ${currentFile}`; line += ` | 当前: ${currentFile}`;
} }
// 清除当前行并输出新进度 // Clear the current line and output the new progress
process.stdout.write( process.stdout.write(
'\r' + ' '.repeat(process.stdout.columns || 80) + '\r', '\r' + ' '.repeat(process.stdout.columns || 80) + '\r',
); );
@ -294,7 +294,7 @@ export class ProgressDisplay {
} }
/** /**
* * completion progress display
*/ */
complete(): void { complete(): void {
process.stdout.write('\n'); process.stdout.write('\n');

View File

@ -10,7 +10,7 @@ import { isValidTranslation } from '../utils/chinese';
import { translate as volcTranslate, TranslateConfig as VolcTranslateConfig } from '../volc/translate'; import { translate as volcTranslate, TranslateConfig as VolcTranslateConfig } from '../volc/translate';
/** /**
* * Translation services
*/ */
export class TranslationService { export class TranslationService {
private config: TranslationConfig; private config: TranslationConfig;
@ -21,7 +21,7 @@ export class TranslationService {
} }
/** /**
* * Convert to Volcano Engine Translation Configuration
*/ */
private toVolcConfig(): VolcTranslateConfig { private toVolcConfig(): VolcTranslateConfig {
return { return {
@ -34,17 +34,17 @@ export class TranslationService {
} }
/** /**
* * Calculate translation confidence level (simple implementation)
*/ */
private calculateConfidence(translated: string, original: string): number { private calculateConfidence(translated: string, original: string): number {
// 基于长度比例和有效性的简单置信度计算 // Simple confidence level calculation based on length ratio and validity
const lengthRatio = translated.length / original.length; const lengthRatio = translated.length / original.length;
if (!isValidTranslation(original, translated)) { if (!isValidTranslation(original, translated)) {
return 0; return 0;
} }
// 理想的长度比例在0.8-2.0之间 // The ideal length ratio is between 0.8-2
let confidence = 0.8; let confidence = 0.8;
if (lengthRatio >= 0.8 && lengthRatio <= 2.0) { if (lengthRatio >= 0.8 && lengthRatio <= 2.0) {
confidence = 0.9; confidence = 0.9;
@ -54,7 +54,7 @@ export class TranslationService {
} }
/** /**
* API进行翻译 * Call Volcano Engine API for translation
*/ */
private async callVolcTranslate(texts: string[]): Promise<string[]> { private async callVolcTranslate(texts: string[]): Promise<string[]> {
const volcConfig = this.toVolcConfig(); const volcConfig = this.toVolcConfig();
@ -64,13 +64,13 @@ export class TranslationService {
} }
/** /**
* * Translate a single comment
*/ */
async translateComment( async translateComment(
comment: string, comment: string,
context?: TranslationContext, context?: TranslationContext,
): Promise<TranslationResult> { ): Promise<TranslationResult> {
// 检查缓存 // Check cache
const cacheKey = this.getCacheKey(comment, context); const cacheKey = this.getCacheKey(comment, context);
const cached = this.cache.get(cacheKey); const cached = this.cache.get(cacheKey);
if (cached) { if (cached) {
@ -95,7 +95,7 @@ export class TranslationService {
confidence: this.calculateConfidence(translated, comment), confidence: this.calculateConfidence(translated, comment),
}; };
// 缓存结果 // cache results
this.cache.set(cacheKey, result); this.cache.set(cacheKey, result);
return result; return result;
@ -108,7 +108,7 @@ export class TranslationService {
} }
/** /**
* * generate cache key
*/ */
private getCacheKey(comment: string, context?: TranslationContext): string { private getCacheKey(comment: string, context?: TranslationContext): string {
const contextStr = context const contextStr = context
@ -118,17 +118,17 @@ export class TranslationService {
} }
/** /**
* * batch translation annotations
*/ */
async batchTranslate( async batchTranslate(
comments: ChineseComment[], comments: ChineseComment[],
concurrency: number = this.config.concurrency, concurrency: number = this.config.concurrency,
): Promise<TranslationResult[]> { ): Promise<TranslationResult[]> {
// 提取未缓存的注释 // Extract uncached comments
const uncachedComments: { comment: ChineseComment; index: number }[] = []; const uncachedComments: { comment: ChineseComment; index: number }[] = [];
const results: TranslationResult[] = new Array(comments.length); const results: TranslationResult[] = new Array(comments.length);
// 检查缓存 // Check cache
comments.forEach((comment, index) => { comments.forEach((comment, index) => {
const cacheKey = this.getCacheKey(comment.content); const cacheKey = this.getCacheKey(comment.content);
const cached = this.cache.get(cacheKey); const cached = this.cache.get(cacheKey);
@ -139,12 +139,12 @@ export class TranslationService {
} }
}); });
// 如果所有注释都已缓存,直接返回 // If all comments are cached, return directly
if (uncachedComments.length === 0) { if (uncachedComments.length === 0) {
return results; return results;
} }
// 分批翻译未缓存的注释 // Batch translation of uncached comments
const chunks = chunk(uncachedComments, concurrency); const chunks = chunk(uncachedComments, concurrency);
for (const chunkItems of chunks) { for (const chunkItems of chunks) {
@ -156,7 +156,7 @@ export class TranslationService {
1000, 1000,
); );
// 处理翻译结果 // Processing translation results
chunkItems.forEach((item, chunkIndex) => { chunkItems.forEach((item, chunkIndex) => {
const translated = translations[chunkIndex]; const translated = translations[chunkIndex];
if (translated) { if (translated) {
@ -166,26 +166,26 @@ export class TranslationService {
confidence: this.calculateConfidence(translated, item.comment.content), confidence: this.calculateConfidence(translated, item.comment.content),
}; };
// 缓存结果 // cache results
const cacheKey = this.getCacheKey(item.comment.content); const cacheKey = this.getCacheKey(item.comment.content);
this.cache.set(cacheKey, result); this.cache.set(cacheKey, result);
results[item.index] = result; results[item.index] = result;
} else { } else {
// 如果翻译失败,创建一个错误结果 // If the translation fails, an error result is created
results[item.index] = { results[item.index] = {
original: item.comment.content, original: item.comment.content,
translated: item.comment.content, // 翻译失败时保持原文 translated: item.comment.content, // Keep the original text when translation fails
confidence: 0, confidence: 0,
}; };
} }
}); });
} catch (error) { } catch (error) {
// 如果整个批次翻译失败,为这个批次的所有注释创建错误结果 // If the entire batch translation fails, an error result is created for all comments in that batch
chunkItems.forEach(item => { chunkItems.forEach(item => {
results[item.index] = { results[item.index] = {
original: item.comment.content, original: item.comment.content,
translated: item.comment.content, // 翻译失败时保持原文 translated: item.comment.content, // Keep the original text when translation fails
confidence: 0, confidence: 0,
}; };
}); });
@ -198,7 +198,7 @@ export class TranslationService {
} }
/** /**
* * Save translation cache to file
*/ */
async saveCache(filePath: string): Promise<void> { async saveCache(filePath: string): Promise<void> {
const cacheData = Object.fromEntries(this.cache); const cacheData = Object.fromEntries(this.cache);
@ -207,7 +207,7 @@ export class TranslationService {
} }
/** /**
* * Load translation cache from file
*/ */
async loadCache(filePath: string): Promise<void> { async loadCache(filePath: string): Promise<void> {
try { try {
@ -216,24 +216,24 @@ export class TranslationService {
const cacheData = JSON.parse(data); const cacheData = JSON.parse(data);
this.cache = new Map(Object.entries(cacheData)); this.cache = new Map(Object.entries(cacheData));
} catch { } catch {
// 缓存文件不存在或损坏,忽略 // The cache file does not exist or is corrupted, ignore it
} }
} }
/** /**
* * clear cache
*/ */
clearCache(): void { clearCache(): void {
this.cache.clear(); this.cache.clear();
} }
/** /**
* * Get cache statistics
*/ */
getCacheStats(): { size: number; hitRate: number } { getCacheStats(): { size: number; hitRate: number } {
return { return {
size: this.cache.size, size: this.cache.size,
hitRate: 0, // 需要实际统计命中率 hitRate: 0, // Actual statistical hit rate is required
}; };
} }
} }

View File

@ -1,5 +1,5 @@
/** /**
* * translation configuration
*/ */
export interface TranslationConfig { export interface TranslationConfig {
accessKeyId: string; accessKeyId: string;
@ -13,7 +13,7 @@ export interface TranslationConfig {
} }
/** /**
* * File Scan Configuration
*/ */
export interface FileScanConfig { export interface FileScanConfig {
root: string; root: string;
@ -23,7 +23,7 @@ export interface FileScanConfig {
} }
/** /**
* * handle configuration
*/ */
export interface ProcessingConfig { export interface ProcessingConfig {
defaultExtensions: string[]; defaultExtensions: string[];
@ -31,7 +31,7 @@ export interface ProcessingConfig {
} }
/** /**
* Git配置 * Git Configuration
*/ */
export interface GitConfig { export interface GitConfig {
ignorePatterns: string[]; ignorePatterns: string[];
@ -39,7 +39,7 @@ export interface GitConfig {
} }
/** /**
* * application configuration
*/ */
export interface AppConfig { export interface AppConfig {
translation: TranslationConfig; translation: TranslationConfig;
@ -48,7 +48,7 @@ export interface AppConfig {
} }
/** /**
* * command line options
*/ */
export interface CliOptions { export interface CliOptions {
root: string; root: string;

View File

@ -1,5 +1,5 @@
/** /**
* * Source file language type
*/ */
export type SourceFileLanguage = export type SourceFileLanguage =
| 'typescript' | 'typescript'
@ -27,12 +27,12 @@ export type SourceFileLanguage =
| 'other'; | 'other';
/** /**
* * comment type
*/ */
export type CommentType = 'single-line' | 'multi-line' | 'documentation'; export type CommentType = 'single-line' | 'multi-line' | 'documentation';
/** /**
* * source file information
*/ */
export interface SourceFile { export interface SourceFile {
path: string; path: string;
@ -41,7 +41,7 @@ export interface SourceFile {
} }
/** /**
* * multiline comment context information
*/ */
export interface MultiLineContext { export interface MultiLineContext {
isPartOfMultiLine: boolean; isPartOfMultiLine: boolean;
@ -51,7 +51,7 @@ export interface MultiLineContext {
} }
/** /**
* * Chinese annotation information
*/ */
export interface ChineseComment { export interface ChineseComment {
content: string; content: string;
@ -64,7 +64,7 @@ export interface ChineseComment {
} }
/** /**
* * Files containing Chinese annotations
*/ */
export interface FileWithComments { export interface FileWithComments {
file: SourceFile; file: SourceFile;
@ -72,7 +72,7 @@ export interface FileWithComments {
} }
/** /**
* * translation result
*/ */
export interface TranslationResult { export interface TranslationResult {
original: string; original: string;
@ -81,7 +81,7 @@ export interface TranslationResult {
} }
/** /**
* * translation context
*/ */
export interface TranslationContext { export interface TranslationContext {
language: string; language: string;
@ -90,7 +90,7 @@ export interface TranslationContext {
} }
/** /**
* * replace operation
*/ */
export interface Replacement { export interface Replacement {
start: number; start: number;
@ -100,7 +100,7 @@ export interface Replacement {
} }
/** /**
* * file replacement operation
*/ */
export interface ReplacementOperation { export interface ReplacementOperation {
file: string; file: string;
@ -108,7 +108,7 @@ export interface ReplacementOperation {
} }
/** /**
* * Document processing details
*/ */
export interface FileProcessingDetail { export interface FileProcessingDetail {
file: string; file: string;
@ -120,7 +120,7 @@ export interface FileProcessingDetail {
} }
/** /**
* * Processing statistics
*/ */
export interface ProcessingStats { export interface ProcessingStats {
totalFiles: number; totalFiles: number;
@ -133,7 +133,7 @@ export interface ProcessingStats {
} }
/** /**
* * processing report
*/ */
export interface ProcessingReport { export interface ProcessingReport {
stats: ProcessingStats; stats: ProcessingStats;
@ -142,7 +142,7 @@ export interface ProcessingReport {
} }
/** /**
* * File Scan Configuration
*/ */
export interface FileScanConfig { export interface FileScanConfig {
root: string; root: string;
@ -152,7 +152,7 @@ export interface FileScanConfig {
} }
/** /**
* * Parsed annotations
*/ */
export interface ParsedComment { export interface ParsedComment {
content: string; content: string;
@ -164,7 +164,7 @@ export interface ParsedComment {
} }
/** /**
* * Comment mode configuration
*/ */
export interface CommentPattern { export interface CommentPattern {
single: RegExp; single: RegExp;
@ -173,14 +173,14 @@ export interface CommentPattern {
} }
/** /**
* * Functional programming result type
*/ */
export type Result<T, E = Error> = export type Result<T, E = Error> =
| { success: true; data: T } | { success: true; data: T }
| { success: false; error: E }; | { success: false; error: E };
/** /**
* * translation error
*/ */
export class TranslationError extends Error { export class TranslationError extends Error {
constructor( constructor(

View File

@ -1,25 +1,25 @@
/** /**
* Unicode范围正则表达式 * Unicode Range Regular Expressions for Chinese Characters
*/ */
const CHINESE_REGEX = /[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/; const CHINESE_REGEX = /[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/;
const CHINESE_EXTRACT_REGEX = /[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff\u3000-\u303f\uff00-\uffef]+/g; const CHINESE_EXTRACT_REGEX = /[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff\u3000-\u303f\uff00-\uffef]+/g;
/** /**
* * Detect whether the text contains Chinese characters
*/ */
export const containsChinese = (text: string): boolean => { export const containsChinese = (text: string): boolean => {
return CHINESE_REGEX.test(text); return CHINESE_REGEX.test(text);
}; };
/** /**
* * Extract the Chinese part of the text
*/ */
export const extractChineseParts = (text: string): string[] => { export const extractChineseParts = (text: string): string[] => {
return text.match(CHINESE_EXTRACT_REGEX) || []; return text.match(CHINESE_EXTRACT_REGEX) || [];
}; };
/** /**
* * Count the number of Chinese characters in a text
*/ */
export const countChineseCharacters = (text: string): number => { export const countChineseCharacters = (text: string): number => {
const matches = text.match(CHINESE_EXTRACT_REGEX); const matches = text.match(CHINESE_EXTRACT_REGEX);
@ -29,7 +29,7 @@ export const countChineseCharacters = (text: string): number => {
}; };
/** /**
* * Detect whether the text is mainly composed of Chinese
*/ */
export const isPrimarilyChinese = (text: string, threshold: number = 0.5): boolean => { export const isPrimarilyChinese = (text: string, threshold: number = 0.5): boolean => {
const totalLength = text.length; const totalLength = text.length;
@ -40,7 +40,7 @@ export const isPrimarilyChinese = (text: string, threshold: number = 0.5): boole
}; };
/** /**
* * Clean up comment text, remove comment symbols and extra spaces
*/ */
export const cleanCommentText = ( export const cleanCommentText = (
text: string, text: string,
@ -50,7 +50,7 @@ export const cleanCommentText = (
let cleaned = text; let cleaned = text;
if (commentType === 'single-line') { if (commentType === 'single-line') {
// 根据语言类型移除不同的单行注释符号 // Remove different single-line comment symbols based on language type
switch (language) { switch (language) {
case 'yaml': case 'yaml':
case 'toml': case 'toml':
@ -70,7 +70,7 @@ export const cleanCommentText = (
cleaned = cleaned.replace(/^\/\/\s*/, ''); cleaned = cleaned.replace(/^\/\/\s*/, '');
} }
} else if (commentType === 'multi-line') { } else if (commentType === 'multi-line') {
// 根据语言类型移除不同的多行注释符号 // Remove different multi-line comment symbols based on language type
switch (language) { switch (language) {
case 'html': case 'html':
case 'xml': case 'xml':
@ -86,32 +86,32 @@ export const cleanCommentText = (
default: default:
// JavaScript/TypeScript/Go/Java/C/C++/C#/CSS style // JavaScript/TypeScript/Go/Java/C/C++/C#/CSS style
cleaned = cleaned.replace(/^\/\*\s*/, '').replace(/\s*\*\/$/, ''); cleaned = cleaned.replace(/^\/\*\s*/, '').replace(/\s*\*\/$/, '');
// 移除每行开头的 * 符号 // Remove the * symbol at the beginning of each line
cleaned = cleaned.replace(/^\s*\*\s?/gm, ''); cleaned = cleaned.replace(/^\s*\*\s?/gm, '');
} }
} }
// 移除多余的空格和换行 // Remove extra spaces and newlines
cleaned = cleaned.trim(); cleaned = cleaned.trim();
return cleaned; return cleaned;
}; };
/** /**
* * Verify whether the translation result is valid.
*/ */
export const isValidTranslation = (original: string, translated: string): boolean => { export const isValidTranslation = (original: string, translated: string): boolean => {
// 基本验证 // basic verification
if (!translated || translated.trim().length === 0) { if (!translated || translated.trim().length === 0) {
return false; return false;
} }
// 检查是否还包含中文(可能翻译失败) // Check if Chinese is also included (translation may fail)
if (containsChinese(translated)) { if (containsChinese(translated)) {
return false; return false;
} }
// 检查长度是否合理(翻译后的文本不应该比原文长太多) // Check if the length is reasonable (the translated text should not be much longer than the original).
if (translated.length > original.length * 3) { if (translated.length > original.length * 3) {
return false; return false;
} }

View File

@ -1,7 +1,7 @@
import { Result } from '../types/index'; import { Result } from '../types/index';
/** /**
* - * Function composition - executed from left to right
*/ */
export const pipe = export const pipe =
<T>(...fns: Function[]) => <T>(...fns: Function[]) =>
@ -9,7 +9,7 @@ export const pipe =
fns.reduce((acc, fn) => fn(acc), value); fns.reduce((acc, fn) => fn(acc), value);
/** /**
* - * Function composition - executed from right to left
*/ */
export const compose = export const compose =
<T>(...fns: Function[]) => <T>(...fns: Function[]) =>
@ -17,7 +17,7 @@ export const compose =
fns.reduceRight((acc, fn) => fn(acc), value); fns.reduceRight((acc, fn) => fn(acc), value);
/** /**
* * currying function
*/ */
export const curry = export const curry =
(fn: Function) => (fn: Function) =>
@ -27,7 +27,7 @@ export const curry =
: (...more: any[]) => curry(fn)(...args, ...more); : (...more: any[]) => curry(fn)(...args, ...more);
/** /**
* * asynchronous mapping
*/ */
export const asyncMap = curry( export const asyncMap = curry(
async <T, U>(fn: (item: T) => Promise<U>, items: T[]): Promise<U[]> => async <T, U>(fn: (item: T) => Promise<U>, items: T[]): Promise<U[]> =>
@ -35,7 +35,7 @@ export const asyncMap = curry(
); );
/** /**
* * asynchronous filtering
*/ */
export const asyncFilter = curry( export const asyncFilter = curry(
async <T>( async <T>(
@ -48,7 +48,7 @@ export const asyncFilter = curry(
); );
/** /**
* * asynchronous reduction
*/ */
export const asyncReduce = curry( export const asyncReduce = curry(
async <T, U>( async <T, U>(
@ -65,12 +65,12 @@ export const asyncReduce = curry(
); );
/** /**
* * Create a successful result
*/ */
export const success = <T>(data: T): Result<T> => ({ success: true, data }); export const success = <T>(data: T): Result<T> => ({ success: true, data });
/** /**
* * Create failed result
*/ */
export const failure = <E>(error: E): Result<never, E> => ({ export const failure = <E>(error: E): Result<never, E> => ({
success: false, success: false,
@ -78,7 +78,7 @@ export const failure = <E>(error: E): Result<never, E> => ({
}); });
/** /**
* * Safe asynchronous packaging
*/ */
export const tryCatch = async <T>(fn: () => Promise<T>): Promise<Result<T>> => { export const tryCatch = async <T>(fn: () => Promise<T>): Promise<Result<T>> => {
try { try {
@ -90,7 +90,7 @@ export const tryCatch = async <T>(fn: () => Promise<T>): Promise<Result<T>> => {
}; };
/** /**
* * Synchronized version of the security operation wrapper
*/ */
export const tryCatchSync = <T>(fn: () => T): Result<T> => { export const tryCatchSync = <T>(fn: () => T): Result<T> => {
try { try {
@ -102,7 +102,7 @@ export const tryCatchSync = <T>(fn: () => T): Result<T> => {
}; };
/** /**
* * Array chunking
*/ */
export const chunk = <T>(array: T[], size: number): T[][] => { export const chunk = <T>(array: T[], size: number): T[][] => {
const chunks: T[][] = []; const chunks: T[][] = [];
@ -113,13 +113,13 @@ export const chunk = <T>(array: T[], size: number): T[][] => {
}; };
/** /**
* * delayed execution
*/ */
export const delay = (ms: number): Promise<void> => export const delay = (ms: number): Promise<void> =>
new Promise(resolve => setTimeout(resolve, ms)); new Promise(resolve => setTimeout(resolve, ms));
/** /**
* * retry mechanism
*/ */
export const retry = async <T>( export const retry = async <T>(
fn: () => Promise<T>, fn: () => Promise<T>,
@ -135,7 +135,7 @@ export const retry = async <T>(
lastError = error instanceof Error ? error : new Error(String(error)); lastError = error instanceof Error ? error : new Error(String(error));
if (attempt < maxAttempts) { if (attempt < maxAttempts) {
await delay(delayMs * attempt); // 指数退避 await delay(delayMs * attempt); // exponential backoff
} }
} }
} }
@ -144,7 +144,7 @@ export const retry = async <T>(
}; };
/** /**
* * deep merge object
*/ */
export const deepMerge = <T extends Record<string, any>>( export const deepMerge = <T extends Record<string, any>>(
target: T, target: T,

View File

@ -4,7 +4,7 @@ import { tryCatch } from './fp';
import { Result } from '../types/index'; import { Result } from '../types/index';
/** /**
* Git仓库中的所有已跟踪文件 * Get all tracked files in the Git repository
*/ */
export const getGitTrackedFiles = async ( export const getGitTrackedFiles = async (
root: string, root: string,
@ -21,7 +21,7 @@ export const getGitTrackedFiles = async (
}; };
/** /**
* Git仓库中的所有文件 * Get all files in the Git repository (including untracked ones)
*/ */
export const getAllGitFiles = async ( export const getAllGitFiles = async (
root: string, root: string,
@ -29,20 +29,20 @@ export const getAllGitFiles = async (
return tryCatch(async () => { return tryCatch(async () => {
const git = simpleGit(root); const git = simpleGit(root);
// 获取已跟踪的文件 // Get tracked files
const trackedFiles = await git.raw(['ls-files']); const trackedFiles = await git.raw(['ls-files']);
const trackedFilesArray = trackedFiles const trackedFilesArray = trackedFiles
.split('\n') .split('\n')
.filter(Boolean) .filter(Boolean)
.map(file => path.resolve(root, file)); .map(file => path.resolve(root, file));
// 获取未跟踪的文件 // Get untracked files
const status = await git.status(); const status = await git.status();
const untrackedFiles = status.not_added.map(file => const untrackedFiles = status.not_added.map(file =>
path.resolve(root, file), path.resolve(root, file),
); );
// 合并并去重 // Merge and deduplicate
const allFiles = [...new Set([...trackedFilesArray, ...untrackedFiles])]; const allFiles = [...new Set([...trackedFilesArray, ...untrackedFiles])];
return allFiles; return allFiles;
@ -50,7 +50,7 @@ export const getAllGitFiles = async (
}; };
/** /**
* Git仓库 * Check if the directory is a Git repository
*/ */
export const isGitRepository = async ( export const isGitRepository = async (
root: string, root: string,
@ -63,7 +63,7 @@ export const isGitRepository = async (
}; };
/** /**
* Git仓库的根目录 * Get the root directory of the Git repository
*/ */
export const getGitRoot = async (cwd: string): Promise<Result<string>> => { export const getGitRoot = async (cwd: string): Promise<Result<string>> => {
return tryCatch(async () => { return tryCatch(async () => {
@ -74,7 +74,7 @@ export const getGitRoot = async (cwd: string): Promise<Result<string>> => {
}; };
/** /**
* Git忽略 * Check if the file is ignored by Git
*/ */
export const isIgnoredByGit = async ( export const isIgnoredByGit = async (
root: string, root: string,
@ -86,9 +86,9 @@ export const isIgnoredByGit = async (
try { try {
await git.raw(['check-ignore', relativePath]); await git.raw(['check-ignore', relativePath]);
return true; // 文件被忽略 return true; // File is ignored
} catch { } catch {
return false; // 文件未被忽略 return false; // File is not ignored
} }
}); });
}; };

View File

@ -1,7 +1,7 @@
import { SourceFileLanguage, CommentPattern } from '../types/index'; import { SourceFileLanguage, CommentPattern } from '../types/index';
/** /**
* * Identify programming languages by file extension
*/ */
export const detectLanguage = (filePath: string): SourceFileLanguage => { export const detectLanguage = (filePath: string): SourceFileLanguage => {
const ext = filePath.toLowerCase().split('.').pop(); const ext = filePath.toLowerCase().split('.').pop();
@ -51,14 +51,14 @@ export const detectLanguage = (filePath: string): SourceFileLanguage => {
}; };
/** /**
* * Filter files by file extension
*/ */
export const filterFilesByExtensions = ( export const filterFilesByExtensions = (
files: string[], files: string[],
extensions: string[] extensions: string[]
): string[] => { ): string[] => {
if (extensions.length === 0) { if (extensions.length === 0) {
// 默认支持的文本文件扩展名 // Default supported text file extensions
const defaultExtensions = [ const defaultExtensions = [
'.ts', '.tsx', '.js', '.jsx', '.go', '.md', '.txt', '.json', '.ts', '.tsx', '.js', '.jsx', '.go', '.md', '.txt', '.json',
'.yaml', '.yml', '.toml', '.ini', '.conf', '.config', '.yaml', '.yml', '.toml', '.ini', '.conf', '.config',
@ -75,7 +75,7 @@ export const filterFilesByExtensions = (
const lowerFile = file.toLowerCase(); const lowerFile = file.toLowerCase();
return extensions.some(ext => { return extensions.some(ext => {
const lowerExt = ext.toLowerCase(); const lowerExt = ext.toLowerCase();
// 如果扩展名已经有点号,直接使用;否则添加点号 // If the extension is already numbered, use it directly; otherwise, add a dot.
const extWithDot = lowerExt.startsWith('.') ? lowerExt : `.${lowerExt}`; const extWithDot = lowerExt.startsWith('.') ? lowerExt : `.${lowerExt}`;
return lowerFile.endsWith(extWithDot); return lowerFile.endsWith(extWithDot);
}); });
@ -83,7 +83,7 @@ export const filterFilesByExtensions = (
}; };
/** /**
* * Obtain comment modes for different programming languages
*/ */
export const getCommentPatterns = (language: SourceFileLanguage): CommentPattern | null => { export const getCommentPatterns = (language: SourceFileLanguage): CommentPattern | null => {
const commentPatterns: Record<SourceFileLanguage, CommentPattern> = { const commentPatterns: Record<SourceFileLanguage, CommentPattern> = {
@ -108,33 +108,33 @@ export const getCommentPatterns = (language: SourceFileLanguage): CommentPattern
multiEnd: /-->/g multiEnd: /-->/g
}, },
text: { text: {
single: /^(.*)$/gm, // 文本文件每行都可能是注释 single: /^(.*)$/gm, // Every line of a text file can be a comment
multiStart: /^/g, multiStart: /^/g,
multiEnd: /$/g multiEnd: /$/g
}, },
json: { json: {
single: /\/\/(.*)$/gm, // JSON通常不支持注释,但一些工具支持 single: /\/\/(.*)$/gm, // JSON usually doesn't support comments, but some tools do
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g
}, },
yaml: { yaml: {
single: /#(.*)$/gm, single: /#(.*)$/gm,
multiStart: /^$/g, // YAML不支持多行注释 multiStart: /^$/g, // YAML does not support multi-line comments
multiEnd: /^$/g multiEnd: /^$/g
}, },
toml: { toml: {
single: /#(.*)$/gm, single: /#(.*)$/gm,
multiStart: /^$/g, // TOML不支持多行注释 multiStart: /^$/g, // TOML does not support multi-line comments
multiEnd: /^$/g multiEnd: /^$/g
}, },
ini: { ini: {
single: /[;#](.*)$/gm, // INI文件支持 ; 和 # 作为注释 single: /[;#](.*)$/gm, // INI file support; and #as comments
multiStart: /^$/g, // INI不支持多行注释 multiStart: /^$/g, // INI does not support multi-line comments
multiEnd: /^$/g multiEnd: /^$/g
}, },
shell: { shell: {
single: /#(.*)$/gm, single: /#(.*)$/gm,
multiStart: /^$/g, // Shell脚本不支持多行注释 multiStart: /^$/g, // Shell scripts do not support multi-line comments
multiEnd: /^$/g multiEnd: /^$/g
}, },
python: { python: {
@ -143,22 +143,22 @@ export const getCommentPatterns = (language: SourceFileLanguage): CommentPattern
multiEnd: /[\s\S]*?"""/gm multiEnd: /[\s\S]*?"""/gm
}, },
css: { css: {
single: /^$/g, // CSS不支持单行注释 single: /^$/g, // CSS does not support single-line comments
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g
}, },
html: { html: {
single: /^$/g, // HTML不支持单行注释 single: /^$/g, // HTML does not support single-line comments
multiStart: /<!--/g, multiStart: /<!--/g,
multiEnd: /-->/g multiEnd: /-->/g
}, },
xml: { xml: {
single: /^$/g, // XML不支持单行注释 single: /^$/g, // XML does not support single-line comments
multiStart: /<!--/g, multiStart: /<!--/g,
multiEnd: /-->/g multiEnd: /-->/g
}, },
php: { php: {
single: /(?:\/\/|#)(.*)$/gm, // PHP支持 // 和 # 作为单行注释 single: /(?:\/\/|#)(.*)$/gm, // PHP supports//and #as single-line comments
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g
}, },
@ -208,7 +208,7 @@ export const getCommentPatterns = (language: SourceFileLanguage): CommentPattern
}; };
/** /**
* * Check if the file supports processing
*/ */
export const isSupportedFile = (filePath: string): boolean => { export const isSupportedFile = (filePath: string): boolean => {
const language = detectLanguage(filePath); const language = detectLanguage(filePath);
@ -216,7 +216,7 @@ export const isSupportedFile = (filePath: string): boolean => {
}; };
/** /**
* MIME类型 * Get the MIME type of the file (used to determine whether it is a text file)
*/ */
export const isTextFile = (filePath: string): boolean => { export const isTextFile = (filePath: string): boolean => {
const textExtensions = [ const textExtensions = [

View File

@ -1,5 +1,5 @@
/** /**
* * semaphore concurrency control class
*/ */
export class Semaphore { export class Semaphore {
private permits: number; private permits: number;
@ -10,7 +10,7 @@ export class Semaphore {
} }
/** /**
* * Get permission
*/ */
async acquire(): Promise<void> { async acquire(): Promise<void> {
if (this.permits > 0) { if (this.permits > 0) {
@ -24,7 +24,7 @@ export class Semaphore {
} }
/** /**
* * release permission
*/ */
release(): void { release(): void {
this.permits++; this.permits++;
@ -36,14 +36,14 @@ export class Semaphore {
} }
/** /**
* * Get the number of currently available licenses
*/ */
available(): number { available(): number {
return this.permits; return this.permits;
} }
/** /**
* * Get the waiting queue length
*/ */
waitingCount(): number { waitingCount(): number {
return this.waiting.length; return this.waiting.length;

View File

@ -20,7 +20,7 @@ import { URLSearchParams } from 'url';
const debuglog = util.debuglog('signer'); const debuglog = util.debuglog('signer');
/** /**
* * signature parameter interface
*/ */
export interface SignParams { export interface SignParams {
headers?: Record<string, string>; headers?: Record<string, string>;
@ -36,95 +36,95 @@ export interface SignParams {
} }
/** /**
* * query parameter type
*/ */
export type QueryParams = Record<string, string | string[] | undefined | null>; export type QueryParams = Record<string, string | string[] | undefined | null>;
/** /**
* * request header type
*/ */
export type Headers = Record<string, string>; export type Headers = Record<string, string>;
/** /**
* * translation request parameter interface
*/ */
export interface TranslateRequest { export interface TranslateRequest {
/** 源语言代码 */ /** source language code */
SourceLanguage: string; SourceLanguage: string;
/** 目标语言代码 */ /** target language code */
TargetLanguage: string; TargetLanguage: string;
/** 要翻译的文本列表 */ /** List of texts to be translated */
TextList: string[]; TextList: string[];
} }
/** /**
* * Additional information in the translation results
*/ */
export interface TranslationExtra { export interface TranslationExtra {
/** 输入字符数 */ /** Number of characters entered */
input_characters: string; input_characters: string;
/** 源语言 */ /** source language */
source_language: string; source_language: string;
} }
/** /**
* * Single translation result
*/ */
export interface TranslationItem { export interface TranslationItem {
/** 翻译结果 */ /** translation result */
Translation: string; Translation: string;
/** 检测到的源语言 */ /** Detected source language */
DetectedSourceLanguage: string; DetectedSourceLanguage: string;
/** 额外信息 */ /** Additional information */
Extra: TranslationExtra; Extra: TranslationExtra;
} }
/** /**
* * Response metadata
*/ */
export interface ResponseMetadata { export interface ResponseMetadata {
/** 请求ID */ /** Request ID */
RequestId: string; RequestId: string;
/** 操作名称 */ /** operation name */
Action: string; Action: string;
/** API版本 */ /** API version */
Version: string; Version: string;
/** 服务名称 */ /** service name */
Service: string; Service: string;
/** 区域 */ /** area */
Region: string; Region: string;
} }
/** /**
* API响应接口 * Volcano Engine Translation API Response Interface
*/ */
export interface VolcTranslateResponse { export interface VolcTranslateResponse {
/** 翻译结果列表 */ /** List of translation results */
TranslationList: TranslationItem[]; TranslationList: TranslationItem[];
/** 响应元数据 */ /** Response metadata */
ResponseMetadata: ResponseMetadata; ResponseMetadata: ResponseMetadata;
/** 响应元数据(备用字段) */ /** Response metadata (alternate field) */
ResponseMetaData?: ResponseMetadata; ResponseMetaData?: ResponseMetadata;
} }
/** /**
* * translation configuration parameters
*/ */
export interface TranslateConfig { export interface TranslateConfig {
/** 访问密钥ID */ /** Access Key ID */
accessKeyId: string; accessKeyId: string;
/** 秘密访问密钥 */ /** secret access key */
secretAccessKey: string; secretAccessKey: string;
/** 服务区域 */ /** service area */
region?: string; region?: string;
/** 源语言代码 */ /** source language code */
sourceLanguage?: string; sourceLanguage?: string;
/** 目标语言代码 */ /** target language code */
targetLanguage?: string; targetLanguage?: string;
} }
/** /**
* header key * Header key that does not participate in the signature process
*/ */
const HEADER_KEYS_TO_IGNORE = new Set([ const HEADER_KEYS_TO_IGNORE = new Set([
'authorization', 'authorization',
@ -136,10 +136,10 @@ const HEADER_KEYS_TO_IGNORE = new Set([
]); ]);
/** /**
* * Volcano Engine Translation Interface
* @param textArray * @Param textArray Array of text to translate
* @param config 使 * @Param config Translate configuration parameters, use default configuration if not provided
* @returns * @Returns translation response result
*/ */
export async function translate( export async function translate(
textArray: string[], textArray: string[],
@ -163,7 +163,7 @@ export async function translate(
const requestBodyString = JSON.stringify(requestBody); const requestBodyString = JSON.stringify(requestBody);
const signParams: SignParams = { const signParams: SignParams = {
headers: { headers: {
// x-date header 是必传的 // The x-date header is required
'X-Date': getDateTimeNow(), 'X-Date': getDateTimeNow(),
'content-type': 'application/json', 'content-type': 'application/json',
}, },
@ -179,7 +179,7 @@ export async function translate(
bodySha: getBodySha(requestBodyString), bodySha: getBodySha(requestBodyString),
}; };
// 正规化 query object 防止串化后出现 query 值为 undefined 情况 // Normalize the query object to prevent the query value from being undefined after serialization
if (signParams.query) { if (signParams.query) {
for (const [key, val] of Object.entries(signParams.query)) { for (const [key, val] of Object.entries(signParams.query)) {
if (val === undefined || val === null) { if (val === undefined || val === null) {
@ -216,7 +216,7 @@ export async function translate(
} }
/** /**
* * generate signature
*/ */
function sign(params: SignParams): string { function sign(params: SignParams): string {
const { const {
@ -233,7 +233,7 @@ function sign(params: SignParams): string {
} = params; } = params;
const datetime = headers['X-Date']; const datetime = headers['X-Date'];
const date = datetime.substring(0, 8); // YYYYMMDD const date = datetime.substring(0, 8); // YYYYMMDD
// 创建正规化请求 // Create a regularization request
const [signedHeaders, canonicalHeaders] = getSignHeaders( const [signedHeaders, canonicalHeaders] = getSignHeaders(
headers, headers,
needSignHeaderKeys, needSignHeaderKeys,
@ -247,14 +247,14 @@ function sign(params: SignParams): string {
bodySha || hash(''), bodySha || hash(''),
].join('\n'); ].join('\n');
const credentialScope = [date, region, serviceName, 'request'].join('/'); const credentialScope = [date, region, serviceName, 'request'].join('/');
// 创建签名字符串 // Create signature string
const stringToSign = [ const stringToSign = [
'HMAC-SHA256', 'HMAC-SHA256',
datetime, datetime,
credentialScope, credentialScope,
hash(canonicalRequest), hash(canonicalRequest),
].join('\n'); ].join('\n');
// 计算签名 // Compute signature
const kDate = hmac(secretAccessKey, date); const kDate = hmac(secretAccessKey, date);
const kRegion = hmac(kDate, region); const kRegion = hmac(kDate, region);
const kService = hmac(kRegion, serviceName); const kService = hmac(kRegion, serviceName);
@ -275,21 +275,21 @@ function sign(params: SignParams): string {
} }
/** /**
* HMAC-SHA256 * HMAC-SHA256 encryption
*/ */
function hmac(secret: string | Buffer, s: string): Buffer { function hmac(secret: string | Buffer, s: string): Buffer {
return crypto.createHmac('sha256', secret).update(s, 'utf8').digest(); return crypto.createHmac('sha256', secret).update(s, 'utf8').digest();
} }
/** /**
* SHA256 * SHA256 hash
*/ */
function hash(s: string): string { function hash(s: string): string {
return crypto.createHash('sha256').update(s, 'utf8').digest('hex'); return crypto.createHash('sha256').update(s, 'utf8').digest('hex');
} }
/** /**
* * Query parameter to string
*/ */
function queryParamsToString(params: QueryParams): string { function queryParamsToString(params: QueryParams): string {
return Object.keys(params) return Object.keys(params)
@ -313,7 +313,7 @@ function queryParamsToString(params: QueryParams): string {
} }
/** /**
* * Get signature header
*/ */
function getSignHeaders( function getSignHeaders(
originHeaders: Headers, originHeaders: Headers,
@ -324,14 +324,14 @@ function getSignHeaders(
} }
let h = Object.keys(originHeaders); let h = Object.keys(originHeaders);
// 根据 needSignHeaders 过滤 // Filter by needSignHeaders
if (Array.isArray(needSignHeaders)) { if (Array.isArray(needSignHeaders)) {
const needSignSet = new Set( const needSignSet = new Set(
[...needSignHeaders, 'x-date', 'host'].map(k => k.toLowerCase()), [...needSignHeaders, 'x-date', 'host'].map(k => k.toLowerCase()),
); );
h = h.filter(k => needSignSet.has(k.toLowerCase())); h = h.filter(k => needSignSet.has(k.toLowerCase()));
} }
// 根据 ignore headers 过滤 // Filter by ignoring headers
h = h.filter(k => !HEADER_KEYS_TO_IGNORE.has(k.toLowerCase())); h = h.filter(k => !HEADER_KEYS_TO_IGNORE.has(k.toLowerCase()));
const signedHeaderKeys = h const signedHeaderKeys = h
.slice() .slice()
@ -346,7 +346,7 @@ function getSignHeaders(
} }
/** /**
* URI * URI escape
*/ */
function uriEscape(str: string): string { function uriEscape(str: string): string {
try { try {
@ -364,7 +364,7 @@ function uriEscape(str: string): string {
} }
/** /**
* * Get the current time format string
*/ */
export function getDateTimeNow(): string { export function getDateTimeNow(): string {
const now = new Date(); const now = new Date();
@ -372,7 +372,7 @@ export function getDateTimeNow(): string {
} }
/** /**
* body SHA256 * Get the SHA256 value of the body
*/ */
export function getBodySha(body: string | URLSearchParams | Buffer): string { export function getBodySha(body: string | URLSearchParams | Buffer): string {
const hashInstance = crypto.createHash('sha256'); const hashInstance = crypto.createHash('sha256');

View File

@ -5,7 +5,7 @@ const { getChangedPackages } = require('./utils')
/** /**
* 针对不同类型的 commit prefix message * For different types of commit prefix messages
*/ */
const typesConfig = [ const typesConfig = [
{ value: 'feat', name: 'A new feature' }, { value: 'feat', name: 'A new feature' },

View File

@ -19,7 +19,7 @@ function getChangedPackages(changedFiles) {
const lookup = rushConfiguration.getProjectLookupForRoot(rushJsonFolder) const lookup = rushConfiguration.getProjectLookupForRoot(rushJsonFolder)
for (const file of changedFiles) { for (const file of changedFiles) {
const project = lookup.findChildPath(file) const project = lookup.findChildPath(file)
// 如果没找到注册的包信息,则认为是通用文件更改 // If the registered package information is not found, it is considered a generic file change
const packageName = project?.packageName || 'misc' const packageName = project?.packageName || 'misc'
if (!changedPackages.has(packageName)) { if (!changedPackages.has(packageName)) {
changedPackages.add(packageName) changedPackages.add(packageName)

View File

@ -25,7 +25,7 @@ module.exports = {
.map(f => path.relative(projectFolder, f)) .map(f => path.relative(projectFolder, f))
.join(' '); .join(' ');
// TSESTREE_SINGLE_RUN doc https://typescript-eslint.io/packages/parser/#allowautomaticsingleruninference // TSESTREE_SINGLE_RUN doc https://typescript-eslint.io/packages/parser/#allowautomaticsingleruninference
// 切换到项目文件夹,并运行 ESLint 命令 // Switch to the project folder and run the ESLint command
const cmd = [ const cmd = [
`cd ${projectFolder}`, `cd ${projectFolder}`,
`TSESTREE_SINGLE_RUN=true eslint --fix --cache ${filesToCheck} --no-error-on-unmatched-pattern`, `TSESTREE_SINGLE_RUN=true eslint --fix --cache ${filesToCheck} --no-error-on-unmatched-pattern`,
@ -47,8 +47,8 @@ module.exports = {
} }
return [ return [
// 这里不能直接返回 eslintCmds 数组,因为 lint-staged 会依次串行执行每个命令 // The eslintCmds array cannot be returned directly here, because lint-staged executes each command in sequence
// 而 concurrently 会并行执行多个命令 // And concurrently execute multiple commands in parallel
`concurrently --max-process 8 --names ${eslintCmds `concurrently --max-process 8 --names ${eslintCmds
.map(r => `${r.name}`) .map(r => `${r.name}`)
.join(',')} --kill-others-on-fail ${eslintCmds .join(',')} --kill-others-on-fail ${eslintCmds
@ -57,7 +57,7 @@ module.exports = {
]; ];
}, },
'**/*.{less,scss,css}': files => { '**/*.{less,scss,css}': files => {
// 暂时只修复,不报错卡点 // It is only repaired for the time being, and no errors are reported.
return [`stylelint ${files.join(' ')} --fix || exit 0`]; return [`stylelint ${files.join(' ')} --fix || exit 0`];
}, },
'**/package.json': async files => { '**/package.json': async files => {
@ -68,7 +68,7 @@ module.exports = {
if (!filesToLint) return []; if (!filesToLint) return [];
return [ return [
// https://eslint.org/docs/latest/flags/#enable-feature-flags-with-the-cli // https://eslint.org/docs/latest/flags/#enable-feature-flags-with-the-cli
// eslint v9默认从cwd找配置这里需要使用 unstable_config_lookup_from_file 配置,否则会报错 // Eslint v9 finds the configuration from cwd by default. You need to use unstable_config_lookup_from_file configuration here, otherwise an error will be reported.
`eslint --cache ${filesToLint} --flag unstable_config_lookup_from_file`, `eslint --cache ${filesToLint} --flag unstable_config_lookup_from_file`,
`prettier ${filesToLint} --write`, `prettier ${filesToLint} --write`,
]; ];

View File

@ -13,7 +13,7 @@ const getRushConfiguration = (function () {
}; };
})(); })();
// 获取变更文件所在的项目路径 // Get the project path where the change file is located
function withProjectFolder(changedFiles) { function withProjectFolder(changedFiles) {
const projectFolders = []; const projectFolders = [];
@ -24,7 +24,7 @@ function withProjectFolder(changedFiles) {
for (const file of changedFiles) { for (const file of changedFiles) {
const project = lookup.findChildPath(path.relative(rushJsonFolder, file)); const project = lookup.findChildPath(path.relative(rushJsonFolder, file));
// 忽略不在 rush.json 内定义的项目 // Ignore items not defined in rush.json
if (project) { if (project) {
const projectFolder = project?.projectFolder ?? rushJsonFolder; const projectFolder = project?.projectFolder ?? rushJsonFolder;
const packageName = project?.packageName; const packageName = project?.packageName;
@ -72,7 +72,7 @@ async function excludeIgnoredFiles(changedFiles) {
} }
} }
// 获取发生变更的项目路径 // Get the project path that changed
function getChangedProjects(changedFiles) { function getChangedProjects(changedFiles) {
const changedProjectFolders = new Set(); const changedProjectFolders = new Set();
const changedProjects = new Set(); const changedProjects = new Set();

View File

@ -2,15 +2,15 @@
"$schema": "https://json-schema.bytedance.net/rush-plugins/rush-build-cache-plugin-options.schema.json", "$schema": "https://json-schema.bytedance.net/rush-plugins/rush-build-cache-plugin-options.schema.json",
"key": "Wek6C-xcBtNNroagxV305NFAcmXOriQRps64", "key": "Wek6C-xcBtNNroagxV305NFAcmXOriQRps64",
"envList": [ "envList": [
// BUILD_TYPE SCM offlinetestonline [Witty] // BUILD_TYPE in SCM should be offline, test, online [Witty]
"BUILD_TYPE", "BUILD_TYPE",
// bot studio region // When building bot studio, it needs to be packaged according to the region environment
"REGION", "REGION",
// inhouse/release // Used to differentiate inhouse/release environments
"CUSTOM_VERSION", "CUSTOM_VERSION",
"CI", "CI",
"CI_LIGHTING", "CI_LIGHTING",
// coze cli inhouse/release // Coze cli builds need to differentiate between inhouse/release environments
"PUBLIC_INHOUSE" "PUBLIC_INHOUSE"
] ]
} }

View File

@ -14,7 +14,7 @@
# limitations under the License. # limitations under the License.
brokerClusterName = DefaultCluster brokerClusterName = DefaultCluster
# 禁用磁盘使用率告警 # Disable Disk Usage Alerts
# min:1, max:95 # min:1, max:95
diskMaxUsedSpaceRatio=95.0 diskMaxUsedSpaceRatio=95.0
@ -24,5 +24,5 @@ deleteWhen = 04
fileReservedTime = 48 fileReservedTime = 48
brokerRole = ASYNC_MASTER brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH flushDiskType = ASYNC_FLUSH
# 使用宿主机IP地址确保客户端可以直接访问 # Use the host Internet Protocol Address to ensure direct access from the client side
brokerIP1 = 127.0.0.1 brokerIP1 = 127.0.0.1

View File

@ -16,7 +16,7 @@ BUILD_BRANCH=opencoze-local rush rebuild -o @coze-studio/app --verbose
popd popd
# 复制构建产物到后端静态目录 # Copy bundle to backend static directory
echo -e "${YELLOW}正在复制构建产物到后端静态目录...${NC}" echo -e "${YELLOW}正在复制构建产物到后端静态目录...${NC}"
BACKEND_STATIC_DIR="${SCRIPT_DIR}/../backend/static" BACKEND_STATIC_DIR="${SCRIPT_DIR}/../backend/static"
BIN_STATIC_DIR="${SCRIPT_DIR}/../bin/resources/static" BIN_STATIC_DIR="${SCRIPT_DIR}/../bin/resources/static"
@ -27,7 +27,7 @@ rm -rf "${BIN_STATIC_DIR}"
mkdir -p "${BACKEND_STATIC_DIR}" mkdir -p "${BACKEND_STATIC_DIR}"
mkdir -p "${BIN_STATIC_DIR}" mkdir -p "${BIN_STATIC_DIR}"
# 清空目标目录并复制新的构建产物 # Clear the target directory and copy the new bundle
rm -rf "${BACKEND_STATIC_DIR}"/* rm -rf "${BACKEND_STATIC_DIR}"/*
cp -r "${FRONTEND_DIST_DIR}"/* "${BACKEND_STATIC_DIR}/" cp -r "${FRONTEND_DIST_DIR}"/* "${BACKEND_STATIC_DIR}/"
cp -r "${FRONTEND_DIST_DIR}"/* "${BIN_STATIC_DIR}/" cp -r "${FRONTEND_DIST_DIR}"/* "${BIN_STATIC_DIR}/"

View File

@ -5,7 +5,7 @@ FRONTEND_DIR="${1:-${SCRIPT_DIR}/../frontend}"
set -ex set -ex
# 设置颜色变量 # Set color variables
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
YELLOW='\033[0;33m' YELLOW='\033[0;33m'
@ -14,7 +14,7 @@ NC='\033[0m' # No Color
pushd "${FRONTEND_DIR}" pushd "${FRONTEND_DIR}"
echo "正在进入前端目录: ${FRONTEND_DIR}" echo "正在进入前端目录: ${FRONTEND_DIR}"
# 检查 Node.js 是否安装 # Check if Node.js is installed
echo -e "正在检查 Node.js 是否已安装..." echo -e "正在检查 Node.js 是否已安装..."
if ! command -v node &> /dev/null; then if ! command -v node &> /dev/null; then
echo -e "${RED}错误: 未检测到 Node.js${NC}" echo -e "${RED}错误: 未检测到 Node.js${NC}"
@ -28,7 +28,7 @@ else
fi fi
# 检查 Rush 是否安装 # Check if Rush is installed
echo -e "正在检查 Rush 是否已安装..." echo -e "正在检查 Rush 是否已安装..."
if ! command -v rush &> /dev/null; then if ! command -v rush &> /dev/null; then
echo -e "${YELLOW}未检测到 Rush正在为您安装...${NC}" echo -e "${YELLOW}未检测到 Rush正在为您安装...${NC}"
@ -48,6 +48,6 @@ echo -e "${GREEN}依赖安装完成!${NC}"
# echo -e "${NC}" # echo -e "${NC}"
# echo -e "${GREEN}构建完成!${NC}" # Echo -e "${GREEN} build complete! ${NC}"
popd popd

View File

@ -144,7 +144,7 @@ func CreateMySQLWhiteList(mysqlInstanceID, ts string) (string, error) {
ProjectName: volcengine.String(projectName), ProjectName: volcengine.String(projectName),
} }
// 复制代码运行示例请自行打印API返回值。 // Copy the code to run the example, please print the API return value yourself.
resp, err := svc.CreateAllowList(createAllowListInput) resp, err := svc.CreateAllowList(createAllowListInput)
if err != nil { if err != nil {
return "", err return "", err
@ -164,7 +164,7 @@ func AssociateMySQLWhiteList(mysqlInstanceID, whitelistID string) error {
InstanceIds: volcengine.StringSlice([]string{mysqlInstanceID}), InstanceIds: volcengine.StringSlice([]string{mysqlInstanceID}),
} }
// 复制代码运行示例请自行打印API返回值。 // Copy the code to run the example, please print the API return value yourself.
_, err := svc.AssociateAllowList(associateAllowListInput) _, err := svc.AssociateAllowList(associateAllowListInput)
if err != nil { if err != nil {
return err return err

View File

@ -250,7 +250,7 @@ func CheckSafeGroupStatus(sgID string) {
SecurityGroupId: volcengine.String(sgID), SecurityGroupId: volcengine.String(sgID),
} }
// 复制代码运行示例请自行打印API返回值。 // Copy the code to run the example, please print the API return value yourself.
resp, err := svc.DescribeSecurityGroupAttributes(describeSecurityGroupAttributesInput) resp, err := svc.DescribeSecurityGroupAttributes(describeSecurityGroupAttributesInput)
if err != nil { if err != nil {
fmt.Printf("[SafeGroup] will retry get safe group = %s failed, err= %s\n", sgID, err.Error()) fmt.Printf("[SafeGroup] will retry get safe group = %s failed, err= %s\n", sgID, err.Error())

View File

@ -165,7 +165,7 @@ func CreateRocketMQAccessKey(instanceID string) (string, string, error) {
InstanceId: volcengine.String(instanceID), InstanceId: volcengine.String(instanceID),
} }
// 复制代码运行示例请自行打印API返回值。 // Copy the code to run the example, please print the API return value yourself.
_, err = svc.CreateAccessKey(createAccessKeyInput) _, err = svc.CreateAccessKey(createAccessKeyInput)
if err != nil { if err != nil {
return "", "", err return "", "", err
@ -245,7 +245,7 @@ func CreateRocketMQTopic(ak, instanceID string) error {
TopicName: volcengine.String(topicName), TopicName: volcengine.String(topicName),
} }
// 复制代码运行示例请自行打印API返回值。 // Copy the code to run the example, please print the API return value yourself.
_, err = svc.CreateTopic(createTopicInput) _, err = svc.CreateTopic(createTopicInput)
if err != nil { if err != nil {
return err return err