From e8dd1f43fb16919007aa865560eaef24e2d6cc08 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Niklas=20Laxstr=C3=B6m?= Date: Wed, 30 Nov 2016 09:35:20 +0100 Subject: [PATCH] mediawiki.language: fix convertNumber( ..., true ) It was not handling separator unformatting. In mediawiki.jqueryMsg.test.js fix broken test case: * Hindi does not use comma as decimal separator! * The number was not formatted as it would be by the formatting code. By definition back-conversion is only defined for input that we generate. For other input the output is undefined. There are other tests with same issue, but I did not touch them now. Bug: T151198 Change-Id: Icc9bc09675151645055c7e7f706472a15cc81b0f --- .../mediawiki.language.numbers.js | 74 +++++++++++++------ .../mediawiki/mediawiki.jqueryMsg.test.js | 2 +- .../mediawiki/mediawiki.language.test.js | 10 +++ 3 files changed, 63 insertions(+), 23 deletions(-) diff --git a/resources/src/mediawiki.language/mediawiki.language.numbers.js b/resources/src/mediawiki.language/mediawiki.language.numbers.js index 11926508b5..10ceecc48d 100644 --- a/resources/src/mediawiki.language/mediawiki.language.numbers.js +++ b/resources/src/mediawiki.language/mediawiki.language.numbers.js @@ -158,6 +158,31 @@ return valueParts.join( options.decimal ); } + /** + * Helper function to flip transformation tables. + * + * @param {...Object} Transformation tables + * @return {Object} + */ + function flipTransform() { + var i, key, table, flipped = {}; + + // Ensure we strip thousand separators. This might be overwritten. + flipped[ ',' ] = ''; + + for ( i = 0; i < arguments.length; i++ ) { + table = arguments[ i ]; + for ( key in table ) { + if ( table.hasOwnProperty( key ) ) { + // The thousand separator should be deleted + flipped[ table[ key ] ] = key === ',' ? '' : key; + } + } + } + + return flipped; + } + $.extend( mw.language, { /** @@ -168,46 +193,51 @@ * @return {number|string} Formatted number */ convertNumber: function ( num, integer ) { - var i, tmp, transformTable, numberString, convertedNumber, pattern; - - pattern = mw.language.getData( mw.config.get( 'wgUserLanguage' ), - 'digitGroupingPattern' ) || '#,##0.###'; + var transformTable, digitTransformTable, separatorTransformTable, + i, numberString, convertedNumber, pattern; - // Set the target transform table: - transformTable = mw.language.getDigitTransformTable(); - - if ( !transformTable ) { + // Quick shortcut for plain numbers + if ( integer && parseInt( num, 10 ) === num ) { return num; } - // Check if the 'restore' to Latin number flag is set: + // Load the transformation tables (can be empty) + digitTransformTable = mw.language.getDigitTransformTable(); + separatorTransformTable = mw.language.getSeparatorTransformTable(); + if ( integer ) { - if ( parseInt( num, 10 ) === num ) { - return num; - } - tmp = []; - for ( i in transformTable ) { - tmp[ transformTable[ i ] ] = i; - } - transformTable = tmp; + // Reverse the digit transformation tables if we are doing unformatting + transformTable = flipTransform( separatorTransformTable, digitTransformTable ); numberString = String( num ); } else { - // Ignore transform table if wgTranslateNumerals is false - if ( !mw.config.get( 'wgTranslateNumerals' ) ) { - transformTable = []; + // This check being here means that digits can still be unformatted + // even if we do not produce them. This seems sane behavior. + if ( mw.config.get( 'wgTranslateNumerals' ) ) { + transformTable = digitTransformTable; } + + // Commaying is more complex, so we handle it here separately. + // When unformatting, we just use separatorTransformTable. + pattern = mw.language.getData( mw.config.get( 'wgUserLanguage' ), + 'digitGroupingPattern' ) || '#,##0.###'; numberString = mw.language.commafy( num, pattern ); } convertedNumber = ''; for ( i = 0; i < numberString.length; i++ ) { - if ( transformTable[ numberString[ i ] ] ) { + if ( transformTable.hasOwnProperty( numberString[ i ] ) ) { convertedNumber += transformTable[ numberString[ i ] ]; } else { convertedNumber += numberString[ i ]; } } - return integer ? parseInt( convertedNumber, 10 ) : convertedNumber; + + if ( integer ) { + // Parse string to integer. This loses decimals! + convertedNumber = parseInt( convertedNumber, 10 ); + } + + return convertedNumber; }, /** diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js index 7a00943e7f..f848f3edc8 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js @@ -884,7 +884,7 @@ }, { lang: 'hi', - number: '१२३४५६,७८९', + number: '१,२३,४५६', result: '123456', integer: true, description: 'formatnum test for Hindi, Devanagari digits passed to get integer value' diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js index e4c3851593..23720a891c 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js @@ -43,6 +43,16 @@ assert.equal( mw.language.commafy( 123456789.567, '###,###,#0.00' ), '1,234,567,89.56', 'Decimal part as group of 3 and last one 2' ); } ); + QUnit.test( 'mw.language.convertNumber', 2, function ( assert ) { + mw.language.setData( 'en', 'digitGroupingPattern', null ); + mw.language.setData( 'en', 'digitTransformTable', null ); + mw.language.setData( 'en', 'separatorTransformTable', { ',': '.', '.': ',' } ); + mw.config.set( 'wgUserLanguage', 'en' ); + + assert.equal( mw.language.convertNumber( 1800 ), '1.800', 'formatting' ); + assert.equal( mw.language.convertNumber( "1.800", true ), '1800', 'unformatting' ); + } ); + function grammarTest( langCode, test ) { // The test works only if the content language is opt.language // because it requires [lang].js to be loaded. -- 2.20.1