技术栈:JavaScript + fs + xlsx.js
简介
前篇: Vue-i18n国际化多语言-在线表格翻译
结合本博客之前的国际化多语言的实现与实际业务场景,意识到人工在项目中手动配置、替换多语言花费的人力成本较高,于是衍生出其他的管理方案,解放双手,核心原理就是多语言配置文件与 Excel 文件相互转换、文件读写。
- 导出:输入多语言配置数据,输出 Excel文件
- 导入: 输入Excel文件,输出多语言配置数据文件
- 管理:Excel文件,可采用本地或者云管理。至于在线编辑的功能,就是将Excel文件在在线平台导入导出即可。
因为Vika单词插入记录最多10条,此处就不演示直接与Vika进行多语言管理的实现,代码在博主本地,有需要的可以私。
实现
数据结构
本篇代码适用于双层嵌套的对象多语言配置文本,每个语种为一个文件。
{
module1: {
label1: "123",
label2: "qwe",
},
module2: {
label1: "345",
label2: "7788",
},
}
例如法语的配置文件为:
安装
涉及到 Excel 的解析和文件读写,就分别需要xlsx、fs这两个插件。
npm install xlsx --save
npm install fs --save
# or
yarn add xls
yarn add fs
导出Excel
import XLSX from 'xlsx'
import zh from '../lang/web/zh.js'
import en from '../lang/web/en.js'
import fr from '../lang/web/fr.js'
// 判断数据是否非undefined,因为可能漏配了
const notUndefined = (data) => {
return !(typeof data === 'undefined')
}
/** 将深层嵌套对象扁平化,对象转数组(以中文为标准,进行补全) */
const objsToExcelData = () => {
const resArr = []
const keysWrapper = Object.keys(zh) // 外层label
keysWrapper.forEach((keyWrap) => {
if (typeof zh[keyWrap] === 'object') {
const keysInner = Object.keys(zh[keyWrap]) // 内层label
typeof zh[keyWrap] === 'object' &&
keysInner.forEach((keyInn) => {
const obj = {
LabelWrapper: keyWrap,
LabelInner: keyInn,
zh: zh[keyWrap][keyInn], // 中文
en: en[keyWrap] && notUndefined(en[keyWrap][keyInn]) ? en[keyWrap][keyInn] : '', // 英文
fr: fr[keyWrap] && notUndefined(en[keyWrap][keyInn]) ? fr[keyWrap][keyInn] : '' // 法语
}
resArr.push(obj)
})
}
})
console.log(resArr)
return resArr
}
/** 将数据解析成Excel格式并导出 */
const exportToExcel = (data) => {
const worksheet = XLSX.utils.json_to_sheet(data) // json数据转Excel表
const workbook = XLSX.utils.book_new() // 新建Excel文件
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1') // 将表添加到EXCEL文件
XLSX.writeFile(workbook, 'exported-data.xlsx') // 导出
}
导入Excel
import * as fs from 'fs'
import XLSX from 'xlsx'
const chartLangLabels = ['zh', 'en', 'fr'] // 表格语言对应的label字段
/** 获取excel数据并解析 */
const getExcelData = (url) => {
const workBook = XLSX.readFile(url) // 目标文件获取
let name = workBook.SheetNames[0] // 读取表格中第一个表
let sheet = workBook.Sheets[name] // 数据获取
console.log(XLSX.utils.sheet_to_json(sheet)) // 数据格式转换
return XLSX.utils.sheet_to_json(sheet)
}
/** 处理excel表格的数据 */
const handleExcelData = (data) => {
// 目标数据结构, 类似于 { zh:{} ,en: {}, fr: {}}
const resData = {}
chartLangLabels.forEach((langLabel) => {
resData[langLabel] = {}
})
data.forEach((item) => {
const labelWrapper = item.LabelWrapper // LabelWrapper 外层label,业务模块
const labelInner = item.LabelInner // LabelInner 内层label(因为有多个业务模块 所以加了一层嵌套)
chartLangLabels.forEach((currLang) => {
if (!resData[currLang][labelWrapper]) resData[currLang][labelWrapper] = {} // 业务模块多语言undefined时,创建{}
resData[currLang][labelWrapper][labelInner] = item[currLang]
})
})
return resData
}
/** 读写数据 */
const writeData = (targetData) => {
chartLangLabels.forEach((lang) => {
let str = `export default {\n ${outputJSONString(targetData[lang], undefined, 4)}}`
// 文件写入,文件名与chartLangLabels内保持一致
fs.writeFile(`./src/lang/web/${lang}.js`, str, 'utf-8', function (err) {
if (err) {
console.log(lang + '写文件操作失败')
console.log(err)
} else console.log(lang + '写文件操作成功')
})
})
}
应用
导出
const handleData = () => {
const data = objsToExcelData()
exportToExcel(data)
}
handleData()
导入
const handleImportData = () => {
let resData = getExcelData('./src/utils/lang.xlsx') // excel数据路径
const targetData = handleExcelData(resData) // 得到需要的数据结构
writeData(targetData) // 文件读写
}
handleImportData()
效果
导出的Excel文件结果
按照导出规则写入的js文件结果