如何在Nuxt中实现多语言批量翻译

529 阅读2分钟

在多语言的项目中,我们会遇到一个挺头疼的问题,那就是如何良好的去实现多语言的翻译,今天恰好写了个脚本,来总结一下,希望能帮到有需要的人~

1.新建一个工具类项目

先新建一个项目,取名为 translateTools,然后进行npm初始化

mkdir translateTools
cd translateTools
npm init -y

接着我们在根目录下,准备一个en.js文件,也就是需要进行翻译的源文件。

可以看到js中的结构,是各种嵌套的对象组合起来的,在实际的项目中,我们也不得不这样去写,这样才方便以后的维护。那么问题来了,如何将后面的英文 value,给批量翻译成我们想要的语言呢?

2. 良好的解决方案

首先,我们想一个事情,如果按照递归的方式去遍历这个对象,给对象最后的value调用翻译的接口,这种方案行不行。答案是可行的,但缺点是特别明显的,就是会阻塞。那么我们如何做到,每个翻译都不会发生阻塞呢?以下我分为几步来进行:

1. 先获取对象中所有value值的完整路径

2. 书写深拷贝,对象取值和设置值相关函数

当然了,我们还不能够对引入的en.js文件进行直接的修改,需要深拷贝一份,因为我们知道我们的目标数据比较简单且明确,所以可以先实现一个简易版的深拷贝。

然后书写对象取值和设置值的函数~

3.结合async模块,goolgle translate模块进行最后的操作

async模块能够更好地帮助我们去实现异步的操作,详见 npm地址

npm i async

import fs from 'fs'
import async from 'async'
import enFile from './locales/en.js'
import translate from '@imlinhanchao/google-translate-api'


// // 需要翻译的语种
const languageList = ['zh-cn','vi']

// 获取所有节点的完整路径
const allPaths = []

const visitNodes = (obj,stack = []) => {
  if (typeof obj === 'object' && obj !== null ) {
    for (let key in obj) {
      visitNodes(obj[key],[...stack, key]);
    }
  } else {
    allPaths.push(stack)
  }
}

visitNodes(enFile)

async.map(languageList,(language,done)=>{
  console.log('language: ', language);
  const originData = deepClone(enFile) // import enFile from './locales/en.js'
  function getPathValue(arr){
    let node = originData
    for (var i = 0; i < arr.length; i ++) {
      var key = arr[i];
      node = node[key];
    }
    return node;
  }
  
  function setPathValue(arr,value){
    let node = originData;
    for (var i = 0; i < arr.length - 1; i ++) {
      var key = arr[i];
      node = node[key];
    }
    node[arr[i]] = value;
    return value;
  }

  async.map(allPaths,(path,done)=>{  
    translate(getPathValue(path),{to: language}).then(res=>{
      setPathValue(path,res.text)
      done()
    })
  },()=>{
    fs.writeFile(`./output/${language}.js`,`export default ${JSON.stringify(originData)}`, function (err) {
      if (err) throw err;
      console.log(`${language}已经翻译成功`)
    })
  })
})


// 简易版深拷贝
function deepClone(source) {
  if (!source && typeof source !== 'object') {
    throw new Error('error arguments', 'deepClone')
  }
  const targetObj = source.constructor === Array ? [] : {}
  Object.keys(source).forEach(keys => {
    if (source[keys] && typeof source[keys] === 'object') {
      targetObj[keys] = deepClone(source[keys])
    } else {
      targetObj[keys] = source[keys]
    }
  })
  return targetObj
}

4.翻译结果

3.小结

因为该问题在网上的解决方案较少,我偏偏就喜欢写一些其他人少写的东西,这样才有意思。欢迎大佬们一起交流~