背景:文档中心需要接入国际化,想节省时间做统一英文方案处理;
文档中心是基于vuepress
框架编写的;
1、利用百度翻译 API 的接口去做底层翻译处理,https://api.fanyi.baidu.com/需要在该平台上注册账号,个人高级版免费,每个月有百万字符容量;
2、利用 Node.js 模块遍历相应的目录的文件,对每一行中文进行翻译,然后替换原内容;
3、将替换好的内容写入到新的 en 目录下的文件里,如果无该目录,且自动创建该目录;
4、修改配置 config.js 添加语言切换的入口,将不同的文件内容放到语言下面;
5、查找中文并翻译的转化文件baiduFanyi.mjs
import fs, { stat } from 'fs'
import path, { resolve } from 'path'
import md5 from 'md5'
import axios from 'axios'
// 百度翻译接口
const requestTranslate = q => {
const apiUrl = 'http://fanyi-api.baidu.com/api/trans/vip/translate'
const appid = '20230731001763594'
const secret = 'R0netNArlgX8YewM9ECl'
const salt = Math.random()
const sign = md5(appid + q + salt + secret)
const params = {
q,
from: 'zh',
to: 'en',
salt,
appid,
sign
}
return axios.get(apiUrl, {
params
})
}
// 获取所有文件
const getListFile = dir => {
let list = []
let arr = fs.readdirSync(dir)
arr.forEach(item => {
let fullpath = path.join(dir, item)
let stats = fs.statSync(fullpath)
if (stats.isDirectory()) {
list = list.concat(getListFile(fullpath))
} else if (fullpath.lastIndexOf('.md') > -1) {
// 指定的md文件后缀
list.push(fullpath.slice(0))
}
})
return list
}
/**
* 读取路径信息
* @param {string} path 路径
*/
function getStat(path) {
return new Promise((resolve, reject) => {
fs.stat(path, (err, stats) => {
if (err) {
resolve(false)
} else {
resolve(stats)
}
})
})
}
/**
* 创建路径
* @param {string} dir 路径
*/
function mkdir(dir) {
return new Promise((resolve, reject) => {
fs.mkdir(dir, err => {
if (err) {
resolve(false)
} else {
resolve(true)
}
})
})
}
/**
* 路径是否存在,不存在则创建
* @param {string} dir 路径
*/
async function dirExists(dir) {
let isExists = await getStat(dir)
// 如果该路径且不是文件,返回true
if (isExists && isExists.isDirectory()) {
return true
} else if (isExists) {
// 如果该路径存在但是文件,返回false
return false
}
// 如果该路径不存在
let tempDir = path.parse(dir).dir // 拿到上级路径
// 递归判断,如果上级目录也不存在,则会代码会在此处继续循环执行,直到目录存在
let status = await dirExists(tempDir)
let mkdirStatus
if (status) {
mkdirStatus = await mkdir(dir)
}
return mkdirStatus
}
// 要翻译的文件遍历,以中文为基础翻译
// const publicDir = ''
const publicPutDir = 'en'
// 需要遍历的文件夹
const dirPaths = [
`agreement`,
`FAQ`,
`instructions`,
`lbs`,
`openapi`,
`simCardRecharge`,
`README.md`
]
// 获取所有的文件列表
let allFiles = []
const getAllFile = () => {
for (let i = 0, len = dirPaths.length; i < len; i++) {
let stats = fs.statSync(dirPaths[i])
if (stats.isDirectory()) {
const filePaths = getListFile(dirPaths[i])
allFiles = [...allFiles, ...filePaths]
} else {
allFiles.push(dirPaths[i])
}
}
}
getAllFile()
console.log(allFiles, '\n', '翻译中...')
let allContent = []
// 遍历文件内容翻译,然后写入指定的文件中
const translateAndWrite = async () => {
// 遍历每个文件路径
for (let i = 0, len = allFiles.length; i < len; i++) {
const item = allFiles[i]
// const fileName = path.basename(item, path.extname(item)) // 文件名
const fullName = path.basename(item) // 文件全称加后缀
const dirName = path.dirname(item) // 文件目录
// let inputFullFile = publicDir + item
// 读取当前文件的内容
let content = fs.readFileSync(item, 'utf8')
// 创建空字符串变量存放合并后的内容
let mergedContent = ''
let newContent = content.split('\n')
let reg =
/([\u4e00-\u9fa5]+\s*\S*[^|]\s*\S*[\u4e00-\u9fa5]+)|([\u4e00-\u9fa5]+)/gu
let transTextArr = newContent.reduce((prev, cur, index, arr) => {
cur = cur.trim()
if (cur && cur.match(reg)) {
return prev.concat(cur.match(reg))
} else {
return prev
}
}, [])
console.log('需要翻译的文本', transTextArr)
allContent = [...allContent, ...transTextArr]
// 修改图片的路径
content = content.replace(/..\/\.vuepress/g, '../../.vuepress')
mergedContent = content
for (let i = 0, len = transTextArr.length; i < len; i++) {
let { data } = await requestTranslate(transTextArr[i])
data.trans_result.forEach(d => {
mergedContent = mergedContent.replace(d.src, d.dst)
})
}
let outputDir = `${publicPutDir}/${dirName}`
// 创建文件夹
await dirExists(outputDir)
let outputFile = `${outputDir}/${fullName}`
// 写文件内容
fs.writeFileSync(outputFile, mergedContent)
console.log(`已成功将${item}翻译为${outputFile}\n`)
}
}
await translateAndWrite()
console.log('本次需要翻译的总字数', allContent.join('').length)
// 像视频类的标签需要手动修改回来