-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
xgettext-html
executable file
·119 lines (102 loc) · 3.61 KB
/
xgettext-html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env node
/*
* xgettext-html: HTML gettext parser
* Copyright (C) 2018 The noVNC authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*/
const { program } = require('commander');
const jsdom = require("jsdom");
const fs = require("fs");
program
.argument('<INPUT...>')
.requiredOption('-o, --output <FILE>', 'write output to specified file')
.parse(process.argv);
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 < program.args.length; i++) {
const fn = program.args[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(program.opts().output, output);