Это третья публикация в серии из 4 частей о создании приложения для iOS и Android для uncovercity с использованием React Native. Вы можете найти другие здесь:
- Ускорение создания приложения с ужином-сюрпризом в React Native с помощью Expo
- Боевое тестирование API райдшеринга и MapView от React Native в Expo
- Поддержка нескольких языков в React Native с Expo Localization
- Тонкости вложения навигаторов в React Native с использованием реакции-навигации
Привет! Вот еще один пост о моем опыте создания приложения для iOS и Android для стартапа-сюрприза uncovercity. Сегодня я расскажу вам, как перевести весь контент приложения (тексты, видео, изображения) с испанского на английский.
Поскольку приложение основано на React Native и Expo, наиболее очевидным делом было поискать какое-то существующее решение в экосистемах этих двух инструментов.
И вуаля, в Expo есть модуль Локализация. Хотя он все еще находится в DangerZone
(пространстве имен, которое Expo использует для группировки функций, которые еще не были полностью одобрены), я был рад, что у меня есть надежная отправная точка для моей задачи.
ВАЖНО: это сообщение в блоге основано на Expo версии 30.0.0 и ниже. Expo недавно выпустила версию 31.0.0, которая включает полностью переработанный модуль Локализация. Наиболее значительным изменением является то, что теперь вы можете получать информацию о локализации со своего устройства синхронно, а не асинхронным способом, о котором я расскажу в этом сообщении блога.
Если вы уже знакомы с основами, вы можете сразу перейти к Распространенным ошибкам, где я расскажу о некоторых более сложных темах локализации.
Если вы используете React Native без Expo, вы можете получить что-то похожее на модуль локализации с response-native-languages. Однако для реальной задачи перевода строк вам все равно понадобится что-то вроде react-i18next.
Основы локализации
Документация, которую предоставляет Expo для этого модуля, очень проста и запутана (что и побудило меня написать этот пост). Но реализовать это на самом деле довольно просто. Все, что вам нужно сделать, это:
- создайте файл JSON для каждого языка, который вы хотите предоставить
- инициализировать языковое хранилище с помощью модуля Expo
Localizaton
- установить текущий язык пользователя в магазине
- замените весь контент в своем приложении соответствующими ключами магазина
Чтобы получить полный пример работы следующего кода, ознакомьтесь с Закуской, которую я создал, где я инициализирую хранилище строк из отдельного файла и добавляю небольшую кнопку переключения для переключения между английским (США) и испанским (США).
Теперь позвольте мне более подробно рассказать вам о каждом из этих шагов:
1. Создайте файл JSON для каждого языка.
Первое, что вам нужно сделать, это поместить все переводимые строки в хранилище JSON. Не имеет значения, делаете ли вы это в одном файле или импортируете их из отдельного файла с помощью import
. Я объясню, почему я предпочитаю последнее, на шаге 2.
const localizedStrings = {
en_GB: { title: "Hello", subtitle: "Welcome" },
es_ES: { title: "Hola", subtitle: "Bienvenido" }
}
Ключи этого объекта - это идентификаторы языка / региона (т.е. en_GB
означает английский / Великобритания), а значение ключа - это все переводимые строки, которые будут доступны после инициализации хранилища, т. Е. localeStore.subtitle
выведет «Bienvenido», если ваш язык был установлен на испанский (es_ES
).
2. Инициализировать магазин с помощью модуля Expo Localizaton.
Во-вторых, мы инициализируем хранилище и запускаем на нем логику инициализации. Импортируйте модуль Localization
из Expo следующим образом:
import { DangerZone } from 'expo'
const { Localization } = DangerZone
// localizedStrings is the object we created in step 1
const localeStore = new Localization.LocaleStore(localizedStrings)
Будет проще, если вы поместите эту строку кода там, где находятся ваши локализованные строки, чтобы у вас был доступ к ним в любом месте, где вам нужно. Поэтому вместо того, чтобы напрямую экспортировать объект JSON, экспортируйте созданное хранилище следующим образом:
const localeStore = new Localization.LocaleStore(localizedStrings)
export default localeStore;
Это localeStore
теперь дает нам доступ к двум важным функциям:
- установка текущей локали, которую мы хотим показать нашим пользователям (см. следующий шаг)
- используя локализованные строки в наших представлениях, например:
{ localeStore.title }
3. Установите текущий язык пользователя в магазине.
Затем нам нужно выяснить, какой язык предпочитает пользователь. Мы можем использовать функцию getCurrentLocaleAsync
из модуля Localization
, которая возвращает идентификатор языка / региона. Затем мы передаем это значение в наше ранее инициализированное хранилище, используя setLocale
.
import { localeStore } from "./localeStore" ... constructor() { super(); Localization.getCurrentLocaleAsync().then(currentLocale => localeStore.setLocale(locale) ); }
Функция getCurrentLocaleAsync
возвращает идентификатор языка / региона пользовательского устройства в виде строки (с которой вы уже должны быть знакомы), например: en_GB
Это асинхронный вызов, поэтому нам нужно убедиться, что где бы мы ни разместили это необходимо выполнить таким образом, используя _18 _ / _ 19_ или Promise
.
Помните, что вместо использования
getCurrentLocaleAsync
вы также можете получить доступ к коду страны или предпочитаемому региону устройства, используя соответствующие функцииgetCurrentDeviceCountryAsync
илиgetPreferredLocalesAsync
.
В дополнение к этому, вы, вероятно, захотите использовать какое-то решение для управления состоянием или React Context API, чтобы сделать вашу текущую локаль доступной где угодно, а не только в состоянии корневого компонента.
4. Заменить все переводимые строки
И последнее, но не менее важное: мы должны использовать локализованные строки из нашего магазина вместо жестко закодированных строк в наших представлениях пользовательского интерфейса.
// we want to replace this... <Text>Hello</Text> // ...with that: <Text>{ localeStore.title }</Text>
Это максимально просто с точки зрения интернационализации. Для более сложных функций перевода, таких как множественное число и форматирование, вы, вероятно, захотите использовать более полную библиотеку, такую как react-i18next
(которая, кстати, отлично работает в сочетании с модулем Expo Localization
, но также намного сложнее).
Распространенные ошибки и их исправления
Все это звучит довольно просто. Но есть несколько менее очевидных проблем, с которыми вы столкнетесь только в том случае, если вы создадите полностью локализованное приложение с несколькими экранами и небольшим взаимодействием.
Установка и применение языка по умолчанию
Вы можете задаться вопросом, что произойдет, если язык пользователя не охвачен ни одним из ваших файлов перевода, и вы сделаете что-то вроде setLocale(locale)
там, где языковой стандарт, который вы пытаетесь установить, не существует.
Или что, если вы хотите обеспечить одинаковый перевод для обоих, en_GB
и en_US
, но предпочитаете не дублировать весь массив строк?
Самым простым решением, которое сработало для меня, является явная установка языкового стандарта на основе некоторого условия, а не просто передача языкового стандарта вслепую функции setLocale
магазина.
// instead of blindly relying on this... Localization.getCurrentLocaleAsync().then(currentLocale => localeStore.setLocale(currentLocale) ); // ...make sure to explicitly set one of your existing locales Localization.getCurrentLocaleAsync().then(currentLocale => { const locale = currentLocale.includes('es') ? 'es_ES' : 'en_GB'; localeStore.setLocale(locale) );
В дополнение к этому, вы, вероятно, захотите защитить свое представление от рендеринга чего-либо, пока мы не назначили сначала языковой стандарт пользователя по умолчанию:
if (!this.state.currentLocale) { return; } return <App />
Переключение между языками
Теперь, когда мы знаем, как установить язык по умолчанию, что, если пользователь действительно хочет переключиться на другой язык?
Вызов setLocale
на localeStore
и обновление нашего состояния до нового языка должны помочь:
localeStore.setLocale(newlocale)
К сожалению, в результате наши взгляды не обновятся. Какое разочарование!
Это потому, что обновление localeStore
происходит вне области состояния React, поэтому React не будет ничего повторно отображать. Кроме того, setLocale
- это асинхронный вызов, поэтому любые изменения, которые мы хотим применить после обновления, должны обрабатываться в функции обратного вызова, которую она принимает в качестве второго аргумента.
localeStore.setLocale(locale, () => this.setState(() => ({ currentLocale: locale }))) });
Теперь наши компоненты будут реагировать на изменение состояния и соответственно обновляться.
Заголовки навигации с реактивной навигацией
Если вы раньше работали с реагирующей навигацией, вы, вероятно, знакомы со статическим navigationOptions
object, который позволяет изменять стиль и содержимое панели заголовка.
Оказывается, поскольку это статическое свойство, любые свойства, которые вы устанавливаете внутри него, будут оцениваться до, который мы установим наш исходный язык, а не при монтировании фактического экрана.
static navigationOptions = { title: localeStore.title // this won't re-render }
Решение здесь - вернуть функцию, возвращающую объект. Таким образом, каждый раз, когда в нашем приложении происходит изменение состояния (например, вызванное обратным вызовом setLocale
), эти реквизиты также будут обновляться.
static navigationOptions = () => { return { title: localeStore.title // this uses the updated locale } }
Продвинутые решения по локализации
Модуль локализации Expo довольно ограничен. Он дает вам доступ к языку пользовательского устройства и позволяет вам переводить объект строк на его основе.
Вероятно, это все, что вам нужно для множества небольших проектов. Но если ваше приложение становится немного сложнее, чем это, и вам нужны такие параметры интернационализации, как заполнители, плюрализация и форматирование валюты / часового пояса, вы можете рассмотреть одно из следующих, более сложных решений:
Вы когда-нибудь переводили приложение React Native на несколько языков? Каким был ваш опыт? Какие инструменты вы использовали и с какими проблемами сталкивались?
Надеюсь, вам понравился этот пост и он оказался полезным. Если у вас есть отзывы, пожалуйста, оставьте комментарий. Спасибо!