UNPKG

4.4 kBJavaScriptView Raw
1var Compiler = require('./compiler');
2
3
4/** A set of utility functions that are called by the compiled Javascript
5 * functions, these are included locally in the output of {@link
6 * MessageFormat#compile compile()}.
7 *
8 * @class
9 * @param {MessageFormat} mf - A MessageFormat instance
10 */
11function Runtime(mf) {
12 this.mf = mf;
13 this.setStrictNumber(mf.strictNumberSign);
14}
15
16module.exports = Runtime;
17
18
19/** Utility function for `#` in plural rules
20 *
21 * Will throw an Error if `value` has a non-numeric value and `offset` is
22 * non-zero or {@link MessageFormat#setStrictNumberSign} is set.
23 *
24 * @function Runtime#number
25 * @param {number} value - The value to operate on
26 * @param {string} name - The name of the argument, used for error reporting
27 * @param {number} [offset=0] - An optional offset, set by the surrounding context
28 * @returns {number|string} The result of applying the offset to the input value
29 */
30function defaultNumber(value, name, offset) {
31 if (!offset) return value;
32 if (isNaN(value)) throw new Error('Can\'t apply offset:' + offset + ' to argument `' + name +
33 '` with non-numerical value ' + JSON.stringify(value) + '.');
34 return value - offset;
35}
36
37
38/** @private */
39function strictNumber(value, name, offset) {
40 if (isNaN(value)) throw new Error('Argument `' + name + '` has non-numerical value ' + JSON.stringify(value) + '.');
41 return value - (offset || 0);
42}
43
44
45/** Set how strictly the {@link number} method parses its input.
46 *
47 * According to the ICU MessageFormat spec, `#` can only be used to replace a
48 * number input of a `plural` statement. By default, messageformat.js does not
49 * throw a runtime error if you use non-numeric argument with a `plural` rule,
50 * unless rule also includes a non-zero `offset`.
51 *
52 * This is called by {@link MessageFormat#setStrictNumberSign} to follow the
53 * stricter ICU MessageFormat spec.
54 *
55 * @param {boolean} [enable=false]
56 */
57Runtime.prototype.setStrictNumber = function(enable) {
58 this.number = enable ? strictNumber : defaultNumber;
59}
60
61
62/** Utility function for `{N, plural|selectordinal, ...}`
63 *
64 * @param {number} value - The key to use to find a pluralization rule
65 * @param {number} offset - An offset to apply to `value`
66 * @param {function} lcfunc - A locale function from `pluralFuncs`
67 * @param {Object.<string,string>} data - The object from which results are looked up
68 * @param {?boolean} isOrdinal - If true, use ordinal rather than cardinal rules
69 * @returns {string} The result of the pluralization
70 */
71Runtime.prototype.plural = function(value, offset, lcfunc, data, isOrdinal) {
72 if ({}.hasOwnProperty.call(data, value)) return data[value];
73 if (offset) value -= offset;
74 var key = lcfunc(value, isOrdinal);
75 if (key in data) return data[key];
76 return data.other;
77}
78
79
80/** Utility function for `{N, select, ...}`
81 *
82 * @param {number} value - The key to use to find a selection
83 * @param {Object.<string,string>} data - The object from which results are looked up
84 * @returns {string} The result of the select statement
85 */
86Runtime.prototype.select = function(value, data) {
87 if ({}.hasOwnProperty.call(data, value)) return data[value];
88 return data.other;
89}
90
91
92/** @private */
93Runtime.prototype.toString = function(pluralFuncs, compiler) {
94 function _stringify(o, level) {
95 if (typeof o != 'object') {
96 var funcStr = o.toString().replace(/^(function )\w*/, '$1');
97 var indent = /([ \t]*)\S.*$/.exec(funcStr);
98 return indent ? funcStr.replace(new RegExp('^' + indent[1], 'mg'), '') : funcStr;
99 }
100 var s = [];
101 for (var i in o) {
102 if (level == 0) s.push('var ' + i + ' = ' + _stringify(o[i], level + 1) + ';\n');
103 else s.push(Compiler.propname(i) + ': ' + _stringify(o[i], level + 1));
104 }
105 if (level == 0) return s.join('');
106 if (s.length == 0) return '{}';
107 var indent = ' '; while (--level) indent += ' ';
108 return '{\n' + s.join(',\n').replace(/^/gm, indent) + '\n}';
109 }
110
111 var obj = {};
112 Object.keys(compiler.locales).forEach(function(lc) { obj[Compiler.funcname(lc)] = pluralFuncs[lc]; });
113 Object.keys(compiler.runtime).forEach(function(fn) { obj[fn] = this[fn]; }, this);
114 var fmtKeys = Object.keys(compiler.formatters);
115 var fmt = this.mf.fmt;
116 if (fmtKeys.length) obj.fmt = fmtKeys.reduce(function(o, key) { o[key] = fmt[key]; return o; }, {});
117 return _stringify(obj, 0);
118}