From: Santhosh Thottingal Date: Sun, 28 Sep 2014 09:01:46 +0000 (+0530) Subject: mediawiki.jqueryMsg: Support arbitrary expressions in plural forms X-Git-Tag: 1.31.0-rc.0~13739^2 X-Git-Url: http://git.cyclocoop.org/%22.%24redirect_annul.%22?a=commitdiff_plain;h=fd6ec11a54e622b0631d530d8289ee0789e993c9;p=lhc%2Fweb%2Fwiklou.git mediawiki.jqueryMsg: Support arbitrary expressions in plural forms In I15c167f245 mw.jqueryMsg.htmlEmitter#plural was modified to convert the plural params to flat html. This caused extlink params as plural forms expanded as text node and escaped. This patch improves the plural support by: * Allowing valid parser expressions as plural form parameters. They wont be converted to html, parsed nodes will be preserved in plural calculation * For explicit plural forms like n=expression, the expression can be any valid parser expression. They also will not be coverted to html, nodes will be preserved * Move the splitting by equal sign logic for explicit plural forms to jqueryMsg, avoiding mediawiki.language#convertPlural to do parsing logc. Explicit plural forms, if any, are passed as a parameter to mediawiki.language#convertPlural Includes test cases for all combinations of the above cases. mediawiki.jqueryMsg.peg can be improved to support digit=expression as an additional form for templateParam to better handle this. But it looks it can potentially disturb other parser functions. Not attempted. Bug: 70617 Change-Id: I3c3cbb6d3676903941c40b658032b4c543556e06 --- diff --git a/resources/src/mediawiki.language/mediawiki.language.js b/resources/src/mediawiki.language/mediawiki.language.js index d4f3c69e0a..dceae1178a 100644 --- a/resources/src/mediawiki.language/mediawiki.language.js +++ b/resources/src/mediawiki.language/mediawiki.language.js @@ -40,39 +40,18 @@ $.extend( mw.language, { * * @param {number} count Non-localized quantifier * @param {Array} forms List of plural forms + * @param {Object} [explicitPluralForms] List of explicit plural forms * @return {string} Correct form for quantifier in this language */ - convertPlural: function ( count, forms ) { + convertPlural: function ( count, forms, explicitPluralForms ) { var pluralRules, - formCount, - form, - index, - equalsPosition, pluralFormIndex = 0; - if ( !forms || forms.length === 0 ) { - return ''; + if ( explicitPluralForms && explicitPluralForms[count] ) { + return explicitPluralForms[count]; } - // Handle for explicit n= forms - for ( index = 0; index < forms.length; index++ ) { - form = forms[index]; - if ( /^\d+=/.test( form ) ) { - equalsPosition = form.indexOf( '=' ); - formCount = parseInt( form.slice( 0, equalsPosition ), 10 ); - if ( formCount === count ) { - return form.slice( equalsPosition + 1 ); - } - forms[index] = undefined; - } - } - - // Remove explicit plural forms from the forms. - forms = $.map( forms, function ( form ) { - return form; - } ); - - if ( forms.length === 0 ) { + if ( !forms || forms.length === 0 ) { return ''; } diff --git a/resources/src/mediawiki/mediawiki.jqueryMsg.js b/resources/src/mediawiki/mediawiki.jqueryMsg.js index ad71b08384..3eaa6d2cd1 100644 --- a/resources/src/mediawiki/mediawiki.jqueryMsg.js +++ b/resources/src/mediawiki/mediawiki.jqueryMsg.js @@ -1129,17 +1129,42 @@ * @return {string} selected pluralized form according to current language */ plural: function ( nodes ) { - var forms, formIndex, node, count; + var forms, firstChild, firstChildText, + explicitPluralForms = {}, explicitPluralFormNumber, formIndex, form, count; + count = parseFloat( this.language.convertNumber( nodes[0], true ) ); forms = nodes.slice( 1 ); for ( formIndex = 0; formIndex < forms.length; formIndex++ ) { - node = forms[formIndex]; - if ( node.jquery && node.hasClass( 'mediaWiki_htmlEmitter' ) ) { - // This is a nested node, already expanded. - forms[formIndex] = forms[formIndex].html(); + form = forms[formIndex]; + + if ( form.jquery && form.hasClass( 'mediaWiki_htmlEmitter' ) ) { + // This is a nested node, may be an explicit plural form like 5=[$2 linktext] + firstChild = form.contents().get( 0 ); + if ( firstChild && firstChild.nodeType === Node.TEXT_NODE ) { + firstChildText = firstChild.textContent; + if ( /^\d+=/.test( firstChildText ) ) { + explicitPluralFormNumber = parseInt( firstChildText.split( /=/ )[0], 10 ); + // Use the digit part as key and rest of first text node and + // rest of child nodes as value. + firstChild.textContent = firstChildText.slice( firstChildText.indexOf( '=' ) + 1 ); + explicitPluralForms[explicitPluralFormNumber] = form; + forms[formIndex] = undefined; + } + } + } else if ( /^\d+=/.test( form ) ) { + // Simple explicit plural forms like 12=a dozen + explicitPluralFormNumber = parseInt( form.split( /=/ )[0], 10 ); + explicitPluralForms[explicitPluralFormNumber] = form.slice( form.indexOf( '=' ) + 1 ); + forms[formIndex] = undefined; } } - return forms.length ? this.language.convertPlural( count, forms ) : ''; + + // Remove explicit plural forms from the forms. They were set undefined in the above loop. + forms = $.map( forms, function ( form ) { + return form; + } ); + + return this.language.convertPlural( count, forms, explicitPluralForms ); }, /** diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js index 906fd27f49..ece5116a36 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js @@ -54,7 +54,9 @@ 'jquerymsg-test-version-entrypoints-index-php': '[https://www.mediawiki.org/wiki/Manual:index.php index.php]', - 'external-link-replace': 'Foo [$1 bar]' + 'external-link-replace': 'Foo [$1 bar]', + 'external-link-plural': 'Foo {{PLURAL:$1|is [$2 one]|are [$2 some]|2=[$2 two]|3=three|4=a=b|5=}} things.', + 'plural-only-explicit-forms': 'It is a {{PLURAL:$1|1=single|2=double}} room.' } } ) ); @@ -85,7 +87,7 @@ } ); } - QUnit.test( 'Replace', 9, function ( assert ) { + QUnit.test( 'Replace', 16, function ( assert ) { mw.messages.set( 'simple', 'Foo $1 baz $2' ); assert.equal( formatParse( 'simple' ), 'Foo $1 baz $2', 'Replacements with no substitutes' ); @@ -133,6 +135,41 @@ 'Foo bar', 'Href is not double-escaped in wikilink function' ); + assert.equal( + formatParse( 'external-link-plural', 1, 'http://example.org' ), + 'Foo is one things.', + 'Link is expanded inside plural and is not escaped html' + ); + assert.equal( + formatParse( 'external-link-plural', 2, 'http://example.org' ), + 'Foo two things.', + 'Link is expanded inside an explicit plural form and is not escaped html' + ); + assert.equal( + formatParse( 'external-link-plural', 3 ), + 'Foo three things.', + 'A simple explicit plural form co-existing with complex explicit plural forms' + ); + assert.equal( + formatParse( 'external-link-plural', 4, 'http://example.org' ), + 'Foo a=b things.', + 'Only first equal sign is used as delimiter for explicit plural form. Repeated equal signs does not create issue' + ); + assert.equal( + formatParse( 'external-link-plural', 5, 'http://example.org' ), + 'Foo are some things.', + 'Invalid explicit plural form. Plural fallback to the "other" plural form' + ); + assert.equal( + formatParse( 'external-link-plural', 6, 'http://example.org' ), + 'Foo are some things.', + 'Plural fallback to the "other" plural form' + ); + assert.equal( + formatParse( 'plural-only-explicit-forms', 2 ), + 'It is a double room.', + 'Plural with explicit forms alone.' + ); } ); QUnit.test( 'Plural', 6, function ( assert ) {