Merge "Added release notes for 'ContentHandler::runLegacyHooks' removal"
[mediawiki.git] / resources / lib / jquery.i18n / src / jquery.i18n.emitter.js
blobb26f147d09ea5ebd37d437c38648e816c04de044
1 /**
2  * jQuery Internationalization library
3  *
4  * Copyright (C) 2011-2013 Santhosh Thottingal, Neil Kandalgaonkar
5  *
6  * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do
7  * anything special to choose one license or the other and you don't have to
8  * notify anyone which license you are using. You are free to use
9  * UniversalLanguageSelector in commercial projects as long as the copyright
10  * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
11  *
12  * @licence GNU General Public Licence 2.0 or later
13  * @licence MIT License
14  */
16 ( function ( $ ) {
17         'use strict';
19         var MessageParserEmitter = function () {
20                 this.language = $.i18n.languages[String.locale] || $.i18n.languages['default'];
21         };
23         MessageParserEmitter.prototype = {
24                 constructor: MessageParserEmitter,
26                 /**
27                  * (We put this method definition here, and not in prototype, to make
28                  * sure it's not overwritten by any magic.) Walk entire node structure,
29                  * applying replacements and template functions when appropriate
30                  *
31                  * @param {Mixed} node abstract syntax tree (top node or subnode)
32                  * @param {Array} replacements for $1, $2, ... $n
33                  * @return {Mixed} single-string node or array of nodes suitable for
34                  *  jQuery appending.
35                  */
36                 emit: function ( node, replacements ) {
37                         var ret, subnodes, operation,
38                                 messageParserEmitter = this;
40                         switch ( typeof node ) {
41                         case 'string':
42                         case 'number':
43                                 ret = node;
44                                 break;
45                         case 'object':
46                                 // node is an array of nodes
47                                 subnodes = $.map( node.slice( 1 ), function ( n ) {
48                                         return messageParserEmitter.emit( n, replacements );
49                                 } );
51                                 operation = node[0].toLowerCase();
53                                 if ( typeof messageParserEmitter[operation] === 'function' ) {
54                                         ret = messageParserEmitter[operation]( subnodes, replacements );
55                                 } else {
56                                         throw new Error( 'unknown operation "' + operation + '"' );
57                                 }
59                                 break;
60                         case 'undefined':
61                                 // Parsing the empty string (as an entire expression, or as a
62                                 // paramExpression in a template) results in undefined
63                                 // Perhaps a more clever parser can detect this, and return the
64                                 // empty string? Or is that useful information?
65                                 // The logical thing is probably to return the empty string here
66                                 // when we encounter undefined.
67                                 ret = '';
68                                 break;
69                         default:
70                                 throw new Error( 'unexpected type in AST: ' + typeof node );
71                         }
73                         return ret;
74                 },
76                 /**
77                  * Parsing has been applied depth-first we can assume that all nodes
78                  * here are single nodes Must return a single node to parents -- a
79                  * jQuery with synthetic span However, unwrap any other synthetic spans
80                  * in our children and pass them upwards
81                  *
82                  * @param {Array} nodes Mixed, some single nodes, some arrays of nodes.
83                  * @return String
84                  */
85                 concat: function ( nodes ) {
86                         var result = '';
88                         $.each( nodes, function ( i, node ) {
89                                 // strings, integers, anything else
90                                 result += node;
91                         } );
93                         return result;
94                 },
96                 /**
97                  * Return escaped replacement of correct index, or string if
98                  * unavailable. Note that we expect the parsed parameter to be
99                  * zero-based. i.e. $1 should have become [ 0 ]. if the specified
100                  * parameter is not found return the same string (e.g. "$99" ->
101                  * parameter 98 -> not found -> return "$99" ) TODO throw error if
102                  * nodes.length > 1 ?
103                  *
104                  * @param {Array} nodes One element, integer, n >= 0
105                  * @param {Array} replacements for $1, $2, ... $n
106                  * @return {string} replacement
107                  */
108                 replace: function ( nodes, replacements ) {
109                         var index = parseInt( nodes[0], 10 );
111                         if ( index < replacements.length ) {
112                                 // replacement is not a string, don't touch!
113                                 return replacements[index];
114                         } else {
115                                 // index not found, fallback to displaying variable
116                                 return '$' + ( index + 1 );
117                         }
118                 },
120                 /**
121                  * Transform parsed structure into pluralization n.b. The first node may
122                  * be a non-integer (for instance, a string representing an Arabic
123                  * number). So convert it back with the current language's
124                  * convertNumber.
125                  *
126                  * @param {Array} nodes List [ {String|Number}, {String}, {String} ... ]
127                  * @return {String} selected pluralized form according to current
128                  *  language.
129                  */
130                 plural: function ( nodes ) {
131                         var count = parseFloat( this.language.convertNumber( nodes[0], 10 ) ),
132                                 forms = nodes.slice( 1 );
134                         return forms.length ? this.language.convertPlural( count, forms ) : '';
135                 },
137                 /**
138                  * Transform parsed structure into gender Usage
139                  * {{gender:gender|masculine|feminine|neutral}}.
140                  *
141                  * @param {Array} nodes List [ {String}, {String}, {String} , {String} ]
142                  * @return {String} selected gender form according to current language
143                  */
144                 gender: function ( nodes ) {
145                         var gender = nodes[0],
146                                 forms = nodes.slice( 1 );
148                         return this.language.gender( gender, forms );
149                 },
151                 /**
152                  * Transform parsed structure into grammar conversion. Invoked by
153                  * putting {{grammar:form|word}} in a message
154                  *
155                  * @param {Array} nodes List [{Grammar case eg: genitive}, {String word}]
156                  * @return {String} selected grammatical form according to current
157                  *  language.
158                  */
159                 grammar: function ( nodes ) {
160                         var form = nodes[0],
161                                 word = nodes[1];
163                         return word && form && this.language.convertGrammar( word, form );
164                 }
165         };
167         $.extend( $.i18n.parser.emitter, new MessageParserEmitter() );
168 }( jQuery ) );