diff --git a/package-lock.json b/package-lock.json index ba15feeacae6..cfaf942936e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,6 @@ "@expensify/react-native-live-markdown": "0.1.5", "@expo/metro-runtime": "~3.1.1", "@formatjs/intl-datetimeformat": "^6.10.0", - "@formatjs/intl-getcanonicallocales": "^2.2.0", "@formatjs/intl-listformat": "^7.2.2", "@formatjs/intl-locale": "^3.3.0", "@formatjs/intl-numberformat": "^8.5.0", diff --git a/package.json b/package.json index d1974b99b91e..9d4782ca0d7a 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,6 @@ "@expensify/react-native-live-markdown": "0.1.5", "@expo/metro-runtime": "~3.1.1", "@formatjs/intl-datetimeformat": "^6.10.0", - "@formatjs/intl-getcanonicallocales": "^2.2.0", "@formatjs/intl-listformat": "^7.2.2", "@formatjs/intl-locale": "^3.3.0", "@formatjs/intl-numberformat": "^8.5.0", @@ -154,8 +153,8 @@ "react-native-plaid-link-sdk": "10.8.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-release-profiler": "^0.1.6", "react-native-reanimated": "^3.7.2", + "react-native-release-profiler": "^0.1.6", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.8.2", "react-native-screens": "3.29.0", diff --git a/src/CONST.ts b/src/CONST.ts index 132b49c16ef7..ebf6ced94798 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -2922,7 +2922,7 @@ const CONST = { CURRENCY: 'XAF', FORMAT: 'symbol', SAMPLE_INPUT: '123456.789', - EXPECTED_OUTPUT: 'FCFA 123,457', + EXPECTED_OUTPUT: 'FCFA 123,457', }, PATHS_TO_TREAT_AS_EXTERNAL: ['NewExpensify.dmg', 'docs/index.html'], diff --git a/src/libs/IntlPolyfill/index.android.ts b/src/libs/IntlPolyfill/index.android.ts new file mode 100644 index 000000000000..7a21ae26bfa4 --- /dev/null +++ b/src/libs/IntlPolyfill/index.android.ts @@ -0,0 +1,17 @@ +import polyfillListFormat from './polyfillListFormat'; +import type IntlPolyfill from './types'; + +/** + * Polyfill the Intl API, always performed for native devices. + */ +const intlPolyfill: IntlPolyfill = () => { + // Native devices require extra polyfills which are + // not yet implemented in hermes. + // see support: https://hermesengine.dev/docs/intl/ + + require('@formatjs/intl-locale/polyfill'); + + polyfillListFormat(); +}; + +export default intlPolyfill; diff --git a/src/libs/IntlPolyfill/index.native.ts b/src/libs/IntlPolyfill/index.ios.ts similarity index 56% rename from src/libs/IntlPolyfill/index.native.ts rename to src/libs/IntlPolyfill/index.ios.ts index ca1c8f4c250e..569b666eb434 100644 --- a/src/libs/IntlPolyfill/index.native.ts +++ b/src/libs/IntlPolyfill/index.ios.ts @@ -7,12 +7,21 @@ import type IntlPolyfill from './types'; * Polyfill the Intl API, always performed for native devices. */ const intlPolyfill: IntlPolyfill = () => { - // Native devices require extra polyfills - require('@formatjs/intl-getcanonicallocales/polyfill'); + // Native devices require extra polyfills which are + // not yet implemented in hermes. + // see support: https://hermesengine.dev/docs/intl/ + require('@formatjs/intl-locale/polyfill'); + + // Required to polyfill NumberFormat on iOS + // see: https://github.com/facebook/hermes/issues/1172#issuecomment-1776156538 require('@formatjs/intl-pluralrules/polyfill'); polyfillNumberFormat(); + + // Required to polyfill DateTimeFormat on iOS + // see: https://github.com/facebook/hermes/issues/1172#issuecomment-1776156538 polyfillDateTimeFormat(); + polyfillListFormat(); }; diff --git a/src/libs/IntlPolyfill/polyfillNumberFormat.ts b/src/libs/IntlPolyfill/polyfillNumberFormat.ts index 1fac01958f05..58d8adf1b761 100644 --- a/src/libs/IntlPolyfill/polyfillNumberFormat.ts +++ b/src/libs/IntlPolyfill/polyfillNumberFormat.ts @@ -1,21 +1,29 @@ import CONST from '@src/CONST'; +const numberFormat = new Intl.NumberFormat(CONST.LOCALES.DEFAULT, { + style: CONST.POLYFILL_TEST.STYLE, + currency: CONST.POLYFILL_TEST.CURRENCY, + currencyDisplay: CONST.POLYFILL_TEST.FORMAT, +}); + /** * Check if the locale data is as expected on the device. * Ensures that the currency data is consistent across devices. */ function hasOldCurrencyData(): boolean { - return ( - new Intl.NumberFormat(CONST.LOCALES.DEFAULT, { - style: CONST.POLYFILL_TEST.STYLE, - currency: CONST.POLYFILL_TEST.CURRENCY, - currencyDisplay: CONST.POLYFILL_TEST.FORMAT, - }).format(Number(CONST.POLYFILL_TEST.SAMPLE_INPUT)) !== CONST.POLYFILL_TEST.EXPECTED_OUTPUT - ); + return numberFormat.format(Number(CONST.POLYFILL_TEST.SAMPLE_INPUT)) !== CONST.POLYFILL_TEST.EXPECTED_OUTPUT; +} + +/** + * Checks if the formatToParts function is available on the + * Intl.NumberFormat object. + */ +function hasFormatToParts(): boolean { + return typeof numberFormat.formatToParts === 'function'; } export default function () { - if (Intl && 'NumberFormat' in Intl && !hasOldCurrencyData()) { + if (Intl && 'NumberFormat' in Intl && !hasOldCurrencyData() && hasFormatToParts()) { return; }