283 lines
6.9 KiB
JavaScript
283 lines
6.9 KiB
JavaScript
/*
|
|
Copyright 1991-2020 Amebis
|
|
Copyright 2016 GÉANT
|
|
|
|
This file is part of MSIBuild.
|
|
|
|
MSIBuild is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
MSIBuild is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with MSIBuild. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*@cc_on @*/
|
|
/*@if (! @_escapePO_JS__) @*/
|
|
/*@set @_escapePO_JS__ = true @*/
|
|
|
|
var escapePO_stat = null;
|
|
function escapePO(str)
|
|
{
|
|
if (!escapePO_stat) {
|
|
escapePO_stat = {
|
|
"re_bslash": new RegExp("\\\\", "g"),
|
|
"re_bs": new RegExp("\b", "g"),
|
|
"re_ff": new RegExp("\f", "g"),
|
|
"re_lf": new RegExp("\n", "g"),
|
|
"re_cr": new RegExp("\r", "g"),
|
|
"re_tab": new RegExp("\t", "g"),
|
|
"re_quot": new RegExp("\"", "g")
|
|
};
|
|
}
|
|
|
|
if (str == null) return null;
|
|
switch (typeof(str)) {
|
|
case "string": break;
|
|
case "undefined": return null;
|
|
default: try { str = str.toString(); } catch (err) { return null; }
|
|
}
|
|
|
|
return str.replace(escapePO_stat.re_bslash, "\\\\").replace(escapePO_stat.re_bs, "\\b").replace(escapePO_stat.re_ff, "\\f").replace(escapePO_stat.re_lf, "\\n").replace(escapePO_stat.re_cr, "\\r").replace(escapePO_stat.re_tab, "\\t").replace(escapePO_stat.re_quot, "\\\"");
|
|
}
|
|
|
|
|
|
var unescapePO_stat = null;
|
|
function unescapePO(str)
|
|
{
|
|
if (!unescapePO_stat) {
|
|
unescapePO_stat = {
|
|
"re_esc": new RegExp("\\\\(.)", "g"),
|
|
"fn_esc": function($0, $1) {
|
|
switch ($1) {
|
|
case "\\": return "\\";
|
|
case "b" : return "\b";
|
|
case "f" : return "\f";
|
|
case "n" : return "\n";
|
|
case "r" : return "\r";
|
|
case "t" : return "\t";
|
|
case "\'": return "\'";
|
|
case "\"": return "\"";
|
|
default : return $0;
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
if (str == null) return null;
|
|
switch (typeof(str)) {
|
|
case "string": break;
|
|
case "undefined": return null;
|
|
default: try { str = str.toString(); } catch (err) { return null; }
|
|
}
|
|
|
|
return str.replace(unescapePO_stat.re_esc, unescapePO_stat.fn_esc);
|
|
}
|
|
|
|
|
|
function POCatalog()
|
|
{
|
|
this.charset = "utf-8";
|
|
this.data = new Array();
|
|
|
|
if (arguments.length) {
|
|
var
|
|
path = arguments[0];
|
|
|
|
// Open file.
|
|
var dat = new ActiveXObject("ADODB.Stream");
|
|
dat.Open();
|
|
try {
|
|
// PO catalogue is text file, uses Unix line breaks and UTF-8.
|
|
dat.Type = adTypeText;
|
|
dat.LineSeparator = adLF;
|
|
dat.Charset = this.charset;
|
|
|
|
// Load file.
|
|
dat.LoadFromFile(path);
|
|
|
|
// Prepare regular expressions for catalogue parsing.
|
|
var regexp = {
|
|
"fuzzy": new RegExp("^\\s*#,\\s*fuzzy", "i"),
|
|
"comment": new RegExp("^\\s*#", ""),
|
|
"record": new RegExp("^\\s*(\\w*)\\s*\"(.*)\"\\s*$", "")
|
|
};
|
|
|
|
var getNext = function() {
|
|
var
|
|
id = null,
|
|
rec = new Array();
|
|
|
|
while (!dat.EOS) {
|
|
var
|
|
s = Trim(dat.ReadText(adReadLine)),
|
|
m;
|
|
|
|
// The line is empty => end of record.
|
|
if (s == "" && "msgid" in rec)
|
|
break;
|
|
|
|
// The record is marked as "fuzzy".
|
|
if (s.search(regexp.fuzzy) != -1) {
|
|
rec["fuzzy"] = true;
|
|
continue;
|
|
}
|
|
|
|
// Concatenate comments.
|
|
if (s.search(regexp.comment) != -1) {
|
|
if ("#" in rec)
|
|
rec["#"] += s + "\n";
|
|
else
|
|
rec["#"] = s + "\n";
|
|
continue;
|
|
}
|
|
|
|
m = s.match(regexp.record);
|
|
if (m) {
|
|
// Record found.
|
|
if (m[1] != "")
|
|
id = new String(m[1]);
|
|
if (id in rec)
|
|
rec[id] += new String(m[2]);
|
|
else
|
|
rec[id] = new String(m[2]);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Unescape messages now that they are concatenated.
|
|
for (id in rec)
|
|
rec[id] = unescapePO(rec[id]);
|
|
return "msgid" in rec ? rec : null;
|
|
}
|
|
|
|
// Read header record.
|
|
var rec = getNext();
|
|
if (rec == null)
|
|
return;
|
|
if (rec.msgid == "") {
|
|
// Parse charset.
|
|
m = rec.msgstr.match(new RegExp("^\\s*Content-Type\\s*:\\s*([-\\w]+/[-\\w]+)\\s*(;\\s*charset\\s*=\\s*([-\\w]+))?$", "im"));
|
|
if (m && m.length >= 4) {
|
|
this.charset = m[3];
|
|
|
|
// Rewind and reconfigure code page.
|
|
dat.Position = 0;
|
|
dat.Charset = this.charset;
|
|
|
|
// Re-read header.
|
|
rec = getNext();
|
|
}
|
|
}
|
|
|
|
// Load header and all the records.
|
|
this.push(rec.msgid, rec.msgstr, rec.fuzzy, "#" in rec ? rec["#"] : null);
|
|
while ((rec = getNext()) != null)
|
|
this.push(rec.msgid, rec.msgstr, rec.fuzzy, "#" in rec ? rec["#"] : null);
|
|
} finally {
|
|
dat.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
POCatalog.prototype.push = function(key, trans, fuzzy, comment)
|
|
{
|
|
var rec = {
|
|
"msgstr" : trans,
|
|
"fuzzy" : fuzzy ? true : false
|
|
};
|
|
if (comment)
|
|
rec["#"] = comment;
|
|
|
|
this.data[key] = rec;
|
|
}
|
|
|
|
|
|
POCatalog.prototype.search = function(key)
|
|
{
|
|
return (key in this.data) ? this.data[key] : null;
|
|
}
|
|
|
|
|
|
POCatalog.prototype.translate = function(key)
|
|
{
|
|
if (!(key in this.data)) {
|
|
// No translation found.
|
|
return key;
|
|
}
|
|
|
|
var rec = this.data[key];
|
|
if (rec.msgstr == "" || rec.fuzzy) {
|
|
// Translation is blank (untranslated) or fuzzy.
|
|
return key;
|
|
}
|
|
|
|
return rec.msgstr;
|
|
}
|
|
|
|
|
|
POCatalog.prototype.save = function(path)
|
|
{
|
|
// Open PO file in memory.
|
|
var dat = new ActiveXObject("ADODB.Stream");
|
|
dat.Open();
|
|
try {
|
|
// PO is text file, uses Unix line breaks and given encoding.
|
|
dat.Type = adTypeText;
|
|
dat.LineSeparator = adLF;
|
|
dat.Charset = this.charset;
|
|
|
|
var writeRec = function(key, rec) {
|
|
if (rec.fuzzy)
|
|
dat.WriteText("#, fuzzy", adWriteLine);
|
|
|
|
if ("#" in rec)
|
|
dat.WriteText(rec["#"], adWriteLine);
|
|
|
|
dat.WriteText("msgid \"" + escapePO(key ) + "\"", adWriteLine);
|
|
dat.WriteText("msgstr \"" + escapePO(rec.msgstr) + "\"", adWriteLine);
|
|
dat.WriteText("", adWriteLine);
|
|
}
|
|
|
|
// Write header first.
|
|
if ("" in this.data)
|
|
writeRec("", this.data[""]);
|
|
|
|
// Write records, skip header.
|
|
for (var key in this.data) {
|
|
if (key == "") continue;
|
|
writeRec(key, this.data[key]);
|
|
}
|
|
|
|
if (this.charset.toLowerCase() == "utf-8") {
|
|
// Write to file without UTF-8 BOM.
|
|
var dat_nobom = new ActiveXObject("ADODB.Stream");
|
|
dat_nobom.Type = adTypeBinary;
|
|
dat_nobom.Mode = adModeReadWrite;
|
|
dat_nobom.Open();
|
|
try {
|
|
// Skip BOM (first three bytes) and copy the rest.
|
|
dat.Position = 3;
|
|
dat.CopyTo(dat_nobom);
|
|
|
|
dat_nobom.SaveToFile(path, adSaveCreateOverWrite);
|
|
} finally {
|
|
dat_nobom.Close();
|
|
}
|
|
} else {
|
|
dat.SaveToFile(path, adSaveCreateOverWrite);
|
|
}
|
|
} finally {
|
|
dat.Close();
|
|
}
|
|
}
|
|
|
|
/*@end @*/
|