]>
Commit | Line | Data |
---|---|---|
edffd9e2 PO |
1 | #!/usr/bin/env node |
2 | /* | |
3 | * xgettext-html: HTML gettext parser | |
4 | * Copyright (C) 2016 Pierre Ossman | |
5 | * Licensed under MPL 2.0 (see LICENSE.txt) | |
6 | */ | |
7 | ||
2b5f94fa JD |
8 | const getopt = require('node-getopt'); |
9 | const jsdom = require("jsdom"); | |
10 | const fs = require("fs"); | |
edffd9e2 | 11 | |
2b5f94fa | 12 | const opt = getopt.create([ |
edffd9e2 PO |
13 | ['o' , 'output=FILE' , 'write output to specified file'], |
14 | ['h' , 'help' , 'display this help'], | |
15 | ]).bindHelp().parseSystem(); | |
16 | ||
2b5f94fa | 17 | const strings = {}; |
edffd9e2 PO |
18 | |
19 | function addString(str, location) { | |
20 | if (str.length == 0) { | |
21 | return; | |
22 | } | |
23 | ||
24 | if (strings[str] === undefined) { | |
25 | strings[str] = {} | |
26 | } | |
27 | strings[str][location] = null; | |
28 | } | |
29 | ||
30 | // See https://html.spec.whatwg.org/multipage/dom.html#attr-translate | |
31 | function process(elem, locator, enabled) { | |
32 | function isAnyOf(searchElement, items) { | |
33 | return items.indexOf(searchElement) !== -1; | |
34 | } | |
35 | ||
36 | if (elem.hasAttribute("translate")) { | |
37 | if (isAnyOf(elem.getAttribute("translate"), ["", "yes"])) { | |
38 | enabled = true; | |
39 | } else if (isAnyOf(elem.getAttribute("translate"), ["no"])) { | |
40 | enabled = false; | |
41 | } | |
42 | } | |
43 | ||
44 | if (enabled) { | |
45 | if (elem.hasAttribute("abbr") && | |
46 | elem.tagName === "TH") { | |
47 | addString(elem.getAttribute("abbr"), locator(elem)); | |
48 | } | |
49 | if (elem.hasAttribute("alt") && | |
50 | isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) { | |
51 | addString(elem.getAttribute("alt"), locator(elem)); | |
52 | } | |
53 | if (elem.hasAttribute("download") && | |
54 | isAnyOf(elem.tagName, ["A", "AREA"])) { | |
55 | addString(elem.getAttribute("download"), locator(elem)); | |
56 | } | |
57 | if (elem.hasAttribute("label") && | |
58 | isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP", | |
59 | "OPTION", "TRACK"])) { | |
60 | addString(elem.getAttribute("label"), locator(elem)); | |
61 | } | |
62 | if (elem.hasAttribute("placeholder") && | |
63 | isAnyOf(elem.tagName in ["INPUT", "TEXTAREA"])) { | |
64 | addString(elem.getAttribute("placeholder"), locator(elem)); | |
65 | } | |
66 | if (elem.hasAttribute("title")) { | |
67 | addString(elem.getAttribute("title"), locator(elem)); | |
68 | } | |
69 | if (elem.hasAttribute("value") && | |
70 | elem.tagName === "INPUT" && | |
3729976a | 71 | isAnyOf(elem.getAttribute("type"), ["reset", "button", "submit"])) { |
edffd9e2 PO |
72 | addString(elem.getAttribute("value"), locator(elem)); |
73 | } | |
74 | } | |
75 | ||
2b5f94fa | 76 | for (let i = 0; i < elem.childNodes.length; i++) { |
edffd9e2 PO |
77 | node = elem.childNodes[i]; |
78 | if (node.nodeType === node.ELEMENT_NODE) { | |
79 | process(node, locator, enabled); | |
80 | } else if (node.nodeType === node.TEXT_NODE && enabled) { | |
81 | addString(node.data.trim(), locator(node)); | |
82 | } | |
83 | } | |
84 | } | |
85 | ||
2b5f94fa JD |
86 | for (let i = 0; i < opt.argv.length; i++) { |
87 | const fn = opt.argv[i]; | |
88 | const file = fs.readFileSync(fn, "utf8"); | |
89 | const dom = new jsdom.JSDOM(file, { includeNodeLocations: true }); | |
90 | const body = dom.window.document.body; | |
edffd9e2 | 91 | |
651c23ec | 92 | const locator = (elem) => { |
2b5f94fa JD |
93 | const offset = dom.nodeLocation(elem).startOffset; |
94 | const line = file.slice(0, offset).split("\n").length; | |
edffd9e2 PO |
95 | return fn + ":" + line; |
96 | }; | |
97 | ||
0f897520 | 98 | process(body, locator, true); |
edffd9e2 PO |
99 | } |
100 | ||
2b5f94fa | 101 | let output = ""; |
edffd9e2 PO |
102 | |
103 | for (str in strings) { | |
104 | output += "#:"; | |
105 | for (location in strings[str]) { | |
106 | output += " " + location; | |
107 | } | |
108 | output += "\n"; | |
109 | ||
110 | output += "msgid " + JSON.stringify(str) + "\n"; | |
111 | output += "msgstr \"\"\n"; | |
112 | output += "\n"; | |
113 | } | |
114 | ||
115 | fs.writeFileSync(opt.options.output, output); |