【新增】插件git同步模块,用于同步项目内容,加速项目开发

【调整】前端暗色问题
This commit is contained in:
chudong
2025-05-14 16:50:56 +08:00
parent dc43da936b
commit e6947ec5c4
215 changed files with 19918 additions and 9710 deletions

View File

@@ -0,0 +1,207 @@
import path from 'path'
/**
* 未使用翻译检测器
* 负责检测和移除未使用的翻译内容
*/
export class UnusedTranslationDetector {
/**
* @param {Object} fileOperation - 文件操作实例
* @param {Object} cacheManager - 缓存管理实例
*/
constructor(fileOperation, cacheManager) {
this.fileOperation = fileOperation
this.cacheManager = cacheManager
}
/**
* 扫描项目中实际使用的翻译键
* @param {string[]} files - 要扫描的文件列表
* @param {RegExp} keyUsageRegex - 匹配翻译键使用的正则表达式
* @returns {Promise<Set<string>>} - 项目中使用的翻译键集合
*/
async scanUsedTranslationKeys(files, keyUsageRegex) {
const usedKeys = new Set()
for (const file of files) {
try {
const content = await this.fileOperation.readFile(file)
// 重置正则表达式的lastIndex确保从头开始匹配
keyUsageRegex.lastIndex = 0
let match
while ((match = keyUsageRegex.exec(content)) !== null) {
if (match[1]) {
usedKeys.add(match[1].trim())
}
}
} catch (error) {
console.error(`[i18n插件] 扫描文件 ${file} 中使用的翻译键失败:`, error)
}
}
return usedKeys
}
/**
* 从翻译文件中加载所有翻译键
* @param {string} translationDir - 翻译文件目录
* @param {string[]} languages - 语言列表
* @returns {Promise<Map<string, Object>>} - 键到翻译对象的映射
*/
async loadAllTranslations(translationDir, languages) {
const allTranslations = new Map()
for (const language of languages) {
const filePath = path.join(translationDir, `${language}.json`)
try {
if (await this.fileOperation.fileExists(filePath)) {
const content = await this.fileOperation.readFile(filePath)
const translations = JSON.parse(content)
// 将每个键加入到总映射中
for (const [key, value] of Object.entries(translations)) {
if (!allTranslations.has(key)) {
allTranslations.set(key, { key, translations: {} })
}
const translationObj = allTranslations.get(key)
translationObj.translations[language] = value
}
}
} catch (error) {
console.error(`[i18n插件] 加载翻译文件 ${filePath} 失败:`, error)
}
}
return allTranslations
}
/**
* 检测未使用的翻译
* @param {Set<string>} usedKeys - 使用的翻译键集合
* @param {Map<string, Object>} allTranslations - 所有翻译
* @returns {Set<string>} - 未使用的翻译键集合
*/
detectUnusedTranslations(usedKeys, allTranslations) {
const unusedKeys = new Set()
for (const [key] of allTranslations.entries()) {
if (!usedKeys.has(key)) {
unusedKeys.add(key)
}
}
return unusedKeys
}
/**
* 从翻译文件中移除未使用的翻译
* @param {Set<string>} unusedKeys - 未使用的翻译键集合
* @param {string} translationDir - 翻译文件目录
* @param {string[]} languages - 语言列表
* @returns {Promise<number>} - 移除的翻译数量
*/
async removeUnusedTranslations(unusedKeys, translationDir, languages) {
let removedCount = 0
for (const language of languages) {
const filePath = path.join(translationDir, `${language}.json`)
try {
if (await this.fileOperation.fileExists(filePath)) {
const content = await this.fileOperation.readFile(filePath)
const translations = JSON.parse(content)
let hasChanges = false
// 移除未使用的翻译
for (const key of unusedKeys) {
if (key in translations) {
delete translations[key]
hasChanges = true
if (language === languages[0]) {
// 只在处理第一种语言时计数,避免重复计数
removedCount++
}
}
}
// 如果有变更,更新文件
if (hasChanges) {
await this.fileOperation.modifyFile(filePath, JSON.stringify(translations, null, 2))
}
}
} catch (error) {
console.error(`[i18n插件] 更新翻译文件 ${filePath} 失败:`, error)
}
}
return removedCount
}
/**
* 从缓存中移除未使用的翻译
* @param {Map<string, Object>} allTranslations - 所有翻译
* @param {Set<string>} unusedKeys - 未使用的翻译键集合
* @returns {Promise<void>}
*/
async removeUnusedFromCache(allTranslations, unusedKeys) {
// 构建需要保留的中文文本列表
const validTexts = []
for (const [key, translationObj] of allTranslations.entries()) {
if (!unusedKeys.has(key)) {
// 如果有原始中文文本,添加到有效列表中
if (translationObj.text) {
validTexts.push(translationObj.text)
}
}
}
// 清理缓存
await this.cacheManager.cleanCache(validTexts)
}
/**
* 执行未使用翻译检查和清理
* @param {Object} config - 配置对象
* @param {string[]} files - 要扫描的文件列表
* @returns {Promise<{removedCount: number}>} - 清理结果
*/
async cleanUnusedTranslations(config, files) {
console.log(`[i18n插件] 开始检测未使用的翻译...`)
// 创建匹配翻译键使用的正则表达式: $t('key') 或 $t("key")
const keyUsageRegex = new RegExp(/\$t\(['"](.+?)['"]\)/g)
// 扫描使用的翻译键
const usedKeys = await this.scanUsedTranslationKeys(files, keyUsageRegex)
console.log(`[i18n插件] 扫描到 ${usedKeys.size} 个使用中的翻译键`)
// 加载所有翻译
const translationDir = path.join(config.outputPath, 'model')
const allTranslations = await this.loadAllTranslations(translationDir, config.languages)
console.log(`[i18n插件] 加载了 ${allTranslations.size} 个翻译键`)
// 检测未使用的翻译
const unusedKeys = this.detectUnusedTranslations(usedKeys, allTranslations)
console.log(`[i18n插件] 检测到 ${unusedKeys.size} 个未使用的翻译键`)
if (unusedKeys.size === 0) {
console.log(`[i18n插件] 没有发现未使用的翻译,无需清理`)
return { removedCount: 0 }
}
// 移除未使用的翻译
const removedCount = await this.removeUnusedTranslations(unusedKeys, translationDir, config.languages)
// 从缓存中移除未使用的翻译
await this.removeUnusedFromCache(allTranslations, unusedKeys)
console.log(`[i18n插件] 已从翻译文件和缓存中移除 ${removedCount} 个未使用的翻译`)
return { removedCount }
}
}
export default UnusedTranslationDetector