|
| 1 | +#!/usr/bin/env node |
| 2 | + |
| 3 | +'use strict'; |
| 4 | + |
| 5 | +var fs = require('fs'); |
| 6 | +var path = require('path'); |
| 7 | +var moment = require('moment'); |
| 8 | +var commander = require('commander'); |
| 9 | +var YAML = require('js-yaml'); |
| 10 | +var colors = require('colors/safe'); |
| 11 | +var AdmZip = require('adm-zip'); |
| 12 | +var rimraf = require('rimraf'); |
| 13 | + |
| 14 | +if (!String.prototype.endsWith) { |
| 15 | + Object.defineProperty(String.prototype, 'endsWith', { |
| 16 | + value: function(searchString, position) { |
| 17 | + var subjectString = this.toString(); |
| 18 | + if (position === undefined || position > subjectString.length) { |
| 19 | + position = subjectString.length; |
| 20 | + } |
| 21 | + position -= searchString.length; |
| 22 | + var lastIndex = subjectString.indexOf(searchString, position); |
| 23 | + return lastIndex !== -1 && lastIndex === position; |
| 24 | + } |
| 25 | + }); |
| 26 | +} |
| 27 | + |
| 28 | +function recurseDir(dir, rootDir, callback) { |
| 29 | + if (dir.indexOf('_code') === -1) { |
| 30 | + var files = fs.readdirSync(dir); |
| 31 | + for (var i = 0; i < files.length; i++) { |
| 32 | + var file = path.join(dir, files[i]); |
| 33 | + var stat = fs.statSync(file); |
| 34 | + if (stat.isDirectory()) { |
| 35 | + recurseDir(file, rootDir, callback); |
| 36 | + } else { |
| 37 | + if (file.indexOf('DS_Store') === -1) { |
| 38 | + callback(file); |
| 39 | + } |
| 40 | + } |
| 41 | + } |
| 42 | + } |
| 43 | +} |
| 44 | + |
| 45 | +function copyFile(source, destination) { |
| 46 | + fs.writeFileSync(destination, fs.readFileSync(source)); |
| 47 | +} |
| 48 | + |
| 49 | +function requiresTranslation(filename) { |
| 50 | + |
| 51 | + // Read the contents of the file |
| 52 | + var content = fs.readFileSync(filename).toString(); |
| 53 | + |
| 54 | + if (content.trimLeft().indexOf('---') === 0) { |
| 55 | + var yamlObj; |
| 56 | + var yamlStart = content.indexOf('---') + 3; |
| 57 | + var yamlStop = content.indexOf('---', yamlStart); |
| 58 | + var yaml = content.substring(yamlStart, yamlStop); |
| 59 | + try { |
| 60 | + yamlObj = YAML.load(yaml); |
| 61 | + } catch (ex) { |
| 62 | + console.log(colors.red('Error:'), 'Unable to parse YAML in file:', filename); |
| 63 | + return false; |
| 64 | + } |
| 65 | + |
| 66 | + // If published: false - skip |
| 67 | + if (yamlObj.published === false) { |
| 68 | + return false; |
| 69 | + } |
| 70 | + |
| 71 | + // Check the translation priority |
| 72 | + var translationPriority = yamlObj.translation_priority; |
| 73 | + if (translationPriority === undefined) { |
| 74 | + translationPriority = 2; |
| 75 | + } |
| 76 | + if (translationPriority > commander.priority) { |
| 77 | + return false; |
| 78 | + } |
| 79 | + |
| 80 | + // Check the date the article was last updated |
| 81 | + var lastUpdated = moment(yamlObj.lastUpdated); |
| 82 | + if (commander.date.isAfter(lastUpdated) === true) { |
| 83 | + return false; |
| 84 | + } |
| 85 | + |
| 86 | + return true; |
| 87 | + } |
| 88 | + return true; |
| 89 | +} |
| 90 | + |
| 91 | +function main() { |
| 92 | + var countAllFiles = 0; |
| 93 | + var countFilesToTranslate = 0; |
| 94 | + |
| 95 | + // Create our temporary working directory |
| 96 | + fs.mkdirSync(commander.temp); |
| 97 | + |
| 98 | + // Copy the EN strings file |
| 99 | + copyFile(commander.pathToStrings, path.join(commander.temp, 'en.arbs')); |
| 100 | + countAllFiles++; |
| 101 | + |
| 102 | + // Walk the source directory and generate the appropriate files. |
| 103 | + recurseDir(commander.pathToEn, commander.pathToEn, function(filename) { |
| 104 | + if ((filename.endsWith('.html')) || (filename.endsWith('.markdown'))) { |
| 105 | + |
| 106 | + // Check if the file needs to be translated or not |
| 107 | + if (requiresTranslation(filename) === true) { |
| 108 | + |
| 109 | + // Create the new file name by removing the source path and flattening |
| 110 | + // the path down to a single directory. |
| 111 | + var newFilename = filename.replace(commander.pathToEn, ''); |
| 112 | + newFilename = newFilename.replace(/\//g, '_-_'); |
| 113 | + copyFile(filename, path.join(commander.temp, newFilename)); |
| 114 | + |
| 115 | + if (commander.verbose) { |
| 116 | + console.log(colors.green('\u2714 %s'), filename); |
| 117 | + } |
| 118 | + } else { |
| 119 | + if (commander.verbose) { |
| 120 | + console.log(colors.yellow('- %s'), filename); |
| 121 | + } |
| 122 | + } |
| 123 | + } |
| 124 | + countAllFiles++; |
| 125 | + }); |
| 126 | + |
| 127 | + var zip = new AdmZip(); |
| 128 | + recurseDir(commander.temp, commander.temp, function(filename) { |
| 129 | + zip.addLocalFile(filename); |
| 130 | + countFilesToTranslate++; |
| 131 | + }); |
| 132 | + zip.writeZip(commander.output); |
| 133 | + |
| 134 | + if (commander.keep !== true) { |
| 135 | + rimraf(commander.temp, function(err) { |
| 136 | + if (err) { |
| 137 | + console.log(colors.red('Error: Unable to remove temporary directory.')); |
| 138 | + } |
| 139 | + }); |
| 140 | + } |
| 141 | + |
| 142 | + console.log('Files inspected: ', countAllFiles); |
| 143 | + console.log('Files to translate: ', colors.green(countFilesToTranslate)); |
| 144 | + console.log('ZIP file created: ', colors.cyan(commander.output)); |
| 145 | +} |
| 146 | + |
| 147 | +function init() { |
| 148 | + var tempDir = '_exporttrans-' + Date.now(); |
| 149 | + var defaultFile = 'WebFundamentals-' + moment().format('YYYYMMDD') + '.zip'; |
| 150 | + console.log('WebFundamentals ExportTrans'); |
| 151 | + commander |
| 152 | + .version('0.0.1') |
| 153 | + .usage('[options]') |
| 154 | + .option('-p, --priority <#>', 'Maximum priority for files (1)', 1) |
| 155 | + .option('-d, --date <YYYY-MM-DD>', 'Cut off date for file selection (2000-01-01)', '2000-01-01') |
| 156 | + .option('-o, --output <filename>', 'ZIP file to create', defaultFile) |
| 157 | + .option('-t, --temp <path>', 'Temporary directory', tempDir) |
| 158 | + .option('-k, --keep', 'Keep temporary directory', false) |
| 159 | + .option('-v, --verbose', 'Verbose and debug output', false) |
| 160 | + .parse(process.argv); |
| 161 | + |
| 162 | + commander.date = moment(commander.date, 'YYYY-MM-DD'); |
| 163 | + commander.pathToEn = 'src/content/en/'; |
| 164 | + commander.pathToStrings = 'src/jekyll/_data/localized_strings/en.json'; |
| 165 | + |
| 166 | + if (fs.existsSync(commander.output) === true) { |
| 167 | + console.log(colors.yellow('Warning:'), 'output file exists, will be overwritten.'); |
| 168 | + } |
| 169 | + |
| 170 | + if (commander.date.isValid() === false) { |
| 171 | + console.log(colors.red('Error:'), 'Invalid date format, try 2014-01-01'); |
| 172 | + return; |
| 173 | + } |
| 174 | + |
| 175 | + var p = parseInt(commander.priority, 10); |
| 176 | + if ((p >= 0) && (p <= 10)) { |
| 177 | + commander.priority = p; |
| 178 | + } else { |
| 179 | + console.log(colors.red('Error:'), 'Invalid priority, must be an integer between 0-10'); |
| 180 | + return; |
| 181 | + } |
| 182 | + |
| 183 | + main(); |
| 184 | + |
| 185 | +} |
| 186 | + |
| 187 | +init(); |
0 commit comments