[ 一同学React系列 -- 10 ] i18n

本日来引见一个非常international的东西。

i18n

国际化(
internationalization)的简称。之所以叫i18n,是由于字母
i和n之间有18个字母,所以才叫i18n。不要以为这是一个嵬峨上的名词,实在就是由于懒才简写的。hiahiahia…

由于本系列是以React为中间,所以只引见React项目中的国际化解决方案。固然另有许多许多…许多别的国际化解决方案,然则否是一切的轮子都合适React这辆开往幼儿园的车。
实际上国际化在一样平常项目顶用的没那末频仍,除非有营业需求,比方要做一个非常international的项目。如今在React中比较热点的两个包就是react-intl-universalreact-intl。由于本文重点引见对象是前者,所以我们先简朴引见下后者。固然在这里不会把它的运用要领列出来,而是把它的瑕玷列出来,为何呢?由于笔者懒啊!
react-intl不足的处所主如果两个:

它只能用于视图层。举个例子,比方React.Comoponent对象,然则关于Vanilla JS就会显得很无力了,由于它没法在Vanilla JS中实例化。(这里会有人以为新鲜,Vanilla JS是什么鬼?哈哈…百gu度ge吧,不会发明新大陆)!

其次

想运用国际化要领,我们必须要利用它的一个要领将本身的组件转化成别的一个class。这就比较蛋疼了,例子以下:

import { injectIntl } from 'react-intl';
class MyComponent extends Component {
  render() {
    const intl = this.props;
    const title = intl.formatMessage({ id: 'title' });
    return (<div>{title}</div>);
  }
};
export default injectIntl(MyComponent);

看我笔者第一篇文章的朋侪应该有印象:一切被包裹过的组件,如果你想取得底本的组件的对象,那得挪用响应的要领。这里也不破例,如果我们想猎取组件的原对象,那就得这么做:

class MyComponent {...}
export default injectIntl(MyComponent, {withRef: true});
 
class App {
  render() {
    <MyComponent ref="my"/>
  }
  getMyInstance() {
    console.log('getMyInstance', this.refs.my.getWrappedInstance());
  }
}

如许写会不会以为太麻烦了…
所以Alibaba前端组就按捺不住了,然后就搞出了本身的react-intl-universal。看名字不就是在react-intl背面加个universal吗?的确是如许,不过笔者不清楚这个框架的中心逻辑是不是是参考的react-intl,然则单从名字来看就有点”可疑”了,翻译就是react-intl的通用版(固然,纯属意淫,一笑而过!)。

react-intl-universal

作为一个国际化解决方案,起首完成国际化是它的基本功用。其次它另有一些别的功用,比方文本格式化、钱银格式化、时刻格式化等等,我置信这些都是我们页面开辟常常运用到的功用。

i18n

起首来看一下它的手艺功用:国际化
react-intl-universal采用了与组件无关的要领来完成国际化。国际化的实质实在就是将我们预先设置好的差别言语的句子依据言语环境显如今页面上。

import intl from 'react-intl-universal';

经由历程intl这个对象来完成初始化和国际化处置惩罚。我们能够以为这个intl是一个单例对象。我们在App启动的时刻对其举行初始化,此后在别的处所再次导入的时刻仍然是一个已初始化过的对象。在这类情况下,国际化处置惩罚就会变得非常简朴。其次就是预备多言语句子了,传统的在前端处置惩罚这个题目是将差别言语的句子放在差别的json文件中再导出,文件构造以下:
《[ 一同学React系列 -- 10 ] i18n》
如许我们就能够在App启动或许切换言语的时刻导入响应的json对象了。

起首是API引见

intl对象主要有三个经常使用的用于国际化处置惩罚的API,determineLocale、init、get

  • determineLocale
    看到要领名就应该晓得它是用来干什么了。它用来肯定在全部体系中运用的是哪一种言语。看代码:
let currentLocale = intl.determineLocale({
    urlLocaleKey: "lang",
    cookieLocaleKey: "lang"
});

react-intl-universal肯定言语的体式格局有三种,一个是经由历程urlLocaleKey,即lang关键字从url中猎取是哪一种言语。比方:http://localhost?lang=en-US,由于lang对应的值是en_US,所以言语为英文。其次是从Cookie猎取,由于Cookie也是以键值对情势存储的,所以会搜检当前域下的Cookie是不是有对应的lang。如果上述两种都没有,那末会默许运用浏览器当前的言语范例。固然上述的urlLocaleKey和cookieLocaleKey是能够自定义的,不是牢固的lang.

  • init

init要领即用来初始化intl对象。初始化参数主如果两个,一个是currentLocale即当前的言语,另一个是locales即当前言语对应的json对象,比方{"en-US":{"key1":"value1"} 或许 {"zh-CN":{"key1":"值1"}}

  • get
    get要领就相对简朴,就是依据键去intl中猎取对应的值,这里不做过量诠释。

完整的初始化历程以下:

class App extends Component{
    ....
    
    componentDidMount() {
        this.loadLocales();
    }

    loadLocales() {
        const _self = this;
        let currentLocale = intl.determineLocale({  //如果cookie和url中均没有相干参数,那末以浏览器言语为准
            urlLocaleKey: "lang",
            cookieLocaleKey: "lang"
        });

        http
            .get(`locales/${currentLocale}.json`)   //理解为按需加载而且locales文件夹须要放在public文件下供http接见
            .then(res => {
                return intl.init({
                    currentLocale,
                    locales: {
                        [currentLocale]: res.data //如果key是变量,那末须要用[]包一下
                    }
                });
            })
            .then(() => {
                _self.setState({initDone: true});
            });
    }
    
    ....
}

然后在须要国际化的处所这么运用

import intl from 'react-intl-universal';
<p>{intl.get('name')}</p>

是不是是很简朴? 而且完整避免了react-intl的两个瑕玷。

格式化东西

前面说了react-intl-universal不单单议能够用来做国际化处置惩罚,还能够用来做简朴的文本格式化处置惩罚。下面我们枚举几个经常使用的。

Html Snippet

如果我们的json文件中有这么一段

...
"red": "<p style='color:red'>赤色</p>",
...

如果我们直接用get要领猎取的话,那末会直接把<p style='color:red'>赤色</p>给打印出来。如果我们想将它以html片断的情势打印出来的话,就运用getHTML要领,它在猎取到句子的时刻会举行剖析并天生终究的Html Snippet。

Default Message

缺省值实在就是默许值,是关于json键值对的默许值。将入我们去猎取一个json中没有的键值对那末体系就会报错。怎样去躲避这个题目呢?react-intl-universal给我们供应了如许一个要领:

intl.get('not-exist-key').defaultMessage('default message')

这是一个链式挪用。如果json中没有not-exist-key这个键,那就会默许返回defaultMessage的参数。简写是intl.get('not-exist-key').d('default message')

Message With Variables

如果某个句子包含了一个变量怎么办?比方一个用户名,我们只要在用户登录的时刻才晓得他的用户名。

{
    "me": "你好,我是{me}"
}

此时就用到了get放的第二个参数。关于上面的例子,我们能够如许处置惩罚:

<p>{intl.get('me', {'me': '皮卡丘'})}</p>

get要领会找出句子中被{}包住的变量me,然后在第二个参数(json对象)找出me对应的值皮卡丘并将{me}全部用皮卡丘替代。别的须要注重的是,json对象只能为一层,不可嵌套

Display Currency

它还能够用来格式化钱银。如果有这么一段句子

{
  "price": "这件衣服是 {price,number,CNY} 人民币",
}

如果我们想将一个数字以人民币的情势写进去的话能够这么做:

{intl.get('price', {'price': 1000})}

终究显现结果是:这件衣服是 ¥1,000 人民币
实在它做了两件事:一个是加标记,另一个是加分隔符。同时CNY示意人民币,USD示意美圆

Display Dates

然后是日期的处置惩罚。如果有这么一段话:

{
    "date": "本日是{date,date,full}"
}

然后我们这么运用它的话:

<p>{intl.get('date',{'date':new Date()})}</p>

显现结果是本日是2018年12月3日星期一。实在{date,date,full}这段指令就是将date变量替代成对应日期(new Date())并以long情势展现。

同时日期展现情势有四种

  • short: shows date as shortest as possible
  • medium: shows short textual representation of the month
  • long: shows long textual representation of the month
  • full: shows dates with the most detail

他们之间有什么差别呢?我们用方才的例子做个展现:

  • short: 本日是18/12/3
  • medium: 本日是2018年12月3日
  • long: 本日是2018年12月3日
  • full: 本日是2018年12月3日星期一

Display Times

末了是时刻。我们循序渐进来。如果有这么一段话:

{
    "time": "如今时刻是{time,time,short}"
}

然后我们这么运用它的话:

 <p>{intl.get('time',{'time':new Date()})}</p>

显现结果是如今时刻是下昼5:54。实在{time,time,short}这段指令就是将time变量替代成对应日期(new Date())并以short情势展现。

然则时刻展现情势只要三种,它没有full

  • short: shows date as shortest as possible
  • medium: shows short textual representation of the month
  • long: shows long textual representation of the month

他们之间有什么差别呢?我们用方才的例子做个展现:

  • short: 如今时刻是下昼5:54
  • medium: 如今时刻是下昼5:58:22
  • long: 如今时刻是GMT+8 下昼5:58:50

上述贴出来的示例都是在中文环境下。如果有兴致的朋侪能够把全部例子download下来当地运转下,边看边写,受益不浅。好了,摒挡放工咯…

    原文作者:风吹过的夏夜
    原文地址: https://segmentfault.com/a/1190000017239270
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞