Ошибка форматирования даты в Android в React native

#javascript #reactjs #react-native

#javascript #reactjs #react-native

Вопрос:

Я получаю значение, подобное 202001.

Я хочу скрыть это, как January_2020.

Есть ли способ преобразовать его таким образом?:

 202001->January_2020
 

я попытался сделать это с помощью Intl, и он отлично работает для ios, но не работает в android.

я попробовал ниже.

 const dateToStr = (input) => {
    if (input.length !== 6) {
      return "wrong date syntax, use YYYYMM";
    }
    const parts = input.match(/([0-9]{4})([0-9]{2})/);
    if (!parts) {
      return "wrong date syntax, use YYYYMM";
    }
    // NOTE: check syntax of parts
    const formatter = new Intl.DateTimeFormat("en-EN", { month: "long" })
      .format;
    const formatted = formatter(
      new Date(Date.UTC(parseInt(parts[1]), parseInt(parts[2]) - 1))
    );

    return `${formatted}_${parts[1]}`;
  };
 

Как я могу получить это обновленное значение в Javascript без использования какой-либо библиотеки как в Android, так и в ios?

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

1. вы можете использовать moment. то есть moment(‘202001′,’ГГГГ’).format(‘MMM_YYYY’).

Ответ №1:

Хотя вы могли бы просто создать функцию синтаксического анализа, игнорируя использование встроенных возможностей форматирования даты или других библиотек для обработки дат (которые, как вы узнаете, также могут не работать на Android!), Давайте рассмотрим, почему ваше использование Intl работает в iOS, а не в Android, поскольку это гораздо интереснеечасть этого вопроса.

Почему я не могу использовать Intl на Android?

Ваш JS-код React Native выполняется в движке javascript, который отличается для iOS и Android.

iOS — использует движок JavaScriptCore (JSC), что важно, это движок, используемый WebKit и полученный из существующей реализации в Safari на устройстве.

Android — также использует JSC, однако он не получен из веб-браузера, предоставляемого операционной системой, вместо этого его двоичные файлы для безголовой версии движка JSC включены в качестве зависимости NPM от React Native.

Hermes — конечно, для iOS и Android можно настроить игнорирование значения по умолчанию и использовать движок Hermes JS, который в этом отношении будет действовать так же, как Android

Intl это спецификация, полезная преимущественно для пользовательских интерфейсов, и реализована в большинстве современных браузеров, включая iOS Safari, поэтому ваш код, выполняемый как часть среды выполнения React Native, может ее использовать.

Однако, как безголовый движок JS, JSC, включенный в Android, урезан и не содержит многих API, ориентированных на пользовательский интерфейс, поскольку безголовые движки JS, как правило, используются для целей, не связанных с пользовательским интерфейсом, поэтому нет необходимости добавлять раздувание пользовательского интерфейса. Как таковой, у него нет Intl доступного API.

Это может привести к исключительной путанице при использовании отладчика React Native, подключенного к симулятору Android или устройству Android, поскольку, похоже, это работает для Android! Это связано с тем, что при использовании отладчика React Native делегирует свою среду выполнения JS среде выполнения отладчика, поэтому фактически запускает ваш JS в движке V8, предоставляемом экземпляром браузера Chrome на вашем компьютере (который будет иметь Intl доступный API).

Итак, как использовать отсутствующую интернационализацию на Android?

Есть несколько способов сделать это…

Используйте другую сборку JSC

Вы можете настроить Android на использование другой сборки JSC, которая имеет функциональность интернационализации

Откройте свой android/app/build.gradle , и вы найдете этот фрагмент конфигурации

 /**
 * The preferred build flavor of JavaScriptCore.
 *
 * For example, to use the international variant, you can use:
 * `def jscFlavor = 'org.webkit:android-jsc-intl: '`
 *
 * The international variant includes ICU i18n library and necessary data
 * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
 * give correct results when using with locales other than en-US.  Note that
 * this variant is about 6MiB larger per architecture than default.
 */
def jscFlavor = 'org.webkit:android-jsc: '
 

Используйте пример и замените его в org.webkit:android-jsc-intl: варианте или найдите другой вариант, который соответствует вашим потребностям.

Добавьте полиполнение

Используя intl polyfill, доступный в NPM, вы можете исправить поддержку Intl API в своем коде. Это всегда будет проверять наличие Intl API перед исправлением, поэтому его можно безопасно включить и для вашего кода iOS.

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

Импорт данных polyfill и locale в файле ввода вашего приложения сделает его доступным для использования в Intl любом месте вашего приложения

 npm install --save intl
 
 // configure Intl polyfill
import 'intl';
import 'intl/locale-data/jsonp/en'; // other local data is available, import each locale that you need
 

Возможно, вам также потребуется отключить кэширование регулярных выражений из-за дополнительных ограничений в среде выполнения React Native JS

 // https://www.npmjs.com/package/intl#regexp-cache--restore
import IntlPolyfill from 'intl';
IntlPolyfill.__disableRegExpRestore();

 

А как насчет Hermes???

При использовании Hermes изменение аромата JSC не будет работать, поскольку Hermes заменяет JSC в качестве среды выполнения JavaScript. Однако использование polyfill также будет работать в сборках Hermes.

Почему еще я могу это исправить?

Помимо того, что это полезно для манипулирования датами в вашем случае использования, исправление Intl API в любой форме является полезным в вашем приложении React Native, поскольку это также позволит вам использовать всю мощь библиотек интернационализации, таких как react-intl, которые могут помочь вам реализовать i18n для дат, времени, числа, валюты, языки и т. Д. Декларативным образом