mediawiki.jqueryMsg: Support {{GENDER:}} with empty first parameter
authorBartosz Dziewoński <matma.rex@gmail.com>
Thu, 13 Feb 2014 13:10:17 +0000 (14:10 +0100)
committerSwalling <swalling@wikimedia.org>
Thu, 13 Feb 2014 17:25:02 +0000 (17:25 +0000)
(That is, gender for the user viewing the page.)

This is a bit hacky – it would be cleaner to allow empty parameters
instead of creating a separate construction for first-parameter-less
brace expansion – but this one works and the cleaner one was throwing
exceptions all over when I tried to do that.

Bug: 61320
Change-Id: I0f273951b2f8cebd50dffc6ef23520bb6fa72ccf

resources/mediawiki/mediawiki.jqueryMsg.js
resources/mediawiki/mediawiki.jqueryMsg.peg
tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js

index e4a9316..5606097 100644 (file)
                                ] );
                                return result === null ? null : [ result[0], result[2] ];
                        }
+                       function templateWithOutFirstParameter() {
+                               var result = sequence( [
+                                       templateName,
+                                       colon
+                               ] );
+                               return result === null ? null : [ result[0], '' ];
+                       }
                        colon = makeStringParser( ':' );
                        templateContents = choice( [
                                function () {
                                        var res = sequence( [
                                                // templates can have placeholders for dynamic replacement eg: {{PLURAL:$1|one car|$1 cars}}
                                                // or no placeholders eg: {{GRAMMAR:genitive|{{SITENAME}}}
-                                               choice( [ templateWithReplacement, templateWithOutReplacement ] ),
+                                               choice( [ templateWithReplacement, templateWithOutReplacement, templateWithOutFirstParameter ] ),
                                                nOrMore( 0, templateParam )
                                        ] );
                                        return res === null ? null : res[0].concat( res[1] );
 
                /**
                 * Transform parsed structure according to gender.
-                * Usage {{gender:[ gender | mw.user object ] | masculine form|feminine form|neutral form}}.
-                * The first node is either a string, which can be "male" or "female",
-                * or a User object (not a username).
                 *
-                * @param {Array} nodes List of nodes, [ {string|mw.User}, {string}, {string}, {string} ]
-                * @return {string} selected gender form according to current language
+                * Usage: {{gender:[ mw.user object | '' | 'male' | 'female' | 'unknown' ] | masculine form | feminine form | neutral form}}.
+                *
+                * The first node must be one of:
+                * - the mw.user object (or a compatible one)
+                * - an empty string - indicating the current user, same effect as passing the mw.user object
+                * - a gender string ('male', 'female' or 'unknown')
+                *
+                * @param {Array} nodes List of nodes, [ {string|mw.user}, {string}, {string}, {string} ]
+                * @return {string} Selected gender form according to current language
                 */
                gender: function ( nodes ) {
-                       var gender, forms;
+                       var gender,
+                               maybeUser = nodes[0],
+                               forms = nodes.slice( 1 );
 
-                       if  ( nodes[0] && nodes[0].options instanceof mw.Map ) {
-                               gender = nodes[0].options.get( 'gender' );
-                       } else {
-                               gender = nodes[0];
+                       if ( maybeUser === '' ) {
+                               maybeUser = mw.user;
                        }
 
-                       forms = nodes.slice( 1 );
+                       // If we are passed a mw.user-like object, check their gender.
+                       // Otherwise, assume the gender string itself was passed .
+                       if ( maybeUser && maybeUser.options instanceof mw.Map ) {
+                               gender = maybeUser.options.get( 'gender' );
+                       } else {
+                               gender = maybeUser;
+                       }
 
                        return this.language.gender( gender, forms );
                },
index 7879d6f..716c326 100644 (file)
@@ -23,6 +23,7 @@ template
 templateContents
   = twr:templateWithReplacement p:templateParam* { return twr.concat(p) }
   / twr:templateWithOutReplacement p:templateParam* { return twr.concat(p) }
+  / twr:templateWithOutFirstParameter p:templateParam* { return twr.concat(p) }
   / t:templateName p:templateParam* { return p.length ? [ t, p ] : [ t ] }
 
 templateWithReplacement
@@ -31,6 +32,9 @@ templateWithReplacement
 templateWithOutReplacement
   = t:templateName ":" p:paramExpression { return [ t, p ] }
 
+templateWithOutFirstParameter
+  = t:templateName ":" { return [ t, "" ] }
+
 templateParam
   = "|" e:paramExpression* { return e.length > 1 ? [ "CONCAT" ].concat(e) : e[0]; }
 
index 6e13e13..292c576 100644 (file)
@@ -17,6 +17,7 @@
                                // The values for gender are not significant,
                                // what matters is which of the values is choosen by the parser
                                'gender-msg': '$1: {{GENDER:$2|blue|pink|green}}',
+                               'gender-msg-currentuser': '{{GENDER:|blue|pink|green}}',
 
                                'plural-msg': 'Found $1 {{PLURAL:$1|item|items}}',
 
                assert.equal( formatParse( 'plural-msg', 2 ), 'Found 2 items', 'Plural test for english' );
        } );
 
-       QUnit.test( 'Gender', 11, function ( assert ) {
+       QUnit.test( 'Gender', 15, function ( assert ) {
+               var originalGender = mw.user.options.get( 'gender' );
+
                // TODO: These tests should be for mw.msg once mw.msg integrated with mw.jqueryMsg
                // TODO: English may not be the best language for these tests. Use a language like Arabic or Russian
-               var user = mw.user;
-
-               user.options.set( 'gender', 'male' );
+               mw.user.options.set( 'gender', 'male' );
                assert.equal(
                        formatParse( 'gender-msg', 'Bob', 'male' ),
                        'Bob: blue',
                        'Masculine from string "male"'
                );
                assert.equal(
-                       formatParse( 'gender-msg', 'Bob', user ),
+                       formatParse( 'gender-msg', 'Bob', mw.user ),
                        'Bob: blue',
                        'Masculine from mw.user object'
                );
-
-               user.options.set( 'gender', 'unknown' );
                assert.equal(
-                       formatParse( 'gender-msg', 'Foo', user ),
-                       'Foo: green',
-                       'Neutral from mw.user object' );
+                       formatParse( 'gender-msg-currentuser' ),
+                       'blue',
+                       'Masculine for current user'
+               );
+
+               mw.user.options.set( 'gender', 'female' );
                assert.equal(
                        formatParse( 'gender-msg', 'Alice', 'female' ),
                        'Alice: pink',
                        'Feminine from string "female"' );
+               assert.equal(
+                       formatParse( 'gender-msg', 'Alice', mw.user ),
+                       'Alice: pink',
+                       'Feminine from mw.user object'
+               );
+               assert.equal(
+                       formatParse( 'gender-msg-currentuser' ),
+                       'pink',
+                       'Feminine for current user'
+               );
+
+               mw.user.options.set( 'gender', 'unknown' );
+               assert.equal(
+                       formatParse( 'gender-msg', 'Foo', mw.user ),
+                       'Foo: green',
+                       'Neutral from mw.user object' );
                assert.equal(
                        formatParse( 'gender-msg', 'User' ),
                        'User: green',
                        'User: green',
                        'Neutral from string "unknown"'
                );
+               assert.equal(
+                       formatParse( 'gender-msg-currentuser' ),
+                       'green',
+                       'Neutral for current user'
+               );
 
                mw.messages.set( 'gender-msg-one-form', '{{GENDER:$1|User}}: $2 {{PLURAL:$2|edit|edits}}' );
 
                        ' test',
                        'Invalid syntax should result in {{gender}} simply being stripped away'
                );
+
+               mw.user.options.set( 'gender', originalGender );
        } );
 
        QUnit.test( 'Grammar', 2, function ( assert ) {