在React Native中本地化应用

在开发我们的一种应用程序期间,我们需要提供多语言支持。任务是使用户能够更改应用程序界面的语言(俄语和英语)。同时,文本和内容应即时翻译。



为此,我们必须解决两个问题:



  1. 确定应用程序的当前语言。
  2. 使用全局状态进行即时翻译。


在本文中,我将尝试详细描述我们如何解决这些问题。所以我们去了。



确定当前设备语言



要确定当前的语言,您当然可以使用react-native-i18n库,但是我们决定不使用它,因为您可以在没有第三方库的情况下做到这一点。为此,请编写以下代码:



import {NativeModules, Platform} from 'react-native';

let deviceLanguage = (Platform.OS === 'ios'
        ? NativeModules.SettingsManager.settings.AppleLocale ||
          NativeModules.SettingsManager.settings.AppleLanguages[0] // iOS 13
        : NativeModules.I18nManager.localeIdentifier


对于ios,我们通过SettingsManager检索应用程序语言,对于android通过本机I18nManager检索应用程序语言。



现在我们已经收到了当前的设备语言,我们可以将其保存到AsyncStorage并继续执行第二个任务。



我们即时翻译



我们使用MobX来管理全局状态,但是您可以使用其他解决方案。



因此,我们必须创建一个类(我喜欢将其称为“模型”),该类将负责当前本地化的全局状态。我们创建:



//   ,      lang
const STORE = '@lang-store';
//    
const RU_LANGS = [
  'ru',
  'az',
  'am',
  'by',
  'ge',
  'kz',
  'kg',
  'md',
  'tj',
  'tm',
  'uz',
  'ua',
];

class LangModel {
  @observable
  lang = 'ru'; //  

  constructor() {
    this.init();
  }

  @action
  async init() {
    const lang = await AsyncStorage.getItem(STORE);
    if (lang) {
      this.lang = lang;
    } else {
      let deviceLanguage: string = (Platform.OS === 'ios'
        ? NativeModules.SettingsManager.settings.AppleLocale ||
          NativeModules.SettingsManager.settings.AppleLanguages[0] // iOS 13
        : NativeModules.I18nManager.localeIdentifier
      ).toLowerCase();

      if (
        RU_LANGS.findIndex((rulang) => deviceLanguage.includes(rulang)) === -1
      ) {
        this.lang = 'en';
      }
      AsyncStorage.setItem(STORE, this.lang);
    }
}

export default new LangModel();


初始化模型时,我们调用init方法,该方法从AsyncStorage中获取语言环境(如果有),或者提取当前的设备语言并将其放入AsyncStorage中。



接下来,我们需要编写一种方法(操作)来更改语言:



  @action
  changeLang(lang: string) {
    this.lang = lang;
    AsyncStorage.setItem(STORE, lang);
  }


我认为这里一切都清楚了。



有趣的来了。我们决定将翻译本身存储在简单的词典中。为此,请在我们的LangModel旁边创建一个js文件,我们将在其中放入翻译文件:



// translations.js
// ,     . 
export default const translations = {
  ", !": {en: "Hello, World!"},
}


接下来,我们将在LangModel中实现另一个方法,该方法将接受文本作为输入并返回当前本地化的文本:



import translations from './translations';

  ...
  rk(text) {
    if (!text) {
      return text;
    }
    //   ru,    
    if (this.lang === 'ru') {
      return text;
    }
    //   ,   
    if (translations[text] === undefined || translations[text][this.lang] === undefined) {
      console.warn(text);
      return text;
    }
    return translations[text][this.lang];
  }


就是这样,我们的LangModel准备好了。



完整的LangModel代码
import {NativeModules, Platform} from 'react-native';
import {observable, action} from 'mobx';
import AsyncStorage from '@react-native-community/async-storage';
import translations from './translations';

const STORE = '@lang-store';
//  ru  
const RU_LANGS = [
  'ru',
  'az',
  'am',
  'by',
  'ge',
  'kz',
  'kg',
  'md',
  'tj',
  'tm',
  'uz',
  'ua',
];

class LangModel {
  @observable
  lang = 'en';

  constructor() {
    this.init();
  }

  @action
  async init() {
    //     AsyncStorage
    const lang = await AsyncStorage.getItem(STORE);
    if (lang) {
      this.lang = lang;
    } else {
      let deviceLanguage: string = (Platform.OS === 'ios'
        ? NativeModules.SettingsManager.settings.AppleLocale ||
          NativeModules.SettingsManager.settings.AppleLanguages[0] // iOS 13
        : NativeModules.I18nManager.localeIdentifier
      ).toLowerCase();

      if (
        RU_LANGS.findIndex((rulang) => deviceLanguage.includes(rulang)) > -1
      ) {
        this.lang = 'ru';
      }
      AsyncStorage.setItem(STORE, this.lang);
  }

  @action
  changeLang(lang: string) {
    this.lang = lang;
    AsyncStorage.setItem(STORE, lang);
  }

  rk(text) {
    if (!text) {
      return text;
    }
    //   ru,    
    if (this.lang === 'ru') {
      return text;
    }
    //   ,   
    if (translations[text] === undefined || translations[text][this.lang] === undefined) {
      console.warn(text);
      return text;
    }
    return translations[text][this.lang];
  }
}
export default new LangModel();




现在,我们可以使用rk方法来定位文本:



<Text>{LangModel.rk(", !")}</Text>


您可以在AppStoreGoogle Play的应用程序中查看它的工作方式(单击图标(!)在右上方,向下滚动)



奖金



当然,每次编写LangModel.rk都不是一件很酷的事情。因此,我们可以创建我们自己的Text组件,并且已经在其中使用LangModel.rk



//components/text.js
import React from 'react';
import {Text} from 'react-native';
import {observer} from 'mobx-react';
import {LangModel} from 'models';

export const MyText = observer((props) => (
   <Text {...props}>{props.notTranslate ? props.children : LangModel.rk(props.children)}</Text>
));


例如,我们可能还需要根据当前本地化来更改应用程序徽标。要做到这一点,你可以简单地改变取决于LangModel.lang内容(不要忘记来包装你的组件在观察者(MobX))



PS:也许这种做法会显得不是一个标准,但我们喜欢它比所提供的一个反应,本机的i18n



在这就是我的全部。谢谢大家!)



All Articles