app/assets/javascripts/i18n.js in i18n-js-3.0.0.rc11 vs app/assets/javascripts/i18n.js in i18n-js-3.0.0.rc12
- old
+ new
@@ -36,10 +36,51 @@
// Apply number padding.
var padding = function(number) {
return ("0" + number.toString()).substr(-2);
};
+ // Improved toFixed number rounding function with support for unprecise floating points
+ // JavaScript's standard toFixed function does not round certain numbers correctly (for example 0.105 with precision 2).
+ var toFixed = function(number, precision) {
+ return decimalAdjust('round', number, -precision).toFixed(precision);
+ };
+
+ // Is a given variable an object?
+ // Borrowed from Underscore.js
+ var isObject = function(obj) {
+ var type = typeof obj;
+ return type === 'function' || type === 'object' && !!obj;
+ };
+
+ // Is a given value an array?
+ // Borrowed from Underscore.js
+ var isArray = function(obj) {
+ if (Array.isArray) {
+ return Array.isArray(obj);
+ };
+ return Object.prototype.toString.call(obj) === '[object Array]';
+ };
+
+ var decimalAdjust = function(type, value, exp) {
+ // If the exp is undefined or zero...
+ if (typeof exp === 'undefined' || +exp === 0) {
+ return Math[type](value);
+ }
+ value = +value;
+ exp = +exp;
+ // If the value is not a number or the exp is not an integer...
+ if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
+ return NaN;
+ }
+ // Shift
+ value = value.toString().split('e');
+ value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
+ // Shift back
+ value = value.toString().split('e');
+ return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
+ }
+
// Set default days/months translations.
var DATE = {
day_names: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
, abbr_day_names: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
, month_names: [null, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
@@ -84,11 +125,11 @@
defaultLocale: "en"
// Set the current locale to `en`.
, locale: "en"
// Set the translation key separator.
, defaultSeparator: "."
- // Set the placeholder format. Accepts `{placeholder}}` and `%{placeholder}`.}
+ // Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
, placeholder: /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm
// Set if engine should fallback to the default locale when a translation
// is missing.
, fallbacks: false
// Set the default translation object.
@@ -177,11 +218,11 @@
if (typeof(result) === "function") {
result = result(locale);
}
- if (result instanceof Array === false) {
+ if (isArray(result) === false) {
result = [result];
}
return result;
};
@@ -406,11 +447,11 @@
return this.missingTranslation(scope, options);
}
if (typeof(translation) === "string") {
translation = this.interpolate(translation, options);
- } else if (translation instanceof Object && this.isSet(options.count)) {
+ } else if (isObject(translation) && this.isSet(options.count)) {
translation = this.pluralize(options.count, translation, options);
}
return translation;
};
@@ -436,13 +477,13 @@
name = placeholder.replace(this.placeholder, "$1");
if (this.isSet(options[name])) {
value = options[name].toString().replace(/\$/gm, "_#$#_");
} else if (name in options) {
- value = this.nullPlaceholder(placeholder, message);
+ value = this.nullPlaceholder(placeholder, message, options);
} else {
- value = this.missingPlaceholder(placeholder, message);
+ value = this.missingPlaceholder(placeholder, message, options);
}
regex = new RegExp(placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}"));
message = message.replace(regex, value);
}
@@ -455,11 +496,11 @@
// which will be retrieved from `options`.
I18n.pluralize = function(count, scope, options) {
options = this.prepareOptions(options);
var translations, pluralizer, keys, key, message;
- if (scope instanceof Object) {
+ if (isObject(scope)) {
translations = scope;
} else {
translations = this.lookup(scope, options);
}
@@ -500,11 +541,11 @@
return '[missing "' + fullScopeWithLocale + '" translation]';
};
// Return a missing placeholder message for given parameters
- I18n.missingPlaceholder = function(placeholder, message) {
+ I18n.missingPlaceholder = function(placeholder, message, options) {
return "[missing " + placeholder + " value]";
};
I18n.nullPlaceholder = function() {
return I18n.missingPlaceholder.apply(I18n, arguments);
@@ -527,11 +568,11 @@
, this.lookup("number.format")
, NUMBER_FORMAT
);
var negative = number < 0
- , string = Math.abs(number).toFixed(options.precision).toString()
+ , string = toFixed(Math.abs(number), options.precision).toString()
, parts = string.split(".")
, precision
, buffer = []
, formattedNumber
, format = options.format || "%n"
@@ -855,10 +896,35 @@
if (options.scope) {
scope = [options.scope, scope].join(this.defaultSeparator);
}
return scope;
- }
+ };
+ /**
+ * Merge obj1 with obj2 (shallow merge), without modifying inputs
+ * @param {Object} obj1
+ * @param {Object} obj2
+ * @returns {Object} Merged values of obj1 and obj2
+ *
+ * In order to support ES3, `Object.prototype.hasOwnProperty.call` is used
+ * Idea is from:
+ * https://stackoverflow.com/questions/8157700/object-has-no-hasownproperty-method-i-e-its-undefined-ie8
+ */
+ I18n.extend = function ( obj1, obj2 ) {
+ var extended = {};
+ var prop;
+ for (prop in obj1) {
+ if (Object.prototype.hasOwnProperty.call(obj1, prop)) {
+ extended[prop] = obj1[prop];
+ }
+ }
+ for (prop in obj2) {
+ if (Object.prototype.hasOwnProperty.call(obj2, prop)) {
+ extended[prop] = obj2[prop];
+ }
+ }
+ return extended;
+ };
// Set aliases, so we can save some typing.
I18n.t = I18n.translate;
I18n.l = I18n.localize;
I18n.p = I18n.pluralize;