美文网首页
最懒的前端多语言策略(一)

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

作者: 你的时间非常值钱 | 来源:发表于2019-01-14 21:32 被阅读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地址

    相关文章

      网友评论

          本文标题:最懒的前端多语言策略(一)

          本文链接:https://www.haomeiwen.com/subject/vmxsdqtx.html