mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
New languages - Portuguese (Std/Brazil) & Norwegian (Bokmål) (#1236)
* Update jquery.i18n to 1.07, add extended plurals support * Add additional languages - Portuguese, Portuguese (Brazil), Norwegian (Bokmål)
This commit is contained in:
607
assets/webconfig/js/lib/jquery.i18n/CLDRPluralRuleParser.js
Normal file
607
assets/webconfig/js/lib/jquery.i18n/CLDRPluralRuleParser.js
Normal file
@@ -0,0 +1,607 @@
|
||||
/**
|
||||
* cldrpluralparser.js
|
||||
* A parser engine for CLDR plural rules.
|
||||
*
|
||||
* Copyright 2012-2014 Santhosh Thottingal and other contributors
|
||||
* Released under the MIT license
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* @source https://github.com/santhoshtr/CLDRPluralRuleParser
|
||||
* @author Santhosh Thottingal <santhosh.thottingal@gmail.com>
|
||||
* @author Timo Tijhof
|
||||
* @author Amir Aharoni
|
||||
*/
|
||||
|
||||
/**
|
||||
* Evaluates a plural rule in CLDR syntax for a number
|
||||
* @param {string} rule
|
||||
* @param {integer} number
|
||||
* @return {boolean} true if evaluation passed, false if evaluation failed.
|
||||
*/
|
||||
|
||||
// UMD returnExports https://github.com/umdjs/umd/blob/master/returnExports.js
|
||||
(function(root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
// Node. Does not work with strict CommonJS, but
|
||||
// only CommonJS-like environments that support module.exports,
|
||||
// like Node.
|
||||
module.exports = factory();
|
||||
} else {
|
||||
// Browser globals (root is window)
|
||||
root.pluralRuleParser = factory();
|
||||
}
|
||||
}(this, function() {
|
||||
|
||||
function pluralRuleParser(rule, number) {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
Syntax: see http://unicode.org/reports/tr35/#Language_Plural_Rules
|
||||
-----------------------------------------------------------------
|
||||
condition = and_condition ('or' and_condition)*
|
||||
('@integer' samples)?
|
||||
('@decimal' samples)?
|
||||
and_condition = relation ('and' relation)*
|
||||
relation = is_relation | in_relation | within_relation
|
||||
is_relation = expr 'is' ('not')? value
|
||||
in_relation = expr (('not')? 'in' | '=' | '!=') range_list
|
||||
within_relation = expr ('not')? 'within' range_list
|
||||
expr = operand (('mod' | '%') value)?
|
||||
operand = 'n' | 'i' | 'f' | 't' | 'v' | 'w'
|
||||
range_list = (range | value) (',' range_list)*
|
||||
value = digit+
|
||||
digit = 0|1|2|3|4|5|6|7|8|9
|
||||
range = value'..'value
|
||||
samples = sampleRange (',' sampleRange)* (',' ('…'|'...'))?
|
||||
sampleRange = decimalValue '~' decimalValue
|
||||
decimalValue = value ('.' value)?
|
||||
*/
|
||||
|
||||
// We don't evaluate the samples section of the rule. Ignore it.
|
||||
rule = rule.split('@')[0].replace(/^\s*/, '').replace(/\s*$/, '');
|
||||
|
||||
if (!rule.length) {
|
||||
// Empty rule or 'other' rule.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Indicates the current position in the rule as we parse through it.
|
||||
// Shared among all parsing functions below.
|
||||
var pos = 0,
|
||||
operand,
|
||||
expression,
|
||||
relation,
|
||||
result,
|
||||
whitespace = makeRegexParser(/^\s+/),
|
||||
value = makeRegexParser(/^\d+/),
|
||||
_n_ = makeStringParser('n'),
|
||||
_i_ = makeStringParser('i'),
|
||||
_f_ = makeStringParser('f'),
|
||||
_t_ = makeStringParser('t'),
|
||||
_v_ = makeStringParser('v'),
|
||||
_w_ = makeStringParser('w'),
|
||||
_is_ = makeStringParser('is'),
|
||||
_isnot_ = makeStringParser('is not'),
|
||||
_isnot_sign_ = makeStringParser('!='),
|
||||
_equal_ = makeStringParser('='),
|
||||
_mod_ = makeStringParser('mod'),
|
||||
_percent_ = makeStringParser('%'),
|
||||
_not_ = makeStringParser('not'),
|
||||
_in_ = makeStringParser('in'),
|
||||
_within_ = makeStringParser('within'),
|
||||
_range_ = makeStringParser('..'),
|
||||
_comma_ = makeStringParser(','),
|
||||
_or_ = makeStringParser('or'),
|
||||
_and_ = makeStringParser('and');
|
||||
|
||||
function debug() {
|
||||
// console.log.apply(console, arguments);
|
||||
}
|
||||
|
||||
debug('pluralRuleParser', rule, number);
|
||||
|
||||
// Try parsers until one works, if none work return null
|
||||
function choice(parserSyntax) {
|
||||
return function() {
|
||||
var i, result;
|
||||
|
||||
for (i = 0; i < parserSyntax.length; i++) {
|
||||
result = parserSyntax[i]();
|
||||
|
||||
if (result !== null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
// Try several parserSyntax-es in a row.
|
||||
// All must succeed; otherwise, return null.
|
||||
// This is the only eager one.
|
||||
function sequence(parserSyntax) {
|
||||
var i, parserRes,
|
||||
originalPos = pos,
|
||||
result = [];
|
||||
|
||||
for (i = 0; i < parserSyntax.length; i++) {
|
||||
parserRes = parserSyntax[i]();
|
||||
|
||||
if (parserRes === null) {
|
||||
pos = originalPos;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
result.push(parserRes);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Run the same parser over and over until it fails.
|
||||
// Must succeed a minimum of n times; otherwise, return null.
|
||||
function nOrMore(n, p) {
|
||||
return function() {
|
||||
var originalPos = pos,
|
||||
result = [],
|
||||
parsed = p();
|
||||
|
||||
while (parsed !== null) {
|
||||
result.push(parsed);
|
||||
parsed = p();
|
||||
}
|
||||
|
||||
if (result.length < n) {
|
||||
pos = originalPos;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
// Helpers - just make parserSyntax out of simpler JS builtin types
|
||||
function makeStringParser(s) {
|
||||
var len = s.length;
|
||||
|
||||
return function() {
|
||||
var result = null;
|
||||
|
||||
if (rule.substr(pos, len) === s) {
|
||||
result = s;
|
||||
pos += len;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
function makeRegexParser(regex) {
|
||||
return function() {
|
||||
var matches = rule.substr(pos).match(regex);
|
||||
|
||||
if (matches === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
pos += matches[0].length;
|
||||
|
||||
return matches[0];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Integer digits of n.
|
||||
*/
|
||||
function i() {
|
||||
var result = _i_();
|
||||
|
||||
if (result === null) {
|
||||
debug(' -- failed i', parseInt(number, 10));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
result = parseInt(number, 10);
|
||||
debug(' -- passed i ', result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute value of the source number (integer and decimals).
|
||||
*/
|
||||
function n() {
|
||||
var result = _n_();
|
||||
|
||||
if (result === null) {
|
||||
debug(' -- failed n ', number);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
result = parseFloat(number, 10);
|
||||
debug(' -- passed n ', result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visible fractional digits in n, with trailing zeros.
|
||||
*/
|
||||
function f() {
|
||||
var result = _f_();
|
||||
|
||||
if (result === null) {
|
||||
debug(' -- failed f ', number);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
result = (number + '.').split('.')[1] || 0;
|
||||
debug(' -- passed f ', result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visible fractional digits in n, without trailing zeros.
|
||||
*/
|
||||
function t() {
|
||||
var result = _t_();
|
||||
|
||||
if (result === null) {
|
||||
debug(' -- failed t ', number);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
result = (number + '.').split('.')[1].replace(/0$/, '') || 0;
|
||||
debug(' -- passed t ', result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of visible fraction digits in n, with trailing zeros.
|
||||
*/
|
||||
function v() {
|
||||
var result = _v_();
|
||||
|
||||
if (result === null) {
|
||||
debug(' -- failed v ', number);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
result = (number + '.').split('.')[1].length || 0;
|
||||
debug(' -- passed v ', result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of visible fraction digits in n, without trailing zeros.
|
||||
*/
|
||||
function w() {
|
||||
var result = _w_();
|
||||
|
||||
if (result === null) {
|
||||
debug(' -- failed w ', number);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
result = (number + '.').split('.')[1].replace(/0$/, '').length || 0;
|
||||
debug(' -- passed w ', result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// operand = 'n' | 'i' | 'f' | 't' | 'v' | 'w'
|
||||
operand = choice([n, i, f, t, v, w]);
|
||||
|
||||
// expr = operand (('mod' | '%') value)?
|
||||
expression = choice([mod, operand]);
|
||||
|
||||
function mod() {
|
||||
var result = sequence(
|
||||
[operand, whitespace, choice([_mod_, _percent_]), whitespace, value]
|
||||
);
|
||||
|
||||
if (result === null) {
|
||||
debug(' -- failed mod');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
debug(' -- passed ' + parseInt(result[0], 10) + ' ' + result[2] + ' ' + parseInt(result[4], 10));
|
||||
|
||||
return parseFloat(result[0]) % parseInt(result[4], 10);
|
||||
}
|
||||
|
||||
function not() {
|
||||
var result = sequence([whitespace, _not_]);
|
||||
|
||||
if (result === null) {
|
||||
debug(' -- failed not');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return result[1];
|
||||
}
|
||||
|
||||
// is_relation = expr 'is' ('not')? value
|
||||
function is() {
|
||||
var result = sequence([expression, whitespace, choice([_is_]), whitespace, value]);
|
||||
|
||||
if (result !== null) {
|
||||
debug(' -- passed is : ' + result[0] + ' == ' + parseInt(result[4], 10));
|
||||
|
||||
return result[0] === parseInt(result[4], 10);
|
||||
}
|
||||
|
||||
debug(' -- failed is');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// is_relation = expr 'is' ('not')? value
|
||||
function isnot() {
|
||||
var result = sequence(
|
||||
[expression, whitespace, choice([_isnot_, _isnot_sign_]), whitespace, value]
|
||||
);
|
||||
|
||||
if (result !== null) {
|
||||
debug(' -- passed isnot: ' + result[0] + ' != ' + parseInt(result[4], 10));
|
||||
|
||||
return result[0] !== parseInt(result[4], 10);
|
||||
}
|
||||
|
||||
debug(' -- failed isnot');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function not_in() {
|
||||
var i, range_list,
|
||||
result = sequence([expression, whitespace, _isnot_sign_, whitespace, rangeList]);
|
||||
|
||||
if (result !== null) {
|
||||
debug(' -- passed not_in: ' + result[0] + ' != ' + result[4]);
|
||||
range_list = result[4];
|
||||
|
||||
for (i = 0; i < range_list.length; i++) {
|
||||
if (parseInt(range_list[i], 10) === parseInt(result[0], 10)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
debug(' -- failed not_in');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// range_list = (range | value) (',' range_list)*
|
||||
function rangeList() {
|
||||
var result = sequence([choice([range, value]), nOrMore(0, rangeTail)]),
|
||||
resultList = [];
|
||||
|
||||
if (result !== null) {
|
||||
resultList = resultList.concat(result[0]);
|
||||
|
||||
if (result[1][0]) {
|
||||
resultList = resultList.concat(result[1][0]);
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
debug(' -- failed rangeList');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function rangeTail() {
|
||||
// ',' range_list
|
||||
var result = sequence([_comma_, rangeList]);
|
||||
|
||||
if (result !== null) {
|
||||
return result[1];
|
||||
}
|
||||
|
||||
debug(' -- failed rangeTail');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// range = value'..'value
|
||||
function range() {
|
||||
var i, array, left, right,
|
||||
result = sequence([value, _range_, value]);
|
||||
|
||||
if (result !== null) {
|
||||
debug(' -- passed range');
|
||||
|
||||
array = [];
|
||||
left = parseInt(result[0], 10);
|
||||
right = parseInt(result[2], 10);
|
||||
|
||||
for (i = left; i <= right; i++) {
|
||||
array.push(i);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
debug(' -- failed range');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function _in() {
|
||||
var result, range_list, i;
|
||||
|
||||
// in_relation = expr ('not')? 'in' range_list
|
||||
result = sequence(
|
||||
[expression, nOrMore(0, not), whitespace, choice([_in_, _equal_]), whitespace, rangeList]
|
||||
);
|
||||
|
||||
if (result !== null) {
|
||||
debug(' -- passed _in:' + result);
|
||||
|
||||
range_list = result[5];
|
||||
|
||||
for (i = 0; i < range_list.length; i++) {
|
||||
if (parseInt(range_list[i], 10) === parseFloat(result[0])) {
|
||||
return (result[1][0] !== 'not');
|
||||
}
|
||||
}
|
||||
|
||||
return (result[1][0] === 'not');
|
||||
}
|
||||
|
||||
debug(' -- failed _in ');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The difference between "in" and "within" is that
|
||||
* "in" only includes integers in the specified range,
|
||||
* while "within" includes all values.
|
||||
*/
|
||||
function within() {
|
||||
var range_list, result;
|
||||
|
||||
// within_relation = expr ('not')? 'within' range_list
|
||||
result = sequence(
|
||||
[expression, nOrMore(0, not), whitespace, _within_, whitespace, rangeList]
|
||||
);
|
||||
|
||||
if (result !== null) {
|
||||
debug(' -- passed within');
|
||||
|
||||
range_list = result[5];
|
||||
|
||||
if ((result[0] >= parseInt(range_list[0], 10)) &&
|
||||
(result[0] < parseInt(range_list[range_list.length - 1], 10))) {
|
||||
|
||||
return (result[1][0] !== 'not');
|
||||
}
|
||||
|
||||
return (result[1][0] === 'not');
|
||||
}
|
||||
|
||||
debug(' -- failed within ');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// relation = is_relation | in_relation | within_relation
|
||||
relation = choice([is, not_in, isnot, _in, within]);
|
||||
|
||||
// and_condition = relation ('and' relation)*
|
||||
function and() {
|
||||
var i,
|
||||
result = sequence([relation, nOrMore(0, andTail)]);
|
||||
|
||||
if (result) {
|
||||
if (!result[0]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < result[1].length; i++) {
|
||||
if (!result[1][i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
debug(' -- failed and');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// ('and' relation)*
|
||||
function andTail() {
|
||||
var result = sequence([whitespace, _and_, whitespace, relation]);
|
||||
|
||||
if (result !== null) {
|
||||
debug(' -- passed andTail' + result);
|
||||
|
||||
return result[3];
|
||||
}
|
||||
|
||||
debug(' -- failed andTail');
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
// ('or' and_condition)*
|
||||
function orTail() {
|
||||
var result = sequence([whitespace, _or_, whitespace, and]);
|
||||
|
||||
if (result !== null) {
|
||||
debug(' -- passed orTail: ' + result[3]);
|
||||
|
||||
return result[3];
|
||||
}
|
||||
|
||||
debug(' -- failed orTail');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// condition = and_condition ('or' and_condition)*
|
||||
function condition() {
|
||||
var i,
|
||||
result = sequence([and, nOrMore(0, orTail)]);
|
||||
|
||||
if (result) {
|
||||
for (i = 0; i < result[1].length; i++) {
|
||||
if (result[1][i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return result[0];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
result = condition();
|
||||
|
||||
/**
|
||||
* For success, the pos must have gotten to the end of the rule
|
||||
* and returned a non-null.
|
||||
* n.b. This is part of language infrastructure,
|
||||
* so we do not throw an internationalizable message.
|
||||
*/
|
||||
if (result === null) {
|
||||
throw new Error('Parse error at position ' + pos.toString() + ' for rule: ' + rule);
|
||||
}
|
||||
|
||||
if (pos !== rule.length) {
|
||||
debug('Warning: Rule not parsed completely. Parser stopped at ' + rule.substr(0, pos) + ' for rule: ' + rule);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return pluralRuleParser;
|
||||
|
||||
}));
|
Reference in New Issue
Block a user