/AktiveCortex/samples/aktivecortex-sample-bank/src/main/webapp/resources/lib/i18n.js
JavaScript | 531 lines | 407 code | 98 blank | 26 comment | 90 complexity | 526ce83a7b5bd6f83b1d359e783deba6 MD5 | raw file
Possible License(s): Apache-2.0
- // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
- if (!Array.prototype.indexOf) {
- Array.prototype.indexOf = function(searchElement /*, fromIndex */) {
- "use strict";
- if (this === void 0 || this === null) {
- throw new TypeError();
- }
- var t = Object(this);
- var len = t.length >>> 0;
- if (len === 0) {
- return -1;
- }
- var n = 0;
- if (arguments.length > 0) {
- n = Number(arguments[1]);
- if (n !== n) { // shortcut for verifying if it's NaN
- n = 0;
- } else if (n !== 0 && n !== (Infinity) && n !== -(Infinity)) {
- n = (n > 0 || -1) * Math.floor(Math.abs(n));
- }
- }
- if (n >= len) {
- return -1;
- }
- var k = n >= 0
- ? n
- : Math.max(len - Math.abs(n), 0);
- for (; k < len; k++) {
- if (k in t && t[k] === searchElement) {
- return k;
- }
- }
- return -1;
- };
- }
- // Instantiate the object
- var I18n = I18n || {};
- // Set default locale to english
- I18n.defaultLocale = "en";
- // Set default handling of translation fallbacks to false
- I18n.fallbacks = false;
- // Set default separator
- I18n.defaultSeparator = ".";
- // Set current locale to null
- I18n.locale = null;
- // Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
- I18n.PLACEHOLDER = /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm;
- I18n.fallbackRules = {
- };
- I18n.pluralizationRules = {
- en: function (n) {
- return n == 0 ? ["zero", "none", "other"] : n == 1 ? "one" : "other";
- }
- };
- I18n.getFallbacks = function(locale) {
- if (locale === I18n.defaultLocale) {
- return [];
- } else if (!I18n.fallbackRules[locale]) {
- var rules = []
- , components = locale.split("-");
- for (var l = 1; l < components.length; l++) {
- rules.push(components.slice(0, l).join("-"));
- }
- rules.push(I18n.defaultLocale);
- I18n.fallbackRules[locale] = rules;
- }
- return I18n.fallbackRules[locale];
- }
- I18n.isValidNode = function(obj, node, undefined) {
- return obj[node] !== null && obj[node] !== undefined;
- };
- I18n.lookup = function(scope, options) {
- var options = options || {}
- , lookupInitialScope = scope
- , translations = this.prepareOptions(I18n.translations)
- , locale = options.locale || I18n.currentLocale()
- , messages = translations[locale] || {}
- , options = this.prepareOptions(options)
- , currentScope
- ;
- if (typeof(scope) == "object") {
- scope = scope.join(this.defaultSeparator);
- }
- if (options.scope) {
- scope = options.scope.toString() + this.defaultSeparator + scope;
- }
- scope = scope.split(this.defaultSeparator);
- while (messages && scope.length > 0) {
- currentScope = scope.shift();
- messages = messages[currentScope];
- }
- if (!messages) {
- if (I18n.fallbacks) {
- var fallbacks = this.getFallbacks(locale);
- for (var fallback = 0; fallback < fallbacks.length; fallbacks++) {
- messages = I18n.lookup(lookupInitialScope, this.prepareOptions({locale: fallbacks[fallback]}, options));
- if (messages) {
- break;
- }
- }
- }
- if (!messages && this.isValidNode(options, "defaultValue")) {
- messages = options.defaultValue;
- }
- }
- return messages;
- };
- // Merge serveral hash options, checking if value is set before
- // overwriting any value. The precedence is from left to right.
- //
- // I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"});
- // #=> {name: "John Doe", role: "user"}
- //
- I18n.prepareOptions = function() {
- var options = {}
- , opts
- , count = arguments.length
- ;
- for (var i = 0; i < count; i++) {
- opts = arguments[i];
- if (!opts) {
- continue;
- }
- for (var key in opts) {
- if (!this.isValidNode(options, key)) {
- options[key] = opts[key];
- }
- }
- }
- return options;
- };
- I18n.interpolate = function(message, options) {
- options = this.prepareOptions(options);
- var matches = message.match(this.PLACEHOLDER)
- , placeholder
- , value
- , name
- ;
- if (!matches) {
- return message;
- }
- for (var i = 0; placeholder = matches[i]; i++) {
- name = placeholder.replace(this.PLACEHOLDER, "$1");
- value = options[name];
- if (!this.isValidNode(options, name)) {
- value = "[missing " + placeholder + " value]";
- }
- regex = new RegExp(placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}"));
- message = message.replace(regex, value);
- }
- return message;
- };
- I18n.translate = function(scope, options) {
- options = this.prepareOptions(options);
- var translation = this.lookup(scope, options);
- try {
- if (typeof(translation) == "object") {
- if (typeof(options.count) == "number") {
- return this.pluralize(options.count, scope, options);
- } else {
- return translation;
- }
- } else {
- return this.interpolate(translation, options);
- }
- } catch(err) {
- return this.missingTranslation(scope);
- }
- };
- I18n.localize = function(scope, value) {
- switch (scope) {
- case "currency":
- return this.toCurrency(value);
- case "number":
- scope = this.lookup("number.format");
- return this.toNumber(value, scope);
- case "percentage":
- return this.toPercentage(value);
- default:
- if (scope.match(/^(date|time)/)) {
- return this.toTime(scope, value);
- } else {
- return value.toString();
- }
- }
- };
- I18n.parseDate = function(date) {
- var matches, convertedDate;
- // we have a date, so just return it.
- if (typeof(date) == "object") {
- return date;
- };
- // it matches the following formats:
- // yyyy-mm-dd
- // yyyy-mm-dd[ T]hh:mm::ss
- // yyyy-mm-dd[ T]hh:mm::ss
- // yyyy-mm-dd[ T]hh:mm::ssZ
- // yyyy-mm-dd[ T]hh:mm::ss+0000
- //
- matches = date.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2}))?(Z|\+0000)?/);
- if (matches) {
- for (var i = 1; i <= 6; i++) {
- matches[i] = parseInt(matches[i], 10) || 0;
- }
- // month starts on 0
- matches[2] -= 1;
- if (matches[7]) {
- convertedDate = new Date(Date.UTC(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6]));
- } else {
- convertedDate = new Date(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6]);
- }
- } else if (typeof(date) == "number") {
- // UNIX timestamp
- convertedDate = new Date();
- convertedDate.setTime(date);
- } else if (date.match(/\d+ \d+:\d+:\d+ [+-]\d+ \d+/)) {
- // a valid javascript format with timezone info
- convertedDate = new Date();
- convertedDate.setTime(Date.parse(date))
- } else {
- // an arbitrary javascript string
- convertedDate = new Date();
- convertedDate.setTime(Date.parse(date));
- }
- return convertedDate;
- };
- I18n.toTime = function(scope, d) {
- var date = this.parseDate(d)
- , format = this.lookup(scope)
- ;
- if (date.toString().match(/invalid/i)) {
- return date.toString();
- }
- if (!format) {
- return date.toString();
- }
- return this.strftime(date, format);
- };
- I18n.strftime = function(date, format) {
- var options = this.lookup("date");
- if (!options) {
- return date.toString();
- }
- options.meridian = options.meridian || ["AM", "PM"];
- var weekDay = date.getDay()
- , day = date.getDate()
- , year = date.getFullYear()
- , month = date.getMonth() + 1
- , hour = date.getHours()
- , hour12 = hour
- , meridian = hour > 11 ? 1 : 0
- , secs = date.getSeconds()
- , mins = date.getMinutes()
- , offset = date.getTimezoneOffset()
- , absOffsetHours = Math.floor(Math.abs(offset / 60))
- , absOffsetMinutes = Math.abs(offset) - (absOffsetHours * 60)
- , timezoneoffset = (offset > 0 ? "-" : "+") + (absOffsetHours.toString().length < 2 ? "0" + absOffsetHours : absOffsetHours) + (absOffsetMinutes.toString().length < 2 ? "0" + absOffsetMinutes : absOffsetMinutes)
- ;
- if (hour12 > 12) {
- hour12 = hour12 - 12;
- } else if (hour12 === 0) {
- hour12 = 12;
- }
- var padding = function(n) {
- var s = "0" + n.toString();
- return s.substr(s.length - 2);
- };
- var f = format;
- f = f.replace("%a", options.abbr_day_names[weekDay]);
- f = f.replace("%A", options.day_names[weekDay]);
- f = f.replace("%b", options.abbr_month_names[month]);
- f = f.replace("%B", options.month_names[month]);
- f = f.replace("%d", padding(day));
- f = f.replace("%e", day);
- f = f.replace("%-d", day);
- f = f.replace("%H", padding(hour));
- f = f.replace("%-H", hour);
- f = f.replace("%I", padding(hour12));
- f = f.replace("%-I", hour12);
- f = f.replace("%m", padding(month));
- f = f.replace("%-m", month);
- f = f.replace("%M", padding(mins));
- f = f.replace("%-M", mins);
- f = f.replace("%p", options.meridian[meridian]);
- f = f.replace("%S", padding(secs));
- f = f.replace("%-S", secs);
- f = f.replace("%w", weekDay);
- f = f.replace("%y", padding(year));
- f = f.replace("%-y", padding(year).replace(/^0+/, ""));
- f = f.replace("%Y", year);
- f = f.replace("%z", timezoneoffset);
- return f;
- };
- I18n.toNumber = function(number, options) {
- options = this.prepareOptions(
- options,
- this.lookup("number.format"),
- {precision: 3, separator: ".", delimiter: ",", strip_insignificant_zeros: false}
- );
- var negative = number < 0
- , string = Math.abs(number).toFixed(options.precision).toString()
- , parts = string.split(".")
- , precision
- , buffer = []
- , formattedNumber
- ;
- number = parts[0];
- precision = parts[1];
- while (number.length > 0) {
- buffer.unshift(number.substr(Math.max(0, number.length - 3), 3));
- number = number.substr(0, number.length -3);
- }
- formattedNumber = buffer.join(options.delimiter);
- if (options.precision > 0) {
- formattedNumber += options.separator + parts[1];
- }
- if (negative) {
- formattedNumber = "-" + formattedNumber;
- }
- if (options.strip_insignificant_zeros) {
- var regex = {
- separator: new RegExp(options.separator.replace(/\./, "\\.") + "$")
- , zeros: /0+$/
- };
- formattedNumber = formattedNumber
- .replace(regex.zeros, "")
- .replace(regex.separator, "")
- ;
- }
- return formattedNumber;
- };
- I18n.toCurrency = function(number, options) {
- options = this.prepareOptions(
- options,
- this.lookup("number.currency.format"),
- this.lookup("number.format"),
- {unit: "$", precision: 2, format: "%u%n", delimiter: ",", separator: "."}
- );
- number = this.toNumber(number, options);
- number = options.format
- .replace("%u", options.unit)
- .replace("%n", number)
- ;
- return number;
- };
- I18n.toHumanSize = function(number, options) {
- var kb = 1024
- , size = number
- , iterations = 0
- , unit
- , precision
- ;
- while (size >= kb && iterations < 4) {
- size = size / kb;
- iterations += 1;
- }
- if (iterations === 0) {
- unit = this.t("number.human.storage_units.units.byte", {count: size});
- precision = 0;
- } else {
- unit = this.t("number.human.storage_units.units." + [null, "kb", "mb", "gb", "tb"][iterations]);
- precision = (size - Math.floor(size) === 0) ? 0 : 1;
- }
- options = this.prepareOptions(
- options,
- {precision: precision, format: "%n%u", delimiter: ""}
- );
- number = this.toNumber(size, options);
- number = options.format
- .replace("%u", unit)
- .replace("%n", number)
- ;
- return number;
- };
- I18n.toPercentage = function(number, options) {
- options = this.prepareOptions(
- options,
- this.lookup("number.percentage.format"),
- this.lookup("number.format"),
- {precision: 3, separator: ".", delimiter: ""}
- );
- number = this.toNumber(number, options);
- return number + "%";
- };
- I18n.pluralizer = function(locale) {
- pluralizer = this.pluralizationRules[locale];
- if (pluralizer !== undefined) return pluralizer;
- return this.pluralizationRules["en"];
- };
- I18n.findAndTranslateValidNode = function(keys, translation) {
- for (i = 0; i < keys.length; i++) {
- key = keys[i];
- if (this.isValidNode(translation, key)) return translation[key];
- }
- return null;
- };
- I18n.pluralize = function(count, scope, options) {
- var translation;
- try {
- translation = this.lookup(scope, options);
- } catch (error) {}
- if (!translation) {
- return this.missingTranslation(scope);
- }
- var message;
- options = this.prepareOptions(options);
- options.count = count.toString();
- pluralizer = this.pluralizer(this.currentLocale());
- key = pluralizer(Math.abs(count));
- keys = ((typeof key == "object") && (key instanceof Array)) ? key : [key];
- message = this.findAndTranslateValidNode(keys, translation);
- if (message == null) message = this.missingTranslation(scope, keys[0]);
- return this.interpolate(message, options);
- };
- I18n.missingTranslation = function() {
- var message = '[missing "' + this.currentLocale()
- , count = arguments.length
- ;
- for (var i = 0; i < count; i++) {
- message += "." + arguments[i];
- }
- message += '" translation]';
- return message;
- };
- I18n.currentLocale = function() {
- return (I18n.locale || I18n.defaultLocale);
- };
- // shortcuts
- I18n.t = I18n.translate;
- I18n.l = I18n.localize;
- I18n.p = I18n.pluralize;