locale.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.date.hebrew.locale"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.date.hebrew.locale"] = true;
  8. dojo.provide("dojox.date.hebrew.locale");
  9. dojo.require("dojox.date.hebrew.Date");
  10. dojo.require("dojox.date.hebrew.numerals");
  11. dojo.require("dojo.regexp");
  12. dojo.require("dojo.string");
  13. dojo.require("dojo.i18n");
  14. //Load the bundles containing localization information for
  15. // names and formats
  16. dojo.requireLocalization("dojo.cldr", "hebrew", null, "ROOT,ar,bg,el,fa,fi,fr,he,hu,iw,lv,nl,ru,sr,sv,th,tr,uk");
  17. (function(){
  18. // Format a pattern without literals
  19. function formatPattern(dateObject, bundle, locale, fullYear, pattern){
  20. return pattern.replace(/([a-z])\1*/ig, function(match){
  21. var s, pad;
  22. var c = match.charAt(0);
  23. var l = match.length;
  24. var widthList = ["abbr", "wide", "narrow"];
  25. switch(c){
  26. case 'y':
  27. if(locale.match(/^he(?:-.+)?$/)){
  28. s = dojox.date.hebrew.numerals.getYearHebrewLetters(dateObject.getFullYear());
  29. }else{
  30. s = String(dateObject.getFullYear());
  31. }
  32. break;
  33. case 'M':
  34. var m = dateObject.getMonth();
  35. if(l<3){
  36. if(!dateObject.isLeapYear(dateObject.getFullYear()) && m>5){m--;}
  37. if(locale.match(/^he(?:-.+)?$/)){
  38. s = dojox.date.hebrew.numerals.getMonthHebrewLetters(m);
  39. }else{
  40. s = m+1; pad = true;
  41. }
  42. }else{
  43. var monthNames = dojox.date.hebrew.locale.getNames('months',widthList[l-3], 'format', locale, dateObject);
  44. s = monthNames[m];
  45. }
  46. break;
  47. case 'd':
  48. if(locale.match(/^he(?:-.+)?$/)){
  49. s = dateObject.getDateLocalized(locale);
  50. }else{
  51. s = dateObject.getDate(); pad = true;
  52. }
  53. break;
  54. case 'E':
  55. var d = dateObject.getDay();
  56. if(l<3){
  57. s = d+1; pad = true;
  58. }else{
  59. var propD = ["days", "format", widthList[l-3]].join("-");
  60. s = bundle[propD][d];
  61. }
  62. break;
  63. case 'a':
  64. var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm';
  65. s = bundle['dayPeriods-format-wide-' + timePeriod];
  66. break;
  67. case 'h':
  68. case 'H':
  69. case 'K':
  70. case 'k':
  71. var h = dateObject.getHours();
  72. // strange choices in the date format make it impossible to write this succinctly
  73. switch (c){
  74. case 'h': // 1-12
  75. s = (h % 12) || 12;
  76. break;
  77. case 'H': // 0-23
  78. s = h;
  79. break;
  80. case 'K': // 0-11
  81. s = (h % 12);
  82. break;
  83. case 'k': // 1-24
  84. s = h || 24;
  85. break;
  86. }
  87. pad = true;
  88. break;
  89. case 'm':
  90. s = dateObject.getMinutes(); pad = true;
  91. break;
  92. case 's':
  93. s = dateObject.getSeconds(); pad = true;
  94. break;
  95. case 'S':
  96. s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3)); pad = true;
  97. break;
  98. case 'z':
  99. s = "";
  100. break;
  101. default:
  102. throw new Error("dojox.date.hebrew.locale.formatPattern: invalid pattern char: "+pattern);
  103. }
  104. if(pad){ s = dojo.string.pad(s, l); }
  105. return s;
  106. });
  107. }
  108. dojox.date.hebrew.locale.format = function(/*hebrew.Date*/dateObject, /*object?*/options){
  109. // based on and similar to dojo.date.locale.format
  110. //summary:
  111. // Format a Date object as a String, using settings.
  112. //
  113. // description:
  114. // Create a string from a hebrew.Date object using a known pattern.
  115. // By default, this method formats both date and time from dateObject.
  116. // Default formatting lengths is 'short'
  117. //
  118. // dateObject:
  119. // the date and/or time to be formatted. If a time only is formatted,
  120. // the values in the year, month, and day fields are irrelevant. The
  121. // opposite is true when formatting only dates.
  122. options = options || {};
  123. var locale = dojo.i18n.normalizeLocale(options.locale);
  124. var formatLength = options.formatLength || 'short';
  125. var bundle = dojox.date.hebrew.locale._getHebrewBundle(locale);
  126. var str = [];
  127. var sauce = dojo.hitch(this, formatPattern, dateObject, bundle, locale, options.fullYear);
  128. if(options.selector == "year"){
  129. var year = dateObject.getFullYear();
  130. return locale.match(/^he(?:-.+)?$/) ?
  131. dojox.date.hebrew.numerals.getYearHebrewLetters(year) : year;
  132. }
  133. if(options.selector != "time"){
  134. var datePattern = options.datePattern || bundle["dateFormat-"+formatLength];
  135. if(datePattern){str.push(_processPattern(datePattern, sauce));}
  136. }
  137. if(options.selector != "date"){
  138. var timePattern = options.timePattern || bundle["timeFormat-"+formatLength];
  139. if(timePattern){str.push(_processPattern(timePattern, sauce));}
  140. }
  141. var result = str.join(" "); //TODO: use locale-specific pattern to assemble date + time
  142. return result; // String
  143. };
  144. dojox.date.hebrew.locale.regexp = function(/*object?*/options){
  145. // based on and similar to dojo.date.locale.regexp
  146. // summary:
  147. // Builds the regular needed to parse a hebrew.Date
  148. return dojox.date.hebrew.locale._parseInfo(options).regexp; // String
  149. };
  150. dojox.date.hebrew.locale._parseInfo = function(/*oblect?*/options){
  151. /* based on and similar to dojo.date.locale._parseInfo */
  152. options = options || {};
  153. var locale = dojo.i18n.normalizeLocale(options.locale);
  154. var bundle = dojox.date.hebrew.locale._getHebrewBundle(locale);
  155. var formatLength = options.formatLength || 'short';
  156. var datePattern = options.datePattern || bundle["dateFormat-" + formatLength];
  157. var timePattern = options.timePattern || bundle["timeFormat-" + formatLength];
  158. var pattern;
  159. if(options.selector == 'date'){
  160. pattern = datePattern;
  161. }else if(options.selector == 'time'){
  162. pattern = timePattern;
  163. }else{
  164. pattern = (timePattern === undefined) ? datePattern : datePattern + ' ' + timePattern; //hebrew resource file does not contain time patterns - a bug?
  165. }
  166. var tokens = [];
  167. var re = _processPattern(pattern, dojo.hitch(this, _buildDateTimeRE, tokens, bundle, options));
  168. return {regexp: re, tokens: tokens, bundle: bundle};
  169. };
  170. dojox.date.hebrew.locale.parse= function(/*String*/value, /*object?*/options){
  171. // based on and similar to dojo.date.locale.parse
  172. // summary: This function parse string date value according to options
  173. // example:
  174. // | var dateHebrew = dojox.date.hebrew.locale.parse('11/10/5740', {datePattern:'dd/MM/yy', selector:'date'});
  175. // | in Hebrew locale string for parsing contains Hebrew Numerals
  176. // |
  177. // | options = {datePattern:'dd MMMM yy', selector:'date'};
  178. // |
  179. // | y - year
  180. // | M, MM - short month
  181. // | MMM, MMMM - long month
  182. // | d - date
  183. // | a - am, pm
  184. // | E, EE, EEE, EEEE - week day
  185. // |
  186. // | h, H, k, K, m, s, S, - time format
  187. value = value.replace(/[\u200E\u200F\u202A-\u202E]/g, ""); //remove special chars
  188. if(!options){options={};}
  189. var info = dojox.date.hebrew.locale._parseInfo(options);
  190. var tokens = info.tokens, bundle = info.bundle;
  191. var re = new RegExp("^" + info.regexp + "$");
  192. var match = re.exec(value);
  193. var locale = dojo.i18n.normalizeLocale(options.locale);
  194. if(!match){ return null; } // null
  195. var date, date1;
  196. //var result = [1970,0,1,0,0,0,0]; //
  197. var result = [5730,3,23,0,0,0,0]; // hebrew date for [1970,0,1,0,0,0,0] used in gregorian locale
  198. var amPm = "";
  199. var mLength = 0;
  200. var widthList = ["abbr", "wide", "narrow"];
  201. var valid = dojo.every(match, function(v, i){
  202. if(!i){return true;}
  203. var token=tokens[i-1];
  204. var l=token.length;
  205. switch(token.charAt(0)){
  206. case 'y':
  207. if(locale.match(/^he(?:-.+)?$/)){
  208. result[0] = dojox.date.hebrew.numerals.parseYearHebrewLetters(v);
  209. }else{
  210. result[0] = Number(v);
  211. }
  212. break;
  213. case 'M':
  214. //if it is short format, month is one letter or two letter with "geresh"
  215. if(l>2){
  216. //we do not know here if the year is leap or not
  217. var months = dojox.date.hebrew.locale.getNames('months', widthList[l-3], 'format', locale, new dojox.date.hebrew.Date(5769, 1, 1)),
  218. leapmonths = dojox.date.hebrew.locale.getNames('months', widthList[l-3], 'format', locale, new dojox.date.hebrew.Date(5768, 1, 1));
  219. if(!options.strict){
  220. //Tolerate abbreviating period in month part
  221. //Case-insensitive comparison
  222. v = v.replace(".","").toLowerCase();
  223. months = dojo.map(months, function(s){ return s ? s.replace(".","").toLowerCase() : s; } );
  224. leapmonths = dojo.map(leapmonths, function(s){ return s ? s.replace(".","").toLowerCase() : s; } );
  225. }
  226. var monthName = v;
  227. v = dojo.indexOf(months, monthName);
  228. if(v == -1){
  229. v = dojo.indexOf(leapmonths, monthName);
  230. if(v == -1){
  231. //console.debug("dojox.date.hebrew.locale.parse: Could not parse month name: second " + v +"'.");
  232. return false;
  233. }
  234. }
  235. mLength = l;
  236. }else{
  237. if(locale.match(/^he(?:-.+)?$/)){
  238. v = dojox.date.hebrew.numerals.parseMonthHebrewLetters(v);
  239. }else{
  240. v--;
  241. }
  242. }
  243. result[1] = Number(v);
  244. break;
  245. case 'D':
  246. result[1] = 0;
  247. // fallthrough...
  248. case 'd':
  249. if(locale.match(/^he(?:-.+)?$/)){
  250. result[2] = dojox.date.hebrew.numerals.parseDayHebrewLetters(v);
  251. }else{
  252. result[2] = Number(v);
  253. }
  254. break;
  255. case 'a': //am/pm
  256. var am = options.am || bundle['dayPeriods-format-wide-am'],
  257. pm = options.pm || bundle['dayPeriods-format-wide-pm'];
  258. if(!options.strict){
  259. var period = /\./g;
  260. v = v.replace(period,'').toLowerCase();
  261. am = am.replace(period,'').toLowerCase();
  262. pm = pm.replace(period,'').toLowerCase();
  263. }
  264. if(options.strict && v != am && v != pm){
  265. return false;
  266. }
  267. // we might not have seen the hours field yet, so store the state and apply hour change later
  268. amPm = (v == pm) ? 'p' : (v == am) ? 'a' : '';
  269. break;
  270. case 'K': //hour (1-24)
  271. if(v == 24){ v = 0; }
  272. // fallthrough...
  273. case 'h': //hour (1-12)
  274. case 'H': //hour (0-23)
  275. case 'k': //hour (0-11)
  276. //in the 12-hour case, adjusting for am/pm requires the 'a' part
  277. //which could come before or after the hour, so we will adjust later
  278. result[3] = Number(v);
  279. break;
  280. case 'm': //minutes
  281. result[4] = Number(v);
  282. break;
  283. case 's': //seconds
  284. result[5] = Number(v);
  285. break;
  286. case 'S': //milliseconds
  287. result[6] = Number(v);
  288. }
  289. return true;
  290. });
  291. var hours = +result[3];
  292. if(amPm === 'p' && hours < 12){
  293. result[3] = hours + 12; //e.g., 3pm -> 15
  294. }else if(amPm === 'a' && hours == 12){
  295. result[3] = 0; //12am -> 0
  296. }
  297. var dateObject = new dojox.date.hebrew.Date(result[0], result[1], result[2], result[3], result[4], result[5], result[6]); // hebrew.Date
  298. //for non leap year, the index of the short month start from adar should be increased by 1
  299. if(mLength < 3 && result[1] >= 5 && !dateObject.isLeapYear(dateObject.getFullYear())){
  300. dateObject.setMonth(result[1]+1);
  301. }
  302. return dateObject; // hebrew.Date
  303. };
  304. function _processPattern(pattern, applyPattern, applyLiteral, applyAll){
  305. //summary: Process a pattern with literals in it
  306. // Break up on single quotes, treat every other one as a literal, except '' which becomes '
  307. var identity = function(x){return x;};
  308. applyPattern = applyPattern || identity;
  309. applyLiteral = applyLiteral || identity;
  310. applyAll = applyAll || identity;
  311. //split on single quotes (which escape literals in date format strings)
  312. //but preserve escaped single quotes (e.g., o''clock)
  313. var chunks = pattern.match(/(''|[^'])+/g);
  314. var literal = pattern.charAt(0) == "'";
  315. dojo.forEach(chunks, function(chunk, i){
  316. if(!chunk){
  317. chunks[i]='';
  318. }else{
  319. chunks[i]=(literal ? applyLiteral : applyPattern)(chunk);
  320. literal = !literal;
  321. }
  322. });
  323. return applyAll(chunks.join(''));
  324. }
  325. function _buildDateTimeRE (tokens, bundle, options, pattern){
  326. // based on and similar to dojo.date.locale._buildDateTimeRE
  327. //
  328. pattern = dojo.regexp.escapeString(pattern);
  329. var locale = dojo.i18n.normalizeLocale(options.locale);
  330. return pattern.replace(/([a-z])\1*/ig, function(match){
  331. // Build a simple regexp. Avoid captures, which would ruin the tokens list
  332. var s;
  333. var c = match.charAt(0);
  334. var l = match.length;
  335. var p2 = '', p3 = '';
  336. if(options.strict){
  337. if(l > 1){ p2 = '0' + '{'+(l-1)+'}'; }
  338. if(l > 2){ p3 = '0' + '{'+(l-2)+'}'; }
  339. }else{
  340. p2 = '0?'; p3 = '0{0,2}';
  341. }
  342. switch(c){
  343. case 'y':
  344. s = '\\S+';
  345. break;
  346. case 'M':
  347. if(locale.match('^he(?:-.+)?$')){
  348. s = (l>2) ? '\\S+ ?\\S+' : '\\S{1,4}';
  349. }else{
  350. s = (l>2) ? '\\S+ ?\\S+' : p2+'[1-9]|1[0-2]';
  351. }
  352. break;
  353. case 'd':
  354. if(locale.match('^he(?:-.+)?$')){
  355. s = '\\S[\'\"\'\u05F3]{1,2}\\S?';
  356. }else{
  357. s = '[12]\\d|'+p2+'[1-9]|30';
  358. }
  359. break;
  360. case 'E':
  361. if(locale.match('^he(?:-.+)?$')){
  362. s = (l>3) ? '\\S+ ?\\S+' : '\\S';
  363. }else{
  364. s = '\\S+';
  365. }
  366. break;
  367. case 'h': //hour (1-12)
  368. s = p2+'[1-9]|1[0-2]';
  369. break;
  370. case 'k': //hour (0-11)
  371. s = p2+'\\d|1[01]';
  372. break;
  373. case 'H': //hour (0-23)
  374. s = p2+'\\d|1\\d|2[0-3]';
  375. break;
  376. case 'K': //hour (1-24)
  377. s = p2+'[1-9]|1\\d|2[0-4]';
  378. break;
  379. case 'm':
  380. case 's':
  381. s = p2+'\\d|[0-5]\\d';
  382. break;
  383. case 'S':
  384. s = '\\d{'+l+'}';
  385. break;
  386. case 'a':
  387. var am = options.am || bundle['dayPeriods-format-wide-am'],
  388. pm = options.pm || bundle['dayPeriods-format-wide-pm'];
  389. if(options.strict){
  390. s = am + '|' + pm;
  391. }else{
  392. s = am + '|' + pm;
  393. if(am != am.toLowerCase()){ s += '|' + am.toLowerCase(); }
  394. if(pm != pm.toLowerCase()){ s += '|' + pm.toLowerCase(); }
  395. }
  396. break;
  397. default:
  398. s = ".*";
  399. }
  400. if(tokens){ tokens.push(match); }
  401. return "(" + s + ")"; // add capture
  402. }).replace(/[\xa0 ]/g, "[\\s\\xa0]"); // normalize whitespace. Need explicit handling of \xa0 for IE. */
  403. }
  404. })();
  405. (function(){
  406. var _customFormats = [];
  407. dojox.date.hebrew.locale.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){
  408. // summary:
  409. // Add a reference to a bundle containing localized custom formats to be
  410. // used by date/time formatting and parsing routines.
  411. //
  412. // description:
  413. // The user may add custom localized formats where the bundle has properties following the
  414. // same naming convention used by dojo.cldr: `dateFormat-xxxx` / `timeFormat-xxxx`
  415. // The pattern string should match the format used by the CLDR.
  416. // See dojo.date.locale.format() for details.
  417. // The resources must be loaded by dojo.requireLocalization() prior to use
  418. _customFormats.push({pkg:packageName,name:bundleName});
  419. };
  420. dojox.date.hebrew.locale._getHebrewBundle = function(/*String*/locale){
  421. var hebrew = {};
  422. dojo.forEach(_customFormats, function(desc){
  423. var bundle = dojo.i18n.getLocalization(desc.pkg, desc.name, locale);
  424. hebrew = dojo.mixin(hebrew, bundle);
  425. }, this);
  426. return hebrew; /*Object*/
  427. };
  428. })();
  429. dojox.date.hebrew.locale.addCustomFormats("dojo.cldr","hebrew");
  430. dojox.date.hebrew.locale.getNames = function(/*String*/item, /*String*/type, /*String?*/context, /*String?*/locale, /*dojox.date.hebrew.Date?*/date){
  431. // summary:
  432. // Used to get localized strings from dojo.cldr for day or month names.
  433. //
  434. // item:
  435. // 'months' || 'days'
  436. // type:
  437. // 'wide' || 'narrow' || 'abbr' (e.g. "Monday", "Mon", or "M" respectively, in English)
  438. // use:
  439. // 'standAlone' || 'format' (default)
  440. // locale:
  441. // override locale used to find the names
  442. // date:
  443. // required for item=months to determine leap month name
  444. //
  445. // using var monthNames = dojox.date.hebrew.locale.getNames('months', 'wide', 'format', 'he', new dojox.date.hebrew.Date(5768, 2, 12));
  446. var label,
  447. lookup = dojox.date.hebrew.locale._getHebrewBundle(locale),
  448. props = [item, context, type];
  449. if(context == 'standAlone'){
  450. var key = props.join('-');
  451. label = lookup[key];
  452. // Fall back to 'format' flavor of name
  453. if(label[0] == 1){ label = undefined; } // kludge, in the absence of real aliasing support in dojo.cldr
  454. }
  455. props[1] = 'format';
  456. // return by copy so changes won't be made accidentally to the in-memory model
  457. var result = (label || lookup[props.join('-')]).concat();
  458. if(item == "months"){
  459. if(date.isLeapYear(date.getFullYear())){
  460. // Adar I (6th position in the array) will be used.
  461. // Substitute the leap month Adar II for the regular Adar (7th position)
  462. props.push("leap");
  463. result[6] = lookup[props.join('-')];
  464. }else{
  465. // Remove Adar I but leave an empty position in the array
  466. delete result[5];
  467. }
  468. }
  469. return result; /*Array*/
  470. };
  471. }