Files
noVNC/po/xgettext-html
Pierre Ossman 7f5b51acf3 Consistently use "sentence case" style
Try to be more consistent in how we capitalize things. Both the "Title
Case" and "Sentence case" styles are popular, so either would work.
Google and Mozilla both prefer "Sentence case", so let's follow them.
2024-11-27 14:40:40 +01:00

120 lines
3.6 KiB
JavaScript
Executable File

#!/usr/bin/env node
/*
* xgettext-html: HTML gettext parser
* Copyright (C) 2018 The noVNC authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*/
const getopt = require('node-getopt');
const jsdom = require("jsdom");
const fs = require("fs");
const opt = getopt.create([
['o', 'output=FILE', 'write output to specified file'],
['h', 'help', 'display this help'],
]).bindHelp().parseSystem();
const strings = {};
function addString(str, location) {
// We assume surrounding whitespace, and whitespace around line
// breaks, is just for source formatting
str = str.split("\n").map(s => s.trim()).join(" ").trim();
if (str.length == 0) {
return;
}
if (strings[str] === undefined) {
strings[str] = {};
}
strings[str][location] = null;
}
// See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
function process(elem, locator, enabled) {
function isAnyOf(searchElement, items) {
return items.indexOf(searchElement) !== -1;
}
if (elem.hasAttribute("translate")) {
if (isAnyOf(elem.getAttribute("translate"), ["", "yes"])) {
enabled = true;
} else if (isAnyOf(elem.getAttribute("translate"), ["no"])) {
enabled = false;
}
}
if (enabled) {
if (elem.hasAttribute("abbr") &&
elem.tagName === "TH") {
addString(elem.getAttribute("abbr"), locator(elem));
}
if (elem.hasAttribute("alt") &&
isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) {
addString(elem.getAttribute("alt"), locator(elem));
}
if (elem.hasAttribute("download") &&
isAnyOf(elem.tagName, ["A", "AREA"])) {
addString(elem.getAttribute("download"), locator(elem));
}
if (elem.hasAttribute("label") &&
isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP",
"OPTION", "TRACK"])) {
addString(elem.getAttribute("label"), locator(elem));
}
if (elem.hasAttribute("placeholder") &&
isAnyOf(elem.tagName in ["INPUT", "TEXTAREA"])) {
addString(elem.getAttribute("placeholder"), locator(elem));
}
if (elem.hasAttribute("title")) {
addString(elem.getAttribute("title"), locator(elem));
}
if (elem.hasAttribute("value") &&
elem.tagName === "INPUT" &&
isAnyOf(elem.getAttribute("type"), ["reset", "button", "submit"])) {
addString(elem.getAttribute("value"), locator(elem));
}
}
for (let i = 0; i < elem.childNodes.length; i++) {
let node = elem.childNodes[i];
if (node.nodeType === node.ELEMENT_NODE) {
process(node, locator, enabled);
} else if (node.nodeType === node.TEXT_NODE && enabled) {
addString(node.data, locator(node));
}
}
}
for (let i = 0; i < opt.argv.length; i++) {
const fn = opt.argv[i];
const file = fs.readFileSync(fn, "utf8");
const dom = new jsdom.JSDOM(file, { includeNodeLocations: true });
const body = dom.window.document.body;
let locator = (elem) => {
const offset = dom.nodeLocation(elem).startOffset;
const line = file.slice(0, offset).split("\n").length;
return fn + ":" + line;
};
process(body, locator, true);
}
let output = "";
for (let str in strings) {
output += "#:";
for (location in strings[str]) {
output += " " + location;
}
output += "\n";
output += "msgid " + JSON.stringify(str) + "\n";
output += "msgstr \"\"\n";
output += "\n";
}
fs.writeFileSync(opt.options.output, output);