locale.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. define("dojox/date/islamic/locale", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/array", "dojo/date", "dojo/i18n", "dojo/regexp", "dojo/string", "./Date", "dojo/i18n!dojo/cldr/nls/islamic"],
  2. function(dojo, dlang, darray, dd, i18n, regexp, string, islamicDate){
  3. dojo.getObject("date.islamic.locale", true, dojox);
  4. dojo.experimental("dojox.date.islamic.locale");
  5. dojo.requireLocalization("dojo.cldr", "islamic");
  6. // Format a pattern without literals
  7. function formatPattern(dateObject, bundle, locale, fullYear, pattern){
  8. return pattern.replace(/([a-z])\1*/ig, function(match){
  9. var s, pad;
  10. var c = match.charAt(0);
  11. var l = match.length;
  12. var widthList = ["abbr", "wide", "narrow"];
  13. switch(c){
  14. case 'G':
  15. s = bundle["eraAbbr"][0];
  16. break;
  17. case 'y':
  18. s = String(dateObject.getFullYear());
  19. break;
  20. case 'M':
  21. var m = dateObject.getMonth();
  22. if(l<3){
  23. s = m+1; pad = true;
  24. }else{
  25. var propM = ["months", "format", widthList[l-3]].join("-");
  26. s = bundle[propM][m];
  27. }
  28. break;
  29. case 'd':
  30. s = dateObject.getDate(true); pad = true;
  31. break;
  32. case 'E':
  33. var d = dateObject.getDay();
  34. if(l<3){
  35. s = d+1; pad = true;
  36. }else{
  37. var propD = ["days", "format", widthList[l-3]].join("-");
  38. s = bundle[propD][d];
  39. }
  40. break;
  41. case 'a':
  42. var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm';
  43. s = bundle['dayPeriods-format-wide-' + timePeriod];
  44. break;
  45. case 'h':
  46. case 'H':
  47. case 'K':
  48. case 'k':
  49. var h = dateObject.getHours();
  50. switch (c){
  51. case 'h': // 1-12
  52. s = (h % 12) || 12;
  53. break;
  54. case 'H': // 0-23
  55. s = h;
  56. break;
  57. case 'K': // 0-11
  58. s = (h % 12);
  59. break;
  60. case 'k': // 1-24
  61. s = h || 24;
  62. break;
  63. }
  64. pad = true;
  65. break;
  66. case 'm':
  67. s = dateObject.getMinutes(); pad = true;
  68. break;
  69. case 's':
  70. s = dateObject.getSeconds(); pad = true;
  71. break;
  72. case 'S':
  73. s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3)); pad = true;
  74. break;
  75. case 'z':
  76. // We only have one timezone to offer; the one from the browser
  77. s = dd.getTimezoneName(dateObject.toGregorian());
  78. if(s){ break; }
  79. l = 4;
  80. // fallthrough... use GMT if tz not available
  81. case 'Z':
  82. var offset = dateObject.toGregorian().getTimezoneOffset();
  83. var tz = [
  84. (offset <= 0 ? "+" : "-"),
  85. string.pad(Math.floor(Math.abs(offset) / 60), 2),
  86. string.pad(Math.abs(offset) % 60, 2)
  87. ];
  88. if(l == 4){
  89. tz.splice(0, 0, "GMT");
  90. tz.splice(3, 0, ":");
  91. }
  92. s = tz.join("");
  93. break;
  94. default:
  95. throw new Error("dojox.date.islamic.locale.formatPattern: invalid pattern char: "+pattern);
  96. }
  97. if(pad){ s = string.pad(s, l); }
  98. return s;
  99. });
  100. }
  101. // based on and similar to dojo.date.locale.format
  102. dojox.date.islamic.locale.format = function(/*islamic.Date*/dateObject, /*Object?*/options){
  103. // summary:
  104. // Format a Date object as a String, using settings.
  105. options = options || {};
  106. var locale = i18n.normalizeLocale(options.locale);
  107. var formatLength = options.formatLength || 'short';
  108. var bundle = dojox.date.islamic.locale._getIslamicBundle(locale);
  109. var str = [];
  110. var sauce = dojo.hitch(this, formatPattern, dateObject, bundle, locale, options.fullYear);
  111. if(options.selector == "year"){
  112. var year = dateObject.getFullYear();
  113. return year;
  114. }
  115. if(options.selector != "time"){
  116. var datePattern = options.datePattern || bundle["dateFormat-"+formatLength];
  117. if(datePattern){str.push(_processPattern(datePattern, sauce));}
  118. }
  119. if(options.selector != "date"){
  120. var timePattern = options.timePattern || bundle["timeFormat-"+formatLength];
  121. if(timePattern){str.push(_processPattern(timePattern, sauce));}
  122. }
  123. var result = str.join(" "); //TODO: use locale-specific pattern to assemble date + time
  124. return result; // String
  125. };
  126. dojox.date.islamic.locale.regexp = function(/*object?*/options){
  127. // based on and similar to dojo.date.locale.regexp
  128. // summary:
  129. // Builds the regular needed to parse a islamic.Date
  130. return dojox.date.islamic.locale._parseInfo(options).regexp; // String
  131. };
  132. dojox.date.islamic.locale._parseInfo = function(/*oblect?*/options){
  133. /* based on and similar to dojo.date.locale._parseInfo */
  134. options = options || {};
  135. var locale = i18n.normalizeLocale(options.locale);
  136. var bundle = dojox.date.islamic.locale._getIslamicBundle(locale);
  137. var formatLength = options.formatLength || 'short';
  138. var datePattern = options.datePattern || bundle["dateFormat-" + formatLength];
  139. var timePattern = options.timePattern || bundle["timeFormat-" + formatLength];
  140. var pattern;
  141. if(options.selector == 'date'){
  142. pattern = datePattern;
  143. }else if(options.selector == 'time'){
  144. pattern = timePattern;
  145. }else{
  146. pattern = (typeof (timePattern) == "undefined") ? datePattern : datePattern + ' ' + timePattern;
  147. }
  148. var tokens = [];
  149. var re = _processPattern(pattern, dojo.hitch(this, _buildDateTimeRE, tokens, bundle, options));
  150. return {regexp: re, tokens: tokens, bundle: bundle};
  151. };
  152. dojox.date.islamic.locale.parse = function(/*String*/value, /*Object?*/options){
  153. // based on and similar to dojo.date.locale.parse
  154. // summary: This function parse string date value according to options
  155. value = value.replace(/[\u200E\u200F\u202A\u202E]/g, ""); //remove bidi non-printing chars
  156. if(!options){ options={}; }
  157. var info = dojox.date.islamic.locale._parseInfo(options);
  158. var tokens = info.tokens, bundle = info.bundle;
  159. var regexp = info.regexp.replace(/[\u200E\u200F\u202A\u202E]/g, ""); //remove bidi non-printing chars from the pattern
  160. var re = new RegExp("^" + regexp + "$");
  161. var match = re.exec(value);
  162. var locale = i18n.normalizeLocale(options.locale);
  163. if(!match){ return null; } // null
  164. var date, date1;
  165. var result = [1389,0,1,0,0,0,0]; //FIXME: islamic date for [1970,0,1,0,0,0,0] used in gregorian locale
  166. var amPm = "";
  167. var mLength = 0;
  168. var widthList = ["abbr", "wide", "narrow"];
  169. var valid = dojo.every(match, function(v, i){
  170. if(!i){return true;}
  171. var token=tokens[i-1];
  172. var l=token.length;
  173. switch(token.charAt(0)){
  174. case 'y':
  175. result[0] = Number(v);
  176. break;
  177. case 'M':
  178. if(l>2){
  179. var months = bundle['months-format-' + widthList[l-3]].concat();
  180. if(!options.strict){
  181. //Tolerate abbreviating period in month part
  182. //Case-insensitive comparison
  183. v = v.replace(".","").toLowerCase();
  184. months = dojo.map(months, function(s){ return s ? s.replace(".","").toLowerCase() : s; } );
  185. }
  186. v = dojo.indexOf(months, v);
  187. if(v == -1){
  188. return false;
  189. }
  190. mLength = l;
  191. }else{
  192. v--;
  193. }
  194. result[1] = Number(v);
  195. break;
  196. case 'D':
  197. result[1] = 0;
  198. // fallthrough...
  199. case 'd':
  200. result[2] = Number(v);
  201. break;
  202. case 'a': //am/pm
  203. var am = options.am || bundle['dayPeriods-format-wide-am'],
  204. pm = options.pm || bundle['dayPeriods-format-wide-pm'];
  205. if(!options.strict){
  206. var period = /\./g;
  207. v = v.replace(period,'').toLowerCase();
  208. am = am.replace(period,'').toLowerCase();
  209. pm = pm.replace(period,'').toLowerCase();
  210. }
  211. if(options.strict && v != am && v != pm){
  212. return false;
  213. }
  214. // we might not have seen the hours field yet, so store the state and apply hour change later
  215. amPm = (v == pm) ? 'p' : (v == am) ? 'a' : '';
  216. break;
  217. case 'K': //hour (1-24)
  218. if(v == 24){ v = 0; }
  219. // fallthrough...
  220. case 'h': //hour (1-12)
  221. case 'H': //hour (0-23)
  222. case 'k': //hour (0-11)
  223. //in the 12-hour case, adjusting for am/pm requires the 'a' part
  224. //which could come before or after the hour, so we will adjust later
  225. result[3] = Number(v);
  226. break;
  227. case 'm': //minutes
  228. result[4] = Number(v);
  229. break;
  230. case 's': //seconds
  231. result[5] = Number(v);
  232. break;
  233. case 'S': //milliseconds
  234. result[6] = Number(v);
  235. }
  236. return true;
  237. });
  238. var hours = +result[3];
  239. if(amPm === 'p' && hours < 12){
  240. result[3] = hours + 12; //e.g., 3pm -> 15
  241. }else if(amPm === 'a' && hours == 12){
  242. result[3] = 0; //12am -> 0
  243. }
  244. var dateObject = new islamicDate(result[0], result[1], result[2], result[3], result[4], result[5], result[6]);
  245. return dateObject;
  246. };
  247. function _processPattern(pattern, applyPattern, applyLiteral, applyAll){
  248. //summary: Process a pattern with literals in it
  249. // Break up on single quotes, treat every other one as a literal, except '' which becomes '
  250. var identity = function(x){return x;};
  251. applyPattern = applyPattern || identity;
  252. applyLiteral = applyLiteral || identity;
  253. applyAll = applyAll || identity;
  254. //split on single quotes (which escape literals in date format strings)
  255. //but preserve escaped single quotes (e.g., o''clock)
  256. var chunks = pattern.match(/(''|[^'])+/g);
  257. var literal = pattern.charAt(0) == "'";
  258. dojo.forEach(chunks, function(chunk, i){
  259. if(!chunk){
  260. chunks[i]='';
  261. }else{
  262. chunks[i]=(literal ? applyLiteral : applyPattern)(chunk);
  263. literal = !literal;
  264. }
  265. });
  266. return applyAll(chunks.join(''));
  267. }
  268. function _buildDateTimeRE (tokens, bundle, options, pattern){
  269. // based on and similar to dojo.date.locale._buildDateTimeRE
  270. //
  271. pattern = regexp.escapeString(pattern);
  272. var locale = i18n.normalizeLocale(options.locale);
  273. return pattern.replace(/([a-z])\1*/ig, function(match){
  274. // Build a simple regexp. Avoid captures, which would ruin the tokens list
  275. var s;
  276. var c = match.charAt(0);
  277. var l = match.length;
  278. var p2 = '', p3 = '';
  279. if(options.strict){
  280. if(l > 1){ p2 = '0' + '{'+(l-1)+'}'; }
  281. if(l > 2){ p3 = '0' + '{'+(l-2)+'}'; }
  282. }else{
  283. p2 = '0?'; p3 = '0{0,2}';
  284. }
  285. switch(c){
  286. case 'y':
  287. s = '\\d+';
  288. break;
  289. case 'M':
  290. s = (l>2) ? '\\S+ ?\\S+' : p2+'[1-9]|1[0-2]';
  291. break;
  292. case 'd':
  293. s = '[12]\\d|'+p2+'[1-9]|3[01]';
  294. break;
  295. case 'E':
  296. s = '\\S+';
  297. break;
  298. case 'h': //hour (1-12)
  299. s = p2+'[1-9]|1[0-2]';
  300. break;
  301. case 'k': //hour (0-11)
  302. s = p2+'\\d|1[01]';
  303. break;
  304. case 'H': //hour (0-23)
  305. s = p2+'\\d|1\\d|2[0-3]';
  306. break;
  307. case 'K': //hour (1-24)
  308. s = p2+'[1-9]|1\\d|2[0-4]';
  309. break;
  310. case 'm':
  311. case 's':
  312. s = p2+'\\d|[0-5]\\d';
  313. break;
  314. case 'S':
  315. s = '\\d{'+l+'}';
  316. break;
  317. case 'a':
  318. var am = options.am || bundle['dayPeriods-format-wide-am'],
  319. pm = options.pm || bundle['dayPeriods-format-wide-pm'];
  320. if(options.strict){
  321. s = am + '|' + pm;
  322. }else{
  323. s = am + '|' + pm;
  324. if(am != am.toLowerCase()){ s += '|' + am.toLowerCase(); }
  325. if(pm != pm.toLowerCase()){ s += '|' + pm.toLowerCase(); }
  326. }
  327. break;
  328. default:
  329. s = ".*";
  330. }
  331. if(tokens){ tokens.push(match); }
  332. return "(" + s + ")"; // add capture
  333. }).replace(/[\xa0 ]/g, "[\\s\\xa0]"); // normalize whitespace. Need explicit handling of \xa0 for IE. */
  334. }
  335. var _customFormats = [];
  336. dojox.date.islamic.locale.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){
  337. // summary:
  338. // Add a reference to a bundle containing localized custom formats to be
  339. // used by date/time formatting and parsing routines.
  340. _customFormats.push({pkg:packageName,name:bundleName});
  341. };
  342. dojox.date.islamic.locale._getIslamicBundle = function(/*String*/locale){
  343. var islamic = {};
  344. dojo.forEach(_customFormats, function(desc){
  345. var bundle = i18n.getLocalization(desc.pkg, desc.name, locale);
  346. islamic = dojo.mixin(islamic, bundle);
  347. }, this);
  348. return islamic; /*Object*/
  349. };
  350. dojox.date.islamic.locale.addCustomFormats("dojo.cldr","islamic");
  351. dojox.date.islamic.locale.getNames = function(/*String*/item, /*String*/type, /*String?*/context, /*String?*/locale, /*islamic Date Object?*/date){
  352. // summary:
  353. // Used to get localized strings from dojo.cldr for day or month names.
  354. var label;
  355. var lookup = dojox.date.islamic.locale._getIslamicBundle(locale);
  356. var props = [item, context, type];
  357. if(context == 'standAlone'){
  358. var key = props.join('-');
  359. label = lookup[key];
  360. // Fall back to 'format' flavor of name
  361. if(label[0] == 1){ label = undefined; } // kludge, in the absence of real aliasing support in dojo.cldr
  362. }
  363. props[1] = 'format';
  364. // return by copy so changes won't be made accidentally to the in-memory model
  365. return (label || lookup[props.join('-')]).concat(); /*Array*/
  366. };
  367. dojox.date.islamic.locale.weekDays = dojox.date.islamic.locale.getNames('days', 'wide', 'format');
  368. dojox.date.islamic.locale.months = dojox.date.islamic.locale.getNames('months', 'wide', 'format');
  369. return dojox.date.islamic.locale;
  370. });