UNPKG

i18nucleus-transifex

Version:
319 lines (289 loc) 10.3 kB
var pjson = require('./package.json') , path = require('path') , os = require('os') , Transifex = require('transifex') , async = require('breeze-async') , request = require('request') , _ = require('underscore') , countryLanguage = require('country-language') , flat = require('flat') , fs = require('node-fs') , rmdir = require('rimraf') , colors = require('colors') , defineOptions = require('./options') , baseUrl = 'https://www.transifex.com/api/2/' , transifex = null; _.mixin(require('underscore.string')) function i18nucleus_transifex () { var version = pjson.version , type = 'translationProvider' , name = pjson.name , options = {} , utils = null , parentOptions = null , MwareError = null , namespaces = [] , authHeader = ''; function setOptions (_options, _utils) { utils = _utils; var optionObj = defineOptions(_options, utils); if (!optionObj.err) { options = optionObj.options; } return optionObj; } function init (_parentOptions, _MwareError, cb) { var credential = options.username + ':' + options.password; parentOptions = _parentOptions; MwareError = _MwareError; namespaces = parentOptions.namespaces; transifex = new Transifex({ project_slug: options.projectSlug , credential: credential }); authHeader = 'Basic ' + new Buffer(credential).toString('base64'); cb(); } function adaptNsForTransifex (ns) { var trimChars = [ '\\.' ] // TODO: add other charapters need to be stripped , reg = null , res = ns; trimChars.forEach(function (chr) { reg = new RegExp(chr, 'g'); res = res.replace(reg, ''); }); return res; } function getLocalesSummary (cb) { var defaultLng = parentOptions.defaultLng , languagesInfo = [] , countriesInfo = [] , resObj = []; function pushToResArray (language, data) { var langInfo = _.find(languagesInfo, function (lInfo) { return lInfo.locale == language }).language , countryInfo = _.find(countriesInfo, function (lInfo) { return lInfo.locale == language }).country resObj.push({ locale: language , region: countryInfo.name , name: { local: langInfo.nativeName[0] , english: langInfo.name[0] } , translatedTerms: data[language].translated_entities , totalTerms: data[language].translated_entities + data[language].untranslated_entities , is_base_language: language == defaultLng }); } function nsIterrator (ns, next) { var nsSlug = adaptNsForTransifex(ns) , res = {} , lngCountryPairs = []; transifex.statisticsMethods(options.projectSlug, nsSlug, function (err, data) { if (err) { if (_.endsWith(err.message, 'returned 404')) { // namespace does not exist yet on Transifex next(); } else { next(err); } } else { if (resObj.length == 0) { var lngCountryPairs = utils.splitLocalesTo_lngCountries(_.keys(data)); languagesInfo = lngCountryPairs[0] countriesInfo = lngCountryPairs[1] pushToResArray(defaultLng, data); _.keys(data).forEach(function (locale) { if (locale != defaultLng) { pushToResArray(locale, data); } }); } else { _.keys(data).forEach(function (locale) { res = _.find(resObj, function (item) { return item.locale == locale }); res.translatedTerms += data[locale].translated_entities; res.totalTerms += data[locale].translated_entities + data[locale].untranslated_entities; res.completeness = parseInt(res.translatedTerms / res.totalTerms * 1000) / 10; }); } next(); } }); } function finish (err) { if (err) { return cb(new MwareError(err, name)); } else { resObj.forEach(function (res) { delete res.translatedTerms; delete res.totalTerms; }); return cb(null, resObj); } } async.forEachSeries( namespaces , nsIterrator , finish ); } function getTranslations (locale, cb) { var totalTerms = 0 , retObj = { translations: {} } , missedNss = []; function nsIterrator (ns, next) { var nsSlug = adaptNsForTransifex(ns); function getTermsNumber (next_int) { var translatedTerms = []; transifex.translationStringsMethod(options.projectSlug, nsSlug, locale, function (err, data) { if (err) { if (_.endsWith(err.message, 'returned 404')) { missedNss.push(ns); next(); } else { next_int(err); } } else { data = JSON.parse(data); translatedTerms = _.filter(data, function (term) { return term.translation != '' }); totalTerms += translatedTerms.length; next_int(null, true); } }); } function getTerms (next_int) { transifex.translationInstanceMethod(options.projectSlug, nsSlug, locale, function (err, data) { if (err) { next_int(err); } else { retObj.translations[ns] = JSON.parse(data); next_int(null, true); } }); } async.series([ getTermsNumber , getTerms ], next); } function finish (err) { if (err) { return cb(new MwareError(err, name)); } else { retObj.totalTerms = totalTerms; if (missedNss.length) { retObj.missingNamespaces = missedNss; } return cb(null, retObj); } } async.forEachSeries( namespaces , nsIterrator , finish ); } function updateResources (resources, cb) { var totalTerms = 0 , totalAdded = 0 , totalDeleted = 0; function resIterrator (resource, next) { if (options.ignoredNamespaces.indexOf(resource.namespace) == -1) { var ns = resource.namespace , nsSlug = adaptNsForTransifex(ns) , resourceData = resource.resources , resourceDataStr = JSON.stringify(resource.resources) , rand = Math.floor(Math.random() * 1000000000) , environment = process.env.NODE_ENV , tmpFilePath = ((environment == 'development') ? path.dirname(require.main.filename) + '/tmp' : os.tmpdir()) + '/' + rand , filePath = tmpFilePath + '/' + ns + '.json' , url = baseUrl + 'project/' + options.projectSlug + '/resource/' + nsSlug + '/content/' , requestParams = { url: url , options: {} , headers: { 'Authorization': authHeader } } fs.mkdir(tmpFilePath, 0777, true, function (err) { if (err) { return next(err); } else { fs.writeFile(filePath, resourceDataStr, { mode: 777 }, function (err) { if (err) { return next(err); } else { var r = request.put(requestParams, function (err, incomingMsg, response) { if (err) { return next(err); } else if (response.indexOf('Not Found') > -1) { requestParams.url = baseUrl + 'project/' + options.projectSlug + '/resources/'; delete requestParams.options; var r2 = request.post(requestParams, function (err, incomingMsg, response) { if (err) { return next(err); } else { rmdir(tmpFilePath, function (err) { if (err) { console.log(('WARNING: Resources temp file ' + filePath + ' could not be deleted.').magenta); } }); var flatResources = flat.flatten(resourceData); totalAdded += _.size(flatResources); totalTerms += _.size(flatResources); next(); } }); var form2 = r2.form(); form2.append('slug', nsSlug); form2.append('name', ns); form2.append('accept_translations', 'true'); form2.append('i18n_type', 'KEYVALUEJSON'); form2.append('content', fs.createReadStream(filePath)); } else { var responseObj = JSON.parse(response); totalAdded += responseObj.strings_added + responseObj.strings_updated; totalDeleted += responseObj.strings_delete; rmdir(tmpFilePath, function (err) { if (err) { console.log(('WARNING: Resources temp file ' + filePath + ' could not be deleted.').magenta); } }); var flatResources = flat.flatten(resourceData); totalTerms += _.size(flatResources); next(); } }); var form = r.form(); form.append('content', fs.createReadStream(filePath)); } }); } }); } } function finish (err) { if (err) { return cb(new MwareError(err, name)); } else { console.log(('Resource strings updated in Transifex. Strings added/updated: ' + totalAdded + ', strings deleted: ' + totalDeleted).green); cb(null, { totalTerms: totalTerms }); } } async.forEach( resources , resIterrator , finish ); } return { version: version , type: type , name: name , setOptions: setOptions , init: init , options: options , getLocalesSummary: getLocalesSummary , getTranslations: getTranslations , updateResources: updateResources } } module.exports = i18nucleus_transifex;