UNPKG

zpt

Version:

Zenon Page Templates - JS (ZPT-JS)

1,478 lines (1,333 loc) 136 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.MessageFormat = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ var reserved = require('reserved-words'); var parse = require('messageformat-parser').parse; /** Creates a new message compiler. Called internally from {@link MessageFormat#compile}. * * @class * @param {MessageFormat} mf - A MessageFormat instance * @property {object} locales - The locale identifiers that are used by the compiled functions * @property {object} runtime - Names of the core runtime functions that are used by the compiled functions * @property {object} formatters - The formatter functions that are used by the compiled functions */ function Compiler(mf) { this.mf = mf; this.lc = null; this.locales = {}; this.runtime = {}; this.formatters = {}; } module.exports = Compiler; /** Utility function for quoting an Object's key value iff required * * Quotes the key if it contains invalid characters or is an * ECMAScript 3rd Edition reserved word (for IE8). */ Compiler.propname = function(key, obj) { if (/^[A-Z_$][0-9A-Z_$]*$/i.test(key) && ['break', 'continue', 'delete', 'else', 'for', 'function', 'if', 'in', 'new', 'return', 'this', 'typeof', 'var', 'void', 'while', 'with', 'case', 'catch', 'default', 'do', 'finally', 'instanceof', 'switch', 'throw', 'try'].indexOf(key) < 0) { return obj ? obj + '.' + key : key; } else { var jkey = JSON.stringify(key); return obj ? obj + '[' + jkey + ']' : jkey; } } /** Utility function for escaping a function name iff required */ Compiler.funcname = function(key) { var fn = key.trim().replace(/\W+/g, '_'); return reserved.check(fn, 'es2015', true) || /^\d/.test(fn) ? '_' + fn : fn; } /** Utility formatter function for enforcing Bidi Structured Text by using UCC * * List inlined from data extracted from CLDR v27 & v28 * To verify/recreate, use the following: * * git clone https://github.com/unicode-cldr/cldr-misc-full.git * cd cldr-misc-full/main/ * grep characterOrder -r . | tr '"/' '\t' | cut -f2,6 | grep -C4 right-to-left */ Compiler.bidiMarkText = function(text, locale) { function isLocaleRTL(locale) { var rtlLanguages = ['ar', 'ckb', 'fa', 'he', 'ks($|[^bfh])', 'lrc', 'mzn', 'pa-Arab', 'ps', 'ug', 'ur', 'uz-Arab', 'yi']; return new RegExp('^' + rtlLanguages.join('|^')).test(locale); } var mark = JSON.stringify(isLocaleRTL(locale) ? '\u200F' : '\u200E'); return mark + ' + ' + text + ' + ' + mark; } /** @private */ Compiler.prototype.cases = function(token, plural) { var needOther = true; var r = token.cases.map(function(c) { if (c.key === 'other') needOther = false; var s = c.tokens.map(function(tok) { return this.token(tok, plural); }, this); return Compiler.propname(c.key) + ': ' + (s.join(' + ') || '""'); }, this); if (needOther) throw new Error("No 'other' form found in " + JSON.stringify(token)); return '{ ' + r.join(', ') + ' }'; } /** @private */ Compiler.prototype.token = function(token, plural) { if (typeof token == 'string') return JSON.stringify(token); var fn, args = [ Compiler.propname(token.arg, 'd') ]; switch (token.type) { case 'argument': return this.mf.bidiSupport ? Compiler.bidiMarkText(args[0], this.lc) : args[0]; case 'select': fn = 'select'; args.push(this.cases(token, this.mf.strictNumberSign ? null : plural)); this.runtime.select = true; break; case 'selectordinal': fn = 'plural'; args.push(0, Compiler.funcname(this.lc), this.cases(token, token), 1); this.locales[this.lc] = true; this.runtime.plural = true; break; case 'plural': fn = 'plural'; args.push(token.offset || 0, Compiler.funcname(this.lc), this.cases(token, token)); this.locales[this.lc] = true; this.runtime.plural = true; break; case 'function': if (this.mf.intlSupport && !(token.key in this.mf.fmt) && (token.key in this.mf.constructor.formatters)) { var fmt = this.mf.constructor.formatters[token.key]; this.mf.fmt[token.key] = (typeof fmt(this.mf) == 'function') ? fmt(this.mf) : fmt; } if (!this.mf.fmt[token.key]) throw new Error('Formatting function ' + JSON.stringify(token.key) + ' not found!'); args.push(JSON.stringify(this.lc)); if (token.params) switch (token.params.length) { case 0: break; case 1: args.push(JSON.stringify(token.params[0])); break; default: args.push(JSON.stringify(token.params)); break; } fn = Compiler.propname(token.key, 'fmt'); this.formatters[token.key] = true; break; case 'octothorpe': if (!plural) return '"#"'; fn = 'number'; args = [ Compiler.propname(plural.arg, 'd'), JSON.stringify(plural.arg) ]; if (plural.offset) args.push(plural.offset); this.runtime.number = true; break; } if (!fn) throw new Error('Parser error for token ' + JSON.stringify(token)); return fn + '(' + args.join(', ') + ')'; }; /** Recursively compile a string or a tree of strings to JavaScript function sources * * If `src` is an object with a key that is also present in `plurals`, the key * in question will be used as the locale identifier for its value. To disable * the compile-time checks for plural & selectordinal keys while maintaining * multi-locale support, use falsy values in `plurals`. * * @param {string|object} src - the source for which the JS code should be generated * @param {string} lc - the default locale * @param {object} plurals - a map of pluralization keys for all available locales */ Compiler.prototype.compile = function(src, lc, plurals) { if (typeof src != 'object') { this.lc = lc; var pc = plurals[lc] || { cardinal: [], ordinal: [] }; var r = parse(src, pc).map(function(token) { return this.token(token); }, this); return 'function(d) { return ' + (r.join(' + ') || '""') + '; }'; } else { var result = {}; for (var key in src) { var lcKey = plurals.hasOwnProperty(key) ? key : lc; result[key] = this.compile(src[key], lcKey, plurals); } return result; } } },{"messageformat-parser":8,"reserved-words":10}],2:[function(require,module,exports){ /** @file messageformat.js - ICU PluralFormat + SelectFormat for JavaScript * * @author Alex Sexton - @SlexAxton, Eemeli Aro * @version 1.0.2 * @copyright 2012-2016 Alex Sexton, Eemeli Aro, and Contributors * @license To use or fork, MIT. To contribute back, Dojo CLA */ var Compiler = require('./compiler'); var Runtime = require('./runtime'); /** Utility getter/wrapper for pluralization functions from * {@link http://github.com/eemeli/make-plural.js make-plural} * * @private */ function getPluralFunc(locale, noPluralKeyChecks) { var plurals = require('make-plural/plurals'); var pluralCategories = require('make-plural/pluralCategories'); for (var l = locale; l; l = l.replace(/[-_]?[^-_]*$/, '')) { var pf = plurals[l]; if (pf) { var pc = noPluralKeyChecks ? { cardinal: [], ordinal: [] } : (pluralCategories[l] || {}); var fn = function() { return pf.apply(this, arguments); }; fn.toString = function() { return pf.toString(); }; fn.cardinal = pc.cardinal; fn.ordinal = pc.ordinal; return fn; } } throw new Error('Localisation function not found for locale ' + JSON.stringify(locale)); } /** Create a new message formatter * * If `locale` is not set, calls to `compile()` will fetch the default locale * each time. A string `locale` will create a single-locale MessageFormat * instance, with pluralisation rules fetched from the Unicode CLDR using * {@link http://github.com/eemeli/make-plural.js make-plural}. * * Using an array of strings as `locale` will create a MessageFormat object * with multi-language support, with pluralisation rules fetched as above. To * select which to use, use the second parameter of `compile()`, or use message * keys corresponding to your locales. * * Using an object `locale` with all properties of type `function` allows for * the use of custom/externally defined pluralisation rules. * * @class * @param {string|string[]|Object.<string,function>} [locale] - The locale(s) to use */ function MessageFormat(locale) { this.pluralFuncs = {}; if (locale) { if (typeof locale == 'string') { this.pluralFuncs[locale] = getPluralFunc(locale); } else if (Array.isArray(locale)) { locale.forEach(function(lc) { this.pluralFuncs[lc] = getPluralFunc(lc); }, this); } else if (typeof locale == 'object') { for (var lc in locale) if (locale.hasOwnProperty(lc)) { if (typeof locale[lc] != 'function') throw new Error('Expected function value for locale ' + JSON.stringify(lc)); this.pluralFuncs[lc] = locale[lc]; } } } this.fmt = {}; this.runtime = new Runtime(this); } /** The default locale * * Read by `compile()` when no locale has been previously set * * @memberof MessageFormat * @default 'en' */ MessageFormat.defaultLocale = 'en'; /** Escape special characaters * * Prefix the characters `#`, `{`, `}` and `\` in the input string with a `\`. * This will allow those characters to not be considered as MessageFormat * control characters. * * @param {string} str - The input string * @returns {string} The escaped string */ MessageFormat.escape = function(str) { return str.replace(/[#{}\\]/g, '\\$&'); } /** Default number formatting functions in the style of ICU's * {@link http://icu-project.org/apiref/icu4j/com/ibm/icu/text/MessageFormat.html simpleArg syntax} * implemented using the * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl Intl} * object defined by ECMA-402. * * **Note**: Intl is not defined in default Node until 0.11.15 / 0.12.0, so * earlier versions require a {@link https://www.npmjs.com/package/intl polyfill}. * Therefore {@link MessageFormat.intlSupport} needs to be true for these default * functions to be available for inclusion in the output. * * @see MessageFormat#setIntlSupport * * @namespace */ MessageFormat.formatters = { /** Represent a number as an integer, percent or currency value * * Available in MessageFormat strings as `{VAR, number, integer|percent|currency}`. * Internally, calls Intl.NumberFormat with appropriate parameters. `currency` will * default to USD; to change, set `MessageFormat#currency` to the appropriate * three-letter currency code. * * @param {number} value - The value to operate on * @param {string} type - One of `'integer'`, `'percent'` , or `currency` * * @example * var mf = new MessageFormat('en').setIntlSupport(true); * mf.currency = 'EUR'; // needs to be set before first compile() call * * mf.compile('{N} is almost {N, number, integer}')({ N: 3.14 }) * // '3.14 is almost 3' * * mf.compile('{P, number, percent} complete')({ P: 0.99 }) * // '99% complete' * * mf.compile('The total is {V, number, currency}.')({ V: 5.5 }) * // 'The total is €5.50.' */ number: function(self) { return new Function("v,lc,p", "return new Intl.NumberFormat(lc,\n" + " p=='integer' ? {maximumFractionDigits:0}\n" + " : p=='percent' ? {style:'percent'}\n" + " : p=='currency' ? {style:'currency', currency:'" + (self.currency || 'USD') + "', minimumFractionDigits:2, maximumFractionDigits:2}\n" + " : {}).format(v)" ); }, /** Represent a date as a short/default/long/full string * * The input value needs to be in a form that the * {@link https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date Date object} * can process using its single-argument form, `new Date(value)`. * * @param {number|string} value - Either a Unix epoch time in milliseconds, or a string value representing a date * @param {string} [type='default'] - One of `'short'`, `'default'`, `'long'` , or `full` * * @example * var mf = new MessageFormat(['en', 'fi']).setIntlSupport(true); * * mf.compile('Today is {T, date}')({ T: Date.now() }) * // 'Today is Feb 21, 2016' * * mf.compile('Tänään on {T, date}', 'fi')({ T: Date.now() }) * // 'Tänään on 21. helmikuuta 2016' * * mf.compile('Unix time started on {T, date, full}')({ T: 0 }) * // 'Unix time started on Thursday, January 1, 1970' * * var cf = mf.compile('{sys} became operational on {d0, date, short}'); * cf({ sys: 'HAL 9000', d0: '12 January 1999' }) * // 'HAL 9000 became operational on 1/12/1999' */ date: function(v,lc,p) { var o = {day:'numeric', month:'short', year:'numeric'}; switch (p) { case 'full': o.weekday = 'long'; case 'long': o.month = 'long'; break; case 'short': o.month = 'numeric'; } return (new Date(v)).toLocaleDateString(lc, o) }, /** Represent a time as a short/default/long string * * The input value needs to be in a form that the * {@link https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date Date object} * can process using its single-argument form, `new Date(value)`. * * @param {number|string} value - Either a Unix epoch time in milliseconds, or a string value representing a date * @param {string} [type='default'] - One of `'short'`, `'default'`, `'long'` , or `full` * * @example * var mf = new MessageFormat(['en', 'fi']).setIntlSupport(true); * * mf.compile('The time is now {T, time}')({ T: Date.now() }) * // 'The time is now 11:26:35 PM' * * mf.compile('Kello on nyt {T, time}', 'fi')({ T: Date.now() }) * // 'Kello on nyt 23.26.35' * * var cf = mf.compile('The Eagle landed at {T, time, full} on {T, date, full}'); * cf({ T: '1969-07-20 20:17:40 UTC' }) * // 'The Eagle landed at 10:17:40 PM GMT+2 on Sunday, July 20, 1969' */ time: function(v,lc,p) { var o = {second:'numeric', minute:'numeric', hour:'numeric'}; switch (p) { case 'full': case 'long': o.timeZoneName = 'short'; break; case 'short': delete o.second; } return (new Date(v)).toLocaleTimeString(lc, o) } }; /** Add custom formatter functions to this MessageFormat instance * * The general syntax for calling a formatting function in MessageFormat is * `{var, fn[, args]*}`, where `var` is the variable that will be set by the * user code, `fn` determines the formatting function, and `args` is an * optional comma-separated list of additional arguments. * * In JavaScript, each formatting function is called with three parameters; * the variable value `v`, the current locale `lc`, and (if set) `args` as a * single string, or an array of strings. Formatting functions should not have * side effects. * * @see MessageFormat.formatters * * @memberof MessageFormat * @param {Object.<string,function>} fmt - A map of formatting functions * @returns {MessageFormat} The MessageFormat instance, to allow for chaining * * @example * var mf = new MessageFormat('en-GB'); * mf.addFormatters({ * upcase: function(v) { return v.toUpperCase(); }, * locale: function(v, lc) { return lc; }, * prop: function(v, lc, p) { return v[p] } * }); * * mf.compile('This is {VAR, upcase}.')({ VAR: 'big' }) * // 'This is BIG.' * * mf.compile('The current locale is {_, locale}.')({ _: '' }) * // 'The current locale is en-GB.' * * mf.compile('Answer: {obj, prop, a}')({ obj: {q: 3, a: 42} }) * // 'Answer: 42' */ MessageFormat.prototype.addFormatters = function(fmt) { for (var name in fmt) if (fmt.hasOwnProperty(name)) { this.fmt[name] = fmt[name]; } return this; }; /** Disable the validation of plural & selectordinal keys * * Previous versions of messageformat.js allowed the use of plural & * selectordinal statements with any keys; now we throw an error when a * statement uses a non-numerical key that will never be matched as a * pluralization category for the current locale. * * Use this method to disable the validation and allow usage as previously. * To re-enable, you'll need to create a new MessageFormat instance. * * @returns {MessageFormat} The MessageFormat instance, to allow for chaining * * @example * var mf = new MessageFormat('en'); * var msg = '{X, plural, zero{no answers} one{an answer} other{# answers}}'; * * mf.compile(msg); * // Error: Invalid key `zero` for argument `X`. Valid plural keys for this * // locale are `one`, `other`, and explicit keys like `=0`. * * mf.disablePluralKeyChecks(); * mf.compile(msg)({ X: 0 }); * // '0 answers' */ MessageFormat.prototype.disablePluralKeyChecks = function() { this.noPluralKeyChecks = true; for (var lc in this.pluralFuncs) if (this.pluralFuncs.hasOwnProperty(lc)) { this.pluralFuncs[lc].cardinal = []; this.pluralFuncs[lc].ordinal = []; } return this; }; /** Enable or disable the addition of Unicode control characters to all input * to preserve the integrity of the output when mixing LTR and RTL text. * * @see http://cldr.unicode.org/development/development-process/design-proposals/bidi-handling-of-structured-text * * @memberof MessageFormat * @param {boolean} [enable=true] * @returns {MessageFormat} The MessageFormat instance, to allow for chaining * * @example * // upper case stands for RTL characters, output is shown as rendered * var mf = new MessageFormat('en'); * * mf.compile('{0} >> {1} >> {2}')(['first', 'SECOND', 'THIRD']); * // 'first >> THIRD << SECOND' * * mf.setBiDiSupport(true); * mf.compile('{0} >> {1} >> {2}')(['first', 'SECOND', 'THIRD']); * // 'first >> SECOND >> THIRD' */ MessageFormat.prototype.setBiDiSupport = function(enable) { this.bidiSupport = !!enable || (typeof enable == 'undefined'); return this; }; /** Enable or disable support for the default formatters, which require the * `Intl` object. Note that this can't be autodetected, as the environment * in which the formatted text is compiled into Javascript functions is not * necessarily the same environment in which they will get executed. * * @see MessageFormat.formatters * * @memberof MessageFormat * @param {boolean} [enable=true] * @returns {MessageFormat} The MessageFormat instance, to allow for chaining */ MessageFormat.prototype.setIntlSupport = function(enable) { this.intlSupport = !!enable || (typeof enable == 'undefined'); return this; }; /** According to the ICU MessageFormat spec, a `#` character directly inside a * `plural` or `selectordinal` statement should be replaced by the number * matching the surrounding statement. By default, messageformat.js will * replace `#` signs with the value of the nearest surrounding `plural` or * `selectordinal` statement. * * Set this to true to follow the stricter ICU MessageFormat spec, and to * throw a runtime error if `#` is used with non-numeric input. * * @memberof MessageFormat * @param {boolean} [enable=true] * @returns {MessageFormat} The MessageFormat instance, to allow for chaining * * @example * var mf = new MessageFormat('en'); * * var cookieMsg = '#: {X, plural, =0{no cookies} one{a cookie} other{# cookies}}'; * mf.compile(cookieMsg)({ X: 3 }); * // '#: 3 cookies' * * var pastryMsg = '{X, plural, one{{P, select, cookie{a cookie} other{a pie}}} other{{P, select, cookie{# cookies} other{# pies}}}}'; * mf.compile(pastryMsg)({ X: 3, P: 'pie' }); * // '3 pies' * * mf.setStrictNumberSign(true); * mf.compile(pastryMsg)({ X: 3, P: 'pie' }); * // '# pies' */ MessageFormat.prototype.setStrictNumberSign = function(enable) { this.strictNumberSign = !!enable || (typeof enable == 'undefined'); this.runtime.setStrictNumber(this.strictNumberSign); return this; }; /** Compile messages into storable functions * * If `messages` is a single string including ICU MessageFormat declarations, * the result of `compile()` is a function taking a single Object parameter * `d` representing each of the input's defined variables. * * If `messages` is a hierarchical structure of such strings, the output of * `compile()` will match that structure, with each string replaced by its * corresponding JavaScript function. * * If the input `messages` -- and therefore the output -- of `compile()` is an * object, the output object will have a `toString(global)` method that may be * used to store or cache the compiled functions to disk, for later inclusion * in any JS environment, without a local MessageFormat instance required. Its * `global` parameters sets the name (if any) of the resulting global variable, * with special handling for `exports`, `module.exports`, and `export default`. * If `global` does not contain a `.`, the output defaults to an UMD pattern. * * If `locale` is not set, the first locale set in the object's constructor * will be used by default; using a key at any depth of `messages` that is a * declared locale will set its child elements to use that locale. * * If `locale` is set, it is used for all messages. If the constructor * declared any locales, `locale` needs to be one of them. * * @memberof MessageFormat * @param {string|Object} messages - The input message(s) to be compiled, in ICU MessageFormat * @param {string} [locale] - A locale to use for the messages * @returns {function|Object} The first match found for the given locale(s) * * @example * var mf = new MessageFormat('en'); * var cf = mf.compile('A {TYPE} example.'); * * cf({ TYPE: 'simple' }) * // 'A simple example.' * * @example * var mf = new MessageFormat(['en', 'fi']); * var cf = mf.compile({ * en: { a: 'A {TYPE} example.', * b: 'This is the {COUNT, selectordinal, one{#st} two{#nd} few{#rd} other{#th}} example.' }, * fi: { a: '{TYPE} esimerkki.', * b: 'Tämä on {COUNT, selectordinal, other{#.}} esimerkki.' } * }); * * cf.en.b({ COUNT: 2 }) * // 'This is the 2nd example.' * * cf.fi.b({ COUNT: 2 }) * // 'Tämä on 2. esimerkki.' * * @example * var fs = require('fs'); * var mf = new MessageFormat('en').setIntlSupport(); * var msgSet = { * a: 'A {TYPE} example.', * b: 'This has {COUNT, plural, one{one member} other{# members}}.', * c: 'We have {P, number, percent} code coverage.' * }; * var cfStr = mf.compile(msgSet).toString('module.exports'); * fs.writeFileSync('messages.js', cfStr); * ... * var messages = require('./messages'); * * messages.a({ TYPE: 'more complex' }) * // 'A more complex example.' * * messages.b({ COUNT: 3 }) * // 'This has 3 members.' */ MessageFormat.prototype.compile = function(messages, locale) { function _stringify(obj, level) { if (!level) level = 0; if (typeof obj != 'object') return obj; var o = [], indent = ''; for (var i = 0; i < level; ++i) indent += ' '; for (var k in obj) o.push('\n' + indent + ' ' + Compiler.propname(k) + ': ' + _stringify(obj[k], level + 1)); return '{' + o.join(',') + '\n' + indent + '}'; } var pf; if (Object.keys(this.pluralFuncs).length == 0) { if (!locale) locale = MessageFormat.defaultLocale; pf = {}; pf[locale] = getPluralFunc(locale, this.noPluralKeyChecks); } else if (locale) { pf = {}; pf[locale] = this.pluralFuncs[locale]; if (!pf[locale]) throw new Error('Locale ' + JSON.stringify(locale) + 'not found in ' + JSON.stringify(this.pluralFuncs) + '!'); } else { pf = this.pluralFuncs; locale = Object.keys(pf)[0]; } var compiler = new Compiler(this); var obj = compiler.compile(messages, locale, pf); if (typeof messages != 'object') { var fn = new Function( 'number, plural, select, fmt', Compiler.funcname(locale), 'return ' + obj); var rt = this.runtime; return fn(rt.number, rt.plural, rt.select, this.fmt, pf[locale]); } var rtStr = this.runtime.toString(pf, compiler) + '\n'; var objStr = _stringify(obj); var result = new Function(rtStr + 'return ' + objStr)(); if (result.hasOwnProperty('toString')) throw new Error('The top-level message key `toString` is reserved'); result.toString = function(global) { switch (global || '') { case 'exports': var o = []; for (var k in obj) o.push(Compiler.propname(k, 'exports') + ' = ' + _stringify(obj[k])); return rtStr + o.join(';\n'); case 'module.exports': return rtStr + 'module.exports = ' + objStr; case 'export default': return rtStr + 'export default ' + objStr; case '': return rtStr + 'return ' + objStr; default: if (global.indexOf('.') > -1) return rtStr + global + ' = ' + objStr; return rtStr + [ '(function (root, G) {', ' if (typeof define === "function" && define.amd) { define(G); }', ' else if (typeof exports === "object") { module.exports = G; }', ' else { ' + Compiler.propname(global, 'root') + ' = G; }', '})(this, ' + objStr + ');' ].join('\n'); } } return result; } module.exports = MessageFormat; },{"./compiler":1,"./runtime":3,"make-plural/pluralCategories":6,"make-plural/plurals":7}],3:[function(require,module,exports){ var Compiler = require('./compiler'); /** A set of utility functions that are called by the compiled Javascript * functions, these are included locally in the output of {@link * MessageFormat#compile compile()}. * * @class * @param {MessageFormat} mf - A MessageFormat instance */ function Runtime(mf) { this.mf = mf; this.setStrictNumber(mf.strictNumberSign); } module.exports = Runtime; /** Utility function for `#` in plural rules * * Will throw an Error if `value` has a non-numeric value and `offset` is * non-zero or {@link MessageFormat#setStrictNumberSign} is set. * * @function Runtime#number * @param {number} value - The value to operate on * @param {string} name - The name of the argument, used for error reporting * @param {number} [offset=0] - An optional offset, set by the surrounding context * @returns {number|string} The result of applying the offset to the input value */ function defaultNumber(value, name, offset) { if (!offset) return value; if (isNaN(value)) throw new Error('Can\'t apply offset:' + offset + ' to argument `' + name + '` with non-numerical value ' + JSON.stringify(value) + '.'); return value - offset; } /** @private */ function strictNumber(value, name, offset) { if (isNaN(value)) throw new Error('Argument `' + name + '` has non-numerical value ' + JSON.stringify(value) + '.'); return value - (offset || 0); } /** Set how strictly the {@link number} method parses its input. * * According to the ICU MessageFormat spec, `#` can only be used to replace a * number input of a `plural` statement. By default, messageformat.js does not * throw a runtime error if you use non-numeric argument with a `plural` rule, * unless rule also includes a non-zero `offset`. * * This is called by {@link MessageFormat#setStrictNumberSign} to follow the * stricter ICU MessageFormat spec. * * @param {boolean} [enable=false] */ Runtime.prototype.setStrictNumber = function(enable) { this.number = enable ? strictNumber : defaultNumber; } /** Utility function for `{N, plural|selectordinal, ...}` * * @param {number} value - The key to use to find a pluralization rule * @param {number} offset - An offset to apply to `value` * @param {function} lcfunc - A locale function from `pluralFuncs` * @param {Object.<string,string>} data - The object from which results are looked up * @param {?boolean} isOrdinal - If true, use ordinal rather than cardinal rules * @returns {string} The result of the pluralization */ Runtime.prototype.plural = function(value, offset, lcfunc, data, isOrdinal) { if ({}.hasOwnProperty.call(data, value)) return data[value]; if (offset) value -= offset; var key = lcfunc(value, isOrdinal); if (key in data) return data[key]; return data.other; } /** Utility function for `{N, select, ...}` * * @param {number} value - The key to use to find a selection * @param {Object.<string,string>} data - The object from which results are looked up * @returns {string} The result of the select statement */ Runtime.prototype.select = function(value, data) { if ({}.hasOwnProperty.call(data, value)) return data[value]; return data.other; } /** @private */ Runtime.prototype.toString = function(pluralFuncs, compiler) { function _stringify(o, level) { if (typeof o != 'object') { var funcStr = o.toString().replace(/^(function )\w*/, '$1'); var indent = /([ \t]*)\S.*$/.exec(funcStr); return indent ? funcStr.replace(new RegExp('^' + indent[1], 'mg'), '') : funcStr; } var s = []; for (var i in o) { if (level == 0) s.push('var ' + i + ' = ' + _stringify(o[i], level + 1) + ';\n'); else s.push(Compiler.propname(i) + ': ' + _stringify(o[i], level + 1)); } if (level == 0) return s.join(''); if (s.length == 0) return '{}'; var indent = ' '; while (--level) indent += ' '; return '{\n' + s.join(',\n').replace(/^/gm, indent) + '\n}'; } var obj = {}; Object.keys(compiler.locales).forEach(function(lc) { obj[Compiler.funcname(lc)] = pluralFuncs[lc]; }); Object.keys(compiler.runtime).forEach(function(fn) { obj[fn] = this[fn]; }, this); var fmtKeys = Object.keys(compiler.formatters); var fmt = this.mf.fmt; if (fmtKeys.length) obj.fmt = fmtKeys.reduce(function(o, key) { o[key] = fmt[key]; return o; }, {}); return _stringify(obj, 0); } },{"./compiler":1}],4:[function(require,module,exports){ // http://wiki.commonjs.org/wiki/Unit_Testing/1.0 // // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! // // Originally from narwhal.js (http://narwhaljs.org) // Copyright (c) 2009 Thomas Robinson <280north.com> // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the 'Software'), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // when used in node, this will actually load the util module we depend on // versus loading the builtin util module as happens otherwise // this is a bug in node module loading as far as I am concerned var util = require('util/'); var pSlice = Array.prototype.slice; var hasOwn = Object.prototype.hasOwnProperty; // 1. The assert module provides functions that throw // AssertionError's when particular conditions are not met. The // assert module must conform to the following interface. var assert = module.exports = ok; // 2. The AssertionError is defined in assert. // new assert.AssertionError({ message: message, // actual: actual, // expected: expected }) assert.AssertionError = function AssertionError(options) { this.name = 'AssertionError'; this.actual = options.actual; this.expected = options.expected; this.operator = options.operator; if (options.message) { this.message = options.message; this.generatedMessage = false; } else { this.message = getMessage(this); this.generatedMessage = true; } var stackStartFunction = options.stackStartFunction || fail; if (Error.captureStackTrace) { Error.captureStackTrace(this, stackStartFunction); } else { // non v8 browsers so we can have a stacktrace var err = new Error(); if (err.stack) { var out = err.stack; // try to strip useless frames var fn_name = stackStartFunction.name; var idx = out.indexOf('\n' + fn_name); if (idx >= 0) { // once we have located the function frame // we need to strip out everything before it (and its line) var next_line = out.indexOf('\n', idx + 1); out = out.substring(next_line + 1); } this.stack = out; } } }; // assert.AssertionError instanceof Error util.inherits(assert.AssertionError, Error); function replacer(key, value) { if (util.isUndefined(value)) { return '' + value; } if (util.isNumber(value) && !isFinite(value)) { return value.toString(); } if (util.isFunction(value) || util.isRegExp(value)) { return value.toString(); } return value; } function truncate(s, n) { if (util.isString(s)) { return s.length < n ? s : s.slice(0, n); } else { return s; } } function getMessage(self) { return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + self.operator + ' ' + truncate(JSON.stringify(self.expected, replacer), 128); } // At present only the three keys mentioned above are used and // understood by the spec. Implementations or sub modules can pass // other keys to the AssertionError's constructor - they will be // ignored. // 3. All of the following functions must throw an AssertionError // when a corresponding condition is not met, with a message that // may be undefined if not provided. All assertion methods provide // both the actual and expected values to the assertion error for // display purposes. function fail(actual, expected, message, operator, stackStartFunction) { throw new assert.AssertionError({ message: message, actual: actual, expected: expected, operator: operator, stackStartFunction: stackStartFunction }); } // EXTENSION! allows for well behaved errors defined elsewhere. assert.fail = fail; // 4. Pure assertion tests whether a value is truthy, as determined // by !!guard. // assert.ok(guard, message_opt); // This statement is equivalent to assert.equal(true, !!guard, // message_opt);. To test strictly for the value true, use // assert.strictEqual(true, guard, message_opt);. function ok(value, message) { if (!value) fail(value, true, message, '==', assert.ok); } assert.ok = ok; // 5. The equality assertion tests shallow, coercive equality with // ==. // assert.equal(actual, expected, message_opt); assert.equal = function equal(actual, expected, message) { if (actual != expected) fail(actual, expected, message, '==', assert.equal); }; // 6. The non-equality assertion tests for whether two objects are not equal // with != assert.notEqual(actual, expected, message_opt); assert.notEqual = function notEqual(actual, expected, message) { if (actual == expected) { fail(actual, expected, message, '!=', assert.notEqual); } }; // 7. The equivalence assertion tests a deep equality relation. // assert.deepEqual(actual, expected, message_opt); assert.deepEqual = function deepEqual(actual, expected, message) { if (!_deepEqual(actual, expected)) { fail(actual, expected, message, 'deepEqual', assert.deepEqual); } }; function _deepEqual(actual, expected) { // 7.1. All identical values are equivalent, as determined by ===. if (actual === expected) { return true; } else if (util.isBuffer(actual) && util.isBuffer(expected)) { if (actual.length != expected.length) return false; for (var i = 0; i < actual.length; i++) { if (actual[i] !== expected[i]) return false; } return true; // 7.2. If the expected value is a Date object, the actual value is // equivalent if it is also a Date object that refers to the same time. } else if (util.isDate(actual) && util.isDate(expected)) { return actual.getTime() === expected.getTime(); // 7.3 If the expected value is a RegExp object, the actual value is // equivalent if it is also a RegExp object with the same source and // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). } else if (util.isRegExp(actual) && util.isRegExp(expected)) { return actual.source === expected.source && actual.global === expected.global && actual.multiline === expected.multiline && actual.lastIndex === expected.lastIndex && actual.ignoreCase === expected.ignoreCase; // 7.4. Other pairs that do not both pass typeof value == 'object', // equivalence is determined by ==. } else if (!util.isObject(actual) && !util.isObject(expected)) { return actual == expected; // 7.5 For all other Object pairs, including Array objects, equivalence is // determined by having the same number of owned properties (as verified // with Object.prototype.hasOwnProperty.call), the same set of keys // (although not necessarily the same order), equivalent values for every // corresponding key, and an identical 'prototype' property. Note: this // accounts for both named and indexed properties on Arrays. } else { return objEquiv(actual, expected); } } function isArguments(object) { return Object.prototype.toString.call(object) == '[object Arguments]'; } function objEquiv(a, b) { if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) return false; // an identical 'prototype' property. if (a.prototype !== b.prototype) return false; // if one is a primitive, the other must be same if (util.isPrimitive(a) || util.isPrimitive(b)) { return a === b; } var aIsArgs = isArguments(a), bIsArgs = isArguments(b); if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) return false; if (aIsArgs) { a = pSlice.call(a); b = pSlice.call(b); return _deepEqual(a, b); } var ka = objectKeys(a), kb = objectKeys(b), key, i; // having the same number of owned properties (keys incorporates // hasOwnProperty) if (ka.length != kb.length) return false; //the same set of keys (although not necessarily the same order), ka.sort(); kb.sort(); //~~~cheap key test for (i = ka.length - 1; i >= 0; i--) { if (ka[i] != kb[i]) return false; } //equivalent values for every corresponding key, and //~~~possibly expensive deep test for (i = ka.length - 1; i >= 0; i--) { key = ka[i]; if (!_deepEqual(a[key], b[key])) return false; } return true; } // 8. The non-equivalence assertion tests for any deep inequality. // assert.notDeepEqual(actual, expected, message_opt); assert.notDeepEqual = function notDeepEqual(actual, expected, message) { if (_deepEqual(actual, expected)) { fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); } }; // 9. The strict equality assertion tests strict equality, as determined by ===. // assert.strictEqual(actual, expected, message_opt); assert.strictEqual = function strictEqual(actual, expected, message) { if (actual !== expected) { fail(actual, expected, message, '===', assert.strictEqual); } }; // 10. The strict non-equality assertion tests for strict inequality, as // determined by !==. assert.notStrictEqual(actual, expected, message_opt); assert.notStrictEqual = function notStrictEqual(actual, expected, message) { if (actual === expected) { fail(actual, expected, message, '!==', assert.notStrictEqual); } }; function expectedException(actual, expected) { if (!actual || !expected) { return false; } if (Object.prototype.toString.call(expected) == '[object RegExp]') { return expected.test(actual); } else if (actual instanceof expected) { return true; } else if (expected.call({}, actual) === true) { return true; } return false; } function _throws(shouldThrow, block, expected, message) { var actual; if (util.isString(expected)) { message = expected; expected = null; } try { block(); } catch (e) { actual = e; } message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + (message ? ' ' + message : '.'); if (shouldThrow && !actual) { fail(actual, expected, 'Missing expected exception' + message); } if (!shouldThrow && expectedException(actual, expected)) { fail(actual, expected, 'Got unwanted exception' + message); } if ((shouldThrow && actual && expected && !expectedException(actual, expected)) || (!shouldThrow && actual)) { throw actual; } } // 11. Expected to throw an error: // assert.throws(block, Error_opt, message_opt); assert.throws = function(block, /*optional*/error, /*optional*/message) { _throws.apply(this, [true].concat(pSlice.call(arguments))); }; // EXTENSION! This is annoying to write outside this module. assert.doesNotThrow = function(block, /*optional*/message) { _throws.apply(this, [false].concat(pSlice.call(arguments))); }; assert.ifError = function(err) { if (err) {throw err;}}; var objectKeys = Object.keys || function (obj) { var keys = []; for (var key in obj) { if (hasOwn.call(obj, key)) keys.push(key); } return keys; }; },{"util/":13}],5:[function(require,module,exports){ if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { ctor.super_ = superCtor ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }); }; } else { // old school shim for old browsers module.exports = function inherits(ctor, superCtor) { ctor.super_ = superCtor var TempCtor = function () {} TempCtor.prototype = superCtor.prototype ctor.prototype = new TempCtor() ctor.prototype.constructor = ctor } } },{}],6:[function(require,module,exports){ var _cc = [ {cardinal:["other"],ordinal:["other"]}, {cardinal:["one","other"],ordinal:["other"]}, {cardinal:["one","other"],ordinal:["one","other"]}, {cardinal:["one","two","other"],ordinal:["other"]} ]; (function (root, pluralCategories) { if (typeof define === 'function' && define.amd) { define(pluralCategories); } else if (typeof exports === 'object') { module.exports = pluralCategories; } else { root.pluralCategories = pluralCategories; } }(this, { af: _cc[1], ak: _cc[1], am: _cc[1], ar: {cardinal:["zero","one","two","few","many","other"],ordinal:["other"]}, as: {cardinal:["one","other"],ordinal:["one","two","few","many","other"]}, asa: _cc[1], ast: _cc[1], az: {cardinal:["one","other"],ordinal:["one","few","many","other"]}, be: {cardinal:["one","few","many","other"],ordinal:["few","other"]}, bem: _cc[1], bez: _cc[1], bg: _cc[1], bh: _cc[1], bm: _cc[0], bn: {cardinal:["one","other"],ordinal:["one","two","few","many","other"]}, bo: _cc[0], br: {cardinal:["one","two","few","many","other"],ordinal:["other"]}, brx: _cc[1], bs: {cardinal:["one","few","other"],ordinal:["other"]}, ca: {cardinal:["one","other"],ordinal:["one","two","few","other"]}, ce: _cc[1], cgg: _cc[1], chr: _cc[1], ckb: _cc[1], cs: {cardinal:["one","few","many","other"],ordinal:["other"]}, cy: {cardinal:["zero","one","two","few","many","other"],ordinal:["zero","one","two","few","many","other"]}, da: _cc[1], de: _cc[1], dsb: {cardinal:["one","two","few","other"],ordinal:["other"]}, dv: _cc[1], dz: _cc[0], ee: _cc[1], el: _cc[1], en: {cardinal:["one","other"],ordinal:["one","two","few","other"]}, eo: _cc[1], es: _cc[1], et: _cc[1], eu: _cc[1], fa: _cc[1], ff: _cc[1], fi: _cc[1], fil: _cc[2], fo: _cc[1], fr: _cc[2], fur: _cc[1], fy: _cc[1], ga: {cardinal:["one","two","few","many","other"],ordinal:["one","other"]}, gd: {cardinal:["one","two","few","other"],ordinal:["other"]}, gl: _cc[1], gsw: _cc[1], gu: {cardinal:["one","other"],ordinal:["one","two","few","many","other"]}, guw: _cc[1], gv: {cardinal:["one","two","few","many","other"],ordinal:["other"]}, ha: _cc[1], haw: _cc[1], he: {cardinal:["one","two","many","other"],ordinal:["other"]}, hi: {cardinal:["one","other"],ordinal:["one","two","few","many","other"]}, hr: {cardinal:["one","few","other"],ordinal:["other"]}, hsb: {cardinal:["one","two","few","other"],ordinal:["other"]}, hu: _cc[2], hy: _cc[2], id: _cc[0], ig: _cc[0], ii: _cc[0], "in": _cc[0], is: _cc[1], it: {cardinal:["one","other"],ordinal:["many","other"]}, iu: _cc[3], iw: {cardinal:["one","two","many","other"],ordinal:["other"]}, ja: _cc[0], jbo: _cc[0], jgo: _cc[1], ji: _cc[1], jmc: _cc[1], jv: _cc[0], jw: _cc[0], ka: {cardinal:["one","other"],ordinal:["one","many","other"]}, kab: _cc[1], kaj: _cc[1], kcg: _cc[1], kde: _cc[0], kea: _cc[0], kk: {cardinal:["one","other"],ordinal:["many","other"]}, kkj: _cc[1], kl: _cc[1], km: _cc[0], kn: _cc[1], ko: _cc[0], ks: _cc[1], ksb: _cc[1], ksh: {cardinal:["zero","one","other"],ordinal:["other"]}, ku: _cc[1], kw: _cc[3], ky: _cc[1], lag: {cardinal:["zero","one","other"],ordinal:["other"]}, lb: _cc[1], lg: _cc[1], lkt: _cc[0], ln: _cc[1], lo: {cardinal:["other"],ordinal:["one","other"]}, lt: {cardinal:["one","few","many","other"],ordinal:["other"]}, lv: {cardinal:["zero","one","other"],ordinal:["other"]}, mas: _cc[1], mg: _cc[1], mgo: _cc[1], mk: {cardinal:["one","other"],ordinal:["one","two","many","other"]}, ml: _cc[1], mn: _cc[1], mo: {cardinal:["one","few","other"],ordinal:["one","other"]}, mr: {cardinal:["one","other"],ordinal:["one","two","few","other"]}, ms: {cardinal:["other"],ordinal:["one","other"]}, mt: {cardinal:["one","few","many","other"],ordinal:["other"]}, my: _cc[0], nah: _cc[1], naq: _cc[3], nb: _cc[1], nd: _cc[1], ne: _cc[2], nl: _cc[1], nn: _cc[1], nnh: _cc[1], no: _cc[1], nqo: _cc[0], nr: _cc[1], nso: _cc[1], ny: _cc[1], nyn: _cc[1], om: _cc[1], or: _cc[1], os: _cc[1], pa: _cc[1], pap: _cc[1], pl: {cardinal:["one","few","many","other"],ordinal:["other"]}, prg: {cardinal:["zero","one","other"],ordinal:["other"]}, ps: _cc[1], pt: _cc[1], "pt-PT": _cc[1], rm: _cc[1], ro: {cardinal:["one","few","other"],ordinal:["one","other"]}, rof: _cc[1], root: _cc[0], ru: {cardinal:["one","few","many","other"],ordinal:["other"]}, rwk: _cc[1], sah: _cc[0], saq: _cc[1], sdh: _cc[1], se: _cc[3], seh: _cc[1], ses: _cc[0], sg: _cc[0], sh: {cardinal:["one","few","other"],ordinal:["other"]}, shi: {cardinal:["one","few","other"],ordinal:["other"]}, si: _cc[1], sk: {cardinal:["one","few","many","other"],ordinal:["other"]}, sl: {cardinal:["one","two","few","other"],ordinal:["other"]}, sma: _cc[3], smi: _cc[3], smj: _cc[3], smn: _cc[3], sms: _cc[3], sn: _cc[1], so: _cc[1], sq: {cardinal:["one","other"],ordinal:["one","many","other"]}, sr: {cardinal:["one","few","other"],ordinal:["other"]}, ss: _cc[1], ssy: _cc[1], st: _cc[1], sv: _cc[2], sw: _cc[1], syr: _cc[1], ta: _cc[1], te: _cc[1], teo: _cc[1], th: _cc[0], ti: _cc[1], tig: _cc[1], tk: _cc[1], tl: _cc[2], tn: _cc[1], to: _cc[0], tr: _cc[1], ts: _cc[1], tzm: _cc[1], ug: _cc[1], uk: {cardinal:["one","few","many","other"],ordinal:["few","other"]}, ur: _cc[1], uz: _cc[1], ve: _cc[1], vi: {cardinal:["other"],ordinal:["one","other"]}, vo: _cc[1], vun: _cc[1], wa: _cc[1], wae: _cc[1], wo: _cc[0], xh: _cc[1], xog: _cc[1], yi: _cc[1], yo: _cc[0], zh: _cc[0], zu: _cc[1] })); },{}],7:[function(require,module,exports){ var _cp = [ function(n, ord) { if (ord) return 'other'; return 'other'; }, function(n, ord) { if (ord) return 'other'; return (n == 1) ? 'one' : 'other'; }, function(n, ord) { if (ord) return 'other'; return ((n == 0 || n == 1)) ? 'one' : 'other'; }, function(n, ord) { var s = String(n).split('.'), v0 = !s[1]; if (ord) return 'other'; return (n == 1 && v0) ? 'one' : 'other'; } ]; (function (root, plurals) { if (typeof define === 'function' && define.amd) { define(plurals); } else if (typeof exports === 'object') { module.exports = plurals; } else { root.plurals = plurals; } }(this, { af: _cp[1], ak: _cp[2], am: function(n, ord) { if (ord) return 'other'; return (n >= 0 && n <= 1) ? 'one' : 'other'; }, ar: function(n, ord) { var s = String(n).split('.'), t0 = Number(s[0]) == n, n100 = t0 && s[0].slice(-2); if (ord) return 'other'; return (n == 0) ? 'zero' : (n == 1) ? 'one' : (n == 2) ? 'two' : ((n100 >= 3 && n100 <= 10)) ? 'few' : ((n100 >= 11 && n100 <= 99)) ? 'many' : 'other'; }, as: function(n, ord) { if (ord) return ((n == 1 || n == 5 || n == 7 || n == 8 || n == 9 || n == 10)) ? 'one' : ((n == 2 || n == 3)) ? 'two' : (n == 4) ? 'few' : (n == 6) ? 'many' : 'other'; return (n >= 0 && n <= 1) ? 'one' : 'other'; }, asa: _cp[1], ast: _cp[3], az: function(n, ord) { var s = String(n).split('.'), i = s[0], i10 = i.slice(-1), i100 = i.slice(-2), i1000 = i.slice(-3); if (ord) return ((i10 == 1 || i10 == 2 || i10 == 5 |