scratch-www/bin/build-locales
2016-05-19 10:43:25 -04:00

168 lines
5.8 KiB
JavaScript
Executable file

#!/usr/bin/env node
/*
Converts the existing .po translation files in the module to JSON files.
Requires po2json in order to work. Takes as input a directory
in which to store the resulting json translation files.
Takes in as an argument an output directory to put translation files.
Searches for files named `l10n.json` in the `src/views/` directory to get
template english strings (as well as the general template at `src/l10n.json`).
It compiles the template strings into a flat object that is compared against the
translations in the .po files from the `scratchr2_translations` dependency, using
an md5 of the template string without whitespace, and an md5 of the .po msgid string
without whitespace.
The output files are javascript files that declare objects by locale. Each locale
has a sub-object with FormattedMessage ids as keys, and translated strings as
values. If no translation was found for a string, the default english will be the
value.
Output Example:
'''
var message = {
en: {
'general.inAWorld': 'In a world, where bears are invisible...',
'general.question': 'Are there bears here?',
'general.answer': 'I dunno, but there could be...'
},
es: {
'general.inAWorld': 'En un mundo, donde hay osos invisibles',
'general.question': 'Are there bears here?',
'general.answer': 'No sé, pero es posible...'
}
}
'''
*/
var fs = require('fs');
var merge = require('lodash.merge');
var path = require('path');
var languages = require('../languages.json');
var localeCompare = require('./lib/locale-compare');
var localizedUrls = require('./lib/localized-urls');
var routes = require('../src/routes.json');
// -----------------------------------------------------------------------------
// Main script
// -----------------------------------------------------------------------------
var args = process.argv.slice(2);
if (!args.length) {
process.stdout.write('A destination directory must be specified.');
process.exit(1);
}
var outputDir = path.resolve(__dirname, '../', args[0]);
try {
fs.accessSync(outputDir, fs.F_OK);
} catch (err) {
// Doesn't exist - create it.
fs.mkdirSync(outputDir);
}
// get global locale strings first.
var globalTemplateFile = path.resolve(__dirname, '../src/l10n.json');
var ids = require(globalTemplateFile);
// var ids = JSON.parse(fs.readFileSync(globalTemplateFile, 'utf8'));
// message key with english string values (i.e. default values)
var viewLocales = {
general: {
en: ids
}
};
var idsWithICU = localeCompare.idToICUMap('general', ids);
var icuWithIds = localeCompare.icuToIdMap('general', ids);
var views = [];
var localizedAssetUrls = {};
// start with all views, and remove localized ones as they are iterated over
for (var v in routes) {
if (typeof routes[v].redirect !== 'undefined') {
continue;
}
views.push(routes[v].name);
try {
var subdir = routes[v].view.split('/');
subdir.pop();
var l10n = path.resolve(__dirname, '../src/views/' + subdir.join('/') + '/l10n.json');
ids = require(l10n);
viewLocales[routes[v].name] = {
en: ids
};
idsWithICU = merge(idsWithICU, localeCompare.idToICUMap(routes[v].name, ids));
icuWithIds = merge(icuWithIds, localeCompare.icuToIdMap(routes[v].name, ids));
} catch (err) {
if (err.code !== 'MODULE_NOT_FOUND') {
throw err;
}
try {
fs.accessSync(path.resolve(__dirname, '../src/views/' + routes[v].view + '.jsx'));
} catch (err) {
// the config for the view is not set up correctly, so throw the error.
throw err;
}
}
// get asset url translations
try {
subdir = routes[v].view.split('/');
subdir.pop();
var l10nStatic = path.resolve(__dirname, '../src/views/' + subdir.join('/') + '/l10n-static.json');
localizedAssetUrls[routes[v].name] = {};
var assetUrls = require(l10nStatic);
for (var lang in localizedUrls) {
localizedAssetUrls[routes[v].name][lang] = {};
for (var key in assetUrls) {
if (localizedUrls[lang].hasOwnProperty(key)) {
localizedAssetUrls[routes[v].name][lang][key] = localizedUrls[lang][key];
} else {
localizedAssetUrls[routes[v].name][lang][key] = assetUrls[key];
}
}
}
} catch (err) {
if (err.code !== 'MODULE_NOT_FOUND') {
throw err;
}
try {
fs.accessSync(path.resolve(__dirname, '../src/views/' + routes[v].view + '.jsx'));
} catch (err) {
// the config for the view is not set up correctly, so throw the error.
throw err;
}
}
}
// md5 of english strings with message key as the value for searching po files.
// Sample structure: { 'sdfas43534sdfasdf': 'general-general.blah', 'lkjfasdf4t342asdfa': 'about-about.blah' }
var md5WithIds = localeCompare.getMD5Map(icuWithIds);
// Get ui localization strings first
var isoCodes = Object.keys(languages);
for (var isoCode in isoCodes) {
var translations = localeCompare.getTranslationsForLanguage(isoCodes[isoCode], idsWithICU, md5WithIds);
for (var messageId in translations) {
viewLocales[messageId] = merge(viewLocales[messageId], translations[messageId]);
}
}
for (var view in views) {
var viewTranslations = viewLocales['general'];
if (views[view] in viewLocales) {
viewTranslations = merge(viewLocales[views[view]], viewTranslations);
}
if (views[view] in localizedAssetUrls) {
viewTranslations = merge(viewTranslations, localizedAssetUrls[[views[view]]]);
}
localeCompare.writeTranslationsToJS(outputDir, views[view], viewTranslations);
}