Пишем мультиязычное приложение на React Native

Автор оригинала: Vikrant Negi
  • Перевод


Локализация продукции очень важна для международных компаний, осваивающих новые для себя страны и регионы. Аналогично локализация нужна и мобильным приложениям. Если разработчик начинает международную экспансию, важно дать пользователям из другой страны возможность работать с интерфейсом на родном языке. В этой статье мы создадим приложение React Native, используя пакет react-native-localize.

Skillbox рекомендует: Образовательный онлайн-курс «Профессия Java-разработчик».
Напоминаем: для всех читателей «Хабра» — скидка 10 000 рублей при записи на любой курс Skillbox по промокоду «Хабр».

Инструменты и навыки


Для понимания этой статьи нужны базовые навыки работы с React Native. Для ознакомления с настройками рабочей машины можно воспользоваться официальной инструкцией.

Нам понадобятся вот такие версии программных инструментов:
  • Node v10.15.0
  • npm 6.4.1
  • yarn 1.16.0
  • react-native 0.59.9
  • react-native-localize 1.1.3
  • i18n-js 3.3.0

Начинаем


Мы создадим приложение, которое будет поддерживать английский, французский и арабский языки. Сначала создаем новый проект, используя react-native-cli. Для этого в терминале нужно набрать вот что:

$ react-native init multiLanguage
$ cd multiLanguage


Добавляем необходимые библиотеки

Первым делом нужно установить react-native-localize, набрав следующее:
$ yarn add react-native-localize

Если в процессе установки возникают проблемы, стоит изучить мануал по установке.

Библиотека react-native-localize дает разработчику доступ к мультиязычным функциям. Но ей нужна еще одна библиотека — i18n.

В статье описывается использование I18n.js для того, чтобы обеспечить перевод в JavaScript.

$ yarn add i18n-js

Ну а поскольку i18n-js не предоставляет кэширования или мемоизации, я предлагаю использовать для этого lodash.memoize:

$ yarn add lodash.memoize

Работа с переводами

Для того, чтобы приложение умело работать и с другими языками, сначала нужно создать каталог translations внутри src, потом — три файла JSON, для каждого из языков.

1. en.json для английского;

2. fr.json для французского;

3. ar.json для арабского.

Эти файлы содержат объекты JSON с ключами и значениями. Ключ будет один и тот же для каждого языка. Он используется приложением для отображения текстовой информации.

Значение (value) — это текст, который нужно показывать пользователю.

Английский язык:

{ «hello»: «Hello World!»}

Французский

{ «hello»: «Salut le Monde!»}

Арабский

{ «hello»: "أهلاً بالعالم"}

Аналогичным образом можно добавлять и другие языки.

Основной код


На этом этапе нужно открыть файл App.js и добавить в него импорт:

import React from "react";
import * as RNLocalize from "react-native-localize";
import i18n from "i18n-js";
import memoize from "lodash.memoize"; // Use for caching/memoize for better performance
 
import {
  I18nManager,
  SafeAreaView,
  ScrollView,
  StyleSheet,
  Text,
  View
} from "react-native";

После этого добавляются вспомогательные функции и константы, которые пригодятся впоследствии.

const translationGetters = {
  // lazy requires (metro bundler does not support symlinks)
  ar: () => require("./src/translations/ar.json"),
  en: () => require("./src/translations/en.json"),
  fr: () => require("./src/translations/fr.json")
};
 
const translate = memoize(
  (key, config) => i18n.t(key, config),
  (key, config) => (config ? key + JSON.stringify(config) : key)
);
 
const setI18nConfig = () => {
  // fallback if no available language fits
  const fallback = { languageTag: "en", isRTL: false };
 
  const { languageTag, isRTL } =
    RNLocalize.findBestAvailableLanguage(Object.keys(translationGetters)) ||
    fallback;
 
  // clear translation cache
  translate.cache.clear();
  // update layout direction
  I18nManager.forceRTL(isRTL);
  // set i18n-js config
  i18n.translations = { [languageTag]: translationGetters[languageTag]() };
  i18n.locale = languageTag;
};

Ну а теперь создадим компонент класса App:

export default class App extends React.Component {
  constructor(props) {
    super(props);
    setI18nConfig(); // set initial config
  }
 
  componentDidMount() {
    RNLocalize.addEventListener("change", this.handleLocalizationChange);
  }
 
  componentWillUnmount() {
    RNLocalize.removeEventListener("change", this.handleLocalizationChange);
  }
 
  handleLocalizationChange = () => {
    setI18nConfig();
    this.forceUpdate();
  };
 
  render() {
    return (
      <SafeAreaView style={styles.safeArea}>
        <Text style={styles.value}>{translate("hello")}</Text>
      </SafeAreaView>
    );
  }
}
 
const styles = StyleSheet.create({
  safeArea: {
    backgroundColor: "white",
    flex: 1,
    alignItems: "center",
    justifyContent: "center"
  },
  value: {
    fontSize: 18
  }
});

Первый элемент — setI18nConfig() — устанавливает начальную конфигурацию.

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

Метод handleLocalizationChange() активизирует setI18nConfig() и forceUpdate(). Это необходимо для устройств на Android, так как компонент должен быть отрендерен, чтобы изменения стали заметными.

Затем нужно убрать прослушивание из метода componentWillUnmount().

Наконец, в render() возвращается hello путем использования translate() и добавления в него параметра key. После этих действий приложение сможет «понимать», какой язык нужен, и показывать сообщения именно на нем.

Запуск приложения


Теперь самое время проверить, как работает перевод.

Сначала запускаем приложение в симуляторе или эмуляторе, набирая

$ react-native run-ios
$ react-native run-android

Выглядеть это будет примерно так:



Теперь можно попробовать сменить язык на французский, запустив затем приложение.



С арабским языком проделываем то же самое, разницы нет.

Пока все идет хорошо.

Но что произойдет, если выбрать случайный язык, перевода которого нет в приложении?

Оказывается, задача findBestLanguage — предоставление оптимального из всех доступных перевода. В результате будет отображаться язык, который был установлен по умолчанию.

Речь идет о настройках телефона. Так, например, в эмуляторе iOS можно посмотреть порядок языков.



Если выбранный язык не является предпочитаемым, findBestAvailableLanguage возвращает undefined, так что показывается тот язык, который установлен по умолчанию.

Бонус


У react-native-localize есть API, которое предоставляет доступ к большому количеству языковых элементов. Перед тем, как начать работу, стоит ознакомиться с документацией.

Выводы


Приложение можно сделать мультиязычным без особых проблем. React-native-localize — отличный вариант, который позволяет расширить круг пользователей приложения.

Исходный код проекта находится здесь.

Skillbox рекомендует:

Skillbox
Онлайн-университет профессий будущего

Комментарии 2

    0

    Зачем подключать для этого 2 либы, если то, как это в них реализовано(банально) делается по щелчку пальца?

      0
      Три.
      Ну вообще react-native-localize используется для поиска лучшего языка (а не выбранного) и через него можно получить страну пользователя. Удобно в век всевозможных GPPR.

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое