discourse/lib/javascripts/messageformat.js
Sam 8874c9ea75 Add message format support that can be used on complex localization strings
Add message about new and unread topics at the bottom of topics
move localization helper into lib
2013-05-30 16:49:57 +10:00

1593 lines
48 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* messageformat.js
*
* ICU PluralFormat + SelectFormat for JavaScript
*
* @author Alex Sexton - @SlexAxton
* @version 0.1.5
* @license WTFPL
* @contributor_license Dojo CLA
*/
(function ( root ) {
// Create the contructor function
function MessageFormat ( locale, pluralFunc ) {
var fallbackLocale;
if ( locale && pluralFunc ) {
MessageFormat.locale[ locale ] = pluralFunc;
}
// Defaults
fallbackLocale = locale = locale || "en";
pluralFunc = pluralFunc || MessageFormat.locale[ fallbackLocale = MessageFormat.Utils.getFallbackLocale( locale ) ];
if ( ! pluralFunc ) {
throw new Error( "Plural Function not found for locale: " + locale );
}
// Own Properties
this.pluralFunc = pluralFunc;
this.locale = locale;
this.fallbackLocale = fallbackLocale;
}
// Set up the locales object. Add in english by default
MessageFormat.locale = {
"en" : function ( n ) {
if ( n === 1 ) {
return "one";
}
return "other";
}
};
// Build out our basic SafeString type
// more or less stolen from Handlebars by @wycats
MessageFormat.SafeString = function( string ) {
this.string = string;
};
MessageFormat.SafeString.prototype.toString = function () {
return this.string.toString();
};
MessageFormat.Utils = {
numSub : function ( string, key, depth ) {
// make sure that it's not an escaped octothorpe
return string.replace( /^#|[^\\]#/g, function (m) {
var prefix = m && m.length === 2 ? m.charAt(0) : '';
return prefix + '" + (function(){ var x = ' +
key+';\nif( isNaN(x) ){\nthrow new Error("MessageFormat: `"+lastkey_'+depth+'+"` isnt a number.");\n}\nreturn x;\n})() + "';
});
},
escapeExpression : function (string) {
var escape = {
"\n": "\\n",
"\"": '\\"'
},
badChars = /[\n"]/g,
possible = /[\n"]/,
escapeChar = function(chr) {
return escape[chr] || "&";
};
// Don't escape SafeStrings, since they're already safe
if ( string instanceof MessageFormat.SafeString ) {
return string.toString();
}
else if ( string === null || string === false ) {
return "";
}
if ( ! possible.test( string ) ) {
return string;
}
return string.replace( badChars, escapeChar );
},
getFallbackLocale: function( locale ) {
var tagSeparator = locale.indexOf("-") >= 0 ? "-" : "_";
// Lets just be friends, fallback through the language tags
while ( ! MessageFormat.locale.hasOwnProperty( locale ) ) {
locale = locale.substring(0, locale.lastIndexOf( tagSeparator ));
if (locale.length === 0) {
return null;
}
}
return locale;
}
};
// This is generated and pulled in for browsers.
var mparser = (function(){
/*
* Generated by PEG.js 0.7.0.
*
* http://pegjs.majda.cz/
*/
function quote(s) {
/*
* ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a
* string literal except for the closing quote character, backslash,
* carriage return, line separator, paragraph separator, and line feed.
* Any character may appear in the form of an escape sequence.
*
* For portability, we also escape escape all control and non-ASCII
* characters. Note that "\0" and "\v" escape sequences are not used
* because JSHint does not like the first and IE the second.
*/
return '"' + s
.replace(/\\/g, '\\\\') // backslash
.replace(/"/g, '\\"') // closing quote character
.replace(/\x08/g, '\\b') // backspace
.replace(/\t/g, '\\t') // horizontal tab
.replace(/\n/g, '\\n') // line feed
.replace(/\f/g, '\\f') // form feed
.replace(/\r/g, '\\r') // carriage return
.replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape)
+ '"';
}
var result = {
/*
* Parses the input with a generated parser. If the parsing is successfull,
* returns a value explicitly or implicitly specified by the grammar from
* which the parser was generated (see |PEG.buildParser|). If the parsing is
* unsuccessful, throws |PEG.parser.SyntaxError| describing the error.
*/
parse: function(input, startRule) {
var parseFunctions = {
"start": parse_start,
"messageFormatPattern": parse_messageFormatPattern,
"messageFormatPatternRight": parse_messageFormatPatternRight,
"messageFormatElement": parse_messageFormatElement,
"elementFormat": parse_elementFormat,
"pluralStyle": parse_pluralStyle,
"selectStyle": parse_selectStyle,
"pluralFormatPattern": parse_pluralFormatPattern,
"offsetPattern": parse_offsetPattern,
"selectFormatPattern": parse_selectFormatPattern,
"pluralForms": parse_pluralForms,
"stringKey": parse_stringKey,
"string": parse_string,
"id": parse_id,
"chars": parse_chars,
"char": parse_char,
"digits": parse_digits,
"hexDigit": parse_hexDigit,
"_": parse__,
"whitespace": parse_whitespace
};
if (startRule !== undefined) {
if (parseFunctions[startRule] === undefined) {
throw new Error("Invalid rule name: " + quote(startRule) + ".");
}
} else {
startRule = "start";
}
var pos = 0;
var reportFailures = 0;
var rightmostFailuresPos = 0;
var rightmostFailuresExpected = [];
function padLeft(input, padding, length) {
var result = input;
var padLength = length - input.length;
for (var i = 0; i < padLength; i++) {
result = padding + result;
}
return result;
}
function escape(ch) {
var charCode = ch.charCodeAt(0);
var escapeChar;
var length;
if (charCode <= 0xFF) {
escapeChar = 'x';
length = 2;
} else {
escapeChar = 'u';
length = 4;
}
return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length);
}
function matchFailed(failure) {
if (pos < rightmostFailuresPos) {
return;
}
if (pos > rightmostFailuresPos) {
rightmostFailuresPos = pos;
rightmostFailuresExpected = [];
}
rightmostFailuresExpected.push(failure);
}
function parse_start() {
var result0;
var pos0;
pos0 = pos;
result0 = parse_messageFormatPattern();
if (result0 !== null) {
result0 = (function(offset, messageFormatPattern) { return { type: "program", program: messageFormatPattern }; })(pos0, result0);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_messageFormatPattern() {
var result0, result1, result2;
var pos0, pos1;
pos0 = pos;
pos1 = pos;
result0 = parse_string();
if (result0 !== null) {
result1 = [];
result2 = parse_messageFormatPatternRight();
while (result2 !== null) {
result1.push(result2);
result2 = parse_messageFormatPatternRight();
}
if (result1 !== null) {
result0 = [result0, result1];
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
if (result0 !== null) {
result0 = (function(offset, s1, inner) {
var st = [];
if ( s1 && s1.val ) {
st.push( s1 );
}
for( var i in inner ){
if ( inner.hasOwnProperty( i ) ) {
st.push( inner[ i ] );
}
}
return { type: 'messageFormatPattern', statements: st };
})(pos0, result0[0], result0[1]);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_messageFormatPatternRight() {
var result0, result1, result2, result3, result4, result5;
var pos0, pos1;
pos0 = pos;
pos1 = pos;
if (input.charCodeAt(pos) === 123) {
result0 = "{";
pos++;
} else {
result0 = null;
if (reportFailures === 0) {
matchFailed("\"{\"");
}
}
if (result0 !== null) {
result1 = parse__();
if (result1 !== null) {
result2 = parse_messageFormatElement();
if (result2 !== null) {
result3 = parse__();
if (result3 !== null) {
if (input.charCodeAt(pos) === 125) {
result4 = "}";
pos++;
} else {
result4 = null;
if (reportFailures === 0) {
matchFailed("\"}\"");
}
}
if (result4 !== null) {
result5 = parse_string();
if (result5 !== null) {
result0 = [result0, result1, result2, result3, result4, result5];
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
if (result0 !== null) {
result0 = (function(offset, mfe, s1) {
var res = [];
if ( mfe ) {
res.push(mfe);
}
if ( s1 && s1.val ) {
res.push( s1 );
}
return { type: "messageFormatPatternRight", statements : res };
})(pos0, result0[2], result0[5]);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_messageFormatElement() {
var result0, result1, result2;
var pos0, pos1, pos2;
pos0 = pos;
pos1 = pos;
result0 = parse_id();
if (result0 !== null) {
pos2 = pos;
if (input.charCodeAt(pos) === 44) {
result1 = ",";
pos++;
} else {
result1 = null;
if (reportFailures === 0) {
matchFailed("\",\"");
}
}
if (result1 !== null) {
result2 = parse_elementFormat();
if (result2 !== null) {
result1 = [result1, result2];
} else {
result1 = null;
pos = pos2;
}
} else {
result1 = null;
pos = pos2;
}
result1 = result1 !== null ? result1 : "";
if (result1 !== null) {
result0 = [result0, result1];
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
if (result0 !== null) {
result0 = (function(offset, argIdx, efmt) {
var res = {
type: "messageFormatElement",
argumentIndex: argIdx
};
if ( efmt && efmt.length ) {
res.elementFormat = efmt[1];
}
else {
res.output = true;
}
return res;
})(pos0, result0[0], result0[1]);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_elementFormat() {
var result0, result1, result2, result3, result4, result5, result6;
var pos0, pos1;
pos0 = pos;
pos1 = pos;
result0 = parse__();
if (result0 !== null) {
if (input.substr(pos, 6) === "plural") {
result1 = "plural";
pos += 6;
} else {
result1 = null;
if (reportFailures === 0) {
matchFailed("\"plural\"");
}
}
if (result1 !== null) {
result2 = parse__();
if (result2 !== null) {
if (input.charCodeAt(pos) === 44) {
result3 = ",";
pos++;
} else {
result3 = null;
if (reportFailures === 0) {
matchFailed("\",\"");
}
}
if (result3 !== null) {
result4 = parse__();
if (result4 !== null) {
result5 = parse_pluralStyle();
if (result5 !== null) {
result6 = parse__();
if (result6 !== null) {
result0 = [result0, result1, result2, result3, result4, result5, result6];
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
if (result0 !== null) {
result0 = (function(offset, t, s) {
return {
type : "elementFormat",
key : t,
val : s.val
};
})(pos0, result0[1], result0[5]);
}
if (result0 === null) {
pos = pos0;
}
if (result0 === null) {
pos0 = pos;
pos1 = pos;
result0 = parse__();
if (result0 !== null) {
if (input.substr(pos, 6) === "select") {
result1 = "select";
pos += 6;
} else {
result1 = null;
if (reportFailures === 0) {
matchFailed("\"select\"");
}
}
if (result1 !== null) {
result2 = parse__();
if (result2 !== null) {
if (input.charCodeAt(pos) === 44) {
result3 = ",";
pos++;
} else {
result3 = null;
if (reportFailures === 0) {
matchFailed("\",\"");
}
}
if (result3 !== null) {
result4 = parse__();
if (result4 !== null) {
result5 = parse_selectStyle();
if (result5 !== null) {
result6 = parse__();
if (result6 !== null) {
result0 = [result0, result1, result2, result3, result4, result5, result6];
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
if (result0 !== null) {
result0 = (function(offset, t, s) {
return {
type : "elementFormat",
key : t,
val : s.val
};
})(pos0, result0[1], result0[5]);
}
if (result0 === null) {
pos = pos0;
}
}
return result0;
}
function parse_pluralStyle() {
var result0;
var pos0;
pos0 = pos;
result0 = parse_pluralFormatPattern();
if (result0 !== null) {
result0 = (function(offset, pfp) {
return { type: "pluralStyle", val: pfp };
})(pos0, result0);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_selectStyle() {
var result0;
var pos0;
pos0 = pos;
result0 = parse_selectFormatPattern();
if (result0 !== null) {
result0 = (function(offset, sfp) {
return { type: "selectStyle", val: sfp };
})(pos0, result0);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_pluralFormatPattern() {
var result0, result1, result2;
var pos0, pos1;
pos0 = pos;
pos1 = pos;
result0 = parse_offsetPattern();
result0 = result0 !== null ? result0 : "";
if (result0 !== null) {
result1 = [];
result2 = parse_pluralForms();
while (result2 !== null) {
result1.push(result2);
result2 = parse_pluralForms();
}
if (result1 !== null) {
result0 = [result0, result1];
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
if (result0 !== null) {
result0 = (function(offset, op, pf) {
var res = {
type: "pluralFormatPattern",
pluralForms: pf
};
if ( op ) {
res.offset = op;
}
else {
res.offset = 0;
}
return res;
})(pos0, result0[0], result0[1]);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_offsetPattern() {
var result0, result1, result2, result3, result4, result5, result6;
var pos0, pos1;
pos0 = pos;
pos1 = pos;
result0 = parse__();
if (result0 !== null) {
if (input.substr(pos, 6) === "offset") {
result1 = "offset";
pos += 6;
} else {
result1 = null;
if (reportFailures === 0) {
matchFailed("\"offset\"");
}
}
if (result1 !== null) {
result2 = parse__();
if (result2 !== null) {
if (input.charCodeAt(pos) === 58) {
result3 = ":";
pos++;
} else {
result3 = null;
if (reportFailures === 0) {
matchFailed("\":\"");
}
}
if (result3 !== null) {
result4 = parse__();
if (result4 !== null) {
result5 = parse_digits();
if (result5 !== null) {
result6 = parse__();
if (result6 !== null) {
result0 = [result0, result1, result2, result3, result4, result5, result6];
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
if (result0 !== null) {
result0 = (function(offset, d) {
return d;
})(pos0, result0[5]);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_selectFormatPattern() {
var result0, result1;
var pos0;
pos0 = pos;
result0 = [];
result1 = parse_pluralForms();
while (result1 !== null) {
result0.push(result1);
result1 = parse_pluralForms();
}
if (result0 !== null) {
result0 = (function(offset, pf) {
return {
type: "selectFormatPattern",
pluralForms: pf
};
})(pos0, result0);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_pluralForms() {
var result0, result1, result2, result3, result4, result5, result6, result7;
var pos0, pos1;
pos0 = pos;
pos1 = pos;
result0 = parse__();
if (result0 !== null) {
result1 = parse_stringKey();
if (result1 !== null) {
result2 = parse__();
if (result2 !== null) {
if (input.charCodeAt(pos) === 123) {
result3 = "{";
pos++;
} else {
result3 = null;
if (reportFailures === 0) {
matchFailed("\"{\"");
}
}
if (result3 !== null) {
result4 = parse__();
if (result4 !== null) {
result5 = parse_messageFormatPattern();
if (result5 !== null) {
result6 = parse__();
if (result6 !== null) {
if (input.charCodeAt(pos) === 125) {
result7 = "}";
pos++;
} else {
result7 = null;
if (reportFailures === 0) {
matchFailed("\"}\"");
}
}
if (result7 !== null) {
result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
if (result0 !== null) {
result0 = (function(offset, k, mfp) {
return {
type: "pluralForms",
key: k,
val: mfp
};
})(pos0, result0[1], result0[5]);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_stringKey() {
var result0, result1;
var pos0, pos1;
pos0 = pos;
result0 = parse_id();
if (result0 !== null) {
result0 = (function(offset, i) {
return i;
})(pos0, result0);
}
if (result0 === null) {
pos = pos0;
}
if (result0 === null) {
pos0 = pos;
pos1 = pos;
if (input.charCodeAt(pos) === 61) {
result0 = "=";
pos++;
} else {
result0 = null;
if (reportFailures === 0) {
matchFailed("\"=\"");
}
}
if (result0 !== null) {
result1 = parse_digits();
if (result1 !== null) {
result0 = [result0, result1];
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
if (result0 !== null) {
result0 = (function(offset, d) {
return d;
})(pos0, result0[1]);
}
if (result0 === null) {
pos = pos0;
}
}
return result0;
}
function parse_string() {
var result0, result1, result2, result3, result4;
var pos0, pos1, pos2;
pos0 = pos;
pos1 = pos;
result0 = parse__();
if (result0 !== null) {
result1 = [];
pos2 = pos;
result2 = parse__();
if (result2 !== null) {
result3 = parse_chars();
if (result3 !== null) {
result4 = parse__();
if (result4 !== null) {
result2 = [result2, result3, result4];
} else {
result2 = null;
pos = pos2;
}
} else {
result2 = null;
pos = pos2;
}
} else {
result2 = null;
pos = pos2;
}
while (result2 !== null) {
result1.push(result2);
pos2 = pos;
result2 = parse__();
if (result2 !== null) {
result3 = parse_chars();
if (result3 !== null) {
result4 = parse__();
if (result4 !== null) {
result2 = [result2, result3, result4];
} else {
result2 = null;
pos = pos2;
}
} else {
result2 = null;
pos = pos2;
}
} else {
result2 = null;
pos = pos2;
}
}
if (result1 !== null) {
result0 = [result0, result1];
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
if (result0 !== null) {
result0 = (function(offset, ws, s) {
var tmp = [];
for( var i = 0; i < s.length; ++i ) {
for( var j = 0; j < s[ i ].length; ++j ) {
tmp.push(s[i][j]);
}
}
return {
type: "string",
val: ws + tmp.join('')
};
})(pos0, result0[0], result0[1]);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_id() {
var result0, result1, result2, result3;
var pos0, pos1;
pos0 = pos;
pos1 = pos;
result0 = parse__();
if (result0 !== null) {
if (/^[a-zA-Z$_]/.test(input.charAt(pos))) {
result1 = input.charAt(pos);
pos++;
} else {
result1 = null;
if (reportFailures === 0) {
matchFailed("[a-zA-Z$_]");
}
}
if (result1 !== null) {
result2 = [];
if (/^[^ \t\n\r,.+={}]/.test(input.charAt(pos))) {
result3 = input.charAt(pos);
pos++;
} else {
result3 = null;
if (reportFailures === 0) {
matchFailed("[^ \\t\\n\\r,.+={}]");
}
}
while (result3 !== null) {
result2.push(result3);
if (/^[^ \t\n\r,.+={}]/.test(input.charAt(pos))) {
result3 = input.charAt(pos);
pos++;
} else {
result3 = null;
if (reportFailures === 0) {
matchFailed("[^ \\t\\n\\r,.+={}]");
}
}
}
if (result2 !== null) {
result3 = parse__();
if (result3 !== null) {
result0 = [result0, result1, result2, result3];
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
if (result0 !== null) {
result0 = (function(offset, s1, s2) {
return s1 + (s2 ? s2.join('') : '');
})(pos0, result0[1], result0[2]);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_chars() {
var result0, result1;
var pos0;
pos0 = pos;
result1 = parse_char();
if (result1 !== null) {
result0 = [];
while (result1 !== null) {
result0.push(result1);
result1 = parse_char();
}
} else {
result0 = null;
}
if (result0 !== null) {
result0 = (function(offset, chars) { return chars.join(''); })(pos0, result0);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_char() {
var result0, result1, result2, result3, result4;
var pos0, pos1;
pos0 = pos;
if (/^[^{}\\\0-\x1F \t\n\r]/.test(input.charAt(pos))) {
result0 = input.charAt(pos);
pos++;
} else {
result0 = null;
if (reportFailures === 0) {
matchFailed("[^{}\\\\\\0-\\x1F \\t\\n\\r]");
}
}
if (result0 !== null) {
result0 = (function(offset, x) {
return x;
})(pos0, result0);
}
if (result0 === null) {
pos = pos0;
}
if (result0 === null) {
pos0 = pos;
if (input.substr(pos, 2) === "\\#") {
result0 = "\\#";
pos += 2;
} else {
result0 = null;
if (reportFailures === 0) {
matchFailed("\"\\\\#\"");
}
}
if (result0 !== null) {
result0 = (function(offset) {
return "\\#";
})(pos0);
}
if (result0 === null) {
pos = pos0;
}
if (result0 === null) {
pos0 = pos;
if (input.substr(pos, 2) === "\\{") {
result0 = "\\{";
pos += 2;
} else {
result0 = null;
if (reportFailures === 0) {
matchFailed("\"\\\\{\"");
}
}
if (result0 !== null) {
result0 = (function(offset) {
return "\u007B";
})(pos0);
}
if (result0 === null) {
pos = pos0;
}
if (result0 === null) {
pos0 = pos;
if (input.substr(pos, 2) === "\\}") {
result0 = "\\}";
pos += 2;
} else {
result0 = null;
if (reportFailures === 0) {
matchFailed("\"\\\\}\"");
}
}
if (result0 !== null) {
result0 = (function(offset) {
return "\u007D";
})(pos0);
}
if (result0 === null) {
pos = pos0;
}
if (result0 === null) {
pos0 = pos;
pos1 = pos;
if (input.substr(pos, 2) === "\\u") {
result0 = "\\u";
pos += 2;
} else {
result0 = null;
if (reportFailures === 0) {
matchFailed("\"\\\\u\"");
}
}
if (result0 !== null) {
result1 = parse_hexDigit();
if (result1 !== null) {
result2 = parse_hexDigit();
if (result2 !== null) {
result3 = parse_hexDigit();
if (result3 !== null) {
result4 = parse_hexDigit();
if (result4 !== null) {
result0 = [result0, result1, result2, result3, result4];
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
} else {
result0 = null;
pos = pos1;
}
if (result0 !== null) {
result0 = (function(offset, h1, h2, h3, h4) {
return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4));
})(pos0, result0[1], result0[2], result0[3], result0[4]);
}
if (result0 === null) {
pos = pos0;
}
}
}
}
}
return result0;
}
function parse_digits() {
var result0, result1;
var pos0;
pos0 = pos;
if (/^[0-9]/.test(input.charAt(pos))) {
result1 = input.charAt(pos);
pos++;
} else {
result1 = null;
if (reportFailures === 0) {
matchFailed("[0-9]");
}
}
if (result1 !== null) {
result0 = [];
while (result1 !== null) {
result0.push(result1);
if (/^[0-9]/.test(input.charAt(pos))) {
result1 = input.charAt(pos);
pos++;
} else {
result1 = null;
if (reportFailures === 0) {
matchFailed("[0-9]");
}
}
}
} else {
result0 = null;
}
if (result0 !== null) {
result0 = (function(offset, ds) {
return parseInt((ds.join('')), 10);
})(pos0, result0);
}
if (result0 === null) {
pos = pos0;
}
return result0;
}
function parse_hexDigit() {
var result0;
if (/^[0-9a-fA-F]/.test(input.charAt(pos))) {
result0 = input.charAt(pos);
pos++;
} else {
result0 = null;
if (reportFailures === 0) {
matchFailed("[0-9a-fA-F]");
}
}
return result0;
}
function parse__() {
var result0, result1;
var pos0;
reportFailures++;
pos0 = pos;
result0 = [];
result1 = parse_whitespace();
while (result1 !== null) {
result0.push(result1);
result1 = parse_whitespace();
}
if (result0 !== null) {
result0 = (function(offset, w) { return w.join(''); })(pos0, result0);
}
if (result0 === null) {
pos = pos0;
}
reportFailures--;
if (reportFailures === 0 && result0 === null) {
matchFailed("whitespace");
}
return result0;
}
function parse_whitespace() {
var result0;
if (/^[ \t\n\r]/.test(input.charAt(pos))) {
result0 = input.charAt(pos);
pos++;
} else {
result0 = null;
if (reportFailures === 0) {
matchFailed("[ \\t\\n\\r]");
}
}
return result0;
}
function cleanupExpected(expected) {
expected.sort();
var lastExpected = null;
var cleanExpected = [];
for (var i = 0; i < expected.length; i++) {
if (expected[i] !== lastExpected) {
cleanExpected.push(expected[i]);
lastExpected = expected[i];
}
}
return cleanExpected;
}
function computeErrorPosition() {
/*
* The first idea was to use |String.split| to break the input up to the
* error position along newlines and derive the line and column from
* there. However IE's |split| implementation is so broken that it was
* enough to prevent it.
*/
var line = 1;
var column = 1;
var seenCR = false;
for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) {
var ch = input.charAt(i);
if (ch === "\n") {
if (!seenCR) { line++; }
column = 1;
seenCR = false;
} else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
line++;
column = 1;
seenCR = true;
} else {
column++;
seenCR = false;
}
}
return { line: line, column: column };
}
var result = parseFunctions[startRule]();
/*
* The parser is now in one of the following three states:
*
* 1. The parser successfully parsed the whole input.
*
* - |result !== null|
* - |pos === input.length|
* - |rightmostFailuresExpected| may or may not contain something
*
* 2. The parser successfully parsed only a part of the input.
*
* - |result !== null|
* - |pos < input.length|
* - |rightmostFailuresExpected| may or may not contain something
*
* 3. The parser did not successfully parse any part of the input.
*
* - |result === null|
* - |pos === 0|
* - |rightmostFailuresExpected| contains at least one failure
*
* All code following this comment (including called functions) must
* handle these states.
*/
if (result === null || pos !== input.length) {
var offset = Math.max(pos, rightmostFailuresPos);
var found = offset < input.length ? input.charAt(offset) : null;
var errorPosition = computeErrorPosition();
throw new this.SyntaxError(
cleanupExpected(rightmostFailuresExpected),
found,
offset,
errorPosition.line,
errorPosition.column
);
}
return result;
},
/* Returns the parser source code. */
toSource: function() { return this._source; }
};
/* Thrown when a parser encounters a syntax error. */
result.SyntaxError = function(expected, found, offset, line, column) {
function buildMessage(expected, found) {
var expectedHumanized, foundHumanized;
switch (expected.length) {
case 0:
expectedHumanized = "end of input";
break;
case 1:
expectedHumanized = expected[0];
break;
default:
expectedHumanized = expected.slice(0, expected.length - 1).join(", ")
+ " or "
+ expected[expected.length - 1];
}
foundHumanized = found ? quote(found) : "end of input";
return "Expected " + expectedHumanized + " but " + foundHumanized + " found.";
}
this.name = "SyntaxError";
this.expected = expected;
this.found = found;
this.message = buildMessage(expected, found);
this.offset = offset;
this.line = line;
this.column = column;
};
result.SyntaxError.prototype = Error.prototype;
return result;
})();
MessageFormat.prototype.parse = function () {
// Bind to itself so error handling works
return mparser.parse.apply( mparser, arguments );
};
MessageFormat.prototype.precompile = function ( ast ) {
var self = this,
needOther = false,
fp = {
begin: 'function(d){\nvar r = "";\n',
end : "return r;\n}"
};
function interpMFP ( ast, data ) {
// Set some default data
data = data || {};
var s = '', i, tmp, lastkeyname;
switch ( ast.type ) {
case 'program':
return interpMFP( ast.program );
case 'messageFormatPattern':
for ( i = 0; i < ast.statements.length; ++i ) {
s += interpMFP( ast.statements[i], data );
}
return fp.begin + s + fp.end;
case 'messageFormatPatternRight':
for ( i = 0; i < ast.statements.length; ++i ) {
s += interpMFP( ast.statements[i], data );
}
return s;
case 'messageFormatElement':
data.pf_count = data.pf_count || 0;
s += 'if(!d){\nthrow new Error("MessageFormat: No data passed to function.");\n}\n';
if ( ast.output ) {
s += 'r += d["' + ast.argumentIndex + '"];\n';
}
else {
lastkeyname = 'lastkey_'+(data.pf_count+1);
s += 'var '+lastkeyname+' = "'+ast.argumentIndex+'";\n';
s += 'var k_'+(data.pf_count+1)+'=d['+lastkeyname+'];\n';
s += interpMFP( ast.elementFormat, data );
}
return s;
case 'elementFormat':
if ( ast.key === 'select' ) {
s += interpMFP( ast.val, data );
s += 'r += (pf_' +
data.pf_count +
'[ k_' + (data.pf_count+1) + ' ] || pf_'+data.pf_count+'[ "other" ])( d );\n';
}
else if ( ast.key === 'plural' ) {
s += interpMFP( ast.val, data );
s += 'if ( pf_'+(data.pf_count)+'[ k_'+(data.pf_count+1)+' + "" ] ) {\n';
s += 'r += pf_'+data.pf_count+'[ k_'+(data.pf_count+1)+' + "" ]( d ); \n';
s += '}\nelse {\n';
s += 'r += (pf_' +
data.pf_count +
'[ MessageFormat.locale["' +
self.fallbackLocale +
'"]( k_'+(data.pf_count+1)+' - off_'+(data.pf_count)+' ) ] || pf_'+data.pf_count+'[ "other" ] )( d );\n';
s += '}\n';
}
return s;
/* // Unreachable cases.
case 'pluralStyle':
case 'selectStyle':*/
case 'pluralFormatPattern':
data.pf_count = data.pf_count || 0;
s += 'var off_'+data.pf_count+' = '+ast.offset+';\n';
s += 'var pf_' + data.pf_count + ' = { \n';
needOther = true;
// We're going to simultaneously check to make sure we hit the required 'other' option.
for ( i = 0; i < ast.pluralForms.length; ++i ) {
if ( ast.pluralForms[ i ].key === 'other' ) {
needOther = false;
}
if ( tmp ) {
s += ',\n';
}
else{
tmp = 1;
}
s += '"' + ast.pluralForms[ i ].key + '" : ' + interpMFP( ast.pluralForms[ i ].val,
(function(){ var res = JSON.parse(JSON.stringify(data)); res.pf_count++; return res; })() );
}
s += '\n};\n';
if ( needOther ) {
throw new Error("No 'other' form found in pluralFormatPattern " + data.pf_count);
}
return s;
case 'selectFormatPattern':
data.pf_count = data.pf_count || 0;
s += 'var off_'+data.pf_count+' = 0;\n';
s += 'var pf_' + data.pf_count + ' = { \n';
needOther = true;
for ( i = 0; i < ast.pluralForms.length; ++i ) {
if ( ast.pluralForms[ i ].key === 'other' ) {
needOther = false;
}
if ( tmp ) {
s += ',\n';
}
else{
tmp = 1;
}
s += '"' + ast.pluralForms[ i ].key + '" : ' + interpMFP( ast.pluralForms[ i ].val,
(function(){
var res = JSON.parse( JSON.stringify( data ) );
res.pf_count++;
return res;
})()
);
}
s += '\n};\n';
if ( needOther ) {
throw new Error("No 'other' form found in selectFormatPattern " + data.pf_count);
}
return s;
/* // Unreachable
case 'pluralForms':
*/
case 'string':
return 'r += "' + MessageFormat.Utils.numSub(
MessageFormat.Utils.escapeExpression( ast.val ),
'k_' + data.pf_count + ' - off_' + ( data.pf_count - 1 ),
data.pf_count
) + '";\n';
default:
throw new Error( 'Bad AST type: ' + ast.type );
}
}
return interpMFP( ast );
};
MessageFormat.prototype.compile = function ( message ) {
return (new Function( 'MessageFormat',
'return ' +
this.precompile(
this.parse( message )
)
))(MessageFormat);
};
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = MessageFormat;
}
exports.MessageFormat = MessageFormat;
}
else if (typeof define === 'function' && define.amd) {
define(function() {
return MessageFormat;
});
}
else {
root['MessageFormat'] = MessageFormat;
}
})( this );