var path = require('path'); var fs = require('fs'); var constants = require('./util/constants'); var common = require('./util/common'); var args = process.argv.slice(2); var argLocale = args[0]; var pathToEn = path.join(constants.pathToSrc, 'locale-en.js'); var pathToWCRegions = path.dirname(require.resolve('world-calendars/dist/regional/en-GB')); if(!argLocale) { fs.readdir(pathToWCRegions, function(err, items) { if(err) throw err; items.forEach(function(item) { var itemLocale = item.split('.')[0]; if(itemLocale.substr(0, 2) === 'en') { console.log('skipping English ' + itemLocale); return; } pullOneLocale(itemLocale); }); }); } else { pullOneLocale(argLocale); } function pullOneLocale(locale) { var pathToInput = path.join(pathToWCRegions, locale + '.js'); var pathToOutput = path.join(constants.pathToLib, 'locales', locale.toLowerCase() + '.js'); fs.readFile(pathToInput, 'utf8', function(err, wcCode) { if(err) { throw new Error('pull_date_format failed: ' + pathToInput + ' not found'); } var preStartStr = 'prototype.regionalOptions'; var startStr = '] = {'; var endStr = '};'; var startIndex = wcCode.indexOf(startStr, wcCode.indexOf(preStartStr)) + startStr.length - 1; var endIndex = wcCode.indexOf(endStr, startIndex) + 1; var dataStr = wcCode.substr(startIndex, endIndex - startIndex); // strip out `main.substitute(Chinese)?Digits` - we don't care about the digits field for now anyway dataStr = dataStr.replace(/main[\.][A-Za-z]+\([^\)]*\)/g, '""'); dataStr = cleanHTMLEntities(dataStr); var wcDataObj = eval('a=' + dataStr); fs.readFile(pathToOutput, 'utf8', function(err, existingOutputText) { var isNew = false; if(err || !existingOutputText.trim()) { existingOutputText = fs.readFileSync(pathToEn, 'utf8'); isNew = true; } var outObjStartStr = 'module.exports = '; var outObjEndStr = '};'; var outObjStartIndex = existingOutputText.indexOf(outObjStartStr) + outObjStartStr.length; var outObjEndIndex = existingOutputText.indexOf(outObjEndStr, outObjStartIndex) + 1; var outPrefix = existingOutputText.substr(0, outObjStartIndex); var outSuffix = existingOutputText.substr(outObjEndIndex); var objText = existingOutputText.substr(outObjStartIndex, outObjEndIndex - outObjStartIndex); var outObj; try { outObj = eval('a=' + objText); } catch(e) { throw new Error(locale + '--' + objText); } if(isNew) { outObj.name = locale; outObj.dictionary = {}; outObj.format = {}; } var format = outObj.format = (outObj.format || {}); format.days = wcDataObj.dayNames; format.shortDays = wcDataObj.dayNamesShort; format.months = wcDataObj.monthNames; format.shortMonths = wcDataObj.monthNamesShort; format.date = translateDateFormat(wcDataObj.dateFormat); // leave out `dateTime` and `time` fields. We could include them as cmd line args later // for now these will get inherited from english. var outStr = JSON.stringify(outObj, null, 4) .replace(/'/g, '\\\'') // escape single quotes .replace(/"([A-Za-z]\w+)":/g, '$1:') // unquote simple identifier keys .replace(/([^\\])"/g, '$1\'') // replace unescaped doublequotes with singlequotes .replace(/\\"/g, '"'); // unescape escaped doublequotes outStr = shortenArrays(outStr); common.writeFile(pathToOutput, outPrefix + outStr + outSuffix, function() { console.log('ok pull_date_format ' + locale); }); }); }); } /* * Turn HTML entities into unicode - for explicit compatibility with SVG * There are just a few in world-calendars that aren't already in unicode anyway. */ var entityMap = { ccedil: '\u00e7', auml: '\u00e4', '#x10C': '\u010c' }; function cleanHTMLEntities(s) { return s.replace(/&([^;]+);/g, function(entity, entityID) { var outChar = entityMap[entityID]; if(!outChar) { throw new Error('no unicode character listed for ' + entity); } return outChar; }); } /* * Convert world-calendars date format ('dd.mm.yyyy') to d3 ('%d.%m.%Y') */ function translateDateFormat(wcDateFormat) { var out = wcDateFormat .replace('yyyy', '%Y') // bosnian (bs) uses 2-digit year in world-calendars, but I don't want to continue that! .replace('yy', '%Y') .replace('mm', '%m') .replace('dd', '%d') // gujarati (gu) uses short month name in world-calendars - keep it? .replace('M', '%b'); return out; } /** * Either put the whole array on one line, split it into 2 lines, * or leave it as is (one line per item), whatever we can fit into 90 characters. * A trailing comma may still be after the 90-character limit */ function shortenArrays(s) { var maxLen = 91; // max line length plus one for the initial \n. return s.replace(/(\n.+\[)\n([^\]]+)\n(\s*)\]/g, function(wholeMatch, prefix, arrayStr, bracketSpaces) { var parts = arrayStr.trim().split(/,\n\s*/); var singleLine = prefix + parts.join(', ') + ']'; if(singleLine.length <= maxLen) { return singleLine; } var arraySpaces = bracketSpaces + ' '; var splitPoint = Math.ceil(parts.length / 2); var line1 = arraySpaces + parts.slice(0, splitPoint).join(', ') + ','; var line2 = arraySpaces + parts.slice(splitPoint).join(', '); if(line1.length <= maxLen && line2.length <= maxLen) { return [prefix, line1, line2, bracketSpaces + ']'].join('\n'); } return wholeMatch; }); }