*
* @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 '';
}
* @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 );
},
/**
'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.'
}
} ) );
} );
}
- 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' );
'Foo <a href="http://example.org/?x=y&z">bar</a>',
'Href is not double-escaped in wikilink function'
);
+ assert.equal(
+ formatParse( 'external-link-plural', 1, 'http://example.org' ),
+ 'Foo is <a href="http://example.org">one</a> things.',
+ 'Link is expanded inside plural and is not escaped html'
+ );
+ assert.equal(
+ formatParse( 'external-link-plural', 2, 'http://example.org' ),
+ 'Foo <a href=\"http://example.org\">two</a> 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 <a href="http://example.org">some</a> things.',
+ 'Invalid explicit plural form. Plural fallback to the "other" plural form'
+ );
+ assert.equal(
+ formatParse( 'external-link-plural', 6, 'http://example.org' ),
+ 'Foo are <a href="http://example.org">some</a> 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 ) {