阅读 2758

react 国际化方案react-i18n-auto,全自动化webpack+babel插件

react-i18n-auto具体使用方法,请移步至

react国际化目前现状——前言

国际化对于某些大型公司很常见的业务,他们基本也都有自己的一套国际化规范,但对于小公司而言可能并没有这些需求,平时也不太注重。如果有需求,通常解决的方法就是使用 react-intl ,react-i18next等一些现有的npm包。以下是我大致了解的方案,以react-intl为例,如下:

参考文档:react-intl 国际化 文档指引

方案一:React组件引用

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {IntlProvider, FormattedMessage} from 'react-intl';
...

ReactDOM.render(
  <IntlProvider locale="en">
    <App />
  </IntlProvider>,
  document.getElementById('container')
);)
复制代码

App.js

import {FormattedMessage} from 'react-intl';
...
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'Eric',
      unreadCount: 1000,
    };
  }
  render() {
    const {name, unreadCount} = this.state;
    return <p>
        <FormattedMessage id="welcome"
          defaultMessage={
            `Hello {name}, you have {unreadCount, number} 
             {unreadCount, plural, one {message} other {messages}}`
          } values={{name: <b>{name}</b>, unreadCount}}/>
    </p>
  }
}
复制代码

看出来了吗?如果你没有学习过,你根本不会知道上面的属性代表着什么,这样的国际化已经变了原有的页面结构,而且每用到一处就得改动对应的代码,及其繁琐。

方案二:函数式调用

import React, {Component} from 'react';
import locale from './resources/locale';
import t from 'xxx';
...
class App extends Component {
  render() {
    return <div>
        <header>{ t.i18n('我是要翻译的内容') }</header>
        <div>{ t.text(locale.a.b) }</div> //这是我另一处要翻译的内容
    </div>
  }
}

复制代码
// resources语言包结构
const locale = {
    a:{
        b:'这是我另一处要翻译的内容',
        c:'ccc',
        d:'xxx',
        ...
    }
    ...
}

复制代码

这是通过函数调用的思路来实现的,这种不会对react的层级结构有太大影响,也相对灵活,其痛点在于语言包文件管理时命名让人很头痛,几十个翻译字段还好。想一想你有个项目有几千个翻译字段,而且还是一个老项目,一个个字段取名,然后在翻译到对应的页面上,香不香?这种方法不仅有可能会遗漏,还可能会出错。

对于目前已有的国际化方案,先抛开学习成本不说,立马上手,做一个国际化项目大概需要多久呢?一天?一周?还是一个月?,我的答案是基本在一周以上,对于紧急的项目时间是极其重要的。

由于现有的国际化方案都极其繁琐、枯燥,且随着项目的进展越来越难以维护,尤其是对于多人开发的大型项目。既然不尽如人意,我们不妨探讨一下方便快速的国际化方案。

国际化自动化——思路

对于国际化这种重复性的工作,最合适的就是自动化,一切交给程序来解决,岂不是更香?

自动化的大致思路就是通过代码自动实现上面的方案二,具体做法:

1. 自动提取语言包文件

2. 自动添加页面翻译

3. 额外的其他工作

为了实现自动化,最先想到的是webpack,网上搜索了一遍发现并没有现成的工具可用,只能自己手写一个插件,学习了一番怎么写插件之后,发现webpack文档并没有面面俱到,都只给你个大概,想了解更详细的信息只能自己去看源码,学习成本陡然增加。

ps:学习无果之后,我还试着想能不能通过正则来实现呢,都是字符串处理啊。想想还是太天真了,这估计和写个js解析引擎也差不多了。

由于webpack的构建都是基于babel实现的,直接撸一个babel插件是不是会更好呢?于是着手学习babel,发现文档更齐全,更加规范。学习babel之前,要先了解AST语法树请参考:AST Explorer(https://astexplorer.net),AST很早之前就有了,但很少用于普通开发者,直到nodejsreactwebpack等技术的兴起,才被广泛使用。

babel根据AST规范将我们的js代码解析成树状结构,如同我们常见的dom树一样,用不同的标签,表示不同的语义。AST则定义了不同的类型来表示不同js代码的语义,具体可参考@babel/typesAPI,列出了所有已实现的语法类型及其用法。

关于babel的更多详细解析请移步至:剖析 Babel——Babel 总览 http://www.alloyteam.com/2017/04/analysis-of-babel-babel-overview/

有了babel的认知基础之后我们就可以开始写babel插件了。它能够原子级别的控制我们的代码,轻松实现我们想要的功能。

babel插件开发格式如下

export  default  function() { 
    return { 
        visitor: { 
            Identifier(path) { // 所有类型为Identifier的AST树,都会通过此方法进行处理
                const name = path.node.name; 
                // reverse the name: JavaScript -> tpircSavaJ
                // 编译前 var JavaScript;
                // 编译后 var tpircSavaJ;
                path.node.name = name .split("") .reverse() .join(""); 
            },
            StringLiteral(path) { // 处理StringLiteral(字符串)类型
                let {node} = path;
                ...
            },
        },
    };
}
复制代码

react-i18n-auto全自动化——实现

实现方式:react国际化自动化插件 react-i18n-auto

使用安装

npm install react-i18n-auto --save-dev

添加babel插件配置项

{ 
    "plugins": [
        ...
        "react-i18n-auto"
        ...
    ] 
}
复制代码

编译前效果:

export  default  class App extends React.Comment{
    render(){
        let title = '这是翻译的文字'
        return <div title={title}>
            <div title='这是要翻译的标题'>
                我是要翻译的内容
            </div>
        </div>
    }
}

复制代码

编译后效果:

export  default  class App extends React.Comment{
    render(){
        let title = $T('aa8ds','这是翻译的文字')
        return <div title={title}>
            <div title={$T('see23','这是要翻译的标题')}>
                {$T('ae22s','我是要翻译的内容')}
            </div>
        </div>
    }
}

复制代码

自动生成的语言包配置

locale.js

export let locale = {
    "aa8ds":"这是翻译的文字",
    "see23":"这是要翻译的标题",
    "ae22s":"我是要翻译的内容",
}

复制代码

react-i18n-auto实现了对源码的无污染,开发时无感知,只影响打包后的代码,实现全部自动化。只需将locale.js翻译成对应的语言包文件,根据语言加载对应的语言包即可。对于React项目可实现快速完成国际化开发任务。

更多使用详情请参考:react-i18n-auto github主页

本文参考链接:

  1. 剖析 Babel——Babel 总览
  2. babel plugins
  3. @babel/types
文章分类
前端
文章标签