aboutsummaryrefslogtreecommitdiff
path: root/node_modules/gettext-parser/lib/moparser.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/gettext-parser/lib/moparser.js')
-rw-r--r--node_modules/gettext-parser/lib/moparser.js202
1 files changed, 202 insertions, 0 deletions
diff --git a/node_modules/gettext-parser/lib/moparser.js b/node_modules/gettext-parser/lib/moparser.js
new file mode 100644
index 000000000..8c204716b
--- /dev/null
+++ b/node_modules/gettext-parser/lib/moparser.js
@@ -0,0 +1,202 @@
+'use strict';
+
+var encoding = require('encoding');
+var sharedFuncs = require('./shared');
+
+/**
+ * Parses a binary MO object into translation table
+ *
+ * @param {Buffer} buffer Binary MO object
+ * @param {String} [defaultCharset] Default charset to use
+ * @return {Object} Translation object
+ */
+module.exports = function(buffer, defaultCharset) {
+ var parser = new Parser(buffer, defaultCharset);
+ return parser.parse();
+};
+
+/**
+ * Creates a MO parser object.
+ *
+ * @constructor
+ * @param {Buffer} fileContents Binary MO object
+ * @param {String} [defaultCharset] Default charset to use
+ */
+function Parser(fileContents, defaultCharset) {
+
+ this._fileContents = fileContents;
+
+ /**
+ * Method name for writing int32 values, default littleendian
+ */
+ this._writeFunc = 'writeUInt32LE';
+
+ /**
+ * Method name for reading int32 values, default littleendian
+ */
+ this._readFunc = 'readUInt32LE';
+
+ this._charset = defaultCharset || 'iso-8859-1';
+
+ this._table = {
+ charset: this._charset,
+ headers: undefined,
+ translations: {}
+ };
+}
+
+/**
+ * Magic constant to check the endianness of the input file
+ */
+Parser.prototype.MAGIC = 0x950412de;
+
+/**
+ * Checks if number values in the input file are in big- or littleendian format.
+ *
+ * @return {Boolean} Return true if magic was detected
+ */
+Parser.prototype._checkMagick = function() {
+ if (this._fileContents.readUInt32LE(0) === this.MAGIC) {
+ this._readFunc = 'readUInt32LE';
+ this._writeFunc = 'writeUInt32LE';
+ return true;
+ } else if (this._fileContents.readUInt32BE(0) === this.MAGIC) {
+ this._readFunc = 'readUInt32BE';
+ this._writeFunc = 'writeUInt32BE';
+ return true;
+ } else {
+ return false;
+ }
+};
+
+/**
+ * Read the original strings and translations from the input MO file. Use the
+ * first translation string in the file as the header.
+ */
+Parser.prototype._loadTranslationTable = function() {
+ var offsetOriginals = this._offsetOriginals,
+ offsetTranslations = this._offsetTranslations,
+ position, length,
+ msgid, msgstr;
+
+ for (var i = 0; i < this._total; i++) {
+ // msgid string
+ length = this._fileContents[this._readFunc](offsetOriginals);
+ offsetOriginals += 4;
+ position = this._fileContents[this._readFunc](offsetOriginals);
+ offsetOriginals += 4;
+ msgid = this._fileContents.slice(position, position + length);
+
+ // matching msgstr
+ length = this._fileContents[this._readFunc](offsetTranslations);
+ offsetTranslations += 4;
+ position = this._fileContents[this._readFunc](offsetTranslations);
+ offsetTranslations += 4;
+ msgstr = this._fileContents.slice(position, position + length);
+
+ if (!i && !msgid.toString()) {
+ this._handleCharset(msgstr);
+ }
+
+ msgid = encoding.convert(msgid, 'utf-8', this._charset).toString('utf-8');
+ msgstr = encoding.convert(msgstr, 'utf-8', this._charset).toString('utf-8');
+
+ this._addString(msgid, msgstr);
+ }
+
+ // dump the file contents object
+ this._fileContents = null;
+};
+
+/**
+ * Detects charset for MO strings from the header
+ *
+ * @param {Buffer} headers Header value
+ */
+Parser.prototype._handleCharset = function(headers) {
+
+ var headersStr = headers.toString(),
+ match;
+
+ if ((match = headersStr.match(/[; ]charset\s*=\s*([\w\-]+)/i))) {
+ this._charset = this._table.charset = sharedFuncs.formatCharset(match[1], this._charset);
+ }
+
+ headers = encoding.convert(headers, 'utf-8', this._charset).toString('utf-8');
+
+ this._table.headers = sharedFuncs.parseHeader(headers);
+};
+
+/**
+ * Adds a translation to the translation object
+ *
+ * @param {String} msgid Original string
+ * @params {String} msgstr Translation for the original string
+ */
+Parser.prototype._addString = function(msgid, msgstr) {
+ var translation = {},
+ parts, msgctxt, msgid_plural;
+
+ msgid = msgid.split('\u0004');
+ if (msgid.length > 1) {
+ msgctxt = msgid.shift();
+ translation.msgctxt = msgctxt;
+ } else {
+ msgctxt = '';
+ }
+ msgid = msgid.join('\u0004');
+
+ parts = msgid.split('\u0000');
+ msgid = parts.shift();
+
+ translation.msgid = msgid;
+
+ if ((msgid_plural = parts.join('\u0000'))) {
+ translation.msgid_plural = msgid_plural;
+ }
+
+ msgstr = msgstr.split('\u0000');
+ translation.msgstr = [].concat(msgstr || []);
+
+ if (!this._table.translations[msgctxt]) {
+ this._table.translations[msgctxt] = {};
+ }
+
+ this._table.translations[msgctxt][msgid] = translation;
+};
+
+/**
+ * Parses the MO object and returns translation table
+ *
+ * @return {Object} Translation table
+ */
+Parser.prototype.parse = function() {
+ if (!this._checkMagick()) {
+ return false;
+ }
+
+ /**
+ * GetText revision nr, usually 0
+ */
+ this._revision = this._fileContents[this._readFunc](4);
+
+ /**
+ * Total count of translated strings
+ */
+ this._total = this._fileContents[this._readFunc](8);
+
+ /**
+ * Offset position for original strings table
+ */
+ this._offsetOriginals = this._fileContents[this._readFunc](12);
+
+ /**
+ * Offset position for translation strings table
+ */
+ this._offsetTranslations = this._fileContents[this._readFunc](16);
+
+ // Load translations into this._translationTable
+ this._loadTranslationTable();
+
+ return this._table;
+}; \ No newline at end of file