为此,我们必须解决两个问题:
- 确定应用程序的当前语言。
- 使用全局状态进行即时翻译。
在本文中,我将尝试详细描述我们如何解决这些问题。所以我们去了。
确定当前设备语言
要确定当前的语言,您当然可以使用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>
您可以在AppStore和Google 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
在这就是我的全部。谢谢大家!)