i18n-xy
Version:
自动提取React项目中的中文字符串并进行国际化的CLI工具
1 lines • 25 kB
Source Map (JSON)
{"version":3,"sources":["../main/index.ts","../main/config/index.ts","../main/config/defaults.ts","../main/utils/fs.ts","../main/utils/logger.ts","../main/config/manager.ts","../main/config/validator.ts","../main/cli/wrapper.ts"],"sourcesContent":["// main/index.ts - 主入口文件\nexport * from './config';\nexport * from './utils/logger';\nexport * from './utils/fs';\nexport * from './cli/wrapper';","import { merge } from 'lodash';\nimport { I18nConfig } from './types';\nimport { defaultConfig } from './defaults';\nimport { fileExists, readJsonSync } from '../utils/fs';\nimport { Logger } from '../utils/logger';\n\n/**\n * 验证配置对象的有效性\n */\nfunction validateConfig(config: I18nConfig): void {\n const errors: string[] = [];\n\n // 验证必需字段\n if (!config.include || !Array.isArray(config.include) || config.include.length === 0) {\n errors.push('include 字段必须是非空数组');\n }\n\n if (!config.outputDir || typeof config.outputDir !== 'string') {\n errors.push('outputDir 字段必须是有效的字符串路径');\n }\n\n if (!config.locale || typeof config.locale !== 'string') {\n errors.push('locale 字段必须是有效的语言代码');\n }\n\n // 验证翻译配置\n if (config.translation?.enabled) {\n if (!config.translation.provider) {\n errors.push('启用翻译时必须指定 translation.provider');\n }\n\n if (config.translation.provider === 'baidu') {\n if (!config.translation.baidu?.appid || !config.translation.baidu?.key) {\n errors.push('使用百度翻译时必须配置 translation.baidu.appid 和 translation.baidu.key');\n }\n }\n }\n\n // 验证日志级别\n if (config.logging?.level && !['minimal', 'normal', 'verbose'].includes(config.logging.level)) {\n errors.push('logging.level 必须是 minimal、normal 或 verbose 之一');\n }\n\n if (errors.length > 0) {\n Logger.error('配置验证失败:', 'minimal');\n errors.forEach((error) => Logger.error(` - ${error}`, 'minimal'));\n throw new Error(`配置验证失败: ${errors.join('; ')}`);\n }\n}\n\nexport function loadConfig(customConfigPath?: string): I18nConfig {\n let userConfig: Partial<I18nConfig> = {};\n\n if (customConfigPath) {\n if (fileExists(customConfigPath)) {\n Logger.verbose(`加载配置文件: ${customConfigPath}`);\n try {\n userConfig = readJsonSync(customConfigPath) as Partial<I18nConfig>;\n Logger.verbose('配置文件加载成功');\n } catch (error) {\n throw new Error(`配置文件解析失败: ${error}`);\n }\n } else {\n Logger.warn(`配置文件不存在: ${customConfigPath},使用默认配置`);\n }\n }\n\n const finalConfig = merge({}, defaultConfig, userConfig) as I18nConfig;\n\n // 验证最终配置\n validateConfig(finalConfig);\n\n Logger.verbose('配置验证通过');\n return finalConfig;\n}\n\n// 导出其他相关模块\nexport { ConfigManager } from './manager';\nexport { ConfigValidator } from './validator';\nexport type { I18nConfig } from './types';","import { I18nConfig } from './types';\n\n// 默认配置\nexport const defaultConfig: I18nConfig = {\n // 基础语言配置\n locale: 'zh-CN',\n displayLanguage: 'en-US',\n outputDir: 'locales',\n // tempDir: undefined, // 可选,不设置则直接修改源文件\n\n // 文件处理配置\n include: [\n 'src/**/*.{js,jsx,ts,tsx}',\n ],\n\n exclude: [\n 'node_modules/**',\n 'dist/**',\n 'build/**',\n '**/*.test.{js,jsx,ts,tsx}',\n '**/*.spec.{js,jsx,ts,tsx}',\n ],\n\n // Key 生成配置\n keyGeneration: {\n maxChineseLength: 10, // 最大汉字长度\n hashLength: 6, // 哈希长度\n maxRetryCount: 5, // 最大重试次数\n reuseExistingKey: true, // 默认重复使用相同文案的key\n duplicateKeySuffix: 'hash', // 重复key后缀模式,默认hash\n keyPrefix: '', // key前缀,默认为空\n separator: '_', // 连接符,默认下划线\n pinyinOptions: {\n // 拼音转换选项\n toneType: 'none', // 不带声调\n type: 'array', // 返回数组格式\n },\n },\n\n // 输出配置\n output: {\n prettyJson: true, // 格式化 JSON 输出\n localeFileName: '{locale}.json', // 语言文件名格式\n },\n\n // 日志配置\n logging: {\n enabled: true, // 默认启用日志\n level: 'normal', // 默认正常级别\n },\n\n // 替换配置\n replacement: {\n functionName: '$t', // 默认替换函数名\n quoteType: 'single', // 默认使用单引号\n useOriginalTextAsKey: false, // 默认使用生成的key\n templateString: {\n enabled: true, // 默认启用模板字符串智能处理\n preserveExpressions: true, // 默认保留原始表达式\n splitStrategy: 'smart', // 默认智能拆分策略\n },\n autoImport: {\n enabled: false, // 默认不启用自动引入\n insertPosition: 'afterImports', // 默认在import语句后插入\n imports: {},\n },\n },\n\n // 翻译配置\n translation: {\n enabled: false, // 默认不启用翻译功能\n provider: 'baidu', // 默认使用百度翻译\n defaultSourceLang: 'zh', // 默认源语言:中文\n defaultTargetLang: 'en', // 默认目标语言:英文\n concurrency: 5, // 默认并发数:5 (降低并发数避免API限制)\n retryTimes: 3, // 默认重试次数:3次(不包括第一次)\n retryDelay: 1000, // 默认重试延迟:1秒\n batchDelay: 500, // 默认批次延迟:0.5秒\n baidu: {\n appid: '', // 需要用户配置\n key: '', // 需要用户配置\n },\n },\n};","import * as fs from 'fs-extra';\nimport * as path from 'path';\nimport fg, { Options } from 'fast-glob';\n\n/**\n * 读取文件内容\n */\nexport function readFile(filePath: string, encoding: BufferEncoding = 'utf-8'): Promise<string> {\n const absPath = path.resolve(process.cwd(), filePath);\n return fs.readFile(absPath, encoding);\n}\n\n/**\n * 写入文件内容\n */\nexport function writeFile(filePath: string, data: string | Buffer): Promise<void> {\n const absPath = path.resolve(process.cwd(), filePath);\n return fs.outputFile(absPath, data);\n}\n\n/**\n * 写入文件内容,支持 tempDir 配置\n * @param filePath 原始文件路径\n * @param data 文件内容\n * @param tempDir 临时目录,如果配置则写入到临时目录,否则写入原始位置\n */\nexport function writeFileWithTempDir(\n filePath: string,\n data: string | Buffer,\n tempDir?: string\n): Promise<void> {\n let targetPath: string;\n\n if (tempDir) {\n // 如果配置了 tempDir,则在 tempDir 下按照原始路径结构生成文件\n const relativePath = path.relative(process.cwd(), filePath);\n targetPath = path.resolve(process.cwd(), tempDir, relativePath);\n } else {\n // 如果没有配置 tempDir,则直接写入原始文件\n targetPath = path.resolve(process.cwd(), filePath);\n }\n\n return fs.outputFile(targetPath, data);\n}\n\n/**\n * 创建目录\n */\nexport function ensureDir(dirPath: string): Promise<void> {\n const absPath = path.resolve(process.cwd(), dirPath);\n return fs.ensureDir(absPath);\n}\n\n/**\n * 遍历目录下所有文件,支持glob模式和过滤参数\n */\nexport function findFiles(pattern: string | string[], options: Options = {}): Promise<string[]> {\n return fg(pattern, { dot: true, ...options, cwd: process.cwd() });\n}\n\n/**\n * 根据 include/exclude 参数筛选目标文件,所有路径以 CLI 执行目录为根目录\n * @param include 需要包含的文件模式(glob数组或字符串)\n * @param exclude 需要排除的文件模式(glob数组或字符串)\n */\nexport function findTargetFiles(include: string[], exclude: string[] = []): Promise<string[]> {\n return fg(include, { ignore: exclude, dot: true, cwd: process.cwd() });\n}\n\n/**\n * 检查文件是否存在\n * @param filePath 文件路径\n */\nexport function fileExists(filePath: string): boolean {\n const absPath = path.resolve(process.cwd(), filePath);\n return fs.existsSync(absPath);\n}\n\n/**\n * 同步读取 JSON 文件内容\n * @param filePath JSON 文件路径\n */\nexport function readJsonSync(filePath: string): unknown {\n const absPath = path.resolve(process.cwd(), filePath);\n return fs.readJsonSync(absPath);\n}\n\n/**\n * 异步读取 JSON 文件内容\n * @param filePath JSON 文件路径\n * @param defaultValue 文件不存在时的默认值\n */\nexport async function readJson<T = unknown>(filePath: string, defaultValue?: T): Promise<T> {\n try {\n const content = await readFile(filePath, 'utf-8');\n return JSON.parse(content) as T;\n } catch (error) {\n if (defaultValue !== undefined) {\n return defaultValue;\n }\n throw error;\n }\n}\n\n/**\n * 异步写入 JSON 文件内容\n * @param filePath JSON 文件路径\n * @param data 要写入的数据\n * @param pretty 是否格式化输出,默认为 true\n */\nexport function writeJson(filePath: string, data: unknown, pretty: boolean = true): Promise<void> {\n const content = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);\n return writeFile(filePath, content);\n}","import { ConfigManager } from '../config';\n\nexport class Logger {\n private static temporaryLevel: string | null = null; // 临时日志级别\n \n private static getLogLevel(): string {\n try {\n // 优先使用临时级别\n if (this.temporaryLevel) {\n return this.temporaryLevel;\n }\n const config = ConfigManager.get();\n return config.logging?.level ?? 'normal';\n } catch {\n // 如果ConfigManager未初始化,使用默认值\n return 'normal';\n }\n }\n\n /**\n * 临时设置日志级别(用于进度显示期间)\n */\n static setTemporaryLevel(level: string | null): void {\n this.temporaryLevel = level;\n }\n\n private static shouldLog(level: 'minimal' | 'normal' | 'verbose'): boolean {\n const currentLevel = this.getLogLevel();\n\n if (currentLevel === 'minimal') {\n return level === 'minimal';\n } else if (currentLevel === 'normal') {\n return level !== 'verbose';\n } else if (currentLevel === 'verbose') {\n return true;\n }\n\n return false;\n }\n\n static success(message: string, level: 'minimal' | 'normal' | 'verbose' = 'normal'): void {\n if (this.shouldLog(level)) {\n console.log(`✅ ${message}`);\n }\n }\n\n static info(message: string, level: 'minimal' | 'normal' | 'verbose' = 'normal'): void {\n if (this.shouldLog(level)) {\n console.log(`ℹ️ ${message}`);\n }\n }\n\n static warn(message: string, level: 'minimal' | 'normal' | 'verbose' = 'normal'): void {\n if (this.shouldLog(level)) {\n console.warn(`⚠️ ${message}`);\n }\n }\n\n static error(message: string, level: 'minimal' | 'normal' | 'verbose' = 'normal'): void {\n if (this.shouldLog(level)) {\n console.error(`❌ ${message}`);\n }\n }\n\n static verbose(message: string): void {\n this.info(message, 'verbose');\n }\n}","import { I18nConfig } from './types';\n\n// ConfigManager 单例\nclass ConfigManagerClass {\n private config: I18nConfig | null = null;\n\n init(config: I18nConfig): void {\n this.config = config;\n }\n\n get(): I18nConfig {\n if (!this.config) {\n throw new Error('ConfigManager: config not initialized!');\n }\n return this.config;\n }\n\n reset(): void {\n this.config = null;\n }\n\n isInitialized(): boolean {\n return this.config !== null;\n }\n}\n\nexport const ConfigManager = new ConfigManagerClass();","import { ConfigManager } from './manager';\nimport { Logger } from '../utils/logger';\n\n/**\n * 配置一致性检查工具\n * 用于验证所有配置项是否正确使用,没有硬编码值\n */\nexport class ConfigValidator {\n /**\n * 检查配置的一致性和完整性\n */\n static validateConfigUsage(): {\n isValid: boolean;\n errors: string[];\n warnings: string[];\n } {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n try {\n const config = ConfigManager.get();\n\n // 检查必需配置\n if (!config.include || config.include.length === 0) {\n errors.push('配置项 include 不能为空');\n }\n\n if (!config.outputDir) {\n errors.push('配置项 outputDir 不能为空');\n }\n\n if (!config.locale) {\n errors.push('配置项 locale 不能为空');\n }\n\n // 检查翻译配置一致性\n if (config.translation?.enabled) {\n if (!config.translation.provider) {\n errors.push('启用翻译时必须指定 provider');\n }\n\n if (config.translation.provider === 'baidu') {\n if (!config.translation.baidu?.appid || !config.translation.baidu?.key) {\n warnings.push('百度翻译服务缺少 appid 或 key 配置');\n }\n }\n }\n\n // 检查key生成配置\n if (config.keyGeneration) {\n if (config.keyGeneration.maxChineseLength && config.keyGeneration.maxChineseLength <= 0) {\n warnings.push('maxChineseLength 应该大于0');\n }\n\n if (config.keyGeneration.hashLength && config.keyGeneration.hashLength <= 0) {\n warnings.push('hashLength 应该大于0');\n }\n }\n\n // 检查日志配置\n if (\n config.logging?.level &&\n !['minimal', 'normal', 'verbose'].includes(config.logging.level)\n ) {\n errors.push('logging.level 必须是 minimal、normal 或 verbose 之一');\n }\n\n // 检查输出配置\n if (config.output?.localeFileName && !config.output.localeFileName.includes('{locale}')) {\n warnings.push('localeFileName 建议包含 {locale} 占位符');\n }\n } catch (error) {\n errors.push(`配置检查时发生错误: ${error}`);\n }\n\n const isValid = errors.length === 0;\n\n if (!isValid) {\n Logger.error('配置验证失败:', 'minimal');\n errors.forEach((error) => Logger.error(` - ${error}`, 'minimal'));\n }\n\n if (warnings.length > 0) {\n Logger.warn('配置警告:', 'normal');\n warnings.forEach((warning) => Logger.warn(` - ${warning}`, 'normal'));\n }\n\n // 移除\"配置验证通过,无警告\"输出以减少日志噪音\n\n return { isValid, errors, warnings };\n }\n\n /**\n * 检查是否存在配置与代码不一致的问题\n */\n static checkConfigConsistency(): void {\n const config = ConfigManager.get();\n\n Logger.verbose('检查配置一致性...');\n\n // 检查文件名生成是否使用了配置\n const expectedFileName = (config.output?.localeFileName ?? '{locale}.json').replace(\n '{locale}',\n config.locale\n );\n Logger.verbose(`预期的语言文件名: ${expectedFileName}`);\n\n // 检查替换函数名是否一致\n const functionName = config.replacement?.functionName ?? '$t';\n Logger.verbose(`预期的替换函数名: ${functionName}`);\n\n // 检查目录配置\n Logger.verbose(`输出目录: ${config.outputDir}`);\n if (config.tempDir) {\n Logger.verbose(`临时目录: ${config.tempDir}`);\n }\n\n Logger.verbose('配置一致性检查完成');\n }\n}","import { loadConfig, ConfigManager, ConfigValidator } from '../config';\nimport { Logger } from '../utils/logger';\nimport type { I18nConfig } from '../config';\n\ninterface CLIWrapperOptions<T> {\n configRequired?: boolean;\n validator?: (config: I18nConfig) => void;\n preProcess?: (options: T) => T;\n}\n\n/**\n * CLI统一包裹函数\n * 统一处理配置加载、验证、错误处理等逻辑\n */\nexport function withCLI<T extends Record<string, any>>(\n handler: (options: T, config: I18nConfig) => Promise<void>,\n wrapperOptions: CLIWrapperOptions<T> = {}\n) {\n return async (options: T) => {\n try {\n // 1. 参数预处理\n const processedOptions = wrapperOptions.preProcess?.(options) ?? options;\n \n // 2. 配置加载(统一在这里处理)\n let config: I18nConfig | null = null;\n if (wrapperOptions.configRequired !== false) {\n // 默认使用根目录下的配置文件\n const configPath = (processedOptions as any).config ?? './i18n.config.json';\n config = loadConfig(configPath);\n ConfigManager.init(config);\n \n // 3. 配置验证(统一在这里处理)\n const validation = ConfigValidator.validateConfigUsage();\n if (!validation.isValid) {\n Logger.error('配置验证失败,无法继续执行', 'minimal');\n process.exit(1);\n }\n ConfigValidator.checkConfigConsistency();\n }\n \n // 4. 执行自定义验证器(如果有)\n if (config && wrapperOptions.validator) {\n wrapperOptions.validator(config);\n }\n \n // 5. 执行业务逻辑\n await handler(processedOptions, config!);\n } catch (error) {\n Logger.error(`命令执行失败: ${error}`, 'minimal');\n process.exit(1);\n }\n };\n}"],"mappings":"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","names":["ensureDir","readFile","readJsonSync","readFile","ensureDir","fg","readJsonSync","readJsonSync"]}