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

main
tecvan 3 months ago committed by GitHub
parent f7d73cd391
commit a1f3a9aead
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 6
      .github/scripts/check-file-size.sh
  2. 8
      .github/workflows/ci.yml
  3. 8
      common/_templates/_plugins/SelectTeamPlugin.ts
  4. 6
      common/_templates/_plugins/SetDefaultAuthorPlugin.ts
  5. 6
      common/_templates/_plugins/ShowTemplatePlugin.ts
  6. 14
      common/_templates/_plugins/utils/parse-args.ts
  7. 4
      common/_templates/component/src/demo/index.tsx
  8. 4
      common/_templates/rspack-web/env/index.ts
  9. 20
      common/_templates/rspack-web/env/scripts/index.ts
  10. 2
      common/_templates/rspack-web/src/index.tsx
  11. 2
      common/_templates/rspack-web/src/store/userinfo-slice.ts
  12. 2
      common/_templates/rspack-web/src/typing/env/index.d.ts
  13. 4
      common/_templates/solid-component/src/demo/index.tsx
  14. 8
      common/autoinstallers/rush-commands/src/convert-comments/cli/command.ts
  15. 36
      common/autoinstallers/rush-commands/src/convert-comments/cli/config.ts
  16. 38
      common/autoinstallers/rush-commands/src/convert-comments/index.ts
  17. 86
      common/autoinstallers/rush-commands/src/convert-comments/modules/chinese-detection.ts
  18. 90
      common/autoinstallers/rush-commands/src/convert-comments/modules/file-replacement.ts
  19. 18
      common/autoinstallers/rush-commands/src/convert-comments/modules/file-scan.ts
  20. 38
      common/autoinstallers/rush-commands/src/convert-comments/modules/report.ts
  21. 54
      common/autoinstallers/rush-commands/src/convert-comments/modules/translation.ts
  22. 12
      common/autoinstallers/rush-commands/src/convert-comments/types/config.ts
  23. 36
      common/autoinstallers/rush-commands/src/convert-comments/types/index.ts
  24. 28
      common/autoinstallers/rush-commands/src/convert-comments/utils/chinese.ts
  25. 30
      common/autoinstallers/rush-commands/src/convert-comments/utils/fp.ts
  26. 20
      common/autoinstallers/rush-commands/src/convert-comments/utils/git.ts
  27. 36
      common/autoinstallers/rush-commands/src/convert-comments/utils/language.ts
  28. 10
      common/autoinstallers/rush-commands/src/convert-comments/utils/semaphore.ts
  29. 100
      common/autoinstallers/rush-commands/src/convert-comments/volc/translate.ts
  30. 2
      common/autoinstallers/rush-commitlint/.cz-config.js
  31. 2
      common/autoinstallers/rush-commitlint/utils.js
  32. 10
      common/autoinstallers/rush-lint-staged/.lintstagedrc.js
  33. 6
      common/autoinstallers/rush-lint-staged/utils.js
  34. 8
      common/config/rush-plugins/rush-bytedance-build-cache-plugin.json
  35. 4
      docker/volumes/rocketmq/broker.conf
  36. 4
      scripts/build_fe.sh
  37. 8
      scripts/setup_fe.sh
  38. 4
      scripts/volcengine/mysql.go
  39. 2
      scripts/volcengine/network.go
  40. 4
      scripts/volcengine/rocketmq.go

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

@ -37,10 +37,10 @@ jobs:
- name: Process changed files
id: process-files
run: |
# 获取所有变更文件
# Get all change files
all_files="${{ steps.changed-files.outputs.all_changed_files }}"
# 过滤掉 common/changes 目录下的文件
# Filter out files in the common/changes directory
filtered_files=""
for file in $all_files; do
if [[ ! "$file" =~ ^common/changes/.* ]]; then
@ -52,10 +52,10 @@ jobs:
fi
done
# 创建 JSON 格式的缓存文件
# Create cached files in JSON format
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 "过滤前文件数量: $(echo $all_files | wc -w)"

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

@ -20,9 +20,9 @@ import type {
IPromptsHookParams,
} from 'rush-init-project-plugin';
// FIXME:
// 按照 https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md
// 一文的指引,无法正确 resolve 到对应模块,暂时没找到解决方案,故此处先用相对路径引用
// 未来需要调整为正常的 node_modules 引用方式
// According to https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md
// 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
// Future needs to be adjusted to normal node_modules citation
import { createLog } from '../../autoinstallers/plugins/node_modules/rush-init-project-plugin';
import { exec } from './utils';

@ -21,9 +21,9 @@ import type {
IPromptsHookParams,
} from 'rush-init-project-plugin';
// FIXME:
// 按照 https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md
// 一文的指引,无法正确 resolve 到对应模块,暂时没找到解决方案,故此处先用相对路径引用
// 未来需要调整为正常的 node_modules 引用方式
// According to https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md
// 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
// Future needs to be adjusted to normal node_modules citation
import {
getTemplatesFolder,
getTemplateNameList,

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

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

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

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

@ -17,7 +17,7 @@
import { RouterProvider } from 'react-router-dom';
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 { router } from '@/router';

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

@ -14,7 +14,7 @@
* 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_DEV_MODE: boolean;
declare const IS_PRODUCT_MODE: boolean;

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

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

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

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

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

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

@ -5,7 +5,7 @@ import { getGitTrackedFiles, getAllGitFiles } from '../utils/git';
import { tryCatch } from '../utils/fp';
/**
* SourceFile对象
* Read the file contents and create a SourceFile object
*/
export const readSourceFile = async (filePath: string): Promise<Result<SourceFile>> => {
return tryCatch(async () => {
@ -21,7 +21,7 @@ export const readSourceFile = async (filePath: string): Promise<Result<SourceFil
};
/**
*
* Batch reading of source files
*/
export const readSourceFiles = async (filePaths: string[]): Promise<SourceFile[]> => {
const results = await Promise.allSettled(
@ -36,13 +36,13 @@ export const readSourceFiles = async (filePaths: string[]): Promise<SourceFile[]
};
/**
* Git仓库中的源码文件
* Get the source code file in the Git repository
*/
export const getSourceFiles = async (config: FileScanConfig): Promise<Result<string[]>> => {
const { root, extensions, includeUntracked } = config;
return tryCatch(async () => {
// 获取Git文件列表
// Get a list of Git files
const gitFilesResult = includeUntracked
? await getAllGitFiles(root)
: await getGitTrackedFiles(root);
@ -53,10 +53,10 @@ export const getSourceFiles = async (config: FileScanConfig): Promise<Result<str
let files = gitFilesResult.data;
// 过滤文本文件
// Filter text files
files = files.filter(isTextFile);
// 根据扩展名过滤
// Filter by extension
files = filterFilesByExtensions(files, extensions);
return files;
@ -64,7 +64,7 @@ export const getSourceFiles = async (config: FileScanConfig): Promise<Result<str
};
/**
*
* Scan and read all source code files
*/
export const scanSourceFiles = async (config: FileScanConfig): Promise<Result<SourceFile[]>> => {
return tryCatch(async () => {
@ -80,7 +80,7 @@ export const scanSourceFiles = async (config: FileScanConfig): Promise<Result<So
};
/**
*
* Check if the file exists and is readable
*/
export const isFileAccessible = async (filePath: string): Promise<boolean> => {
try {
@ -92,7 +92,7 @@ export const isFileAccessible = async (filePath: string): Promise<boolean> => {
};
/**
*
* Get file statistics
*/
export const getFileStats = async (filePaths: string[]): Promise<{
total: number;

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

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

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

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

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

@ -1,7 +1,7 @@
import { Result } from '../types/index';
/**
* -
* Function composition - executed from left to right
*/
export const pipe =
<T>(...fns: Function[]) =>
@ -9,7 +9,7 @@ export const pipe =
fns.reduce((acc, fn) => fn(acc), value);
/**
* -
* Function composition - executed from right to left
*/
export const compose =
<T>(...fns: Function[]) =>
@ -17,7 +17,7 @@ export const compose =
fns.reduceRight((acc, fn) => fn(acc), value);
/**
*
* currying function
*/
export const curry =
(fn: Function) =>
@ -27,7 +27,7 @@ export const curry =
: (...more: any[]) => curry(fn)(...args, ...more);
/**
*
* asynchronous mapping
*/
export const asyncMap = curry(
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(
async <T>(
@ -48,7 +48,7 @@ export const asyncFilter = curry(
);
/**
*
* asynchronous reduction
*/
export const asyncReduce = curry(
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 });
/**
*
* Create failed result
*/
export const failure = <E>(error: E): Result<never, E> => ({
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>> => {
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> => {
try {
@ -102,7 +102,7 @@ export const tryCatchSync = <T>(fn: () => T): Result<T> => {
};
/**
*
* Array chunking
*/
export const chunk = <T>(array: T[], size: number): 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> =>
new Promise(resolve => setTimeout(resolve, ms));
/**
*
* retry mechanism
*/
export const retry = async <T>(
fn: () => Promise<T>,
@ -135,7 +135,7 @@ export const retry = async <T>(
lastError = error instanceof Error ? error : new Error(String(error));
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>>(
target: T,

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

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

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

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

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

@ -19,7 +19,7 @@ function getChangedPackages(changedFiles) {
const lookup = rushConfiguration.getProjectLookupForRoot(rushJsonFolder)
for (const file of changedFiles) {
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'
if (!changedPackages.has(packageName)) {
changedPackages.add(packageName)

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save