i18n-xy
Version:
自动提取React项目中的中文字符串并进行国际化的CLI工具
475 lines (466 loc) • 15.8 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// main/index.ts
var index_exports = {};
__export(index_exports, {
ConfigManager: () => ConfigManager,
ConfigValidator: () => ConfigValidator,
Logger: () => Logger,
ensureDir: () => ensureDir2,
fileExists: () => fileExists,
findFiles: () => findFiles,
findTargetFiles: () => findTargetFiles,
loadConfig: () => loadConfig,
readFile: () => readFile2,
readJson: () => readJson,
readJsonSync: () => readJsonSync2,
withCLI: () => withCLI,
writeFile: () => writeFile,
writeFileWithTempDir: () => writeFileWithTempDir,
writeJson: () => writeJson
});
module.exports = __toCommonJS(index_exports);
// main/config/index.ts
var import_lodash = require("lodash");
// main/config/defaults.ts
var defaultConfig = {
// 基础语言配置
locale: "zh-CN",
displayLanguage: "en-US",
outputDir: "locales",
// tempDir: undefined, // 可选,不设置则直接修改源文件
// 文件处理配置
include: [
"src/**/*.{js,jsx,ts,tsx}"
],
exclude: [
"node_modules/**",
"dist/**",
"build/**",
"**/*.test.{js,jsx,ts,tsx}",
"**/*.spec.{js,jsx,ts,tsx}"
],
// Key 生成配置
keyGeneration: {
maxChineseLength: 10,
// 最大汉字长度
hashLength: 6,
// 哈希长度
maxRetryCount: 5,
// 最大重试次数
reuseExistingKey: true,
// 默认重复使用相同文案的key
duplicateKeySuffix: "hash",
// 重复key后缀模式,默认hash
keyPrefix: "",
// key前缀,默认为空
separator: "_",
// 连接符,默认下划线
pinyinOptions: {
// 拼音转换选项
toneType: "none",
// 不带声调
type: "array"
// 返回数组格式
}
},
// 输出配置
output: {
prettyJson: true,
// 格式化 JSON 输出
localeFileName: "{locale}.json"
// 语言文件名格式
},
// 日志配置
logging: {
enabled: true,
// 默认启用日志
level: "normal"
// 默认正常级别
},
// 替换配置
replacement: {
functionName: "$t",
// 默认替换函数名
quoteType: "single",
// 默认使用单引号
useOriginalTextAsKey: false,
// 默认使用生成的key
templateString: {
enabled: true,
// 默认启用模板字符串智能处理
preserveExpressions: true,
// 默认保留原始表达式
splitStrategy: "smart"
// 默认智能拆分策略
},
autoImport: {
enabled: false,
// 默认不启用自动引入
insertPosition: "afterImports",
// 默认在import语句后插入
imports: {}
}
},
// 翻译配置
translation: {
enabled: false,
// 默认不启用翻译功能
provider: "baidu",
// 默认使用百度翻译
defaultSourceLang: "zh",
// 默认源语言:中文
defaultTargetLang: "en",
// 默认目标语言:英文
concurrency: 5,
// 默认并发数:5 (降低并发数避免API限制)
retryTimes: 3,
// 默认重试次数:3次(不包括第一次)
retryDelay: 1e3,
// 默认重试延迟:1秒
batchDelay: 500,
// 默认批次延迟:0.5秒
baidu: {
appid: "",
// 需要用户配置
key: ""
// 需要用户配置
}
}
};
// main/utils/fs.ts
var fs = __toESM(require("fs-extra"), 1);
var path = __toESM(require("path"), 1);
var import_fast_glob = __toESM(require("fast-glob"), 1);
function readFile2(filePath, encoding = "utf-8") {
const absPath = path.resolve(process.cwd(), filePath);
return fs.readFile(absPath, encoding);
}
function writeFile(filePath, data) {
const absPath = path.resolve(process.cwd(), filePath);
return fs.outputFile(absPath, data);
}
function writeFileWithTempDir(filePath, data, tempDir) {
let targetPath;
if (tempDir) {
const relativePath = path.relative(process.cwd(), filePath);
targetPath = path.resolve(process.cwd(), tempDir, relativePath);
} else {
targetPath = path.resolve(process.cwd(), filePath);
}
return fs.outputFile(targetPath, data);
}
function ensureDir2(dirPath) {
const absPath = path.resolve(process.cwd(), dirPath);
return fs.ensureDir(absPath);
}
function findFiles(pattern, options = {}) {
return (0, import_fast_glob.default)(pattern, { dot: true, ...options, cwd: process.cwd() });
}
function findTargetFiles(include, exclude = []) {
return (0, import_fast_glob.default)(include, { ignore: exclude, dot: true, cwd: process.cwd() });
}
function fileExists(filePath) {
const absPath = path.resolve(process.cwd(), filePath);
return fs.existsSync(absPath);
}
function readJsonSync2(filePath) {
const absPath = path.resolve(process.cwd(), filePath);
return fs.readJsonSync(absPath);
}
async function readJson(filePath, defaultValue) {
try {
const content = await readFile2(filePath, "utf-8");
return JSON.parse(content);
} catch (error) {
if (defaultValue !== void 0) {
return defaultValue;
}
throw error;
}
}
function writeJson(filePath, data, pretty = true) {
const content = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
return writeFile(filePath, content);
}
// main/utils/logger.ts
var Logger = class {
static temporaryLevel = null;
// 临时日志级别
static getLogLevel() {
var _a;
try {
if (this.temporaryLevel) {
return this.temporaryLevel;
}
const config = ConfigManager.get();
return ((_a = config.logging) == null ? void 0 : _a.level) ?? "normal";
} catch {
return "normal";
}
}
/**
* 临时设置日志级别(用于进度显示期间)
*/
static setTemporaryLevel(level) {
this.temporaryLevel = level;
}
static shouldLog(level) {
const currentLevel = this.getLogLevel();
if (currentLevel === "minimal") {
return level === "minimal";
} else if (currentLevel === "normal") {
return level !== "verbose";
} else if (currentLevel === "verbose") {
return true;
}
return false;
}
static success(message, level = "normal") {
if (this.shouldLog(level)) {
console.log(`\u2705 ${message}`);
}
}
static info(message, level = "normal") {
if (this.shouldLog(level)) {
console.log(`\u2139\uFE0F ${message}`);
}
}
static warn(message, level = "normal") {
if (this.shouldLog(level)) {
console.warn(`\u26A0\uFE0F ${message}`);
}
}
static error(message, level = "normal") {
if (this.shouldLog(level)) {
console.error(`\u274C ${message}`);
}
}
static verbose(message) {
this.info(message, "verbose");
}
};
// main/config/manager.ts
var ConfigManagerClass = class {
config = null;
init(config) {
this.config = config;
}
get() {
if (!this.config) {
throw new Error("ConfigManager: config not initialized!");
}
return this.config;
}
reset() {
this.config = null;
}
isInitialized() {
return this.config !== null;
}
};
var ConfigManager = new ConfigManagerClass();
// main/config/validator.ts
var ConfigValidator = class {
/**
* 检查配置的一致性和完整性
*/
static validateConfigUsage() {
var _a, _b, _c, _d, _e;
const errors = [];
const warnings = [];
try {
const config = ConfigManager.get();
if (!config.include || config.include.length === 0) {
errors.push("\u914D\u7F6E\u9879 include \u4E0D\u80FD\u4E3A\u7A7A");
}
if (!config.outputDir) {
errors.push("\u914D\u7F6E\u9879 outputDir \u4E0D\u80FD\u4E3A\u7A7A");
}
if (!config.locale) {
errors.push("\u914D\u7F6E\u9879 locale \u4E0D\u80FD\u4E3A\u7A7A");
}
if ((_a = config.translation) == null ? void 0 : _a.enabled) {
if (!config.translation.provider) {
errors.push("\u542F\u7528\u7FFB\u8BD1\u65F6\u5FC5\u987B\u6307\u5B9A provider");
}
if (config.translation.provider === "baidu") {
if (!((_b = config.translation.baidu) == null ? void 0 : _b.appid) || !((_c = config.translation.baidu) == null ? void 0 : _c.key)) {
warnings.push("\u767E\u5EA6\u7FFB\u8BD1\u670D\u52A1\u7F3A\u5C11 appid \u6216 key \u914D\u7F6E");
}
}
}
if (config.keyGeneration) {
if (config.keyGeneration.maxChineseLength && config.keyGeneration.maxChineseLength <= 0) {
warnings.push("maxChineseLength \u5E94\u8BE5\u5927\u4E8E0");
}
if (config.keyGeneration.hashLength && config.keyGeneration.hashLength <= 0) {
warnings.push("hashLength \u5E94\u8BE5\u5927\u4E8E0");
}
}
if (((_d = config.logging) == null ? void 0 : _d.level) && !["minimal", "normal", "verbose"].includes(config.logging.level)) {
errors.push("logging.level \u5FC5\u987B\u662F minimal\u3001normal \u6216 verbose \u4E4B\u4E00");
}
if (((_e = config.output) == null ? void 0 : _e.localeFileName) && !config.output.localeFileName.includes("{locale}")) {
warnings.push("localeFileName \u5EFA\u8BAE\u5305\u542B {locale} \u5360\u4F4D\u7B26");
}
} catch (error) {
errors.push(`\u914D\u7F6E\u68C0\u67E5\u65F6\u53D1\u751F\u9519\u8BEF: ${error}`);
}
const isValid = errors.length === 0;
if (!isValid) {
Logger.error("\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25:", "minimal");
errors.forEach((error) => Logger.error(` - ${error}`, "minimal"));
}
if (warnings.length > 0) {
Logger.warn("\u914D\u7F6E\u8B66\u544A:", "normal");
warnings.forEach((warning) => Logger.warn(` - ${warning}`, "normal"));
}
return { isValid, errors, warnings };
}
/**
* 检查是否存在配置与代码不一致的问题
*/
static checkConfigConsistency() {
var _a, _b;
const config = ConfigManager.get();
Logger.verbose("\u68C0\u67E5\u914D\u7F6E\u4E00\u81F4\u6027...");
const expectedFileName = (((_a = config.output) == null ? void 0 : _a.localeFileName) ?? "{locale}.json").replace(
"{locale}",
config.locale
);
Logger.verbose(`\u9884\u671F\u7684\u8BED\u8A00\u6587\u4EF6\u540D: ${expectedFileName}`);
const functionName = ((_b = config.replacement) == null ? void 0 : _b.functionName) ?? "$t";
Logger.verbose(`\u9884\u671F\u7684\u66FF\u6362\u51FD\u6570\u540D: ${functionName}`);
Logger.verbose(`\u8F93\u51FA\u76EE\u5F55: ${config.outputDir}`);
if (config.tempDir) {
Logger.verbose(`\u4E34\u65F6\u76EE\u5F55: ${config.tempDir}`);
}
Logger.verbose("\u914D\u7F6E\u4E00\u81F4\u6027\u68C0\u67E5\u5B8C\u6210");
}
};
// main/config/index.ts
function validateConfig(config) {
var _a, _b, _c, _d;
const errors = [];
if (!config.include || !Array.isArray(config.include) || config.include.length === 0) {
errors.push("include \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u6570\u7EC4");
}
if (!config.outputDir || typeof config.outputDir !== "string") {
errors.push("outputDir \u5B57\u6BB5\u5FC5\u987B\u662F\u6709\u6548\u7684\u5B57\u7B26\u4E32\u8DEF\u5F84");
}
if (!config.locale || typeof config.locale !== "string") {
errors.push("locale \u5B57\u6BB5\u5FC5\u987B\u662F\u6709\u6548\u7684\u8BED\u8A00\u4EE3\u7801");
}
if ((_a = config.translation) == null ? void 0 : _a.enabled) {
if (!config.translation.provider) {
errors.push("\u542F\u7528\u7FFB\u8BD1\u65F6\u5FC5\u987B\u6307\u5B9A translation.provider");
}
if (config.translation.provider === "baidu") {
if (!((_b = config.translation.baidu) == null ? void 0 : _b.appid) || !((_c = config.translation.baidu) == null ? void 0 : _c.key)) {
errors.push("\u4F7F\u7528\u767E\u5EA6\u7FFB\u8BD1\u65F6\u5FC5\u987B\u914D\u7F6E translation.baidu.appid \u548C translation.baidu.key");
}
}
}
if (((_d = config.logging) == null ? void 0 : _d.level) && !["minimal", "normal", "verbose"].includes(config.logging.level)) {
errors.push("logging.level \u5FC5\u987B\u662F minimal\u3001normal \u6216 verbose \u4E4B\u4E00");
}
if (errors.length > 0) {
Logger.error("\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25:", "minimal");
errors.forEach((error) => Logger.error(` - ${error}`, "minimal"));
throw new Error(`\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25: ${errors.join("; ")}`);
}
}
function loadConfig(customConfigPath) {
let userConfig = {};
if (customConfigPath) {
if (fileExists(customConfigPath)) {
Logger.verbose(`\u52A0\u8F7D\u914D\u7F6E\u6587\u4EF6: ${customConfigPath}`);
try {
userConfig = readJsonSync2(customConfigPath);
Logger.verbose("\u914D\u7F6E\u6587\u4EF6\u52A0\u8F7D\u6210\u529F");
} catch (error) {
throw new Error(`\u914D\u7F6E\u6587\u4EF6\u89E3\u6790\u5931\u8D25: ${error}`);
}
} else {
Logger.warn(`\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728: ${customConfigPath}\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E`);
}
}
const finalConfig = (0, import_lodash.merge)({}, defaultConfig, userConfig);
validateConfig(finalConfig);
Logger.verbose("\u914D\u7F6E\u9A8C\u8BC1\u901A\u8FC7");
return finalConfig;
}
// main/cli/wrapper.ts
function withCLI(handler, wrapperOptions = {}) {
return async (options) => {
var _a;
try {
const processedOptions = ((_a = wrapperOptions.preProcess) == null ? void 0 : _a.call(wrapperOptions, options)) ?? options;
let config = null;
if (wrapperOptions.configRequired !== false) {
const configPath = processedOptions.config ?? "./i18n.config.json";
config = loadConfig(configPath);
ConfigManager.init(config);
const validation = ConfigValidator.validateConfigUsage();
if (!validation.isValid) {
Logger.error("\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25\uFF0C\u65E0\u6CD5\u7EE7\u7EED\u6267\u884C", "minimal");
process.exit(1);
}
ConfigValidator.checkConfigConsistency();
}
if (config && wrapperOptions.validator) {
wrapperOptions.validator(config);
}
await handler(processedOptions, config);
} catch (error) {
Logger.error(`\u547D\u4EE4\u6267\u884C\u5931\u8D25: ${error}`, "minimal");
process.exit(1);
}
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ConfigManager,
ConfigValidator,
Logger,
ensureDir,
fileExists,
findFiles,
findTargetFiles,
loadConfig,
readFile,
readJson,
readJsonSync,
withCLI,
writeFile,
writeFileWithTempDir,
writeJson
});
//# sourceMappingURL=index.cjs.map