From 4cc9011beab33bbd1b9933c222aa2a22086cfed5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bartosz=20Dziewo=C5=84ski?= Date: Tue, 10 Oct 2017 22:52:36 +0200 Subject: [PATCH] mediawiki.language: Implement non-digit-grouping of four-digit numbers In some languages it's conventional not to insert a thousands separator in numbers that are four digits long (1000-9999). This now matches the behavior of the PHP Language class. Bug: T177846 Change-Id: I6f4e51a907b084bd7fde09cd9c16c9bf41cdc98c --- .../ResourceLoaderLanguageDataModule.php | 1 + .../mediawiki.language.init.js | 1 + .../mediawiki.language.numbers.js | 37 ++++++++++++------- .../mediawiki/mediawiki.language.test.js | 12 +++++- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/includes/resourceloader/ResourceLoaderLanguageDataModule.php b/includes/resourceloader/ResourceLoaderLanguageDataModule.php index ef942faf20..e78484a2f5 100644 --- a/includes/resourceloader/ResourceLoaderLanguageDataModule.php +++ b/includes/resourceloader/ResourceLoaderLanguageDataModule.php @@ -40,6 +40,7 @@ class ResourceLoaderLanguageDataModule extends ResourceLoaderModule { return [ 'digitTransformTable' => $language->digitTransformTable(), 'separatorTransformTable' => $language->separatorTransformTable(), + 'minimumGroupingDigits' => $language->minimumGroupingDigits(), 'grammarForms' => $language->getGrammarForms(), 'grammarTransformations' => $language->getGrammarTransformations(), 'pluralRules' => $language->getPluralRules(), diff --git a/resources/src/mediawiki.language/mediawiki.language.init.js b/resources/src/mediawiki.language/mediawiki.language.init.js index 808f6e5e02..e5cf26e8d3 100644 --- a/resources/src/mediawiki.language/mediawiki.language.init.js +++ b/resources/src/mediawiki.language/mediawiki.language.init.js @@ -32,6 +32,7 @@ * * - `digitTransformTable` * - `separatorTransformTable` + * - `minimumGroupingDigits` * - `grammarForms` * - `pluralRules` * - `digitGroupingPattern` diff --git a/resources/src/mediawiki.language/mediawiki.language.numbers.js b/resources/src/mediawiki.language/mediawiki.language.numbers.js index 83277cb00f..2392089cc2 100644 --- a/resources/src/mediawiki.language/mediawiki.language.numbers.js +++ b/resources/src/mediawiki.language/mediawiki.language.numbers.js @@ -66,9 +66,10 @@ * @private * @param {number} value the number to be formatted, ignores sign * @param {string} pattern the number portion of a pattern (e.g. `#,##0.00`) - * @param {Object} [options] If provided, both option keys must be present: + * @param {Object} [options] If provided, all option keys must be present: * @param {string} options.decimal The decimal separator. Defaults to: `'.'`. * @param {string} options.group The group separator. Defaults to: `','`. + * @param {number|null} options.minimumGroupingDigits * @return {string} */ function commafyNumber( value, pattern, options ) { @@ -143,17 +144,22 @@ } } - for ( whole = valueParts[ 0 ]; whole; ) { - off = groupSize ? whole.length - groupSize : 0; - pieces.push( ( off > 0 ) ? whole.slice( off ) : whole ); - whole = ( off > 0 ) ? whole.slice( 0, off ) : ''; - - if ( groupSize2 ) { - groupSize = groupSize2; - groupSize2 = null; + if ( + options.minimumGroupingDigits === null || + valueParts[ 0 ].length >= groupSize + options.minimumGroupingDigits + ) { + for ( whole = valueParts[ 0 ]; whole; ) { + off = groupSize ? whole.length - groupSize : 0; + pieces.push( ( off > 0 ) ? whole.slice( off ) : whole ); + whole = ( off > 0 ) ? whole.slice( 0, off ) : ''; + + if ( groupSize2 ) { + groupSize = groupSize2; + groupSize2 = null; + } } + valueParts[ 0 ] = pieces.reverse().join( options.group ); } - valueParts[ 0 ] = pieces.reverse().join( options.group ); return valueParts.join( options.decimal ); } @@ -194,7 +200,7 @@ */ convertNumber: function ( num, integer ) { var transformTable, digitTransformTable, separatorTransformTable, - i, numberString, convertedNumber, pattern; + i, numberString, convertedNumber, pattern, minimumGroupingDigits; // Quick shortcut for plain numbers if ( integer && parseInt( num, 10 ) === num ) { @@ -220,7 +226,9 @@ // When unformatting, we just use separatorTransformTable. pattern = mw.language.getData( mw.config.get( 'wgUserLanguage' ), 'digitGroupingPattern' ) || '#,##0.###'; - numberString = mw.language.commafy( num, pattern ); + minimumGroupingDigits = mw.language.getData( mw.config.get( 'wgUserLanguage' ), + 'minimumGroupingDigits' ) || null; + numberString = mw.language.commafy( num, pattern, minimumGroupingDigits ); } if ( transformTable ) { @@ -271,10 +279,11 @@ * * @param {number} value * @param {string} pattern Pattern string as described by Unicode TR35 + * @param {number|null} [minimumGroupingDigits=null] * @throws {Error} If unable to find a number expression in `pattern`. * @return {string} */ - commafy: function ( value, pattern ) { + commafy: function ( value, pattern, minimumGroupingDigits ) { var numberPattern, transformTable = mw.language.getSeparatorTransformTable(), group = transformTable[ ',' ] || ',', @@ -285,12 +294,14 @@ pattern = patternList[ ( value < 0 ) ? 1 : 0 ] || ( '-' + positivePattern ); numberPattern = positivePattern.match( numberPatternRE ); + minimumGroupingDigits = minimumGroupingDigits !== undefined ? minimumGroupingDigits : null; if ( !numberPattern ) { throw new Error( 'unable to find a number expression in pattern: ' + pattern ); } return pattern.replace( numberPatternRE, commafyNumber( value, numberPattern[ 0 ], { + minimumGroupingDigits: minimumGroupingDigits, decimal: decimal, group: group } ) ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js index 5ce61ea752..31548b6bd2 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js @@ -49,11 +49,20 @@ mw.language.setData( 'en', 'digitGroupingPattern', null ); mw.language.setData( 'en', 'digitTransformTable', null ); mw.language.setData( 'en', 'separatorTransformTable', { ',': '.', '.': ',' } ); + mw.language.setData( 'en', 'minimumGroupingDigits', null ); mw.config.set( 'wgUserLanguage', 'en' ); mw.config.set( 'wgTranslateNumerals', true ); - assert.equal( mw.language.convertNumber( 1800 ), '1.800', 'formatting' ); + assert.equal( mw.language.convertNumber( 180 ), '180', 'formatting 3-digit' ); + assert.equal( mw.language.convertNumber( 1800 ), '1.800', 'formatting 4-digit' ); + assert.equal( mw.language.convertNumber( 18000 ), '18.000', 'formatting 5-digit' ); + assert.equal( mw.language.convertNumber( '1.800', true ), '1800', 'unformatting' ); + + mw.language.setData( 'en', 'minimumGroupingDigits', 2 ); + assert.equal( mw.language.convertNumber( 180 ), '180', 'formatting 3-digit with minimumGroupingDigits=2' ); + assert.equal( mw.language.convertNumber( 1800 ), '1800', 'formatting 4-digit with minimumGroupingDigits=2' ); + assert.equal( mw.language.convertNumber( 18000 ), '18.000', 'formatting 5-digit with minimumGroupingDigits=2' ); } ); QUnit.test( 'mw.language.convertNumber - digitTransformTable', function ( assert ) { @@ -61,6 +70,7 @@ mw.config.set( 'wgTranslateNumerals', true ); mw.language.setData( 'hi', 'digitGroupingPattern', null ); mw.language.setData( 'hi', 'separatorTransformTable', { ',': '.', '.': ',' } ); + mw.language.setData( 'hi', 'minimumGroupingDigits', null ); // Example from Hindi (MessagesHi.php) mw.language.setData( 'hi', 'digitTransformTable', { -- 2.20.1