🌐 chore: translate non-English comments to English in scripts (#13690)

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
LobeHub Bot 2026-04-09 14:38:29 +08:00 committed by GitHub
parent b268f44f06
commit f804d0fc7c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 77 additions and 77 deletions

View file

@ -18,7 +18,7 @@ import {
root,
} from './utils';
// 定义常量
// Define constants
const GITHUB_CDN = 'https://github.com/lobehub/lobe-chat/assets/';
const CHECK_CDN = [
'https://cdn.nlark.com/yuque/0/',
@ -41,7 +41,7 @@ class ImageCDNUploader {
this.loadCache();
}
// 从文件加载缓存数据
// Load cache data from file
private loadCache() {
try {
this.cache = JSON.parse(readFileSync(CACHE_FILE, 'utf8'));
@ -50,7 +50,7 @@ class ImageCDNUploader {
}
}
// 将缓存数据写入文件
// Write cache data to file
private writeCache() {
try {
writeFileSync(CACHE_FILE, JSON.stringify(this.cache, null, 2));
@ -59,18 +59,18 @@ class ImageCDNUploader {
}
}
// 收集所有的图片链接
// Collect all image links
private collectImageLinks(): string[] {
const links: string[][] = posts.map((post) => {
const mdx = readFileSync(post, 'utf8');
const { content, data } = matter(mdx);
const inlineLinks: string[] = extractHttpsLinks(content);
// 添加特定字段中的图片链接
// Add image links from specific fields
if (data?.image) inlineLinks.push(data.image);
if (data?.seo?.image) inlineLinks.push(data.seo.image);
// 过滤出有效的 CDN 链接
// Filter out valid CDN links
return inlineLinks.filter(
(link) =>
(link.startsWith(GITHUB_CDN) || CHECK_CDN.some((cdn) => link.startsWith(cdn))) &&
@ -96,11 +96,11 @@ class ImageCDNUploader {
!this.cache[link],
) as string[];
// 合并和去重链接数组
// Merge and deduplicate link arrays
return mergeAndDeduplicateArrays(links.flat().concat(communityLinks, cloudLinks));
}
// 上传图片到 CDN
// Upload images to CDN
private async uploadImagesToCDN(links: string[]) {
const cdnLinks: { [link: string]: string } = {};
@ -120,12 +120,12 @@ class ImageCDNUploader {
}
});
// 更新缓存
// Update cache
this.cache = { ...this.cache, ...cdnLinks };
this.writeCache();
}
// 根据不同的 CDN 来处理文件上传
// Handle file upload based on CDN type
private async uploadFileToCDN(file: File, link: string): Promise<string | undefined> {
if (link.startsWith(GITHUB_CDN)) {
const filename = link.replaceAll(GITHUB_CDN, '');
@ -139,7 +139,7 @@ class ImageCDNUploader {
return;
}
// 替换文章中的图片链接
// Replace image links in posts
private replaceLinksInPosts() {
let count = 0;
@ -155,7 +155,7 @@ class ImageCDNUploader {
}
}
// 更新特定字段的图片链接
// Update image links in specific fields
if (data['image'] && this.cache[data['image']]) {
data['image'] = this.cache[data['image']];
@ -206,7 +206,7 @@ class ImageCDNUploader {
);
}
// 运行上传过程
// Run upload process
async run() {
const links = this.collectImageLinks();
@ -218,13 +218,13 @@ class ImageCDNUploader {
consola.info('No new images to upload.');
}
// 替换文章和 changelog index 中的图片链接
// Replace image links in posts and changelog index
this.replaceLinksInPosts();
this.replaceLinksInChangelogIndex();
}
}
// 实例化并运行
// Instantiate and run
const instance = new ImageCDNUploader();
instance.run();

View file

@ -39,12 +39,12 @@ export const mergeAndDeduplicateArrays = (...arrays: string[][]) => {
const mimeToExtensions = {
'image/gif': '.gif',
// 图片类型
// Image types
'image/jpeg': '.jpg',
'image/png': '.png',
'image/svg+xml': '.svg',
'image/webp': '.webp',
// 视频类型
// Video types
'video/mp4': '.mp4',
'video/mpeg': '.mpeg',
'video/ogg': '.ogv',

View file

@ -162,7 +162,7 @@ async function migrateFromClerk() {
}
}
// Clerk API 不返回 credential external_account若用户开启密码并且 CSV 提供散列,则补齐本地密码账号
// Clerk API does not return credential external_account; if the user has password enabled and the CSV provides a hash, supplement the local password account
const passwordEnabled = Boolean(clerkUser?.password_enabled);
if (passwordEnabled && user.password_digest) {
const passwordUpdatedAt = clerkUser?.password_last_updated_at;

View file

@ -1,10 +1,10 @@
import fs from 'node:fs';
import path from 'node:path';
// 配置项
// Configuration
const config: Config = {
dirPath: './locales/en-US', // 替换为你的目录路径
ignoredFiles: ['models', 'providers', 'auth'], // 需要忽略的文件名
dirPath: './locales/en-US', // Replace with your directory path
ignoredFiles: ['models', 'providers', 'auth'], // Files to ignore
};
interface FileCount {
@ -17,13 +17,13 @@ interface Config {
ignoredFiles: string[];
}
// 统计字符串中的字符数量
// Count the number of characters in a string
function countChineseChars(str: string): number {
if (typeof str !== 'string') return 0;
return str.split(' ').length;
}
// 递归处理对象中的所有值
// Recursively process all values in an object
function processValue(value: any): number {
let count = 0;
@ -42,7 +42,7 @@ function processValue(value: any): number {
return count;
}
// 读取并处理 JSON 文件
// Read and process JSON file
function processJsonFile(filePath: string): number {
try {
const content = fs.readFileSync(filePath, 'utf8');
@ -54,7 +54,7 @@ function processJsonFile(filePath: string): number {
}
}
// 递归遍历目录
// Recursively traverse directory
function traverseDirectory(dirPath: string, ignoredFiles: string[]): FileCount[] {
const results: FileCount[] = [];
const files = fs.readdirSync(dirPath);
@ -64,7 +64,7 @@ function traverseDirectory(dirPath: string, ignoredFiles: string[]): FileCount[]
const stat = fs.statSync(fullPath);
const filename = path.parse(file).name;
// 跳过被忽略的文件
// Skip ignored files
if (ignoredFiles.includes(filename)) {
return;
}
@ -80,7 +80,7 @@ function traverseDirectory(dirPath: string, ignoredFiles: string[]): FileCount[]
return results;
}
// 主函数
// Main function
function main(config: Config): void {
const { dirPath, ignoredFiles } = config;
@ -89,13 +89,13 @@ function main(config: Config): void {
const results = traverseDirectory(dirPath, ignoredFiles);
// 按单词数降序排序
// Sort by word count in descending order
const sortedResults = results.sort((a, b) => b.count - a.count);
// 计算总数
// Calculate total count
const totalCount = results.reduce((sum, item) => sum + item.count, 0);
// 输出结果
// Output results
console.log('文件统计结果(按单词数降序):');
console.log('----------------------------------------');
sortedResults.forEach(({ filename, count }) => {

View file

@ -15,7 +15,7 @@ import {
root,
} from './utils';
// 定义常量
// Define constants
const GITHUB_CDN = 'https://github.com/lobehub/lobe-chat/assets/';
const CHECK_CDN = [
'https://cdn.nlark.com/yuque/0/',
@ -38,7 +38,7 @@ class ImageCDNUploader {
this.loadCache();
}
// 从文件加载缓存数据
// Load cache data from file
private loadCache() {
try {
this.cache = JSON.parse(readFileSync(CACHE_FILE, 'utf8'));
@ -47,7 +47,7 @@ class ImageCDNUploader {
}
}
// 将缓存数据写入文件
// Write cache data to file
private writeCache() {
try {
writeFileSync(CACHE_FILE, JSON.stringify(this.cache, null, 2));
@ -56,18 +56,18 @@ class ImageCDNUploader {
}
}
// 收集所有的图片链接
// Collect all image links
private collectImageLinks(): string[] {
const links: string[][] = posts.map((post) => {
const mdx = readFileSync(post, 'utf8');
const { content, data } = matter(mdx);
const inlineLinks: string[] = extractHttpsLinks(content);
// 添加特定字段中的图片链接
// Add image links from specific fields
if (data?.image) inlineLinks.push(data.image);
if (data?.seo?.image) inlineLinks.push(data.seo.image);
// 过滤出有效的 CDN 链接
// Filter out valid CDN links
return inlineLinks.filter(
(link) =>
(link.startsWith(GITHUB_CDN) || CHECK_CDN.some((cdn) => link.startsWith(cdn))) &&
@ -75,11 +75,11 @@ class ImageCDNUploader {
);
});
// 合并和去重链接数组
// Merge and deduplicate link arrays
return mergeAndDeduplicateArrays(...links);
}
// 上传图片到 CDN
// Upload images to CDN
private async uploadImagesToCDN(links: string[]) {
const cdnLinks: { [link: string]: string } = {};
@ -99,12 +99,12 @@ class ImageCDNUploader {
}
});
// 更新缓存
// Update cache
this.cache = { ...this.cache, ...cdnLinks };
this.writeCache();
}
// 根据不同的 CDN 来处理文件上传
// Handle file upload based on CDN type
private async uploadFileToCDN(file: File, link: string): Promise<string | undefined> {
if (link.startsWith(GITHUB_CDN)) {
const filename = link.replaceAll(GITHUB_CDN, '');
@ -118,7 +118,7 @@ class ImageCDNUploader {
return;
}
// 替换文章中的图片链接
// Replace image links in posts
private replaceLinksInPosts() {
let count = 0;
@ -134,7 +134,7 @@ class ImageCDNUploader {
}
}
// 更新特定字段的图片链接
// Update image links in specific fields
if (data['image'] && this.cache[data['image']]) {
data['image'] = this.cache[data['image']];
@ -152,7 +152,7 @@ class ImageCDNUploader {
consola.success(`${count} images have been uploaded to CDN and links have been replaced`);
}
// 运行上传过程
// Run upload process
async run() {
const links = this.collectImageLinks();
@ -167,7 +167,7 @@ class ImageCDNUploader {
}
}
// 实例化并运行
// Instantiate and run
const instance = new ImageCDNUploader();
instance.run();

View file

@ -61,12 +61,12 @@ export const mergeAndDeduplicateArrays = (...arrays: string[][]) => {
const mimeToExtensions = {
'image/gif': '.gif',
// 图片类型
// Image types
'image/jpeg': '.jpg',
'image/png': '.png',
'image/svg+xml': '.svg',
'image/webp': '.webp',
// 视频类型
// Video types
'video/mp4': '.mp4',
'video/mpeg': '.mpeg',
'video/ogg': '.ogv',

View file

@ -4,11 +4,11 @@ import fs from 'fs-extra';
type ReleaseType = 'stable' | 'beta' | 'nightly' | 'canary';
// 获取脚本的命令行参数
// Get command line arguments for the script
const version = process.argv[2];
const releaseType = process.argv[3] as ReleaseType;
// 验证参数
// Validate parameters
if (!version || !releaseType) {
console.error(
'Missing parameters. Usage: bun run setDesktopVersion.ts <version> <stable|beta|nightly|canary>',
@ -23,14 +23,14 @@ if (!['stable', 'beta', 'nightly', 'canary'].includes(releaseType)) {
process.exit(1);
}
// 获取根目录
// Get root directory
const rootDir = path.resolve(__dirname, '../..');
// 桌面应用 package.json 的路径
// Path to the desktop app package.json
const desktopPackageJsonPath = path.join(rootDir, 'apps/desktop/package.json');
const buildDir = path.join(rootDir, 'apps/desktop/build');
// 更新应用图标
// Update app icon
function updateAppIcon(type: 'beta' | 'nightly') {
console.log(`📦 Updating app icon for ${type} version...`);
try {
@ -56,7 +56,7 @@ function updateAppIcon(type: 'beta' | 'nightly') {
}
} catch (error) {
console.error(' ❌ Error updating icons:', error);
// 不终止程序,继续处理 package.json
// Don't terminate the program, continue processing package.json
}
}
@ -70,10 +70,10 @@ function updatePackageJson() {
const packageJson = fs.readJSONSync(desktopPackageJsonPath);
// 始终更新版本号
// Always update the version number
packageJson.version = version;
// 根据 releaseType 修改其他字段
// Modify other fields based on releaseType
switch (releaseType) {
case 'stable': {
packageJson.productName = 'LobeHub';
@ -103,7 +103,7 @@ function updatePackageJson() {
}
}
// 写回文件
// Write back to file
fs.writeJsonSync(desktopPackageJsonPath, packageJson, { spaces: 2 });
console.log(
@ -115,5 +115,5 @@ function updatePackageJson() {
}
}
// 执行更新
// Execute update
updatePackageJson();

View file

@ -2,22 +2,22 @@ import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
import { join, relative } from 'node:path';
interface ReplaceConfig {
/** 要替换的组件列表 */
/** List of components to replace */
components: string[];
/** 是否为 dry-run 模式(仅预览,不实际修改) */
/** Whether to run in dry-run mode (preview only, no actual modifications) */
dryRun?: boolean;
/** 文件扩展名白名单 */
/** File extension whitelist */
fileExtensions?: string[];
/** 原始包名 */
/** Source package name */
fromPackage: string;
/** 要扫描的目录 */
/** Directory to scan */
targetDir: string;
/** 目标包名 */
/** Target package name */
toPackage: string;
}
/**
*
* Recursively get all files in a directory
*/
function getAllFiles(dir: string, extensions: string[]): string[] {
const files: string[] = [];
@ -30,7 +30,7 @@ function getAllFiles(dir: string, extensions: string[]): string[] {
const stat = statSync(fullPath);
if (stat.isDirectory()) {
// 跳过 node_modules 等目录
// Skip directories like node_modules
if (!['node_modules', '.git', 'dist', 'build', '.next'].includes(item)) {
walk(fullPath);
}
@ -48,10 +48,10 @@ function getAllFiles(dir: string, extensions: string[]): string[] {
}
/**
* import
* Parse import statements and extract imported components
*/
function parseImportStatement(line: string, packageName: string) {
// 匹配 import { ... } from 'package'
// Match import { ... } from 'package'
const importRegex = new RegExp(
`import\\s+{([^}]+)}\\s+from\\s+['"]${packageName.replaceAll(/[$()*+.?[\\\]^{|}]/g, '\\$&')}['"]`,
);
@ -64,7 +64,7 @@ function parseImportStatement(line: string, packageName: string) {
.split(',')
.map((item) => {
const trimmed = item.trim();
// 处理 as 别名: ComponentName as AliasName
// Handle as aliases: ComponentName as AliasName
const asMatch = trimmed.match(/^(\w+)(?:\s+as\s+(\w+))?/);
return asMatch
? {
@ -84,7 +84,7 @@ function parseImportStatement(line: string, packageName: string) {
}
/**
* import
* Replace import statements in a file
*/
function replaceImportsInFile(filePath: string, config: ReplaceConfig): boolean {
const content = readFileSync(filePath, 'utf8');
@ -100,28 +100,28 @@ function replaceImportsInFile(filePath: string, config: ReplaceConfig): boolean
continue;
}
// 找出需要替换的组件和保留的组件
// Find components to replace and components to keep
const toReplace = parsed.components.filter((comp) => config.components.includes(comp.name));
const toKeep = parsed.components.filter((comp) => !config.components.includes(comp.name));
if (toReplace.length === 0) {
// 没有需要替换的组件
// No components to replace
newLines.push(line);
continue;
}
modified = true;
// 生成新的 import 语句
// Generate new import statement
const { indentation } = parsed;
// 如果有保留的组件,保留原来的 import
// If there are components to keep, preserve the original import
if (toKeep.length > 0) {
const keepImports = toKeep.map((c) => c.raw).join(', ');
newLines.push(`${indentation}import { ${keepImports} } from '${config.fromPackage}';`);
}
// 添加新的 import
// Add new import
const replaceImports = toReplace.map((c) => c.raw).join(', ');
newLines.push(`${indentation}import { ${replaceImports} } from '${config.toPackage}';`);
}
@ -138,7 +138,7 @@ function replaceImportsInFile(filePath: string, config: ReplaceConfig): boolean
}
/**
*
* Execute replacement
*/
function executeReplace(config: ReplaceConfig) {
const extensions = config.fileExtensions || ['.ts', '.tsx', '.js', '.jsx'];
@ -175,10 +175,10 @@ function executeReplace(config: ReplaceConfig) {
}
}
// ============ 主函数 ============
// ============ Main function ============
/**
*
* Parse configuration from command line arguments
*/
function parseArgs(): ReplaceConfig | null {
const args = process.argv.slice(2);
@ -244,7 +244,7 @@ function parseArgs(): ReplaceConfig | null {
};
}
// 执行脚本
// Execute script
const config = parseArgs();
if (config) {
executeReplace(config);