react项目国际化实现过程以及store中如何实现多语言开发

前言

前段时间公司拓展了海外业务,因此需要前端系统的开发在完成业务需求的同时,可以实现国际化,以满足用户的使用需要。

技术挑战

之前完全没有接触相关的技术,乍一看感觉很是简单,就是翻译一下文案。但是真正着手做的时候发现面临很多技术上的挑战,随着项目上线,所以梳理一下整个开发过程中的思路。

需要进行国际化开发的内容

label、placeholder、字段校验提示信息
需要进行语言切换的内容.png
第三方插件

公司项目中用到了第三发组件:Antdesign和bootstraptable,都支持国际化开发,但是其中bootstraptable的官方文档对相关的内容较少,所以花费了较多的时间。

开发思路

了解到React有支持国际化的组件-ReactIntl,所以除第三方插件以外,项目中的文案,基本都可以实现。
项目中文案整理.png

把需要翻译的文案提取出来,放到对应的语言文件(en_US.js)中,因为项目中好多内容是重复的,所以工作量不是很大,如果内容很多的话,这种方式的工作量太大了,需要更换方案。
开发过程

  • 安装ReactR-Intl组件
    React-intl是雅虎的语言国际化开源项目FormatJS的一部分,通过其提供的组件和API可以与ReactJS绑定。上面这句话援引了官方文档的说辞,主要表达的是,这是一个很好的开源项目,有大团队支持,使用量也很大,不会有太多坑,可以放心用。
    React-intl提供了两种使用方法,一种是引用React组件,另一种是直接调取API,官方更加推荐在React项目中使用前者,只有在无法使用React组件的地方,才应该调用框架提供的API,事实上,我在项目的过程大部分都是用API的方式。
  1. 安装react-intl需要执行下面的命令:
npm install intl --save
  1. 在项目中引入react-intl
import { FormattedMessage } from 'react-intl';

该组件提供了全面的API来帮助我们进行开发,这里我们不详细讲解各个API,只是介绍如何使用,其中使用频率较高API包括:FormattedMessage(字符串格式化API)、injectIntl(高阶组件)、FormattedPlural(格式化量词)

  1. 通过代码来了解一下如何使用上述API
import { injectIntl, FormattedMessage  } from 'react-intl';
class  Mycomponent extends Reflux.Component{
render(){
      const {messages, loacal} = this.props.intl;
    return (
        
      
        )
    }
}
export default injectIntl(Mycomponent );

通过injectIntl 在我们在 组件的 props 上会得到一个 intl 对象,它提供formatDate、formatTime、formatPlural、formatMessage等方法和locale、formats、messages等属性,这时候我们想要显示字符串,可以使用formatMessage进行字符串的格式化。loacal可以拿到当前代码的语言环境。

可以直接利用messages['id]的方式,可以直接从语言文件中拿到当前语言环境下文档中对应id的字符串。
对于其他的字符串,可以使用formatMessageAPI进行格式化。
这种方式的应用场景还是蛮多的。

  • 配置语言文件
    语言的配置文件zh-config.js是比较关键的,我们举例说明
import appLocaleData from 'react-intl/locale-data/zh';
import messages from './zh_CN';
window.appLocale = {
  messages: Object.assign({}, messages),
  locale: 'zh-CN',
  data: appLocaleData,
  },
};
export default window.appLocale;

下面是语言文件zh.js,即key-value键值对

const zh_CN = {
            id: "中文字符串",
}
export default zh_CN;

主入口文件mian.js

import React, {Component} from 'react';
import { IntlProvider, addLocaleData } from 'react-intl';

function getLocale(lang){
  let result={};
  switch(lang){
    case 'zh_CN':
    result = require('./locale/zh-config');
    break;
    case 'en_US':
    result = require('./locale/en-US.config');
    break;
    default: result = require('./locale/zh-config');
  }
  return result.default || result;
}

class Lang extends React.Component{
  constructor(props){
      super(props);
      this.state={
          lan:" "
      }
      this.changeLang=this.changeLang.bind(this);
  }
  changeLang(p){
     if(p==='en-US'){
      this.setState({
        lan:"en_US"
      })
    }
   else {
      this.setState(
        {lan:"zh_CN"}
        )
    }
  }
  render(){
    const {lan} = this.state;
    const appLocale = getLocale(lan);
    addLocaleData(...appLocale.data);
    window.lang = appLocale.locale;
      return (
      
this.changeLang('zh-CN')} >中文 this.changeLang('en-US')}>En
) } } ReactDOM.render(,document.getElementById('root'));

当设置了上述两个文件时,我们可以根据当前locale值来找对应的配置文件,从而找到对应的语言文件,再去匹配对应的id,拿到value值。我们在主入口文件中进行设置,切换到对应语言时,导入该语言的配置文件和语言包,从而全面替换字符串,实现多语言切换。

  • bootstraptable的国际化开发
    bootstraptable的国际化开发难点在于,他的官方文档这方面写的较简洁,所以摸索了较长时间,最后也是同过injectIntl高阶组件包裹table,从而拿到当前语言,再配置表格自动导入对应的语言包。
import createReactClass from 'create-react-class';
import 'bootstrap';
import 'bootstrap-table';
import {injectIntl } from "react-intl";
import Main from './main/Main';

const Layout = createReactClass({
changeLang (p){
    switch(p){
      case "en-US": require("bootstrap-table-locale-en");
      break;
      case "th-TH":  require("bootstrap-table-locale-th");
      break;
      case "zh-CN": require("bootstrap-table-locale-zh");
      break;
      default:  require("bootstrap-table-locale-en");
    }
  },
  render(){
    this.changeLang(this.props.intl.locale)
    return (
      
); }, }); module.exports = injectIntl(Layout);
  • antd国际化开发
    antd 提供了一个 React 组件 LocaleProvider 用于全局配置国际化文案。
    LocaleProvider 使用 React 的 context 特性,只需在应用外围包裹一次即可全局生效。
    mian.js中有具体的使用方法,可以参考。

解决store中的多语言实现

项目中调用接口的回调处理都在store文件中实现,会有一些提示信息。但是react-intl并不支持store中字符串的多语言,这个比较不好处理,在git上找到了一种解决方案。
首先添加一个组件 CurrentLocale.js

import {injectIntl} from 'react-intl';

// Does not actually render anything visible. 
// We need it to provide access to internationalization for classes
// which are not a React component
class CurrentLocale extends React.Component {
    static CurrentLocale = null;

    componentWillMount() {
        if (!CurrentLocale.instance)
            CurrentLocale.instance = this;
    }

    render() {
        return null;
    }
}

export default injectIntl(CurrentLocale);

export function intl() {
    return CurrentLocale.instance.props.intl;
}

export function formatMessage(...args) {
    return intl().formatMessage(...args);
}

在项目入口处引入
然后在store文件中引入使用即可

import {formatMessage} from "../../../../locale/CurrentLocale";

class MyComponent extends Reflux.Store{
     onFunctionCompleted(res){
            if(res.state==='success'){
                message.success(formatMessage({id:"OperateSuccess"}));
            }else{
                Modal.error({title:formatMessage({id:"OperateFailed"}),content:res.error});
            }
        }
     }
export default MyComponent ;

写在后面

毕业后的第一个项目就要求实现国际化,对于之前没有项目经验又没有人带的我来说,挑战巨大。因为之前没有接触过,所以全部都是边学边用,发现可以参考的文章不是很多,所以总结一下自己开发过程中的难点和通点,如果这篇文章可以帮助到大家,那么也算是做了一件有意义的事情。

你可能感兴趣的:(react项目国际化实现过程以及store中如何实现多语言开发)