最懒的前端多语言策略(一)

2019-01-14  本文已影响0人  你的时间非常值钱

github地址
https://github.com/wjjhhh/Translatejs.git

以往的方式都是先写一个默认简体中文json(或一个不正规的object),到时翻译人员把一个个json复制编写成各种语言的json,前端动态判断映射到哪个语言的json,然后一个个key映射到所写json的value
键值对应(中文key是因为懒得命名)

看到键值相同(最讨厌写多余代码),然后我又只想把工作量都交给翻译,就连默认的简体中文的翻译表都不想写

首先想到有什么方法可以让对象的值自动等于键,马上想到用defineProperty做数据劫持使用对象的访问器属性马上返回属性值,好,开工

// const lang = {}
  Object.defineProperty(lang, ???, {})

不知道属性的啊,因为我懒得初始化赋值给lang

于是我想起了es6的Proxy(下面称代理方法),直接上代码

// 代理的逻辑最好放初始化地方,这里只是方便演示
 const trans= new Proxy({},{
   get: function(obj, prop) {
     return obj[prop] || prop
   }
 })

 export default () => <div>{trans['首页23123123']}</div>
显示正常
完成最简单的部分,有默认值了,然后用nodejs根据所选目录,扒下目录下所有文件的包含trans对象的属性(严谨点是要排除一些不必要扒的文件),生成语言的json模板,执行的主体逻辑如下(时间关系,注释会慢慢添加)
const fs = require('fs')
const readline = require('readline')
const path = require('path')

const reg = /(trans\(.*\))/gi
const dispose = /\/\//
const obj = {}
const separator = 'lang[' // 分隔符
const suffix = ['.js', '.jsx'] // 后缀白名单
// const ignore = ['./pages']
const entry = './src/pages' // 入口
const output = './src/lang/' // 输出路径
const outputFile = `${output}en.json`
let increment = process.argv[2] !== 'new' // 是否增量生成
console.log('-----start-----')
let readNum = 0

function readFileToObj(fReadName, value, callback) {
  var fRead = fs.createReadStream(fReadName)
  var objReadline = readline.createInterface({
    input: fRead,
  });

  objReadline.on('line', line => {
    // 注释的忽略
    if (line.includes('//') || line.includes('*')) {
      return
    }
    if (line) {
      const arr = line.split(separator)
      if (arr.length > 1) {
        const bb = arr.slice(1)
        for (let i in bb) {
          const v0 = bb[i].split(']')[0]
          const v = v0.substr(1, v0.length - 2)
          if (!v) {
            // 空输出提示
            console.warn(`空行为:${line}`)
            continue
          }
          // 增量就不覆盖了
          if (increment && value && value[v]) {
            obj[v] = value[v]
          } else {
            obj[v] = v
          }

        }
      }
    }
  })
  objReadline.on('close', () => {
    if (--readNum === 0) {
      let result = JSON.stringify(obj, null, 2)
      fs.writeFile(outputFile, result, err => {
        if (err) {
          console.warn(err)
        }
      })
      callback && callback()
    }
  })
}


const filePath = path.resolve(entry)

// 递归执行,直到判断是文件就执行readFileToObj
function fileDisplay(filePath, value, callback) {
  fs.readdir(filePath, (err, files) => {
    let count = 0
    function checkEnd() {
      if (++count === files.length && callback) {
        callback()
      }
    }
    if (err) {
      console.warn(err)
    } else {
      files.forEach(filename => {
        var fileDir = path.join(filePath, filename)
        fs.stat(fileDir, (err2, status) => {
          if (err2) {
            console.warn(err2)
          } else {
            if (status.isDirectory()) {
              return fileDisplay(fileDir, value, checkEnd)
            }
            else if (status.isFile()) {
              // 后缀不符合的跳过
              if (!suffix.includes(path.extname(fileDir))) {
                // return
              } else {
                readNum++
                readFileToObj(fileDir, value)
              }
            }
            checkEnd()
          }
        })
      })
    }
  })


}


// 开始逻辑
function run() {
  new Promise((resolve, reject) => {
    fs.exists(outputFile, exists => {
      // 存在且增量生成
      if (exists && increment) {
        console.log('增量更新')
        fs.readFile(outputFile, 'utf-8', (err, data) => {
          if (err) {
            console.warn(err)
          } else {
            try {
              // 旧文件已存在的json
              const json = JSON.parse(data)
              // console.log(json)
              resolve(json)
            } catch (e) {
              // 翻车
              console.warn(e)
              errDeal(resolve).then(res => {
                resolve()
              })
            }
          }
        })
      } else {
        console.log('全量更新')
        resolve()
      }
    })
  }).then(value => {
    let startTime = Date.now()
    fileDisplay(filePath, value, function (value) {
      console.log('finish:', Date.now() - startTime)
    })
  })


}

// 异常处理
function errDeal(resolve) {
  const tips = '出现异常情况1.重新全量生成2.放弃\n'
  return new Promise(resolve2 => {
    const r1 = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
    })
    r1.question(tips, (answer) => {
      r1.close()
      if (answer == 1) {
        console.log('重新')
        resolve2(resolve)
        // process.exit()
      } else if (answer == 2) {
        console.log('放弃')
        process.exit()
      } else {
        // resolve()
        errDeal(resolve)
      }
    })
  }).then(r => {
    return resolve
  })
}


run()


生成的json模板 得闲饮茶

github地址

上一篇下一篇

猜你喜欢

热点阅读