react-native .toLocaleString() not working on android

React Native

React Native Problem Overview


I'm using .toLocaleString() on react-native for my number output. All work on IOS but seems not working on Android. This is normal or? Do I need to use a function for the decimal?

enter image description here

React Native Solutions


Solution 1 - React Native

rather than using a polyfill or an external dependency, change the JSC your android app builds with. For the newer versions of react-native add or override the following line in app/build.gradle

def jscFlavor = 'org.webkit:android-jsc-intl:+'

Solution 2 - React Native

You can use

number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")

Solution 3 - React Native

This is an issue with Javascript core used to run react native in Android and not with react native itself. To overcome this, you'll have to integrate latest javascript core into your android build or upgrade react native to 0.59.

The details are documented in JSC Android Buildscripts repo.

Now for people who would like to do the locale string formatting without needing to integrate the entire javascript core, Javascript has Internationalization API which lets you format numbers to language sensitive format. Documentation available at MDN

This API is not available in android and needs to be polyfilled using Intl

In your project root, install the Intl library

yarn add intl

And then in your project's index file (index.js) add the following code at the top of the file:

if(Platform.OS === 'android') { // only android needs polyfill
  require('intl'); // import intl object
  require('intl/locale-data/jsonp/en-IN'); // load the required locale details
}

After doing the above two steps, you can now get locale string anywhere in your project using

new Intl.NumberFormat('en-IN', { style: 'currency', currency: 'INR' }).format(10000000);

In case you need to format number for another locale code, all the locale code details are available under the intl/locale-data/jsonp/ directory. Simply require the ones you need in your index.js file.

Solution 4 - React Native

On newer versions of RN >0.62 you can change the JSC (JavaScriptCore) build variant to support/include ICU i18n library and necessary data allowing to use e.g. Date.toLocaleString and String.localeCompare

Replace this line in your android/app/build.gradle file

def jscFlavor = 'org.webkit:android-jsc:+'

with this line

def jscFlavor = 'org.webkit:android-jsc-intl:+'

Clean build and react-native run android

Note

This variant is about 6MiB larger per architecture than default. So, expect your APK size to increase by about 4MB for each APK architecture build if using def enableSeparateBuildPerCPUArchitecture = true and a more bigger APK if separate build per architecture is disabled

Solution 5 - React Native

The reason for this is very old version of JavaScriptCore used by react-native. iOS embeds own version which is why it is working fine there.

Issue still exists (some reading about where it's heading https://github.com/facebook/react-native/issues/19737)

And more info about this from Airbnb devs https://medium.com/airbnb-engineering/react-native-at-airbnb-the-technology-dafd0b43838 (search for "JavaScriptCore inconsistencies")

Solution 6 - React Native

(value) => {
    if (typeof value === 'number') {
      const [currency, cents] = (value / 100).toFixed(2).toString().split('.');

      return `${currency.replace(/\B(?=(\d{3})+(?!\d))/g, '.')},${cents}`;
    }

    return '0,00';
  }

Solution 7 - React Native

it's more recent and lightweight, please check

  1. First install:

> yarn add @formatjs/intl-getcanonicallocales @formatjs/intl-locale @formatjs/intl-pluralrules @formatjs/intl-numberformat

  1. Check if need polyfill

import {shouldPolyfill} from '@formatjs/intl-numberformat/should-polyfill'

if (shouldPolyfill()) {
	require('@formatjs/intl-getcanonicallocales/polyfill');
	require('@formatjs/intl-locale/polyfill');
	require('@formatjs/intl-pluralrules/polyfill');
	require('@formatjs/intl-numberformat/polyfill');
	require('@formatjs/intl-numberformat/locale-data/en-US');
}

see source: https://formatjs.io/docs/polyfills/intl-numberformat/

Solution 8 - React Native

A very easy and straight forward way is to use a polyfill: First it needs to be installed:

npm i number-to-locale-string-polyfill

This has to be added in your code, best just outside the class/function where you want to use .toLocaleString().

require('number-to-locale-string-polyfill');

Solution 9 - React Native

Displaying currency values in React Native

A zero dependencies solution:

const parseCurr = (value) =>
   Platform.OS === 'android'  
      ?  '$' + price.toFixed(2)  
      :  price.toLocaleString('en-US', { style: 'currency', currency:'USD' });


parseCurr(25.75) // => $25.75

A real life example (money values are multiplied by 100 for better cents precision) and converting the value to Brazilian Reais (R$)

export const getBRPrice = (price: number) => {
   const parsedPrice = 
      ( price / 100 ).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });

	return Platform.OS === 'android'
		? `R$${ ( price / 100 ).toFixed(2) }`
		: parsedPrice;
};


// getBRPrice(450) => R$4,50

Solution 10 - React Native

I solved this using a custom function

function numberToMoney(amount, simbol = '$', decimalCount = 2, decimal 
   = ".", thousands = ",") {
   decimalCount = Math.abs(decimalCount)
   decimalCount = isNaN(decimalCount) ? 2 : decimalCount

   const negativeSign = amount < 0 ? "-" : ""

   const i = parseInt(amount = Math.abs(Number(amount) || 
             0).toFixed(decimalCount)).toString()
   const j = (i.length > 3) ? i.length % 3 : 0

   return simbol + negativeSign + (j ? i.substr(0, j) + thousands : '') + 
   i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands) + (decimalCount ? 
   decimal + Math.abs(amount - i).toFixed(decimalCount).slice(2) : "")
};

No need to install extra packages

Solution 11 - React Native

Merging some responses from this thread, you can use this code where it is possible to customize the formatted response

const defaultOptions = {
  significantDigits: 2,
  thousandsSeparator: ',',
  decimalSeparator: '.',
  symbol: '$'
}

const currencyFormatter = (value, options) => {
  if (typeof value !== 'number') value = 0.0
  options = { ...defaultOptions, ...options }
  value = value.toFixed(options.significantDigits)

  const [currency, decimal] = value.split('.')
  return `${options.symbol} ${currency.replace(
    /\B(?=(\d{3})+(?!\d))/g,
    options.thousandsSeparator
  )}${options.decimalSeparator}${decimal}`
}

Solution 12 - React Native

function numberWithCommas(x) {
   return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
}

This will remove commas after decimal point

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEQuimperView Question on Stackoverflow
Solution 1 - React NativeTaylor JohnsonView Answer on Stackoverflow
Solution 2 - React NativeTamir Haim RabiaView Answer on Stackoverflow
Solution 3 - React NativeDani AkashView Answer on Stackoverflow
Solution 4 - React NativeIsaac OluwatemilorunView Answer on Stackoverflow
Solution 5 - React NativeSebastian SuchanowskiView Answer on Stackoverflow
Solution 6 - React NativeJoão ViniciusView Answer on Stackoverflow
Solution 7 - React NativeMike VargasView Answer on Stackoverflow
Solution 8 - React NativeAnna Ira HurnausView Answer on Stackoverflow
Solution 9 - React NativeFelipe ChernicharoView Answer on Stackoverflow
Solution 10 - React NativeMaicon GiltonView Answer on Stackoverflow
Solution 11 - React NativeGabriel BritoView Answer on Stackoverflow
Solution 12 - React Nativeolaleye olabanjoView Answer on Stackoverflow