最近在玩React Native,一套代码在多个平台使用确实很爽,而当App做大以后国际化是不可避免的一个问题。趁着元旦假期有空研究了一下,虽然没有Android(不是iOS)上那么方便,但也不算太麻烦。

I18n

这里需要使用一个第三方库react-native-i18n ,安装:

npm i react-native-i18n --save

安装后还需要link,官方文档里有很长的介绍,亲测只需要运行react native link就OK了。

字符串本地化

字符串以json格式存储,这样可以嵌套对象以实现资源模块化,这里我们统一将国际化资源文件放在locales目录下,目录结构如下:

ios
android
src
locales
  |__ en.json // English
  |__ zh.json // Chinese
...

资源文件如下:

// en.json
{
  "login": {
    "welcome": "Welcome  to our localized app!",
    "login_button": "Login",
    "signup_button": "Sign Up"
  },
  "user_profile": {
    "title": "Your Profile"  
  }
}
// zh.json
{
  "login": {
    "welcome": "欢迎  回来!",
    "login_button": "登录",
    "signup_button": "注册"
  },
  "user_profile": {
    "title": "个人资料"  
  }
}

需要注意的是,对iOS来说,还需要手动在XCode中添加多语言支持,如下图:

在React Native中使用资源文件

i18n.js

首先在locales目录下新建一个i18n.js文件,内容如下:

import ReactNative from 'react-native';
import I18n from 'react-native-i18n';

// Import all locales
import en from './en.json';
import zh from './zh.json';

// Should the app fallback to English if user locale doesn't exists
I18n.fallbacks = true;

// Define the supported translations
I18n.translations = {
  en,
  zh
};

// The method we'll use instead of a regular string
export function strings(name, params = {}) {
  return I18n.t(name, params);
};

export default I18n;

在这里引入所有的国际化配置文件,然后封装了一个strings()的方法方便其它地方使用。

使用国际化字符串

举例如下:

import React, { Component } from 'react';
import {
  View,
  Text,
  Button
} from 'react-native';

import { strings } from '../locales/i18n';

class LoginScreen extends Component {
  constructor(props) {
    super(props);

    this.state = {
      username: 'Daniel'
    };
  }

  render() {
    return (
      <View>
        <Text>{strings('login.welcome', { name: this.state.username })}</Text>
        <Button title={strings('login.login_button')}></Button>
        <Button title={strings('login.singup_button')}></Button>
      </View>
    );
  }
}

export default LoginScreen;

上面的示例中,我们可以使用如login.login_button的层级调用字符串,还可以通过类似strings('login.welcome', { name: this.state.username })的方式指定参数,非常方便。