Node - 国际化JSON key值去重 + JSON文件转Excel

1、转excel需要用到 xlsx 

转excel的方法

const XLSX = require("xlsx");

// 将 JSON 转换为适合 Excel 的数据格式(数组)
/**
 * 将 JSON 对象转换为数组格式
 * @param {Object} jsonObj - 需要转换的 JSON 对象
 * @returns {Array<Object>} 转换后的数组,每个元素包含 key值 和 翻译结果 两个属性
 * @description 遍历 JSON 对象的所有属性,将每个键值对转换为包含 key值 和 翻译结果 的对象,并存入数组中
 */
function convertJSONToArray(jsonObj) {
  const result = [];
  for (const key in jsonObj) {
    if (jsonObj.hasOwnProperty(key)) {
      result.push({
        key值: key,
        翻译结果: jsonObj[key],
      });
    }
  }
  return result;
}

// 将 JSON 转换为 Excel
/**
 * 将 JSON 对象转换为 Excel 文件并保存
 * @param {Object} jsonObj - 需要转换的 JSON 对象
 * @param {string} outputFilePath - 输出的 Excel 文件路径
 * @description 将传入的 JSON 对象转换为数组格式,然后创建 Excel 工作簿并写入数据,最后保存为指定路径的 Excel 文件
 */
const workbook = XLSX.utils.book_new();
function convertJSONToExcel(jsonObj, outputFilePath, sheetName) {
  const dataArray = convertJSONToArray(jsonObj);
  const worksheet = XLSX.utils.json_to_sheet(dataArray);
  XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
  XLSX.writeFile(workbook, outputFilePath);
  console.log("Excel file written successfully");
}

module.exports = {
  convertJSONToExcel,
};

2、去重方法已经读写 JSON,生成新的国际化JSON文件

const fs = require("fs");
const axios = require("axios");
const convertJSONToExcel = require("./transformExcel.js");

// 读取 JSON 文件
/**
 * 读取并解析 JSON 文件内容
 * @param {string} filePath - JSON 文件的路径
 * @returns {Object|null} 返回解析后的 JSON 对象,如果读取或解析失败则返回 null
 */
function readJSONFile(filePath, isRepeat = false) {
  try {
    // "utf8" 参数确保返回字符串而非 buffer
    const data = fs.readFileSync(filePath, "utf8");
    if (isRepeat) {
      // 做去重操作
      // result 是去重后的结果
      // duplicates key是国际化中重复了的值,value是国际化中重复值对应的key; 项目中如果要统一国际化JSON 需要根据这个手动全局搜索替换一下
      const { result, duplicates } = transformJSON(JSON.parse(data));
      return { result, duplicates };
    } else {
      return JSON.parse(data);
    }
  } catch (error) {
    console.error("Error reading file:", error);
    return null;
  }
}

// 提取 JSON 对象中的值
function extractValues(jsonObj) {
  const values = [];
  for (const key in jsonObj) {
    if (jsonObj.hasOwnProperty(key)) {
      values.push(jsonObj[key]);
    }
  }
  return values;
}

// 调用翻译接口
/**
 * 将文本数组批量翻译成多种目标语言
 * @param {string[]} values - 需要翻译的文本数组
 * @returns {Promise<Object>} 返回包含翻译结果的对象,格式为 {de: [], fr: [], it: [], ja: [], es: [], ko: [], th: []}
 * @description
 * - 将输入文本按每批10条进行分组
 * - 并行调用翻译接口进行批量翻译
 * - 支持德语(de)、法语(fr)、意大利语(it)、日语(ja)、西班牙语(es)、韩语(ko)、泰语(th)
 * - 如果某批翻译失败,将保留原文本内容
 */
async function translateValues(values) {
  let translatedValues = {
    de: [],
    fr: [],
    it: [],
    ja: [],
    es: [],
    ko: [],
    th: [],
  };
  const batchSize = 10;
  const batches = [];
  for (let i = 0; i < values.length; i += batchSize) {
    const batch = values.slice(i, i + batchSize);
    batches.push(batch);
  }
  const results = await Promise.allSettled(
    batches.map((batch) => {
      return axios
        .post(
          "接口名",
          {
            access_token:
              "xxx",
            source_text: batch,
            target_language: ["de", "fr", "it", "ja", "es", "ko", "th"],
          }
        )
        .then((response) => response.data.data.translate)
        .catch((error) => {
          console.log("接口错误", batch);
          // console.error("Error translating batch:", batch, error);
          // 若翻译出错,保留原内容
          return batch;
        });
    })
  );
  const translatedBatches = results.map((result) =>
    result.status === "fulfilled" ? result.value : result.reason
  );
  translatedBatches.map((item) => {
    if (Array.isArray(item)) {
      Object.keys(translatedValues).forEach((key) => {
        translatedValues[key] = [...translatedValues[key], ...item];
      });
    } else {
      Object.keys(item).forEach((key) => {
        translatedValues[key] = [...translatedValues[key], ...item[key]];
      });
    }
  });
  return translatedValues;
}

// 更新 JSON 对象
/**
 * 更新 JSON 对象中的值
 * @param {Object} jsonObj - 需要更新的 JSON 对象
 * @param {Array} translatedValues - 新的翻译值数组
 * @returns {Object} 更新后的 JSON 对象
 * @description 将传入的翻译值数组按顺序替换 JSON 对象中对应 key 的值
 */
function updateJSONValues(jsonObj, translatedValues) {
  const keys = Object.keys(jsonObj);
  for (let i = 0; i < keys.length; i++) {
    jsonObj[keys[i]] = translatedValues[i];
  }
  return jsonObj;
}

// 追加更新后的 JSON 对象到原文件
/**
 * 将 JSON 对象写入指定文件
 * @param {string} filePath - 文件路径
 * @param {Object} jsonObj - 要写入的 JSON 对象
 * @throws {Error} 写入文件失败时抛出错误
 */
function writeJSONFile(filePath, jsonObj) {
  try {
    return new Promise((resolve, reject) => {
      // 将 JSON 对象格式化为带缩进(2空格)的字符串,提升可读性。
      const data = JSON.stringify(jsonObj, null, 2);
      // fs.writeFileSync(filePath, data, "utf8");
      fs.writeFile(filePath, data, (err) => {
        if (err) {
          console.error("文件写入失败:", err);
        } else {
          resolve(true);
        }
      });
    });
  } catch (error) {
    console.error("Error writing file:", error);
  }
}

/**
 * 转换 JSON 对象,处理重复值的情况
 * @param {Object} jsonObj - 输入的 JSON 对象
 * @returns {Object} 返回包含两个属性的对象:
 *   - result: 不含重复值的对象
 *   - duplicates: 包含重复值的键名映射
 * @example
 * const input = { a: 1, b: 2, c: 1 };
 * transformJSON(input);
 * // 返回: {
 * //   result: { a: 1, b: 2 },
 * //   duplicates: { '1': ['a', 'c'] }
 * // }
 */
function transformJSON(jsonObj) {
  const valueToKey = {};
  const result = {};
  const duplicates = {};
  for (const key in jsonObj) {
    if (jsonObj.hasOwnProperty(key)) {
      const value = jsonObj[key];
      if (valueToKey[value]) {
        if (!duplicates[value]) {
          duplicates[value] = [valueToKey[value]];
        }
        duplicates[value].push(key);
      } else {
        valueToKey[value] = key;
        result[key] = value;
      }
    }
  }
  return { result, duplicates };
}

// 主函数
/**
 * 主函数,用于处理 JSON 文件的翻译流程
 * 1. 读取中文源文件 zh_CN.json
 * 2. 提取需要翻译的值
 * 3. 调用翻译接口进行翻译
 * 4. 将翻译结果更新到原 JSON 结构中
 * 5. 将结果保存到不同的目标语言文件
 *
 * @async
 * @function main
 * @returns {Promise<void>}
 */
async function main() {
  const inputFilePath = "zh_CN.json";

  const { result: inputJSON, duplicates } = readJSONFile(inputFilePath, true);

  if (inputJSON) {
    const values = extractValues(inputJSON);
    const translatedValues = await translateValues(values);
    await writeJSONFile(`结果/repeat.json`, duplicates);
    for (let i in translatedValues) {
      const newTranslateValues = translatedValues[i];
      const updatedJSON = updateJSONValues(inputJSON, newTranslateValues);
      const writeResult = await writeJSONFile(`结果/${i}.json`, updatedJSON);
      if (writeResult) {
        const transFormJSON = readJSONFile(`结果/${i}.json`);
        if (transFormJSON) {
          convertJSONToExcel.convertJSONToExcel(
            transFormJSON,
            `excel文件/全部.xlsx`,
            i
          );
        }
      }
    }
  }
}

// 调用主函数
main();

 

posted @ 2025-03-10 18:57  敲代码的树先生  阅读(53)  评论(0)    收藏  举报