lib/qx/tool/compiler/app/Translation.js
function() {
      var t = this;
      if (t.__onRead) {
        return t.__onRead; 
      }
      
      return t.__onRead = new Promise((resolve, reject) => {
        t.__translations = {};
        t.__headers = {};
        var poFile = this.getPoFilename();
        
        fs.stat(poFile, function(err, stat) {
          if (err) {
            if (err.code == "ENOENT") {
              resolve();
              return undefined;
            }
            reject(err);
            return undefined;
          }
          t.__mtime = stat.mtime;
          return readFile(poFile, { encoding: "utf8" })
            .then(data => {
              var entry = null;
              var lastKey = null;
              
              function saveEntry() {
                if (entry) {
                  var key;
                  if (entry.msgctxt) {
                    key = entry.msgctxt + ":" + entry.msgid;
                  } else {
                    key = entry.msgid;
                  }
                  t.__translations[key] = entry;
                }
                entry = null;
                lastKey = null;
              }
  
              function set(key, value, append) {
                var index = null;
                var m = key.match(/^([^[]+)\[([0-9]+)\]$/);
                if (m) {
                  key = m[1];
                  index = parseInt(m[2]);
                  if (entry[key] === undefined) {
                    entry[key] = []; 
                  }
                  if (!append || typeof entry[key][index] !== "string") {
                    entry[key][index] = value; 
                  } else {
                    entry[key][index] += value;
                  }
                } else if (!append || typeof entry[key] !== "string") {
                  entry[key] = value;
                } else {
                  entry[key] += value; 
                }
              }
  
              data.split("\n").forEach(function(line, lineNo) {
                line = line.trim();
                if (!line) {
                  saveEntry();
                  return;
                }
  
                if (!entry) {
                  entry = {}; 
                }
  
                // Comment?
                var m = line.match(/^#([^ ]?) (.*)$/);
                if (m) {
                  var type = m[1];
                  var comment = m[2];
                  var key;
                  if (!entry.comments) {
                    entry.comments = {}; 
                  }
                  switch (type) {
                    case "":
                      entry.comments.translator = comment;
                      break;
  
                    case ".":
                      entry.comments.extracted = comment;
                      break;
  
                    case ":":
                      if (!entry.comments.reference) {
                        entry.comments.reference = {};
                      }
                      {
                        const ref = entry.comments.reference;
                        (comment && comment.match(/[\w/\.]+:\d+/g) || []).forEach(entry => {
                          const split = entry.split(":");
                          const classname = split[0];
                          const lineNo = parseInt(split[1], 10);
                          if (!ref[classname]) {
                            ref[classname] = [lineNo];
                          } else if (!ref[classname].includes(lineNo)) {
                            ref[classname].push(lineNo);
                          }
                        });
                      }
                      break;
  
                    case ",":
                      entry.comments.flags = comment.split(",");
                      break;
  
                    case "|":
                      m = comment.match(/^([^\s]+)\s+(.*)$/);
                      if (m) {
                        if (!entry.previous) {
                          entry.previous = {}; 
                        }
                        var tmp = m[1];
                        if (tmp == "msgctxt" || tmp == "msgid") {
                          entry[tmp] = m[2]; 
                        } else {
                          log.warn("Cannot interpret line " + (lineNo + 1));
                        }
                      } else {
                        log.warn("Cannot interpret line " + (lineNo + 1)); 
                      }
                      break;
                  }
                  return;
                }
  
                if (line[0] == "\"" && line[line.length - 1] == "\"") {
                  line = line.substring(1, line.length - 1);
                  if (!lastKey.match(/^.*\[\d+\]$/) && (lastKey === null || entry[lastKey] === undefined)) {
                    log.error("Cannot interpret line because there is no key to append to, line " + (lineNo+1)); 
                  } else {
                    set(lastKey, line, true); 
                  }
                  return;
                }
  
                // Part of the translation
                if (line == "#") {
                  return; 
                }
                m = line.match(/^([^\s]+)\s+(.*)$/);
                if (!m) {
                  log.warn("Cannot interpret line " + (lineNo + 1));
                  return;
                }
  
                key = lastKey = m[1];
                var value = m[2];
                if (value.length >= 2 && value[0] == "\"" && value[value.length - 1] == "\"") {
                  value = value.substring(1, value.length - 1);
                  value = value.replace(/\\t/g, "\t").replace(/\\r/g, "\r")
                    .replace(/\\n/g, "\n")
                    .replace(/\\"/g, "\"");
                  set(key, value);
                }
              });
              
              resolve();
            });
        });
      });
    }
function() {
      var t = this;
      if (t.__onRead) {
        return t.__onRead; 
      }
      
      return t.__onRead = new Promise((resolve, reject) => {
        t.__translations = {};
        t.__headers = {};
        var poFile = this.getPoFilename();
        
        fs.stat(poFile, function(err, stat) {
          if (err) {
            if (err.code == "ENOENT") {
              resolve();
              return undefined;
            }
            reject(err);
            return undefined;
          }
          t.__mtime = stat.mtime;
          return readFile(poFile, { encoding: "utf8" })
            .then(data => {
              var entry = null;
              var lastKey = null;
              
              function saveEntry() {
                if (entry) {
                  var key;
                  if (entry.msgctxt) {
                    key = entry.msgctxt + ":" + entry.msgid;
                  } else {
                    key = entry.msgid;
                  }
                  t.__translations[key] = entry;
                }
                entry = null;
                lastKey = null;
              }
  
              function set(key, value, append) {
                var index = null;
                var m = key.match(/^([^[]+)\[([0-9]+)\]$/);
                if (m) {
                  key = m[1];
                  index = parseInt(m[2]);
                  if (entry[key] === undefined) {
                    entry[key] = []; 
                  }
                  if (!append || typeof entry[key][index] !== "string") {
                    entry[key][index] = value; 
                  } else {
                    entry[key][index] += value;
                  }
                } else if (!append || typeof entry[key] !== "string") {
                  entry[key] = value;
                } else {
                  entry[key] += value; 
                }
              }
  
              data.split("\n").forEach(function(line, lineNo) {
                line = line.trim();
                if (!line) {
                  saveEntry();
                  return;
                }
  
                if (!entry) {
                  entry = {}; 
                }
  
                // Comment?
                var m = line.match(/^#([^ ]?) (.*)$/);
                if (m) {
                  var type = m[1];
                  var comment = m[2];
                  var key;
                  if (!entry.comments) {
                    entry.comments = {}; 
                  }
                  switch (type) {
                    case "":
                      entry.comments.translator = comment;
                      break;
  
                    case ".":
                      entry.comments.extracted = comment;
                      break;
  
                    case ":":
                      if (!entry.comments.reference) {
                        entry.comments.reference = {};
                      }
                      {
                        const ref = entry.comments.reference;
                        (comment && comment.match(/[\w/\.]+:\d+/g) || []).forEach(entry => {
                          const split = entry.split(":");
                          const classname = split[0];
                          const lineNo = parseInt(split[1], 10);
                          if (!ref[classname]) {
                            ref[classname] = [lineNo];
                          } else if (!ref[classname].includes(lineNo)) {
                            ref[classname].push(lineNo);
                          }
                        });
                      }
                      break;
  
                    case ",":
                      entry.comments.flags = comment.split(",");
                      break;
  
                    case "|":
                      m = comment.match(/^([^\s]+)\s+(.*)$/);
                      if (m) {
                        if (!entry.previous) {
                          entry.previous = {}; 
                        }
                        var tmp = m[1];
                        if (tmp == "msgctxt" || tmp == "msgid") {
                          entry[tmp] = m[2]; 
                        } else {
                          log.warn("Cannot interpret line " + (lineNo + 1));
                        }
                      } else {
                        log.warn("Cannot interpret line " + (lineNo + 1)); 
                      }
                      break;
                  }
                  return;
                }
  
                if (line[0] == "\"" && line[line.length - 1] == "\"") {
                  line = line.substring(1, line.length - 1);
                  if (!lastKey.match(/^.*\[\d+\]$/) && (lastKey === null || entry[lastKey] === undefined)) {
                    log.error("Cannot interpret line because there is no key to append to, line " + (lineNo+1)); 
                  } else {
                    set(lastKey, line, true); 
                  }
                  return;
                }
  
                // Part of the translation
                if (line == "#") {
                  return; 
                }
                m = line.match(/^([^\s]+)\s+(.*)$/);
                if (!m) {
                  log.warn("Cannot interpret line " + (lineNo + 1));
                  return;
                }
  
                key = lastKey = m[1];
                var value = m[2];
                if (value.length >= 2 && value[0] == "\"" && value[value.length - 1] == "\"") {
                  value = value.substring(1, value.length - 1);
                  value = value.replace(/\\t/g, "\t").replace(/\\r/g, "\r")
                    .replace(/\\n/g, "\n")
                    .replace(/\\"/g, "\"");
                  set(key, value);
                }
              });
              
              resolve();
            });
        });
      });
    }
Reads the .po file