generateLanguages.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. module.exports = function(grunt) {
  2. var config = grunt.config('generateLanguages');
  3. grunt.registerTask('generateLanguages', function() {
  4. var combinedJS = '';
  5. var languageCnt = 0;
  6. var skippedLangCodes = [];
  7. grunt.file.mkdir(config.dest, 0755);
  8. grunt.file.expand(config.moment + '/*.js').forEach(function(momentPath) {
  9. var langCode = momentPath.match(/([^\/]*)\.js$/)[1];
  10. var js = getLangJS(langCode, momentPath);
  11. if (js) {
  12. grunt.file.write(
  13. config.dest + '/' + langCode + '.js',
  14. wrapWithUMD(js)
  15. );
  16. combinedJS += wrapWithClosure(js) + '\n';
  17. languageCnt++;
  18. }
  19. else {
  20. skippedLangCodes.push(langCode);
  21. }
  22. });
  23. // code for resetting the language back to English
  24. combinedJS += '\nmoment.lang("en");';
  25. combinedJS += '\n$.fullCalendar.lang("en");';
  26. combinedJS += '\nif ($.datepicker) $.datepicker.setDefaults($.datepicker.regional[""]);';
  27. grunt.file.write(
  28. config.dest + '/all.js',
  29. wrapWithUMD(combinedJS)
  30. );
  31. grunt.log.writeln(skippedLangCodes.length + ' skipped languages: ' + skippedLangCodes.join(', '));
  32. grunt.log.writeln(languageCnt + ' generated languages.');
  33. });
  34. function getLangJS(langCode, momentPath) {
  35. var shortLangCode;
  36. var momentLangJS;
  37. var datepickerLangJS;
  38. var fullCalendarLangJS;
  39. // given "fr-ca", get just "fr"
  40. if (langCode.indexOf('-') != -1) {
  41. shortLangCode = langCode.replace(/-.*/, '');
  42. }
  43. momentLangJS = getMomentLangJS(momentPath);
  44. datepickerLangJS = getDatepickerLangJS(langCode);
  45. if (!datepickerLangJS && shortLangCode) {
  46. datepickerLangJS = getDatepickerLangJS(shortLangCode, langCode);
  47. }
  48. fullCalendarLangJS = getFullCalendarLangJS(langCode);
  49. if (!fullCalendarLangJS && shortLangCode) {
  50. fullCalendarLangJS = getFullCalendarLangJS(shortLangCode, langCode);
  51. }
  52. // If this is an "en" language, only the Moment config is needed.
  53. // For all other languages, all 3 configs are needed.
  54. if (momentLangJS && (shortLangCode == 'en' || (datepickerLangJS && fullCalendarLangJS))) {
  55. // if there is no definition, we still need to tell FC to set the default
  56. if (!fullCalendarLangJS) {
  57. fullCalendarLangJS = '$.fullCalendar.lang("' + langCode + '");';
  58. }
  59. datepickerLangJS = datepickerLangJS || '';
  60. return momentLangJS + '\n' +
  61. datepickerLangJS + '\n' +
  62. fullCalendarLangJS;
  63. }
  64. }
  65. function wrapWithUMD(body) {
  66. return [
  67. '(function(factory) {',
  68. ' if (typeof define === "function" && define.amd) {',
  69. ' define([ "jquery", "moment" ], factory);',
  70. ' }',
  71. ' else {',
  72. ' factory(jQuery, moment);',
  73. ' }',
  74. '})(function($, moment) {',
  75. '',
  76. body,
  77. '',
  78. '});'
  79. ].join('\n');
  80. }
  81. function wrapWithClosure(body) {
  82. return [
  83. '(function() {',
  84. '',
  85. body,
  86. '',
  87. '})();'
  88. ].join('\n');
  89. }
  90. function getMomentLangJS(path) { // file assumed to exist
  91. var js = grunt.file.read(path);
  92. js = js.replace( // remove the UMD wrap
  93. /\(\s*function[\S\s]*?function\s*\(\s*moment\s*\)\s*\{([\S\s]*)\}\)\);?/,
  94. function(m0, body) {
  95. body = body.replace(/^ /mg, ''); // remove 1 level of indentation
  96. return body;
  97. }
  98. );
  99. js = js.replace( // replace the `return` statement so execution continues
  100. /^(\s*)return moment\.lang\(/m,
  101. '$1moment.lang('
  102. );
  103. return js;
  104. }
  105. function getDatepickerLangJS(langCode, targetLangCode) {
  106. // convert "en-ca" to "en-CA"
  107. var datepickerLangCode = langCode.replace(/\-(\w+)/, function(m0, m1) {
  108. return '-' + m1.toUpperCase();
  109. });
  110. var path = config.datepicker + '/jquery.ui.datepicker-' + datepickerLangCode + '.js';
  111. var js;
  112. try {
  113. js = grunt.file.read(path);
  114. }
  115. catch (ex) {
  116. return false;
  117. }
  118. js = js.replace(
  119. /^jQuery\([\S\s]*?\{([\S\s]*)\}\);?/m, // inside the jQuery(function) wrap,
  120. function(m0, body) { // use only the function body, modified.
  121. var match = body.match(/\$\.datepicker\.regional[\S\s]*?(\{[\S\s]*?\});?/);
  122. var props = match[1];
  123. // remove 1 level of tab indentation
  124. props = props.replace(/^\t/mg, '');
  125. return "$.fullCalendar.datepickerLang(" +
  126. "'" + (targetLangCode || langCode) + "', " + // for FullCalendar
  127. "'" + datepickerLangCode + "', " + // for datepicker
  128. props +
  129. ");";
  130. }
  131. );
  132. return js;
  133. }
  134. function getFullCalendarLangJS(langCode, targetLangCode) {
  135. var path = config.fullCalendar + '/' + langCode + '.js';
  136. var js;
  137. try {
  138. js = grunt.file.read(path);
  139. }
  140. catch (ex) {
  141. return false;
  142. }
  143. // if we originally wanted "ar-ma", but only "ar" is available, we have to adjust
  144. // the declaration
  145. if (targetLangCode && targetLangCode != langCode) {
  146. js = js.replace(
  147. /\$\.fullCalendar\.lang\(['"]([^'"]*)['"]/,
  148. '$.fullCalendar.lang("' + targetLangCode + '"'
  149. );
  150. }
  151. return js;
  152. }
  153. };