/*! * jQuery Internationalization library * * Copyright (C) 2011-2013 Santhosh Thottingal, Neil Kandalgaonkar * * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do * anything special to choose one license or the other and you don't have to * notify anyone which license you are using. You are free to use * UniversalLanguageSelector in commercial projects as long as the copyright * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details. * * @licence GNU General Public Licence 2.0 or later * @licence MIT License */ ( function ( $ ) { 'use strict'; var MessageParserEmitter = function () { this.language = $.i18n.languages[ String.locale ] || $.i18n.languages[ 'default' ]; }; MessageParserEmitter.prototype = { constructor: MessageParserEmitter, /** * (We put this method definition here, and not in prototype, to make * sure it's not overwritten by any magic.) Walk entire node structure, * applying replacements and template functions when appropriate * * @param {Mixed} node abstract syntax tree (top node or subnode) * @param {Array} replacements for $1, $2, ... $n * @return {Mixed} single-string node or array of nodes suitable for * jQuery appending. */ emit: function ( node, replacements ) { var ret, subnodes, operation, messageParserEmitter = this; switch ( typeof node ) { case 'string': case 'number': ret = node; break; case 'object': // node is an array of nodes subnodes = $.map( node.slice( 1 ), function ( n ) { return messageParserEmitter.emit( n, replacements ); } ); operation = node[ 0 ].toLowerCase(); if ( typeof messageParserEmitter[ operation ] === 'function' ) { ret = messageParserEmitter[ operation ]( subnodes, replacements ); } else { throw new Error( 'unknown operation "' + operation + '"' ); } break; case 'undefined': // Parsing the empty string (as an entire expression, or as a // paramExpression in a template) results in undefined // Perhaps a more clever parser can detect this, and return the // empty string? Or is that useful information? // The logical thing is probably to return the empty string here // when we encounter undefined. ret = ''; break; default: throw new Error( 'unexpected type in AST: ' + typeof node ); } return ret; }, /** * Parsing has been applied depth-first we can assume that all nodes * here are single nodes Must return a single node to parents -- a * jQuery with synthetic span However, unwrap any other synthetic spans * in our children and pass them upwards * * @param {Array} nodes Mixed, some single nodes, some arrays of nodes. * @return {string} */ concat: function ( nodes ) { var result = ''; $.each( nodes, function ( i, node ) { // strings, integers, anything else result += node; } ); return result; }, /** * Return escaped replacement of correct index, or string if * unavailable. Note that we expect the parsed parameter to be * zero-based. i.e. $1 should have become [ 0 ]. if the specified * parameter is not found return the same string (e.g. "$99" -> * parameter 98 -> not found -> return "$99" ) TODO throw error if * nodes.length > 1 ? * * @param {Array} nodes One element, integer, n >= 0 * @param {Array} replacements for $1, $2, ... $n * @return {string} replacement */ replace: function ( nodes, replacements ) { var index = parseInt( nodes[ 0 ], 10 ); if ( index < replacements.length ) { // replacement is not a string, don't touch! return replacements[ index ]; } else { // index not found, fallback to displaying variable return '$' + ( index + 1 ); } }, /** * Transform parsed structure into pluralization n.b. The first node may * be a non-integer (for instance, a string representing an Arabic * number). So convert it back with the current language's * convertNumber. * * @param {Array} nodes List [ {String|Number}, {String}, {String} ... ] * @return {string} selected pluralized form according to current * language. */ plural: function ( nodes ) { var count = parseFloat( this.language.convertNumber( nodes[ 0 ], 10 ) ), forms = nodes.slice( 1 ); return forms.length ? this.language.convertPlural( count, forms ) : ''; }, /** * Transform parsed structure into gender Usage * {{gender:gender|masculine|feminine|neutral}}. * * @param {Array} nodes List [ {String}, {String}, {String} , {String} ] * @return {string} selected gender form according to current language */ gender: function ( nodes ) { var gender = nodes[ 0 ], forms = nodes.slice( 1 ); return this.language.gender( gender, forms ); }, /** * Transform parsed structure into grammar conversion. Invoked by * putting {{grammar:form|word}} in a message * * @param {Array} nodes List [{Grammar case eg: genitive}, {String word}] * @return {string} selected grammatical form according to current * language. */ grammar: function ( nodes ) { var form = nodes[ 0 ], word = nodes[ 1 ]; return word && form && this.language.convertGrammar( word, form ); } }; $.extend( $.i18n.parser.emitter, new MessageParserEmitter() ); }( jQuery ) );