[TIMOB-27874] TiAPI: Add Ti.Locale.parseDecimal() method
GitHub Issue | n/a |
---|---|
Type | New Feature |
Priority | Medium |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2020-08-07T10:46:11.000+0000 |
Affected Version/s | n/a |
Fix Version/s | Release 9.1.0 |
Components | Android, iOS |
Labels | android, decimal, ios, locale, parse |
Reporter | Joshua Quick |
Assignee | Joshua Quick |
Created | 2020-04-30T05:33:30.000+0000 |
Updated | 2020-08-07T10:46:11.000+0000 |
Description
*Summary:*
Titanium has APIs to turn numbers into localized strings, but there are no APIs to convert a localized numeric string back to a number type.
*Proposed Solution:*
Add the following method.
Ti.Locale.parseDecimal(text \[, locale \]); // Returns number type.
If the above was given an invalid string, then it will return NaN
(Not-a-Number), which matches JavaScript's standard Number.parseFloat()
method behavior.
*Main Use-Case:*
A TextField
using a decimal keyboard type will be using the device's current locale for the decimal separator. This means the decimal separator will be a comma ,
in Europe. It will can also be a unicode decimal separator for Arabic locales. When reading the TextField
string "value" property, the app developer will need an easy means of parsing the localized numeric string back to a JS number type.
*Test Cases:*
Converting a number to localized string and then back to a number.
var oldNumericValue = 123.456;
var stringValue = String.formatDecimal(oldNumericValue);
var newNumericValue = Ti.Locale.parseDecimal(stringValue);
if (Math.abs(newNumericValue - oldNumericValue) < Number.EPSILON) {
console.log('Parsed number matches original number.');
}
Parsing equivalent numbers from 2 different locales.
var number1 = Ti.Locale.parseDecimal('1,234,567.8', 'en-US');
var number2 = Ti.Locale.parseDecimal('1.234.567,8', 'de-DE');
if (Math.abs(number1 - number2) < Number.EPSILON) {
console.log('Parsed numbers match.');
}
Strings that cannot be converted to a number will return NaN.
var result = Ti.Locale.parseDecimal('Invalid');
if (Number.isNaN(result)) {
console.log('Invalid string returned NaN.');
}
What would the relation be to the Intl APIs for NumberFormat (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat), I believe we don't polyfill Intl right now (core-js skips it due to the size of it), but I think we should deal with this in a spec'd manner rather than our own APIs Edit: Ignore this comment, I totally misread the intention here
[~eharris], I'm pretty sure we do support the
Intl
APIs on iOS, but we definitely don't on Android. If we were to#if
it into V8, then it would add a huge 20 MB ICU (International Components for Unicode) library for just a single architecture... and we would need to include at least 2 architectures. This is not mobile friendly. Especially since the max APK size you can upload to Google Play is 100 MB. I didn't see any official JS APIs that support parsing localized numeric strings, so, I came up with the above. I named them similar to the existingtoLocaleString()
,toLocaleTimeString()
,toLocaleDateString()
, etc. Although it turns out those APIs on Android ignore the current locale and only do the default "en-us" locale. (That should be a separate ticket. We have to localize the strings ourselves on the Java side since Android NDK does not support locale on the C/C++ side.)Maybe instead of extending the
Number
type and risking future collisions, we should add these APIs to ourTi.Locale
module instead.PR (master): https://github.com/appcelerator/titanium_mobile/pull/11683
FR Passed, Waiting on Jenkins build.
merged to master for 9.1.0 target
Below PR improves handling for locales that use whitespace chars for thousands separator like French. PR (master): https://github.com/appcelerator/titanium_mobile/pull/11824
Fix verified on build 9.1.0.v20200804082025. Ticket closed.