/**
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl.
*/
/* globals app, module, __dirname */
/* jshint esversion: 6 */
var translationProvider = require('../provider/translationProvider').factory.create(),
filterApi = require('./translationFilter'),
persistenceStore = require('./persistenceStore').factory.create(),
fileImporter = require('./sampleFileImporter'),
localeMap = require('./localeMap');
/**
* Download all the translated files.<br/>
* This involves downloading each file, merging the translated strings with the original file and creating a new file under the locale folder for the file.
* @constructor
* @alias SampleFileDownloader
*/
var SampleFileDownloader = function () {};
/**
* Download the translated file from the Language Service Provider.<br/>
* <ul>
* <li> For each target language:
* <ul>
* <li>Download the translation for the targeted language.</li>
* <li>Merge the translation with the original file.</li>
* <li>Save the combined file under a folder named for the targeted locale.</li>
* <li>If the file is a binary file, then download the translated binary file to a folder named for the targeted locale.</li>
* </ul>
* </li>
* </ul>
* @param {SampleJobManager.JobConfig} jobConfig - The configuration of the connector job to run. This information is held as metadata in the connector for the job.
* @param {string} jobId - The job identifier that contains this file.
* @param {SampleJobManager.file} file - Details on the site or assets file to import.
* @param {('site'|'assets')} fileType - The type of file being imported.
* @param {string} sourceLanguage - The source language for the file.
* @param {string[]} targetLanguages - Array of target languages for the file.
* @returns {Promise} A Promise that is resolved when all translations have been received.
*/
SampleFileDownloader.prototype.downloadFile = function (jobConfig, jobId, file, fileType, jobDetails) {
var sourceLanguage = jobDetails.sourceLanguage,
targetLanguages = jobDetails.targetLanguages;
return new Promise(function (resolve, reject) {
// ToDo: check if file has already been downloaded
// get the file metadata
persistenceStore.getFileMetadata({
jobId: jobConfig.properties.id,
fileType: fileType,
file: file
}).then(function (fileMetadata) {
if (fileMetadata.folderPath) {
// console.log('downloadFile binary file', fileMetadata.name);
var translatedBinaryFilePromises = [];
targetLanguages.forEach(function (targetLanguage) {
if (fileMetadata.documentId === fileImporter.EMPTY_DOCUMENT_ID) {
// See sampleFileImporter.js, importBinaryFile function.
console.log('SampleFileDownloader.downloadFile(): use original binary file for file -', file.name);
translatedBinaryFilePromises.push(persistenceStore.getBinaryFile({
jobId: jobId,
fileType: fileType,
file: file
}));
}
else {
translatedBinaryFilePromises.push(translationProvider.getBinaryTranslation(jobConfig.authToken, fileMetadata.documentId, targetLanguage));
}
});
Promise.all(translatedBinaryFilePromises).then(function (translatedBinaryFile) {
targetLanguages.forEach(function (targetLocale, index) {
if (translatedBinaryFile[index] && Object.keys(translatedBinaryFile[index]).length === 0) {
console.log('SampleFileDownloader.downloadFile(): no translated binary for file -', fileMetadata.name, 'for locale', targetLocale);
resolve();
}
else {
persistenceStore.addBinaryTranslationFile({
jobId: jobId,
locale: targetLocale,
fileType: fileType,
fileName: fileMetadata.name,
folderPath: fileMetadata.folderPath,
fileContent: translatedBinaryFile[index]
}).then(function () {
resolve();
}).catch(function (error) {
// failed to download translated file
console.log('SampleFileDownloader.downloadFile(): unable to persist binary translation file for file - ' + fileMetadata.name);
console.log(error);
reject(error);
});
}
});
});
}
else {
// read in the original file
persistenceStore.getSourceFile({
jobId: jobId,
fileType: fileType,
filePath: fileMetadata.path
}).then(function (fileContent) {
var originalFile = fileContent && fileContent.length > 0 ? JSON.parse(fileContent) : {};
// create promises to get all the translations for all the target languages
var translatedDocumentPromises = [];
targetLanguages.forEach(function (targetLanguage) {
if (targetLanguage === null) {
// handle unsupported locales
translatedDocumentPromises.push(Promise.resolve({}));
} else if (targetLanguage === sourceLanguage) {
// handle equivalent locales
translatedDocumentPromises.push(Promise.resolve({}));
} else if (fileMetadata.documentId === fileImporter.EMPTY_DOCUMENT_ID) {
// handle empty files
translatedDocumentPromises.push(Promise.resolve({}));
} else {
// handle translated file
translatedDocumentPromises.push(translationProvider.getTranslation(jobConfig.authToken, fileMetadata.documentId, targetLanguage));
}
});
// wait until we have all the translations
Promise.all(translatedDocumentPromises).then(function (translatedDocuments) {
// re-combine and save the translations
targetLanguages.forEach(function (targetLocale, index) {
// overwrite properties with the corresponding translations
var translation = filterApi.applyTranslation(originalFile, translatedDocuments[index], fileType);
// write this translation to all the original languages that map to this target locale
jobDetails.origTargetLanguages.forEach(function (origTargetLocale) {
var lspTargetLocale = localeMap.getLSPLocale(origTargetLocale);
// if this original locale maps to the lsp target locale
if (lspTargetLocale === targetLocale) {
// add the file to the zip
persistenceStore.addTranslationFile({
jobId: jobId,
locale: origTargetLocale,
fileType: fileType,
fileName: fileMetadata.path,
fileContent: JSON.stringify(translation)
}).then(function () {
resolve();
}).catch(function (error) {
// failed to download translated file
console.log('SampleFileDownloader.downloadFile(): unable to persist translation file for file - ' + fileMetadata.name);
console.log(e.toString());
reject(e);
});
}
});
});
}).catch(function (error) {
// failed to download translated file
console.log('SampleFileDownloader.downloadFile(): unable to download translation file for file - ' + fileMetadata.name);
console.log(error && error.toString());
reject(error);
});
}).catch(function (error) {
// failed to get original file
console.log('SampleFileDownloader.downloadFile(): unable to get original content for file - ' + fileMetadata.name);
console.log(error.toString());
reject(error);
});
}
}).catch(function (error) {
// failed to get metadata file
console.log('SampleFileDownloader.downloadFile(): unable to get metadata for original file - ' + file.name);
console.log(error && error.toString());
reject(error);
});
});
};
/**
* Create an array of Promises to download all the translations for all the files in the file list<br/>
* The promises are chained in a "return p1.then(return p2.then(return p3.then(...)))"" model to avoid overloading the Language Service Provider.
* @param {('site'|'assets')} fileType - The type of file being downloaded.
* @param {SampleJobManager.file} file - Details on the site or assets file to download.
* @returns {function[]} An array of functions, each of which returns a promise that resolves when all the translations for the file are downloaded.
*/
SampleFileDownloader.prototype.downloadFileList = function (jobConfig, jobDetails, fileType, files) {
var self = this;
// create the array of functions to return the import promises
return (files || []).map(function (file) {
return function () {
return self.downloadFile(jobConfig, jobConfig.properties.id, file, fileType, jobDetails);
};
});
};
/**
* Download all the translations for all the Site & Assets files into the Language Service Provider for this job <br/>
* The promises are chained in a "return p1.then(return p2.then(return p3.then(...)))"" model to avoid overloading the Language Service Provider.
* @param {SampleJobManager.JobConfig} jobConfig - The configuration of the connector job to run. This information is held as metadata in the connector for the job.
* @param {SampleJobManager.JobDetails} jobDetails - The details of the combined job.json files.
* @returns {Promise} A Promise that resolves when all files have been downloaded.
*/
SampleFileDownloader.prototype.downloadFiles = function (jobConfig, jobDetails) {
var self = this;
return new Promise(function (resolve, reject) {
// make sure necessary files are there and then import all the jobJSON files
if (jobDetails.sourceLanguage && jobDetails.targetLanguages) {
// create a repository for the translations
persistenceStore.createTranslationRepository({
jobId: jobConfig.properties.id,
}).then(function () {
// download the files into the translation zip
var downloadPromises = [];
if (jobDetails.assets) {
downloadPromises = downloadPromises.concat(self.downloadFileList(jobConfig, jobDetails, 'assets', jobDetails.assets && jobDetails.assets.files));
downloadPromises = downloadPromises.concat(self.downloadFileList(jobConfig, jobDetails, 'assets', jobDetails.assets && jobDetails.assets.binaryFiles));
}
if (jobDetails.site) {
downloadPromises = downloadPromises.concat(self.downloadFileList(jobConfig, jobDetails, 'site', jobDetails.site && jobDetails.site.files));
}
// now run through and download all the files
// chain the promises in the array so that they execute as: return p1.then(return p2.then(return p3.then(...)));
var doDownload = downloadPromises.reduce(function (previousPromise, nextPromise) {
return previousPromise.then(function () {
// wait for the previous promise to complete and then return a new promise for the next
return nextPromise();
});
},
// Start with a previousPromise value that is a resolved promise
Promise.resolve());
// once all files are downloaded, can continue
doDownload.then(function () {
console.log('SampleFileDownloader.downloadFiles(): all files downloaded');
resolve();
}).catch(function (e) {
console.log('SampleFileDownloader.downloadFiles(): error downloading files');
console.log(e);
reject(e);
});
});
} else {
reject('no target language specified in job.json files');
}
});
};
module.exports = new SampleFileDownloader();