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

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

Локализация продукции очень важна для международных компаний, осваивающих новые для себя страны и регионы. Аналогично локализация нужна и мобильным приложениям. Если разработчик начинает международную экспансию, важно дать пользователям из другой страны возможность работать с интерфейсом на родном языке. В этой статье мы создадим приложение 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

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

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

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

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

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

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

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

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

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

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

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

Бонус

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

Выводы

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

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

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

Источник: habr.com

Добавить комментарий