Dazu mussten wir 2 Probleme lösen:
- Bestimmen Sie die aktuelle Sprache der Anwendung.
- Verwenden des globalen Status für die On-the-Fly-Übersetzung.
In diesem Artikel werde ich versuchen, detailliert zu beschreiben, wie wir diese Probleme gelöst haben. Und so gingen wir.
Bestimmen Sie die aktuelle Gerätesprache
Um die aktuelle Sprache zu bestimmen, können Sie natürlich die React-Native-i18n-Bibliothek verwenden. Wir haben uns jedoch dafür entschieden, darauf zu verzichten, da Sie dies ohne Bibliotheken von Drittanbietern tun können. Schreiben Sie dazu Folgendes:
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
Für ios extrahieren wir die Anwendungssprache über SettingsManager und für Android über den nativen I18nManager.
Nachdem wir die aktuelle Gerätesprache erhalten haben, können wir sie in AsyncStorage speichern und mit der zweiten Aufgabe fortfahren.
Wir übersetzen "on the fly"
Wir verwenden MobX, um den globalen Status zu verwalten, aber Sie können eine andere Lösung verwenden.
Deshalb müssen wir eine Klasse erstellen (ich nenne sie gerne "Modell"), die für den globalen Status der aktuellen Lokalisierung verantwortlich ist. Wir erstellen:
// , 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();
Wenn wir unser Modell initialisieren, rufen wir die init-Methode auf, die das Gebietsschema entweder aus dem AsyncStorage übernimmt, falls vorhanden, oder wir extrahieren die aktuelle Gerätesprache und fügen sie in den AsyncStorage ein.
Als nächstes müssen wir eine Methode (Aktion) schreiben, die die Sprache ändert:
@action
changeLang(lang: string) {
this.lang = lang;
AsyncStorage.setItem(STORE, lang);
}
Ich denke hier ist alles klar.
Jetzt kommt der lustige Teil. Wir haben uns entschlossen, die Übersetzungen selbst in einem einfachen Wörterbuch zu speichern. Erstellen Sie dazu eine js-Datei neben unserem LangModel, in die wir unsere Übersetzungen einfügen:
// translations.js
// , .
export default const translations = {
", !": {en: "Hello, World!"},
}
Als Nächstes implementieren wir eine weitere Methode in LangModel, die Text als Eingabe akzeptiert und den Text der aktuellen Lokalisierung zurückgibt:
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];
}
Das war's, unser LangModel ist fertig.
Vollständiger LangModel-Code
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();
Wir können jetzt die rk-Methode verwenden, um den Text zu lokalisieren:
<Text>{LangModel.rk(", !")}</Text>
Sie können sehen, wie es in unserer Anwendung im AppStore und bei Google Play funktioniert (Klicken Sie auf das Symbol (!). Scrollen Sie oben rechts nach unten.)
Bonus
Natürlich ist es nicht cool, jedes Mal LangModel.rk zu schreiben. Daher können wir unsere eigene Textkomponente erstellen und bereits LangModel.rk darin verwenden
//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>
));
Abhängig von der aktuellen Lokalisierung müssen wir möglicherweise auch das Anwendungslogo ändern. Zu diesem Zweck können Sie den Inhalt einfach abhängig von LangModel.lang ändern (vergessen Sie nicht, Ihre Komponente in den Observer (MobX) einzuschließen).
PS: Vielleicht scheint dieser Ansatz kein Standard zu sein, aber er hat uns besser gefallen als der von react-native-i18n
On das ist alles für mich Danke an alle!)