node-gettext
Advanced tools
Comparing version 0.2.5 to 0.2.6
var Iconv = require("iconv").Iconv, | ||
pluralsInfo = require("./plurals.json"); | ||
pluralsInfo = require("./plurals.json"), | ||
POParser = require("./poparser"); | ||
/* | ||
* TODO: msgid_plural is currently not used - why is it needed anyway? | ||
* TODO: comments from PO files are not used but should be | ||
*/ | ||
// Expose to the world | ||
@@ -69,26 +75,29 @@ module.exports = GettextDomain; | ||
// Check endianness of the file | ||
this._checkMagick(); | ||
/** | ||
* GetText revision nr, usually 0 | ||
*/ | ||
this.revision = this._fileContents[this._readFunc](4); | ||
if(this._checkMagick()){ | ||
/** | ||
* 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); | ||
/** | ||
* 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(); | ||
// Load translations into this._translationTable | ||
this._loadMOTranslationTable(); | ||
}else{ | ||
// Load translations into this._translationTable | ||
this._loadPOTranslationTable(); | ||
} | ||
} | ||
@@ -131,3 +140,3 @@ | ||
* | ||
* If magic is not found, throw an error | ||
* @return {Boolean} Return true if magic was detected | ||
*/ | ||
@@ -138,7 +147,9 @@ GettextDomain.prototype._checkMagick = function(){ | ||
this._writeFunc = "writeUInt32LE"; | ||
return true; | ||
}else if(this._fileContents.readUInt32BE(0) == this.MAGIC){ | ||
this._readFunc = "readUInt32BE"; | ||
this._writeFunc = "writeUInt32BE"; | ||
return true; | ||
}else{ | ||
throw new Error("Invalid magic!"); | ||
return false; | ||
} | ||
@@ -148,6 +159,6 @@ }; | ||
/** | ||
* Read the original strings and translations from the input file. Use the | ||
* Read the original strings and translations from the input MO file. Use the | ||
* first translation string in the file as the header. | ||
*/ | ||
GettextDomain.prototype._loadTranslationTable = function(){ | ||
GettextDomain.prototype._loadMOTranslationTable = function(){ | ||
var offsetOriginals = this._offsetOriginals, | ||
@@ -188,2 +199,28 @@ offsetTranslations = this._offsetTranslations, | ||
/** | ||
* Read the original strings and translations from the input PO file. Use the | ||
* first translation string in the file as the header. | ||
*/ | ||
GettextDomain.prototype._loadPOTranslationTable = function(){ | ||
var parser = new POParser(this._fileContents), | ||
po = parser.parse(), | ||
context; | ||
for(var i=0, len = po.length; i<len; i++){ | ||
if(!i){ | ||
this._parseHeaders(po[i].msgstr && po[i].msgstr[0] || "", true); | ||
}else{ | ||
context = po[i].msgctxt || ""; | ||
if(!this._translationTable[context]){ | ||
this._translationTable[context] = {}; | ||
} | ||
this._translationTable[context][po[i].msgid || ""] = po[i].msgstr || ""; | ||
} | ||
} | ||
// dump the file contents object | ||
this._fileContents = null; | ||
po = null; | ||
} | ||
/** | ||
* Parse headers - detect charset and plural forms, save the values to this.headers | ||
@@ -193,4 +230,5 @@ * with lowercase keys. | ||
* @param {Buffer} headers Headers string as a Buffer object | ||
* @param {Boolean} keepCharset If true, do not convert charset | ||
*/ | ||
GettextDomain.prototype._parseHeaders = function(headers){ | ||
GettextDomain.prototype._parseHeaders = function(headers, keepCharset){ | ||
@@ -206,3 +244,3 @@ var headersStr = headers.toString(), | ||
if(this.charset != "utf-8"){ | ||
if(!keepCharset && this.charset != "utf-8"){ | ||
this._iconv = new Iconv(this.charset, "UTF-8//TRANSLIT//IGNORE"); | ||
@@ -265,2 +303,3 @@ headersStr = this._iconv.convert(headers).toString("utf-8"); | ||
original = original.split("\u0000")[0]; // keep the first | ||
this._translationTable[context][original] = translation.split("\u0000"); | ||
@@ -503,6 +542,4 @@ }; | ||
Object.keys(this._translationTable[context]).forEach((function(original){ | ||
var originalArr = []; | ||
for(var i=0, len = this._translationTable[context][original].length; i< len; i++){ | ||
originalArr[i] = original; | ||
} | ||
var originalArr = this._translationTable[context][original].length > 1 ? | ||
[original, original] : [original]; | ||
translationTable.push([ | ||
@@ -591,3 +628,1 @@ (context ? context+"\u0004" : "")+originalArr.join("\u0000"), | ||
}; | ||
{ | ||
"name": "node-gettext", | ||
"description": "Gettext client for Node.js to use .mo files for I18N", | ||
"version": "0.2.5", | ||
"version": "0.2.6", | ||
"author" : "Andris Reinman", | ||
@@ -6,0 +6,0 @@ "maintainers":[ |
# node-gettext | ||
**node-gettext** is a Node.JS module to use .MO files. | ||
**node-gettext** is a Node.JS module to use .MO and .PO files. | ||
## Features | ||
* Load binary *MO* files | ||
* Load binary *MO* or source *PO* files | ||
* Supports contexts and plurals | ||
* Add your own translations to the list | ||
* Compile current translation table into a *MO* or a *PO* file! | ||
* Recompile current translation table into a *MO* or a *PO* file! | ||
@@ -32,3 +32,3 @@ [![Build Status](https://secure.travis-ci.org/andris9/node-gettext.png)](http://travis-ci.org/andris9/node-gettext) | ||
Language data needs to be file contents in the Buffer format | ||
Language data needs to be file contents in the Buffer format (can be either a .MO or .PO file) | ||
@@ -40,2 +40,7 @@ *addTextdomain(domain[, file_contents])* | ||
or load a .PO file | ||
var file_contents = fs.readFileSync("et.po"); | ||
gt.addTextdomain("et", file_contents); | ||
### Check or change default language | ||
@@ -42,0 +47,0 @@ |
@@ -184,2 +184,91 @@ var testCase = require('nodeunit').testCase, | ||
exports["LATIN-13 PO"] = { | ||
setUp: function (callback) { | ||
fs.readFile(__dirname+"/latin13.po", (function(err, body){ | ||
if(err){ | ||
throw err; | ||
} | ||
this.g = new Gettext(); | ||
this.g.addTextdomain("et", body); | ||
callback(); | ||
}).bind(this)); | ||
}, | ||
"Simple string, default domain": function(test){ | ||
test.equal(this.g.gettext("o1"), "t1"); | ||
test.done(); | ||
}, | ||
"Simple string, nonexisting domain": function(test){ | ||
this.g.textdomain("en"); | ||
test.equal(this.g.gettext("o1"), "o1"); | ||
test.done(); | ||
}, | ||
"Simple string, existing domain": function(test){ | ||
this.g.textdomain("et"); | ||
test.equal(this.g.gettext("o1"), "t1"); | ||
test.done(); | ||
}, | ||
"Simple string with special chars": function(test){ | ||
test.equal(this.g.gettext("o3-õäöü"), "t3-žš"); | ||
test.done(); | ||
}, | ||
"dgettext": function(test){ | ||
test.equal(this.g.dgettext("et", "o1"), "t1"); | ||
test.equal(this.g.dgettext("en", "o1"), "o1"); | ||
test.done(); | ||
}, | ||
"ngettext": function(test){ | ||
test.equal(this.g.ngettext("o2-1", "a", 0), "t2-2"); | ||
test.equal(this.g.ngettext("o2-1", "b", 1), "t2-1"); | ||
test.equal(this.g.ngettext("o2-1", "c", 2), "t2-2"); | ||
test.equal(this.g.ngettext("o2-1", "d", 3), "t2-2"); | ||
test.done(); | ||
}, | ||
"dngettext": function(test){ | ||
test.equal(this.g.dngettext("et", "o2-1", "a", 0), "t2-2"); | ||
test.equal(this.g.dngettext("et", "o2-1", "b", 1), "t2-1"); | ||
test.equal(this.g.dngettext("et", "o2-1", "c", 2), "t2-2"); | ||
test.equal(this.g.dngettext("et", "o2-1", "c", 3), "t2-2"); | ||
test.equal(this.g.dngettext("en", "o2-1", "a", 0), "a"); | ||
test.equal(this.g.dngettext("en", "o2-1", "a", 1), "o2-1"); | ||
test.equal(this.g.dngettext("en", "o2-1", "a", 2), "a"); | ||
test.equal(this.g.dngettext("en", "o2-1", "a", 3), "a"); | ||
test.done(); | ||
}, | ||
"pgettext": function(test){ | ||
test.equal(this.g.pgettext("c1", "co1"), "ct1"); | ||
test.equal(this.g.pgettext("c2", "co1"), "co1"); | ||
test.done(); | ||
}, | ||
"dpgettext": function(test){ | ||
test.equal(this.g.dpgettext("et", "c1", "co1"), "ct1"); | ||
test.equal(this.g.dpgettext("et", "c2", "co1"), "co1"); | ||
test.equal(this.g.dpgettext("en", "c1", "co1"), "co1"); | ||
test.equal(this.g.dpgettext("en", "c2", "co1"), "co1"); | ||
test.done(); | ||
}, | ||
"npgettext": function(test){ | ||
test.equal(this.g.npgettext("c2", "co2-1", "a", 0), "ct2-2"); | ||
test.equal(this.g.npgettext("c2", "co2-1", "a", 1), "ct2-1"); | ||
test.equal(this.g.npgettext("c2", "co2-1", "a", 2), "ct2-2"); | ||
test.equal(this.g.npgettext("c2", "co2-1", "a", 3), "ct2-2"); | ||
test.done(); | ||
}, | ||
"dnpgettext": function(test){ | ||
test.equal(this.g.dnpgettext("et", "c2", "co2-1", "a", 0), "ct2-2"); | ||
test.equal(this.g.dnpgettext("et", "c2", "co2-1", "a", 1), "ct2-1"); | ||
test.equal(this.g.dnpgettext("et", "c2", "co2-1", "a", 2), "ct2-2"); | ||
test.equal(this.g.dnpgettext("et", "c2", "co2-1", "a", 3), "ct2-2"); | ||
test.equal(this.g.dnpgettext("en", "c2", "co2-1", "a", 0), "a"); | ||
test.equal(this.g.dnpgettext("en", "c2", "co2-1", "a", 1), "co2-1"); | ||
test.equal(this.g.dnpgettext("en", "c2", "co2-1", "a", 2), "a"); | ||
test.equal(this.g.dnpgettext("en", "c2", "co2-1", "a", 3), "a"); | ||
test.done(); | ||
} | ||
}; | ||
exports["Helpers"] = { | ||
@@ -299,3 +388,3 @@ setUp: function (callback) { | ||
compile: function(test){ | ||
"compile MO": function(test){ | ||
var g2 = new Gettext(); | ||
@@ -307,2 +396,9 @@ g2.addTextdomain("et", this.g.compileMO()); | ||
"compile PO": function(test){ | ||
var g2 = new Gettext(); | ||
g2.addTextdomain("et", this.g.compilePO()); | ||
test.equal(this.g.gettext("o1"), g2.gettext("o1")); | ||
test.done(); | ||
}, | ||
"auto plurals": function(test){ | ||
@@ -309,0 +405,0 @@ this.g.addTextdomain("ga"); |
86860
2517
170