Русский
Русский
English
Статистика
Реклама

Локализуем приложение на React Native

В ходе разработки одного из наших приложений нам понадобилось сделать поддержку мультиязычности. Задача была дать пользователю возможность менять язык(русский и английский) интерфейса приложения. При этом текста и контент должны переводиться на лету.

Для этого нам нужно было решить 2 задачи:
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, но вы можете использовать другое решение.

И так мы должны создать класс(мне нравится называть модель), который будет отвечать за глобальное состояния текущей локализации. Создаем:

// ключ локального хранилища, в котором будем записывать текущий langconst 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), который будет менять язык:

  @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 это не круто. Поэтому мы можем создать собственный компонент Text и в нем уже использовать LangModel.rk

//components/text.jsimport 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 (не забудьте обернуть ваш компонент в observer(MobX))

P.S.: Возможно такой подход вам покажется не стандартным, но он нам понравился больше чем то, что предлагает react-native-i18n

На этом у меня все. Всем спасибо!)
Источник: habr.com
К списку статей
Опубликовано: 11.09.2020 02:18:44
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Локализация продуктов

Разработка мобильных приложений

React native

React-native

Mobile development

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2023, personeltest.ru