Merge "Don't check namespace in SpecialWantedtemplates"
[lhc/web/wiklou.git] / resources / lib / jquery.i18n / src / jquery.i18n.emitter.js
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 */
15
16 ( function ( $ ) {
17 'use strict';
18
19 var MessageParserEmitter = function () {
20 this.language = $.i18n.languages[String.locale] || $.i18n.languages['default'];
21 };
22
23 MessageParserEmitter.prototype = {
24 constructor: MessageParserEmitter,
25
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;
39
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 } );
50
51 operation = node[0].toLowerCase();
52
53 if ( typeof messageParserEmitter[operation] === 'function' ) {
54 ret = messageParserEmitter[operation]( subnodes, replacements );
55 } else {
56 throw new Error( 'unknown operation "' + operation + '"' );
57 }
58
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 }
72
73 return ret;
74 },
75
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 = '';
87
88 $.each( nodes, function ( i, node ) {
89 // strings, integers, anything else
90 result += node;
91 } );
92
93 return result;
94 },
95
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 );
110
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 },
119
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 );
133
134 return forms.length ? this.language.convertPlural( count, forms ) : '';
135 },
136
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 );
147
148 return this.language.gender( gender, forms );
149 },
150
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];
162
163 return word && form && this.language.convertGrammar( word, form );
164 }
165 };
166
167 $.extend( $.i18n.parser.emitter, new MessageParserEmitter() );
168 }( jQuery ) );