PageRenderTime 62ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/AktiveCortex/samples/aktivecortex-sample-bank/src/main/webapp/resources/lib/i18n.js

https://bitbucket.org/aktivecortex/aktivecortex
JavaScript | 531 lines | 407 code | 98 blank | 26 comment | 90 complexity | 526ce83a7b5bd6f83b1d359e783deba6 MD5 | raw file
Possible License(s): Apache-2.0
  1. // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
  2. if (!Array.prototype.indexOf) {
  3. Array.prototype.indexOf = function(searchElement /*, fromIndex */) {
  4. "use strict";
  5. if (this === void 0 || this === null) {
  6. throw new TypeError();
  7. }
  8. var t = Object(this);
  9. var len = t.length >>> 0;
  10. if (len === 0) {
  11. return -1;
  12. }
  13. var n = 0;
  14. if (arguments.length > 0) {
  15. n = Number(arguments[1]);
  16. if (n !== n) { // shortcut for verifying if it's NaN
  17. n = 0;
  18. } else if (n !== 0 && n !== (Infinity) && n !== -(Infinity)) {
  19. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  20. }
  21. }
  22. if (n >= len) {
  23. return -1;
  24. }
  25. var k = n >= 0
  26. ? n
  27. : Math.max(len - Math.abs(n), 0);
  28. for (; k < len; k++) {
  29. if (k in t && t[k] === searchElement) {
  30. return k;
  31. }
  32. }
  33. return -1;
  34. };
  35. }
  36. // Instantiate the object
  37. var I18n = I18n || {};
  38. // Set default locale to english
  39. I18n.defaultLocale = "en";
  40. // Set default handling of translation fallbacks to false
  41. I18n.fallbacks = false;
  42. // Set default separator
  43. I18n.defaultSeparator = ".";
  44. // Set current locale to null
  45. I18n.locale = null;
  46. // Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
  47. I18n.PLACEHOLDER = /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm;
  48. I18n.fallbackRules = {
  49. };
  50. I18n.pluralizationRules = {
  51. en: function (n) {
  52. return n == 0 ? ["zero", "none", "other"] : n == 1 ? "one" : "other";
  53. }
  54. };
  55. I18n.getFallbacks = function(locale) {
  56. if (locale === I18n.defaultLocale) {
  57. return [];
  58. } else if (!I18n.fallbackRules[locale]) {
  59. var rules = []
  60. , components = locale.split("-");
  61. for (var l = 1; l < components.length; l++) {
  62. rules.push(components.slice(0, l).join("-"));
  63. }
  64. rules.push(I18n.defaultLocale);
  65. I18n.fallbackRules[locale] = rules;
  66. }
  67. return I18n.fallbackRules[locale];
  68. }
  69. I18n.isValidNode = function(obj, node, undefined) {
  70. return obj[node] !== null && obj[node] !== undefined;
  71. };
  72. I18n.lookup = function(scope, options) {
  73. var options = options || {}
  74. , lookupInitialScope = scope
  75. , translations = this.prepareOptions(I18n.translations)
  76. , locale = options.locale || I18n.currentLocale()
  77. , messages = translations[locale] || {}
  78. , options = this.prepareOptions(options)
  79. , currentScope
  80. ;
  81. if (typeof(scope) == "object") {
  82. scope = scope.join(this.defaultSeparator);
  83. }
  84. if (options.scope) {
  85. scope = options.scope.toString() + this.defaultSeparator + scope;
  86. }
  87. scope = scope.split(this.defaultSeparator);
  88. while (messages && scope.length > 0) {
  89. currentScope = scope.shift();
  90. messages = messages[currentScope];
  91. }
  92. if (!messages) {
  93. if (I18n.fallbacks) {
  94. var fallbacks = this.getFallbacks(locale);
  95. for (var fallback = 0; fallback < fallbacks.length; fallbacks++) {
  96. messages = I18n.lookup(lookupInitialScope, this.prepareOptions({locale: fallbacks[fallback]}, options));
  97. if (messages) {
  98. break;
  99. }
  100. }
  101. }
  102. if (!messages && this.isValidNode(options, "defaultValue")) {
  103. messages = options.defaultValue;
  104. }
  105. }
  106. return messages;
  107. };
  108. // Merge serveral hash options, checking if value is set before
  109. // overwriting any value. The precedence is from left to right.
  110. //
  111. // I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"});
  112. // #=> {name: "John Doe", role: "user"}
  113. //
  114. I18n.prepareOptions = function() {
  115. var options = {}
  116. , opts
  117. , count = arguments.length
  118. ;
  119. for (var i = 0; i < count; i++) {
  120. opts = arguments[i];
  121. if (!opts) {
  122. continue;
  123. }
  124. for (var key in opts) {
  125. if (!this.isValidNode(options, key)) {
  126. options[key] = opts[key];
  127. }
  128. }
  129. }
  130. return options;
  131. };
  132. I18n.interpolate = function(message, options) {
  133. options = this.prepareOptions(options);
  134. var matches = message.match(this.PLACEHOLDER)
  135. , placeholder
  136. , value
  137. , name
  138. ;
  139. if (!matches) {
  140. return message;
  141. }
  142. for (var i = 0; placeholder = matches[i]; i++) {
  143. name = placeholder.replace(this.PLACEHOLDER, "$1");
  144. value = options[name];
  145. if (!this.isValidNode(options, name)) {
  146. value = "[missing " + placeholder + " value]";
  147. }
  148. regex = new RegExp(placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}"));
  149. message = message.replace(regex, value);
  150. }
  151. return message;
  152. };
  153. I18n.translate = function(scope, options) {
  154. options = this.prepareOptions(options);
  155. var translation = this.lookup(scope, options);
  156. try {
  157. if (typeof(translation) == "object") {
  158. if (typeof(options.count) == "number") {
  159. return this.pluralize(options.count, scope, options);
  160. } else {
  161. return translation;
  162. }
  163. } else {
  164. return this.interpolate(translation, options);
  165. }
  166. } catch(err) {
  167. return this.missingTranslation(scope);
  168. }
  169. };
  170. I18n.localize = function(scope, value) {
  171. switch (scope) {
  172. case "currency":
  173. return this.toCurrency(value);
  174. case "number":
  175. scope = this.lookup("number.format");
  176. return this.toNumber(value, scope);
  177. case "percentage":
  178. return this.toPercentage(value);
  179. default:
  180. if (scope.match(/^(date|time)/)) {
  181. return this.toTime(scope, value);
  182. } else {
  183. return value.toString();
  184. }
  185. }
  186. };
  187. I18n.parseDate = function(date) {
  188. var matches, convertedDate;
  189. // we have a date, so just return it.
  190. if (typeof(date) == "object") {
  191. return date;
  192. };
  193. // it matches the following formats:
  194. // yyyy-mm-dd
  195. // yyyy-mm-dd[ T]hh:mm::ss
  196. // yyyy-mm-dd[ T]hh:mm::ss
  197. // yyyy-mm-dd[ T]hh:mm::ssZ
  198. // yyyy-mm-dd[ T]hh:mm::ss+0000
  199. //
  200. matches = date.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2}))?(Z|\+0000)?/);
  201. if (matches) {
  202. for (var i = 1; i <= 6; i++) {
  203. matches[i] = parseInt(matches[i], 10) || 0;
  204. }
  205. // month starts on 0
  206. matches[2] -= 1;
  207. if (matches[7]) {
  208. convertedDate = new Date(Date.UTC(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6]));
  209. } else {
  210. convertedDate = new Date(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6]);
  211. }
  212. } else if (typeof(date) == "number") {
  213. // UNIX timestamp
  214. convertedDate = new Date();
  215. convertedDate.setTime(date);
  216. } else if (date.match(/\d+ \d+:\d+:\d+ [+-]\d+ \d+/)) {
  217. // a valid javascript format with timezone info
  218. convertedDate = new Date();
  219. convertedDate.setTime(Date.parse(date))
  220. } else {
  221. // an arbitrary javascript string
  222. convertedDate = new Date();
  223. convertedDate.setTime(Date.parse(date));
  224. }
  225. return convertedDate;
  226. };
  227. I18n.toTime = function(scope, d) {
  228. var date = this.parseDate(d)
  229. , format = this.lookup(scope)
  230. ;
  231. if (date.toString().match(/invalid/i)) {
  232. return date.toString();
  233. }
  234. if (!format) {
  235. return date.toString();
  236. }
  237. return this.strftime(date, format);
  238. };
  239. I18n.strftime = function(date, format) {
  240. var options = this.lookup("date");
  241. if (!options) {
  242. return date.toString();
  243. }
  244. options.meridian = options.meridian || ["AM", "PM"];
  245. var weekDay = date.getDay()
  246. , day = date.getDate()
  247. , year = date.getFullYear()
  248. , month = date.getMonth() + 1
  249. , hour = date.getHours()
  250. , hour12 = hour
  251. , meridian = hour > 11 ? 1 : 0
  252. , secs = date.getSeconds()
  253. , mins = date.getMinutes()
  254. , offset = date.getTimezoneOffset()
  255. , absOffsetHours = Math.floor(Math.abs(offset / 60))
  256. , absOffsetMinutes = Math.abs(offset) - (absOffsetHours * 60)
  257. , timezoneoffset = (offset > 0 ? "-" : "+") + (absOffsetHours.toString().length < 2 ? "0" + absOffsetHours : absOffsetHours) + (absOffsetMinutes.toString().length < 2 ? "0" + absOffsetMinutes : absOffsetMinutes)
  258. ;
  259. if (hour12 > 12) {
  260. hour12 = hour12 - 12;
  261. } else if (hour12 === 0) {
  262. hour12 = 12;
  263. }
  264. var padding = function(n) {
  265. var s = "0" + n.toString();
  266. return s.substr(s.length - 2);
  267. };
  268. var f = format;
  269. f = f.replace("%a", options.abbr_day_names[weekDay]);
  270. f = f.replace("%A", options.day_names[weekDay]);
  271. f = f.replace("%b", options.abbr_month_names[month]);
  272. f = f.replace("%B", options.month_names[month]);
  273. f = f.replace("%d", padding(day));
  274. f = f.replace("%e", day);
  275. f = f.replace("%-d", day);
  276. f = f.replace("%H", padding(hour));
  277. f = f.replace("%-H", hour);
  278. f = f.replace("%I", padding(hour12));
  279. f = f.replace("%-I", hour12);
  280. f = f.replace("%m", padding(month));
  281. f = f.replace("%-m", month);
  282. f = f.replace("%M", padding(mins));
  283. f = f.replace("%-M", mins);
  284. f = f.replace("%p", options.meridian[meridian]);
  285. f = f.replace("%S", padding(secs));
  286. f = f.replace("%-S", secs);
  287. f = f.replace("%w", weekDay);
  288. f = f.replace("%y", padding(year));
  289. f = f.replace("%-y", padding(year).replace(/^0+/, ""));
  290. f = f.replace("%Y", year);
  291. f = f.replace("%z", timezoneoffset);
  292. return f;
  293. };
  294. I18n.toNumber = function(number, options) {
  295. options = this.prepareOptions(
  296. options,
  297. this.lookup("number.format"),
  298. {precision: 3, separator: ".", delimiter: ",", strip_insignificant_zeros: false}
  299. );
  300. var negative = number < 0
  301. , string = Math.abs(number).toFixed(options.precision).toString()
  302. , parts = string.split(".")
  303. , precision
  304. , buffer = []
  305. , formattedNumber
  306. ;
  307. number = parts[0];
  308. precision = parts[1];
  309. while (number.length > 0) {
  310. buffer.unshift(number.substr(Math.max(0, number.length - 3), 3));
  311. number = number.substr(0, number.length -3);
  312. }
  313. formattedNumber = buffer.join(options.delimiter);
  314. if (options.precision > 0) {
  315. formattedNumber += options.separator + parts[1];
  316. }
  317. if (negative) {
  318. formattedNumber = "-" + formattedNumber;
  319. }
  320. if (options.strip_insignificant_zeros) {
  321. var regex = {
  322. separator: new RegExp(options.separator.replace(/\./, "\\.") + "$")
  323. , zeros: /0+$/
  324. };
  325. formattedNumber = formattedNumber
  326. .replace(regex.zeros, "")
  327. .replace(regex.separator, "")
  328. ;
  329. }
  330. return formattedNumber;
  331. };
  332. I18n.toCurrency = function(number, options) {
  333. options = this.prepareOptions(
  334. options,
  335. this.lookup("number.currency.format"),
  336. this.lookup("number.format"),
  337. {unit: "$", precision: 2, format: "%u%n", delimiter: ",", separator: "."}
  338. );
  339. number = this.toNumber(number, options);
  340. number = options.format
  341. .replace("%u", options.unit)
  342. .replace("%n", number)
  343. ;
  344. return number;
  345. };
  346. I18n.toHumanSize = function(number, options) {
  347. var kb = 1024
  348. , size = number
  349. , iterations = 0
  350. , unit
  351. , precision
  352. ;
  353. while (size >= kb && iterations < 4) {
  354. size = size / kb;
  355. iterations += 1;
  356. }
  357. if (iterations === 0) {
  358. unit = this.t("number.human.storage_units.units.byte", {count: size});
  359. precision = 0;
  360. } else {
  361. unit = this.t("number.human.storage_units.units." + [null, "kb", "mb", "gb", "tb"][iterations]);
  362. precision = (size - Math.floor(size) === 0) ? 0 : 1;
  363. }
  364. options = this.prepareOptions(
  365. options,
  366. {precision: precision, format: "%n%u", delimiter: ""}
  367. );
  368. number = this.toNumber(size, options);
  369. number = options.format
  370. .replace("%u", unit)
  371. .replace("%n", number)
  372. ;
  373. return number;
  374. };
  375. I18n.toPercentage = function(number, options) {
  376. options = this.prepareOptions(
  377. options,
  378. this.lookup("number.percentage.format"),
  379. this.lookup("number.format"),
  380. {precision: 3, separator: ".", delimiter: ""}
  381. );
  382. number = this.toNumber(number, options);
  383. return number + "%";
  384. };
  385. I18n.pluralizer = function(locale) {
  386. pluralizer = this.pluralizationRules[locale];
  387. if (pluralizer !== undefined) return pluralizer;
  388. return this.pluralizationRules["en"];
  389. };
  390. I18n.findAndTranslateValidNode = function(keys, translation) {
  391. for (i = 0; i < keys.length; i++) {
  392. key = keys[i];
  393. if (this.isValidNode(translation, key)) return translation[key];
  394. }
  395. return null;
  396. };
  397. I18n.pluralize = function(count, scope, options) {
  398. var translation;
  399. try {
  400. translation = this.lookup(scope, options);
  401. } catch (error) {}
  402. if (!translation) {
  403. return this.missingTranslation(scope);
  404. }
  405. var message;
  406. options = this.prepareOptions(options);
  407. options.count = count.toString();
  408. pluralizer = this.pluralizer(this.currentLocale());
  409. key = pluralizer(Math.abs(count));
  410. keys = ((typeof key == "object") && (key instanceof Array)) ? key : [key];
  411. message = this.findAndTranslateValidNode(keys, translation);
  412. if (message == null) message = this.missingTranslation(scope, keys[0]);
  413. return this.interpolate(message, options);
  414. };
  415. I18n.missingTranslation = function() {
  416. var message = '[missing "' + this.currentLocale()
  417. , count = arguments.length
  418. ;
  419. for (var i = 0; i < count; i++) {
  420. message += "." + arguments[i];
  421. }
  422. message += '" translation]';
  423. return message;
  424. };
  425. I18n.currentLocale = function() {
  426. return (I18n.locale || I18n.defaultLocale);
  427. };
  428. // shortcuts
  429. I18n.t = I18n.translate;
  430. I18n.l = I18n.localize;
  431. I18n.p = I18n.pluralize;