From 25b627a349369626c70558e89d6f020d3fdb4b98 Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Sat, 8 Jan 2022 03:44:50 +0100 Subject: [PATCH] Remove i18n.js and prevent further exporting of it --- config/i18n-js.yml | 2 + public/javascripts/i18n.js | 1092 ------------------------------------ 2 files changed, 2 insertions(+), 1092 deletions(-) delete mode 100644 public/javascripts/i18n.js diff --git a/config/i18n-js.yml b/config/i18n-js.yml index 60a7d077..c71da13a 100644 --- a/config/i18n-js.yml +++ b/config/i18n-js.yml @@ -23,6 +23,8 @@ # fallbacks: :default_locale +export_i18n_js: false + translations: - file: 'app/javascript/legacy/i18n.js' only: ['*.frontend.*', '*.views.actions.*'] diff --git a/public/javascripts/i18n.js b/public/javascripts/i18n.js deleted file mode 100644 index 0adb3e9f..00000000 --- a/public/javascripts/i18n.js +++ /dev/null @@ -1,1092 +0,0 @@ -// I18n.js -// ======= -// -// This small library provides the Rails I18n API on the Javascript. -// You don't actually have to use Rails (or even Ruby) to use I18n.js. -// Just make sure you export all translations in an object like this: -// -// I18n.translations.en = { -// hello: "Hello World" -// }; -// -// See tests for specific formatting like numbers and dates. -// - -// Using UMD pattern from -// https://github.com/umdjs/umd#regular-module -// `returnExports.js` version -;(function (root, factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define("i18n", function(){ return factory(root);}); - } else if (typeof module === 'object' && module.exports) { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(root); - } else { - // Browser globals (root is window) - root.I18n = factory(root); - } -}(this, function(global) { - "use strict"; - - // Use previously defined object if exists in current scope - var I18n = global && global.I18n || {}; - - // Just cache the Array#slice function. - var slice = Array.prototype.slice; - - // 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' - }; - - var isFunction = function(func) { - var type = typeof func; - return type === 'function' - }; - - // Check if value is different than undefined and null; - var isSet = function(value) { - return typeof(value) !== 'undefined' && value !== null; - }; - - // Is a given value an array? - // Borrowed from Underscore.js - var isArray = function(val) { - if (Array.isArray) { - return Array.isArray(val); - } - return Object.prototype.toString.call(val) === '[object Array]'; - }; - - var isString = function(val) { - return typeof val === 'string' || Object.prototype.toString.call(val) === '[object String]'; - }; - - var isNumber = function(val) { - return typeof val === 'number' || Object.prototype.toString.call(val) === '[object Number]'; - }; - - var isBoolean = function(val) { - return val === true || val === false; - }; - - var isNull = function(val) { - return val === null; - }; - - 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)); - }; - - var lazyEvaluate = function(message, scope) { - if (isFunction(message)) { - return message(scope); - } else { - return message; - } - }; - - var merge = function (dest, obj) { - var key, value; - for (key in obj) if (obj.hasOwnProperty(key)) { - value = obj[key]; - if (isString(value) || isNumber(value) || isBoolean(value) || isArray(value) || isNull(value)) { - dest[key] = value; - } else { - if (dest[key] == null) dest[key] = {}; - merge(dest[key], value); - } - } - return dest; - }; - - // 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"] - , abbr_month_names: [null, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] - , meridian: ["AM", "PM"] - }; - - // Set default number format. - var NUMBER_FORMAT = { - precision: 3 - , separator: "." - , delimiter: "," - , strip_insignificant_zeros: false - }; - - // Set default currency format. - var CURRENCY_FORMAT = { - unit: "$" - , precision: 2 - , format: "%u%n" - , sign_first: true - , delimiter: "," - , separator: "." - }; - - // Set default percentage format. - var PERCENTAGE_FORMAT = { - unit: "%" - , precision: 3 - , format: "%n%u" - , separator: "." - , delimiter: "" - }; - - // Set default size units. - var SIZE_UNITS = [null, "kb", "mb", "gb", "tb"]; - - // Other default options - var DEFAULT_OPTIONS = { - // Set default locale. This locale will be used when fallback is enabled and - // the translation doesn't exist in a particular locale. - defaultLocale: "en" - // Set the current locale to `en`. - , locale: "en" - // Set the translation key separator. - , defaultSeparator: "." - // 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. - , translations: {} - // Set missing translation behavior. 'message' will display a message - // that the translation is missing, 'guess' will try to guess the string - , missingBehaviour: 'message' - // if you use missingBehaviour with 'message', but want to know that the - // string is actually missing for testing purposes, you can prefix the - // guessed string by setting the value here. By default, no prefix! - , missingTranslationPrefix: '' - }; - - // Set default locale. This locale will be used when fallback is enabled and - // the translation doesn't exist in a particular locale. - I18n.reset = function() { - var key; - for (key in DEFAULT_OPTIONS) { - this[key] = DEFAULT_OPTIONS[key]; - } - }; - - // Much like `reset`, but only assign options if not already assigned - I18n.initializeOptions = function() { - var key; - for (key in DEFAULT_OPTIONS) if (!isSet(this[key])) { - this[key] = DEFAULT_OPTIONS[key]; - } - }; - I18n.initializeOptions(); - - // Return a list of all locales that must be tried before returning the - // missing translation message. By default, this will consider the inline option, - // current locale and fallback locale. - // - // I18n.locales.get("de-DE"); - // // ["de-DE", "de", "en"] - // - // You can define custom rules for any locale. Just make sure you return a array - // containing all locales. - // - // // Default the Wookie locale to English. - // I18n.locales["wk"] = function(locale) { - // return ["en"]; - // }; - // - I18n.locales = {}; - - // Retrieve locales based on inline locale, current locale or default to - // I18n's detection. - I18n.locales.get = function(locale) { - var result = this[locale] || this[I18n.locale] || this["default"]; - - if (isFunction(result)) { - result = result(locale); - } - - if (isArray(result) === false) { - result = [result]; - } - - return result; - }; - - // The default locale list. - I18n.locales["default"] = function(locale) { - var locales = [] - , list = [] - ; - - // Handle the inline locale option that can be provided to - // the `I18n.t` options. - if (locale) { - locales.push(locale); - } - - // Add the current locale to the list. - if (!locale && I18n.locale) { - locales.push(I18n.locale); - } - - // Add the default locale if fallback strategy is enabled. - if (I18n.fallbacks && I18n.defaultLocale) { - locales.push(I18n.defaultLocale); - } - - // Locale code format 1: - // According to RFC4646 (http://www.ietf.org/rfc/rfc4646.txt) - // language codes for Traditional Chinese should be `zh-Hant` - // - // But due to backward compatibility - // We use older version of IETF language tag - // @see http://www.w3.org/TR/html401/struct/dirlang.html - // @see http://en.wikipedia.org/wiki/IETF_language_tag - // - // Format: `language-code = primary-code ( "-" subcode )*` - // - // primary-code uses ISO639-1 - // @see http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes - // @see http://www.iso.org/iso/home/standards/language_codes.htm - // - // subcode uses ISO 3166-1 alpha-2 - // @see http://en.wikipedia.org/wiki/ISO_3166 - // @see http://www.iso.org/iso/country_codes.htm - // - // @note - // subcode can be in upper case or lower case - // defining it in upper case is a convention only - - - // Locale code format 2: - // Format: `code = primary-code ( "-" region-code )*` - // primary-code uses ISO 639-1 - // script-code uses ISO 15924 - // region-code uses ISO 3166-1 alpha-2 - // Example: zh-Hant-TW, en-HK, zh-Hant-CN - // - // It is similar to RFC4646 (or actually the same), - // but seems to be limited to language, script, region - - // Compute each locale with its country code. - // So this will return an array containing - // `de-DE` and `de` - // or - // `zh-hans-tw`, `zh-hans`, `zh` - // locales. - locales.forEach(function(locale) { - var localeParts = locale.split("-"); - var firstFallback = null; - var secondFallback = null; - if (localeParts.length === 3) { - firstFallback = [ - localeParts[0], - localeParts[1] - ].join("-"); - secondFallback = localeParts[0]; - } - else if (localeParts.length === 2) { - firstFallback = localeParts[0]; - } - - if (list.indexOf(locale) === -1) { - list.push(locale); - } - - if (! I18n.fallbacks) { - return; - } - - [ - firstFallback, - secondFallback - ].forEach(function(nullableFallbackLocale) { - // We don't want null values - if (typeof nullableFallbackLocale === "undefined") { return; } - if (nullableFallbackLocale === null) { return; } - // We don't want duplicate values - // - // Comparing with `locale` first is faster than - // checking whether value's presence in the list - if (nullableFallbackLocale === locale) { return; } - if (list.indexOf(nullableFallbackLocale) !== -1) { return; } - - list.push(nullableFallbackLocale); - }); - }); - - // No locales set? English it is. - if (!locales.length) { - locales.push("en"); - } - - return list; - }; - - // Hold pluralization rules. - I18n.pluralization = {}; - - // Return the pluralizer for a specific locale. - // If no specify locale is found, then I18n's default will be used. - I18n.pluralization.get = function(locale) { - return this[locale] || this[I18n.locale] || this["default"]; - }; - - // The default pluralizer rule. - // It detects the `zero`, `one`, and `other` scopes. - I18n.pluralization["default"] = function(count) { - switch (count) { - case 0: return ["zero", "other"]; - case 1: return ["one"]; - default: return ["other"]; - } - }; - - // Return current locale. If no locale has been set, then - // the current locale will be the default locale. - I18n.currentLocale = function() { - return this.locale || this.defaultLocale; - }; - - // Check if value is different than undefined and null; - I18n.isSet = isSet; - - // Find and process the translation using the provided scope and options. - // This is used internally by some functions and should not be used as an - // public API. - I18n.lookup = function(scope, options) { - options = options || {}; - - var locales = this.locales.get(options.locale).slice() - , locale - , scopes - , fullScope - , translations - ; - - fullScope = this.getFullScope(scope, options); - - while (locales.length) { - locale = locales.shift(); - scopes = fullScope.split(this.defaultSeparator); - translations = this.translations[locale]; - - if (!translations) { - continue; - } - while (scopes.length) { - translations = translations[scopes.shift()]; - - if (translations === undefined || translations === null) { - break; - } - } - - if (translations !== undefined && translations !== null) { - return translations; - } - } - - if (isSet(options.defaultValue)) { - return lazyEvaluate(options.defaultValue, scope); - } - }; - - // lookup pluralization rule key into translations - I18n.pluralizationLookupWithoutFallback = function(count, locale, translations) { - var pluralizer = this.pluralization.get(locale) - , pluralizerKeys = pluralizer(count) - , pluralizerKey - , message; - - if (isObject(translations)) { - while (pluralizerKeys.length) { - pluralizerKey = pluralizerKeys.shift(); - if (isSet(translations[pluralizerKey])) { - message = translations[pluralizerKey]; - break; - } - } - } - - return message; - }; - - // Lookup dedicated to pluralization - I18n.pluralizationLookup = function(count, scope, options) { - options = options || {}; - var locales = this.locales.get(options.locale).slice() - , locale - , scopes - , translations - , message - ; - scope = this.getFullScope(scope, options); - - while (locales.length) { - locale = locales.shift(); - scopes = scope.split(this.defaultSeparator); - translations = this.translations[locale]; - - if (!translations) { - continue; - } - - while (scopes.length) { - translations = translations[scopes.shift()]; - if (!isObject(translations)) { - break; - } - if (scopes.length === 0) { - message = this.pluralizationLookupWithoutFallback(count, locale, translations); - } - } - if (typeof message !== "undefined" && message !== null) { - break; - } - } - - if (typeof message === "undefined" || message === null) { - if (isSet(options.defaultValue)) { - if (isObject(options.defaultValue)) { - message = this.pluralizationLookupWithoutFallback(count, options.locale, options.defaultValue); - } else { - message = options.defaultValue; - } - translations = options.defaultValue; - } - } - - return { message: message, translations: translations }; - }; - - // Rails changed the way the meridian is stored. - // It started with `date.meridian` returning an array, - // then it switched to `time.am` and `time.pm`. - // This function abstracts this difference and returns - // the correct meridian or the default value when none is provided. - I18n.meridian = function() { - var time = this.lookup("time"); - var date = this.lookup("date"); - - if (time && time.am && time.pm) { - return [time.am, time.pm]; - } else if (date && date.meridian) { - return date.meridian; - } else { - return DATE.meridian; - } - }; - - // 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 args = slice.call(arguments) - , options = {} - , subject - ; - - while (args.length) { - subject = args.shift(); - - if (typeof(subject) != "object") { - continue; - } - - for (var attr in subject) { - if (!subject.hasOwnProperty(attr)) { - continue; - } - - if (isSet(options[attr])) { - continue; - } - - options[attr] = subject[attr]; - } - } - - return options; - }; - - // Generate a list of translation options for default fallbacks. - // `defaultValue` is also deleted from options as it is returned as part of - // the translationOptions array. - I18n.createTranslationOptions = function(scope, options) { - var translationOptions = [{scope: scope}]; - - // Defaults should be an array of hashes containing either - // fallback scopes or messages - if (isSet(options.defaults)) { - translationOptions = translationOptions.concat(options.defaults); - } - - // Maintain support for defaultValue. Since it is always a message - // insert it in to the translation options as such. - if (isSet(options.defaultValue)) { - translationOptions.push({ message: options.defaultValue }); - } - - return translationOptions; - }; - - // Translate the given scope with the provided options. - I18n.translate = function(scope, options) { - options = options || {}; - - var translationOptions = this.createTranslationOptions(scope, options); - - var translation; - var usedScope = scope; - - var optionsWithoutDefault = this.prepareOptions(options) - delete optionsWithoutDefault.defaultValue - - // Iterate through the translation options until a translation - // or message is found. - var translationFound = - translationOptions.some(function(translationOption) { - if (isSet(translationOption.scope)) { - usedScope = translationOption.scope; - translation = this.lookup(usedScope, optionsWithoutDefault); - } else if (isSet(translationOption.message)) { - translation = lazyEvaluate(translationOption.message, scope); - } - - if (translation !== undefined && translation !== null) { - return true; - } - }, this); - - if (!translationFound) { - return this.missingTranslation(scope, options); - } - - if (typeof(translation) === "string") { - translation = this.interpolate(translation, options); - } else if (isArray(translation)) { - translation = translation.map(function(t) { - return (typeof(t) === "string" ? this.interpolate(t, options) : t); - }, this); - } else if (isObject(translation) && isSet(options.count)) { - translation = this.pluralize(options.count, usedScope, options); - } - - return translation; - }; - - // This function interpolates the all variables in the given message. - I18n.interpolate = function(message, options) { - if (message == null) { - return message; - } - - options = options || {}; - var matches = message.match(this.placeholder) - , placeholder - , value - , name - , regex - ; - - if (!matches) { - return message; - } - - while (matches.length) { - placeholder = matches.shift(); - name = placeholder.replace(this.placeholder, "$1"); - - if (isSet(options[name])) { - value = options[name].toString().replace(/\$/gm, "_#$#_"); - } else if (name in options) { - value = this.nullPlaceholder(placeholder, message, options); - } else { - value = this.missingPlaceholder(placeholder, message, options); - } - - regex = new RegExp(placeholder.replace(/{/gm, "\\{").replace(/}/gm, "\\}")); - message = message.replace(regex, value); - } - - return message.replace(/_#\$#_/g, "$"); - }; - - // Pluralize the given scope using the `count` value. - // The pluralized translation may have other placeholders, - // which will be retrieved from `options`. - I18n.pluralize = function(count, scope, options) { - options = this.prepareOptions({count: String(count)}, options) - var pluralizer, result; - - result = this.pluralizationLookup(count, scope, options); - if (typeof result.translations === "undefined" || result.translations == null) { - return this.missingTranslation(scope, options); - } - - if (typeof result.message !== "undefined" && result.message != null) { - return this.interpolate(result.message, options); - } - else { - pluralizer = this.pluralization.get(options.locale); - return this.missingTranslation(scope + '.' + pluralizer(count)[0], options); - } - }; - - // Return a missing translation message for the given parameters. - I18n.missingTranslation = function(scope, options) { - //guess intended string - if(this.missingBehaviour === 'guess'){ - //get only the last portion of the scope - var s = scope.split('.').slice(-1)[0]; - //replace underscore with space && camelcase with space and lowercase letter - return (this.missingTranslationPrefix.length > 0 ? this.missingTranslationPrefix : '') + - s.replace('_',' ').replace(/([a-z])([A-Z])/g, - function(match, p1, p2) {return p1 + ' ' + p2.toLowerCase()} ); - } - - var localeForTranslation = (options != null && options.locale != null) ? options.locale : this.currentLocale(); - var fullScope = this.getFullScope(scope, options); - var fullScopeWithLocale = [localeForTranslation, fullScope].join(this.defaultSeparator); - - return '[missing "' + fullScopeWithLocale + '" translation]'; - }; - - // Return a missing placeholder message for given parameters - I18n.missingPlaceholder = function(placeholder, message, options) { - return "[missing " + placeholder + " value]"; - }; - - I18n.nullPlaceholder = function() { - return I18n.missingPlaceholder.apply(I18n, arguments); - }; - - // Format number using localization rules. - // The options will be retrieved from the `number.format` scope. - // If this isn't present, then the following options will be used: - // - // - `precision`: `3` - // - `separator`: `"."` - // - `delimiter`: `","` - // - `strip_insignificant_zeros`: `false` - // - // You can also override these options by providing the `options` argument. - // - I18n.toNumber = function(number, options) { - options = this.prepareOptions( - options - , this.lookup("number.format") - , NUMBER_FORMAT - ); - - var negative = number < 0 - , string = toFixed(Math.abs(number), options.precision).toString() - , parts = string.split(".") - , precision - , buffer = [] - , formattedNumber - , format = options.format || "%n" - , sign = negative ? "-" : "" - ; - - 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.strip_insignificant_zeros && precision) { - precision = precision.replace(/0+$/, ""); - } - - if (options.precision > 0 && precision) { - formattedNumber += options.separator + precision; - } - - if (options.sign_first) { - format = "%s" + format; - } - else { - format = format.replace("%n", "%s%n"); - } - - formattedNumber = format - .replace("%u", options.unit) - .replace("%n", formattedNumber) - .replace("%s", sign) - ; - - return formattedNumber; - }; - - // Format currency with localization rules. - // The options will be retrieved from the `number.currency.format` and - // `number.format` scopes, in that order. - // - // Any missing option will be retrieved from the `I18n.toNumber` defaults and - // the following options: - // - // - `unit`: `"$"` - // - `precision`: `2` - // - `format`: `"%u%n"` - // - `delimiter`: `","` - // - `separator`: `"."` - // - // You can also override these options by providing the `options` argument. - // - I18n.toCurrency = function(number, options) { - options = this.prepareOptions( - options - , this.lookup("number.currency.format") - , this.lookup("number.format") - , CURRENCY_FORMAT - ); - - return this.toNumber(number, options); - }; - - // Localize several values. - // You can provide the following scopes: `currency`, `number`, or `percentage`. - // If you provide a scope that matches the `/^(date|time)/` regular expression - // then the `value` will be converted by using the `I18n.toTime` function. - // - // It will default to the value's `toString` function. - // - I18n.localize = function(scope, value, options) { - options || (options = {}); - - 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: - var localizedValue; - - if (scope.match(/^(date|time)/)) { - localizedValue = this.toTime(scope, value); - } else { - localizedValue = value.toString(); - } - - return this.interpolate(localizedValue, options); - } - }; - - // Parse a given `date` string into a JavaScript Date object. - // This function is time zone aware. - // - // The following string formats are recognized: - // - // 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 - // yyyy-mm-dd[ T]hh:mm::ss+00:00 - // yyyy-mm-dd[ T]hh:mm::ss.123Z - // - I18n.parseDate = function(date) { - var matches, convertedDate, fraction; - // A date input of `null` or `undefined` will be returned as-is - if (date == null) { - return date; - } - // we have a date, so just return it. - if (typeof(date) === "object") { - return date; - } - - matches = date.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2})([\.,]\d{1,3})?)?(Z|\+00:?00)?/); - - if (matches) { - for (var i = 1; i <= 6; i++) { - matches[i] = parseInt(matches[i], 10) || 0; - } - - // month starts on 0 - matches[2] -= 1; - - fraction = matches[7] ? 1000 * ("0" + matches[7]) : null; - - if (matches[8]) { - convertedDate = new Date(Date.UTC(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], fraction)); - } else { - convertedDate = new Date(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], fraction); - } - } else if (typeof(date) == "number") { - // UNIX timestamp - convertedDate = new Date(); - convertedDate.setTime(date); - } else if (date.match(/([A-Z][a-z]{2}) ([A-Z][a-z]{2}) (\d+) (\d+:\d+:\d+) ([+-]\d+) (\d+)/)) { - // This format `Wed Jul 20 13:03:39 +0000 2011` is parsed by - // webkit/firefox, but not by IE, so we must parse it manually. - convertedDate = new Date(); - convertedDate.setTime(Date.parse([ - RegExp.$1, RegExp.$2, RegExp.$3, RegExp.$6, RegExp.$4, RegExp.$5 - ].join(" "))); - } 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; - }; - - // Formats time according to the directives in the given format string. - // The directives begins with a percent (%) character. Any text not listed as a - // directive will be passed through to the output string. - // - // The accepted formats are: - // - // %a - The abbreviated weekday name (Sun) - // %A - The full weekday name (Sunday) - // %b - The abbreviated month name (Jan) - // %B - The full month name (January) - // %c - The preferred local date and time representation - // %d - Day of the month (01..31) - // %-d - Day of the month (1..31) - // %H - Hour of the day, 24-hour clock (00..23) - // %-H/%k - Hour of the day, 24-hour clock (0..23) - // %I - Hour of the day, 12-hour clock (01..12) - // %-I/%l - Hour of the day, 12-hour clock (1..12) - // %m - Month of the year (01..12) - // %-m - Month of the year (1..12) - // %M - Minute of the hour (00..59) - // %-M - Minute of the hour (0..59) - // %p - Meridian indicator (AM or PM) - // %P - Meridian indicator (am or pm) - // %S - Second of the minute (00..60) - // %-S - Second of the minute (0..60) - // %w - Day of the week (Sunday is 0, 0..6) - // %y - Year without a century (00..99) - // %-y - Year without a century (0..99) - // %Y - Year with century - // %z/%Z - Timezone offset (+0545) - // - I18n.strftime = function(date, format) { - var options = this.lookup("date") - , meridianOptions = I18n.meridian() - ; - - if (!options) { - options = {}; - } - - options = this.prepareOptions(options, DATE); - - if (isNaN(date.getTime())) { - throw new Error('I18n.strftime() requires a valid date object, but received an invalid date.'); - } - - 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; - } - - format = format.replace("%a", options.abbr_day_names[weekDay]); - format = format.replace("%A", options.day_names[weekDay]); - format = format.replace("%b", options.abbr_month_names[month]); - format = format.replace("%B", options.month_names[month]); - format = format.replace("%d", padding(day)); - format = format.replace("%e", day); - format = format.replace("%-d", day); - format = format.replace("%H", padding(hour)); - format = format.replace("%-H", hour); - format = format.replace("%k", hour); - format = format.replace("%I", padding(hour12)); - format = format.replace("%-I", hour12); - format = format.replace("%l", hour12); - format = format.replace("%m", padding(month)); - format = format.replace("%-m", month); - format = format.replace("%M", padding(mins)); - format = format.replace("%-M", mins); - format = format.replace("%p", meridianOptions[meridian]); - format = format.replace("%P", meridianOptions[meridian].toLowerCase()); - format = format.replace("%S", padding(secs)); - format = format.replace("%-S", secs); - format = format.replace("%w", weekDay); - format = format.replace("%y", padding(year)); - format = format.replace("%-y", padding(year).replace(/^0+/, "")); - format = format.replace("%Y", year); - format = format.replace("%z", timezoneoffset); - format = format.replace("%Z", timezoneoffset); - - return format; - }; - - // Convert the given dateString into a formatted date. - I18n.toTime = function(scope, dateString) { - var date = this.parseDate(dateString) - , format = this.lookup(scope) - ; - - // A date input of `null` or `undefined` will be returned as-is - if (date == null) { - return date; - } - - var date_string = date.toString() - if (date_string.match(/invalid/i)) { - return date_string; - } - - if (!format) { - return date_string; - } - - return this.strftime(date, format); - }; - - // Convert a number into a formatted percentage value. - I18n.toPercentage = function(number, options) { - options = this.prepareOptions( - options - , this.lookup("number.percentage.format") - , this.lookup("number.format") - , PERCENTAGE_FORMAT - ); - - return this.toNumber(number, options); - }; - - // Convert a number into a readable size representation. - 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." + SIZE_UNITS[iterations]); - precision = (size - Math.floor(size) === 0) ? 0 : 1; - } - - options = this.prepareOptions( - options - , {unit: unit, precision: precision, format: "%n%u", delimiter: ""} - ); - - return this.toNumber(size, options); - }; - - I18n.getFullScope = function(scope, options) { - options = options || {}; - - // Deal with the scope as an array. - if (isArray(scope)) { - scope = scope.join(this.defaultSeparator); - } - - // Deal with the scope option provided through the second argument. - // - // I18n.t('hello', {scope: 'greetings'}); - // - 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 ) { - if (typeof(obj1) === "undefined" && typeof(obj2) === "undefined") { - return {}; - } - return merge(obj1, obj2); - }; - - // Set aliases, so we can save some typing. - I18n.t = I18n.translate.bind(I18n); - I18n.l = I18n.localize.bind(I18n); - I18n.p = I18n.pluralize.bind(I18n); - - return I18n; -}));