للقيام بذلك ، كان علينا حل مشكلتين:
- تحديد اللغة الحالية للتطبيق.
- استخدام الحالة العالمية للترجمة الفورية.
سأحاول في هذه المقالة أن أصف بالتفصيل كيف حللنا هذه المشاكل. وهكذا ذهبنا.
حدد لغة الجهاز الحالية
لتحديد اللغة الحالية ، يمكنك بالطبع استخدام مكتبة رد فعل-أصلية-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 ، وللروبوت عبر 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);
}
أعتقد أن كل شيء واضح هنا.
الآن يأتي الجزء الممتع. قررنا تخزين الترجمات نفسها في قاموس بسيط. للقيام بذلك ، قم بإنشاء ملف js بجوار LangModel ، حيث سنضع ترجماتنا:
// 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 في كل مرة ليس أمرًا رائعًا. لذلك ، يمكننا إنشاء مكون نص خاص بنا واستخدام 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))
ملاحظة: ربما يبدو هذا النهج ليس معيارًا ، لكننا أحببناه أكثر من ذلك الذي قدمه رد الفعل الأصلي - i18n
On هذا كل شيء بالنسبة لي. شكرا للجميع!)