wallet-core/node_modules/gettext-parser/lib/pocompiler.js
2016-10-10 03:43:44 +02:00

225 lines
6.1 KiB
JavaScript

'use strict';
var encoding = require('encoding');
var sharedFuncs = require('./shared');
/**
* Exposes general compiler function. Takes a translation
* object as a parameter and returns PO object
*
* @param {Object} table Translation object
* @return {Buffer} Compiled PO object
*/
module.exports = function(table) {
var compiler = new Compiler(table);
return compiler.compile();
};
/**
* Creates a PO compiler object.
*
* @constructor
* @param {Object} table Translation table to be compiled
*/
function Compiler(table) {
this._table = table || {};
this._table.headers = this._table.headers || {};
this._table.translations = this._table.translations || {};
this._translations = [];
this._handleCharset();
}
/**
* Converts a comments object to a comment string. The comment object is
* in the form of {translator:'', reference: '', extracted: '', flag: '', previous:''}
*
* @param {Object} comments A comments object
* @return {String} A comment string for the PO file
*/
Compiler.prototype._drawComments = function(comments) {
var lines = [];
var types = [{
key: 'translator',
prefix: '# '
}, {
key: 'reference',
prefix: '#: '
}, {
key: 'extracted',
prefix: '#. '
}, {
key: 'flag',
prefix: '#, '
}, {
key: 'previous',
prefix: '#| '
}];
types.forEach(function(type) {
if (!comments[type.key]) {
return;
}
comments[type.key].split(/\r?\n|\r/).forEach(function(line) {
lines.push(type.prefix + line);
});
});
return lines.join('\n');
};
/**
* Builds a PO string for a single translation object
*
* @param {Object} block Translation object
* @param {Object} [override] Properties of this object will override `block` properties
* @return {String} Translation string for a single object
*/
Compiler.prototype._drawBlock = function(block, override) {
override = override || {};
var response = [],
comments = override.comments || block.comments,
msgctxt = override.msgctxt || block.msgctxt,
msgid = override.msgid || block.msgid,
msgid_plural = override.msgid_plural || block.msgid_plural,
msgstr = [].concat(override.msgstr || block.msgstr);
// add comments
if (comments && (comments = this._drawComments(comments))) {
response.push(comments);
}
if (msgctxt) {
response.push(this._addPOString('msgctxt', msgctxt));
}
response.push(this._addPOString('msgid', msgid || ''));
if (msgid_plural) {
response.push(this._addPOString('msgid_plural', msgid_plural));
}
if (msgstr.length <= 1) {
response.push(this._addPOString('msgstr', msgstr[0] || ''));
} else {
msgstr.forEach((function(msgstr, i) {
response.push(this._addPOString('msgstr[' + i + ']', msgstr || ''));
}).bind(this));
}
return response.join('\n');
};
/**
* Escapes and joins a key and a value for the PO string
*
* @param {String} key Key name
* @param {String} value Key value
* @return {String} Joined and escaped key-value pair
*/
Compiler.prototype._addPOString = function(key, value) {
var line;
key = (key || '').toString();
// escape newlines and quotes
value = (value || '').toString().
replace(/\\/g, '\\\\').
replace(/"/g, '\\"').
replace(/\t/g, '\\t').
replace(/\r/g, '\\r').
replace(/\n/g, '\\n');
var lines = sharedFuncs.foldLine(value);
if (lines.length < 2) {
return key + ' "' + (lines.shift() || '') + '"';
} else {
return key + ' ""\n"' + lines.join('"\n"') + '"';
}
if (value.match(/\n/)) {
value = value.replace(/\n/g, '\\n\n').replace(/\n$/, '');
line = ('\n' + value).split('\n').map(function(l) {
return '"' + l + '"';
}).join('\n');
} else {
line = '"' + value + '"';
}
return key + ' ' + line;
};
/**
* Handles header values, replaces or adds (if needed) a charset property
*/
Compiler.prototype._handleCharset = function() {
var parts = (this._table.headers['content-type'] || 'text/plain').split(';');
var contentType = parts.shift();
var charset = sharedFuncs.formatCharset(this._table.charset);
var params = [];
params = parts.map(function(part) {
var parts = part.split('='),
key = parts.shift().trim(),
value = parts.join('=');
if (key.toLowerCase() === 'charset') {
if (!charset) {
charset = sharedFuncs.formatCharset(value.trim() || 'utf-8');
}
return 'charset=' + charset;
}
return part;
});
if (!charset) {
charset = this._table.charset || 'utf-8';
params.push('charset=' + charset);
}
this._table.charset = charset;
this._table.headers['content-type'] = contentType + '; ' + params.join('; ');
this._charset = charset;
};
/**
* Compiles translation object into a PO object
*
* @return {Buffer} Compiled PO object
*/
Compiler.prototype.compile = function() {
var response = [],
headerBlock = this._table.translations[''] && this._table.translations[''][''] || {};
response.push(this._drawBlock(headerBlock, {
msgstr: sharedFuncs.generateHeader(this._table.headers)
}));
Object.keys(this._table.translations).forEach((function(msgctxt) {
if (typeof this._table.translations[msgctxt] !== 'object') {
return;
}
Object.keys(this._table.translations[msgctxt]).forEach((function(msgid) {
if (typeof this._table.translations[msgctxt][msgid] !== 'object') {
return;
}
if (msgctxt === '' && msgid === '') {
return;
}
response.push(this._drawBlock(this._table.translations[msgctxt][msgid]));
}).bind(this));
}).bind(this));
if (this._charset === 'utf-8' || this._charset === 'ascii') {
return new Buffer(response.join('\n\n'), 'utf-8');
} else {
return encoding.convert(response.join('\n\n'), this._charset);
}
};