2016-01-08 13:50:58 -05:00
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// Helper Methods for build-locales node script.
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
var crypto = require('crypto');
|
2016-03-23 08:22:09 -04:00
|
|
|
|
var fs = require('fs');
|
|
|
|
|
var path = require('path');
|
|
|
|
|
var po2icu = require('po2icu');
|
2016-01-08 13:50:58 -05:00
|
|
|
|
|
|
|
|
|
var Helpers = {};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the md5 has of a string with whitespace removed.
|
|
|
|
|
*
|
|
|
|
|
* @param {string} string a string
|
|
|
|
|
* @return {string} an md5 hash of the string in hex.
|
|
|
|
|
*/
|
|
|
|
|
Helpers.getMD5 = function (string) {
|
|
|
|
|
var cleanedString = string.replace(/\s+/g, '');
|
|
|
|
|
return crypto.createHash('md5').update(cleanedString, 'utf8').digest('hex');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Existing translations should be in the key value format specified by react-intl (i.e.
|
|
|
|
|
formatted message id, with icu string as the value). New Translations should be in the
|
|
|
|
|
format returned by po2icu (i.e. a source language icu string for key, and a localized
|
|
|
|
|
language icu string for value).
|
|
|
|
|
|
|
|
|
|
ICU Map is an object in the reverse react-intl formatting (icu string as key), which will
|
|
|
|
|
help determine if the translation belongs in www currently.
|
|
|
|
|
*/
|
|
|
|
|
Helpers.mergeNewTranslations = function (existingTranslations, newTranslations, icuTemplate, md5Map) {
|
|
|
|
|
for (var id in newTranslations) {
|
|
|
|
|
var md5 = Helpers.getMD5(id);
|
|
|
|
|
if (md5Map.hasOwnProperty(md5) && newTranslations[id].length > 0) {
|
|
|
|
|
existingTranslations[md5Map[md5]] = newTranslations[id];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Fill in defaults
|
2016-04-19 10:47:33 -04:00
|
|
|
|
for (var icuId in icuTemplate) {
|
|
|
|
|
if (!existingTranslations.hasOwnProperty(icuId)) existingTranslations[icuId] = icuTemplate[icuId];
|
2016-01-08 13:50:58 -05:00
|
|
|
|
}
|
|
|
|
|
return existingTranslations;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts a map of icu strings with react-intl id values into a map
|
|
|
|
|
* with md5 hashes of the icu strings as keys and react-intl id values.
|
|
|
|
|
* This is done so as to eliminate potential po conversion misses that
|
|
|
|
|
* could be caused by different white space formatting between po and icu.
|
|
|
|
|
*
|
|
|
|
|
* The md5 is generated after all white space is removed from the string.
|
|
|
|
|
*
|
|
|
|
|
* @param {object} idICUMap map where key=icuString, value=react-intl id
|
|
|
|
|
*
|
|
|
|
|
* @return {object}
|
|
|
|
|
*/
|
|
|
|
|
Helpers.getMD5Map = function (ICUIdMap) {
|
|
|
|
|
var md5Map = {};
|
|
|
|
|
for (var icu in ICUIdMap) {
|
|
|
|
|
var md5 = Helpers.getMD5(icu);
|
|
|
|
|
md5Map[md5] = ICUIdMap[icu];
|
|
|
|
|
}
|
|
|
|
|
return md5Map;
|
|
|
|
|
};
|
|
|
|
|
|
2016-03-23 08:22:09 -04:00
|
|
|
|
/**
|
|
|
|
|
* Grabs the translated strings from the po files for the given language and strings
|
|
|
|
|
* @param {str} lang iso code of the language to use
|
|
|
|
|
* @param {object} idsWithICU key: '<viewName>-<react-intl string id>'.
|
|
|
|
|
* value: english strings for translation
|
|
|
|
|
* @param {object} md5WithIds key: md5 hash of the english strings for translation.
|
|
|
|
|
* value: '<viewName>-<react-intl string id>'
|
|
|
|
|
* @return {object} translations – sub-objects by view containing:
|
|
|
|
|
* key: '<react-intl string id>'
|
|
|
|
|
* value: translated version of string
|
|
|
|
|
*/
|
2016-07-01 14:27:41 -04:00
|
|
|
|
Helpers.getTranslationsForLanguage = function (lang, idsWithICU, md5WithIds, separator) {
|
2016-03-23 08:22:09 -04:00
|
|
|
|
var poUiDir = path.resolve(__dirname, '../../node_modules/scratchr2_translations/ui');
|
|
|
|
|
var jsFile = path.resolve(poUiDir, lang + '/LC_MESSAGES/djangojs.po');
|
|
|
|
|
var pyFile = path.resolve(poUiDir, lang + '/LC_MESSAGES/django.po');
|
|
|
|
|
|
|
|
|
|
var translations = {};
|
2016-07-01 14:27:41 -04:00
|
|
|
|
separator = separator || ':';
|
|
|
|
|
|
2016-03-23 08:22:09 -04:00
|
|
|
|
try {
|
|
|
|
|
fs.accessSync(jsFile, fs.R_OK);
|
|
|
|
|
var jsTranslations = po2icu.poFileToICUSync(lang, jsFile);
|
|
|
|
|
translations = Helpers.mergeNewTranslations(translations, jsTranslations, idsWithICU, md5WithIds);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
if (err.code !== 'ENOENT') {
|
|
|
|
|
throw err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
fs.accessSync(pyFile, fs.R_OK);
|
|
|
|
|
var pyTranslations = po2icu.poFileToICUSync(lang, pyFile);
|
|
|
|
|
translations = Helpers.mergeNewTranslations(translations, pyTranslations, idsWithICU, md5WithIds);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
if (err.code !== 'ENOENT') {
|
|
|
|
|
throw err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var translationsByView = {};
|
|
|
|
|
for (var id in translations) {
|
2016-07-01 14:27:41 -04:00
|
|
|
|
var ids = id.split(separator); // [viewName, stringId]
|
2016-03-23 08:22:09 -04:00
|
|
|
|
var viewName = ids[0];
|
|
|
|
|
var stringId = ids[1];
|
|
|
|
|
|
|
|
|
|
if (!translationsByView.hasOwnProperty(viewName)) {
|
|
|
|
|
translationsByView[viewName] = {};
|
|
|
|
|
}
|
|
|
|
|
if (!translationsByView[viewName].hasOwnProperty(lang)) {
|
|
|
|
|
translationsByView[viewName][lang] = {};
|
|
|
|
|
}
|
|
|
|
|
translationsByView[viewName][lang][stringId] = translations[id];
|
|
|
|
|
}
|
|
|
|
|
return translationsByView;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Helpers.writeTranslationsToJS = function (outputDir, viewName, translationObject) {
|
|
|
|
|
var objectString = JSON.stringify(translationObject);
|
|
|
|
|
var fileString = 'window._messages = ' + objectString + ';';
|
|
|
|
|
fs.writeFileSync(outputDir + '/' + viewName + '.intl.js', fileString);
|
|
|
|
|
};
|
|
|
|
|
|
2016-05-17 15:56:06 -04:00
|
|
|
|
// Returns a FormattedMessage id with english string as value. Use for default values in translations
|
|
|
|
|
// Sample structure: { 'general-general.blah': 'blah', 'about-about.blah': 'blahblah' }
|
2016-07-01 14:27:41 -04:00
|
|
|
|
Helpers.idToICUMap = function (viewName, ids, separator) {
|
2016-05-17 15:56:06 -04:00
|
|
|
|
var idsToICU = {};
|
2016-07-01 14:27:41 -04:00
|
|
|
|
separator = separator || ':';
|
|
|
|
|
|
2016-03-23 08:22:09 -04:00
|
|
|
|
for (var id in ids) {
|
2016-07-01 14:27:41 -04:00
|
|
|
|
idsToICU[viewName + separator + id] = ids[id];
|
2016-03-23 08:22:09 -04:00
|
|
|
|
}
|
2016-05-17 15:56:06 -04:00
|
|
|
|
return idsToICU;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Reuturns reverse (i.e. english string with message key as the value) object for searching po files.
|
|
|
|
|
// Sample structure: { 'blah': 'general-general.blah', 'blahblah': 'about-about.blah' }
|
2016-07-01 14:27:41 -04:00
|
|
|
|
Helpers.icuToIdMap = function (viewName, ids, separator) {
|
2016-05-17 15:56:06 -04:00
|
|
|
|
var icuToIds = {};
|
2016-07-01 14:27:41 -04:00
|
|
|
|
separator = separator || ':';
|
|
|
|
|
|
2016-05-17 15:56:06 -04:00
|
|
|
|
for (var id in ids) {
|
2016-07-01 14:27:41 -04:00
|
|
|
|
icuToIds[ids[id]] = viewName + separator + id;
|
2016-05-17 15:56:06 -04:00
|
|
|
|
}
|
|
|
|
|
return icuToIds;
|
2016-03-23 08:22:09 -04:00
|
|
|
|
};
|
|
|
|
|
|
2016-01-08 13:50:58 -05:00
|
|
|
|
module.exports = Helpers;
|