UNPKG

i18n-sheet-convert

Version:

一个用于在i18n JSON文件和Excel文件之间进行转换的工具

148 lines (147 loc) 5.47 kB
import fs from 'fs'; import path from 'path'; import xlsx from 'xlsx'; class I18nConverter { constructor(options) { this.localesPath = options.localesPath; this.outputPath = options.outputPath; // 确保输出目录存在 if (!fs.existsSync(this.outputPath)) { fs.mkdirSync(this.outputPath, { recursive: true }); } // 如果没有提供语言配置,则自动检测 if (!options.languages) { this.languages = this.detectLanguages(); } else { this.languages = options.languages; } } // 自动检测语言文件 detectLanguages() { const files = fs.readdirSync(this.localesPath); const languages = []; for (const file of files) { if (file.endsWith('.json')) { const code = file.replace('.json', ''); languages.push({ code, name: code // 使用文件名作为显示名称 }); } } if (languages.length === 0) { throw new Error('未在本地化目录中找到语言文件'); } return languages; } // 将扁平的对象转换为带有点符号的键 flattenObject(obj, prefix = '') { return Object.keys(obj).reduce((acc, key) => { const prefixedKey = prefix ? `${prefix}.${key}` : key; if (typeof obj[key] === 'object' && obj[key] !== null) { Object.assign(acc, this.flattenObject(obj[key], prefixedKey)); } else { acc[prefixedKey] = obj[key]; } return acc; }, {}); } // 将带点符号的键转换回嵌套对象 unflattenObject(obj) { const result = {}; for (const key in obj) { const keys = key.split('.'); let current = result; for (let i = 0; i < keys.length; i++) { const k = keys[i]; if (i === keys.length - 1) { current[k] = obj[key]; } else { current[k] = current[k] || {}; current = current[k]; } } } return result; } // JSON 转换为 Excel async jsonToExcel() { try { // 读取所有语言的 JSON 文件 const translations = {}; for (const lang of this.languages) { const content = JSON.parse(fs.readFileSync(path.join(this.localesPath, `${lang.code}.json`), 'utf8')); translations[lang.code] = this.flattenObject(content); } // 获取所有翻译键 const allKeys = new Set(); for (const langData of Object.values(translations)) { Object.keys(langData).forEach(key => allKeys.add(key)); } // 创建数据数组 const data = Array.from(allKeys).map(key => { const entry = { key }; for (const lang of this.languages) { entry[lang.code] = translations[lang.code][key] || ''; } return entry; }); // 创建工作簿 const wb = xlsx.utils.book_new(); const ws = xlsx.utils.json_to_sheet(data); // 设置列宽 const colWidths = [ { wch: 40 }, // 键名列宽 ...this.languages.map(() => ({ wch: 50 })) // 每种语言的列宽 ]; ws['!cols'] = colWidths; // 添加工作表到工作簿 xlsx.utils.book_append_sheet(wb, ws, '翻译'); // 写入文件 xlsx.writeFile(wb, path.join(this.outputPath, 'translations.xlsx')); console.log('Excel文件生成成功!'); } catch (error) { console.error('生成Excel文件时出错:', error); throw error; } } // Excel 转换为 JSON async excelToJson() { try { // 读取 Excel 文件 const workbook = xlsx.readFile(path.join(this.outputPath, 'translations.xlsx')); const worksheet = workbook.Sheets[workbook.SheetNames[0]]; const data = xlsx.utils.sheet_to_json(worksheet); // 为每种语言创建数据对象 const languageData = {}; for (const lang of this.languages) { languageData[lang.code] = {}; } // 填充数据 data.forEach((row) => { if (row.key) { for (const lang of this.languages) { if (row[lang.code]) { languageData[lang.code][row.key] = row[lang.code]; } } } }); // 转换回嵌套结构并写入文件 for (const lang of this.languages) { const jsonData = this.unflattenObject(languageData[lang.code]); fs.writeFileSync(path.join(this.localesPath, `${lang.code}.json`), JSON.stringify(jsonData, null, 2), 'utf8'); } console.log('JSON文件生成成功!'); } catch (error) { console.error('生成JSON文件时出错:', error); throw error; } } } export default I18nConverter;