119 lines
4.3 KiB
JavaScript
119 lines
4.3 KiB
JavaScript
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);
|
|
}
|