Локализация с помощью React Navigation 4 и Context API

Пару недель назад я написал руководство о том, как добавить локализацию с помощью React Navigation. Это руководство использовало global screenProps для передачи функций и экземпляров, необходимых для перевода нашего контента.

Но во время исследования этой статьи меня заинтересовало одно предложение в документации по React Navigation.

Вы также можете использовать контекстный API React […], чтобы упростить доступ к функции перевода из множества компонентов.

Чувствуя любопытство, я потратил день, чтобы посмотреть, как это сработает. Следующий урок - мой подход к этой проблеме. Я не буду использовать глобальные свойства screenProps и буду полагаться исключительно на контекстный API.

Вот полный код, если вы хотите использовать его для отслеживания:

Основные технологии, использованные в этом руководстве:

  • React Native 0.61
  • Реагировать на навигацию 4
  • i18next 19 и response-i18next 10 (но вы можете заменить его на свой собственный фреймворк)
  • Expo SDK 36 (опять же, личные предпочтения. Вам не обязательно его использовать)

Я добавлю всю документацию внизу, если она вам понадобится.

Примечания: я буду использовать response-i18next в качестве среды интернационализации. Если вы решите тоже, проверьте свою версию React Native. Последняя версия react-i18next (v10) использует хуки, которые доступны только в response native версии v0.59 или выше. Если у вас более старая версия React Native, не бойтесь. Вы можете использовать устаревшую версию react-i18next (v9), которая работает так же хорошо, но некоторые функции были переименованы, так что будьте осторожны.

Настройка проекта

Я лично использую Expo для создания и запуска своих приложений React Native. Чтобы создать новый проект, просто запустите expo init [project name], а затем cd в свой проект.

Установите i18next и response-i18next с помощью npm (или пряжи)

npm install i18next react-i18next

Если вам нужны значки для навигатора ящика, могу ли я предложить элементы React Native?

npm install react-native-elements

i18n.js

В корне нашего проекта мы создадим файл i18n.js. Опять же, это зависит от вашей структуры интернационализации.

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

Не забывайте initReactI18next, поскольку это необходимо для проектов React (строка 24).

LocalizationContext.js

В нашем файле LocalizationContext.js мы создаем объект Context.

Мы делаем это, передавая ему значение по умолчанию, будь то строка или объект. В нашем случае это второе, и оно состоит из двух вещей:

  1. функция t, которая используется для перевода нашего контента. Он будет принимать два параметра: уникальный ключ строки, которую мы хотим + любые дополнительные данные (например, имя человека).
  2. экземпляр i18n (используется для изменения языкового стандарта с помощью i18n.changeLanguage (‘fr’)).

Значение по умолчанию используется только в том случае, если компонент не находит соответствующего Provider над ним в дереве React. Итак, недостаточно создать объект Context. Еще нам нужен Провайдер.

LocalizationProvider.js

Если мы создали наш объект контекста со значением по умолчанию, теперь пора передать ему некоторые реальные данные. Все, что мы пройдем, будет доступно всем потомкам в дереве.

Сначала мы импортируем наш файл i18n и withTranslation из response-i18next (строка 2 + 3). Во-вторых, мы заключаем наш LocalizationProvider в withTranslation (строка 18). Это позволяет нам получить доступ к нашей функции перевода и экземпляру i18n из свойств (строка 9). В-третьих, мы импортируем наш объект Context, созданный в LocalizationContext, и создаем нашего провайдера, передавая t и i18n, существенно перезаписывая значение по умолчанию, которое мы использовали в LocalizationContext.js.

Поскольку наш провайдер оборачивается вокруг компонентов, мы также добавляем потомков, чтобы правильно отображать потомков (строка 12).

App.js

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

Доступ к LocalizationContext.js

Наша настройка завершена. Теперь пора использовать наш контекст локализации. Вот пример на простом экране.

После импорта нашего объекта контекста локализации мы передаем его в useContext (строка 6).

useContext принимает объект контекста (созданный с помощью createContext) и возвращает текущее значение контекста, которое, в свою очередь, определяется ближайшим подходящим поставщиком в дереве. В нашем случае это будет наш LocalizationProvider, который мы включили в App.js. Также помните, что в нашем файле LocalizationProvider.js мы передали функцию перевода (t) и экземпляр i18n. И то, и другое теперь можно получить и использовать (строка 6).

Для нашего контента у нас есть функция t (то есть title={t(‘change_language_english’)}) и для изменения языка i18n (то есть i18n.changeLanguage(‘en’)).

Навигация

Здесь вам доступны несколько подходов.

Если вы просто хотите быстро запустить проект, то проще всего использовать screenProps. Как и в случае с Screen1.js, импортируйте объект LocalizationContext, получите t и i18n с помощью useContext и передайте его как реквизит с помощью screenProps.

Вот как бы это выглядело:

Примечание. Прокрутите это руководство до MainNavigator.js, чтобы узнать, как использовать screenProp, чтобы функция t переводила метки и заголовки вкладок / ящиков.

Второй подход - использовать пользовательские компоненты для ваших меток и заголовков. В этих компонентах мы сможем вызвать useContext и получить нашу функцию перевода. К счастью для нас, React Navigation предлагает несколько вариантов, которые принимают компоненты React.

Примечание. Я буду использовать StackNavigator для вкладки / ящика. Если вы не знакомы с ним, он работает, объединяя все экраны, попадающие под конкретную вкладку / ящик, в стек, а затем объединяя все разные стопки вместе, чтобы создать свой навигатор по ящику / вкладкам. Вот руководство, которое объясняет это (и различные типы навигаторов) более подробно.

Заголовок

Например, мы можем использовать headerTitle для создания настраиваемого заголовка и передачи двух реквизитов (ключ перевода и любые данные, которые мы хотим добавить).

Еще более удачливым является то, что HeaderTitle можно импортировать из стека реакции-навигации, чтобы мы могли получить стиль по умолчанию. в этом компоненте мы получаем t из useContext (теперь мы довольно хорошо с ним знакомы) вместе с ключом перевода и данными для получения правильного переведенного содержимого.

Ярлык вкладки

Мы перевели наши заголовки. Теперь переходим к нашим вкладкам. Вы можете получить логическое значение focused и передать его моему TabBarLabel, чтобы узнать, когда вкладка выбрана, и применить соответствующий стиль.

Вот мой компонент TabBarLabel. К сожалению, в React Navigation нет готового компонента, который я мог бы импортировать, но я заставил его работать с простым текстом. Я использовал логическое значение focused, чтобы изменить цвет в зависимости от того, выбрана вкладка или нет.

Этикетка ящика

Логика ярлыка ящика не сильно отличается. Вместо tabBarLabel мы используем drawerLabel.

Полный файл для каждого навигатора можно найти здесь:

В итоге:

  1. Создайте свой проект со всеми необходимыми зависимостями
  2. Инициализируйте свою структуру интернационализации
  3. Создайте свой объект контекста
  4. Создайте своего провайдера и оберните его вокруг своего приложения
  5. Получите доступ к своему значению контекста благодаря React.useContext и переводите свой контент по мере необходимости

Если вам понравилась статья, вы можете подписаться на меня в Twitter.