Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/python-wasm
Path: blob/main/python/pylang/tools/msgfmt.js
1396 views
1
/* vim:fileencoding=utf-8
2
*
3
* Copyright (C) 2015 Kovid Goyal <kovid at kovidgoyal.net>
4
*
5
* Distributed under terms of the BSD license
6
*/
7
"use strict"; /*jshint node:true */
8
9
function unesc(string) {
10
return string
11
.replace(/\\"/g, '"')
12
.replace(/\\n/g, "\n")
13
.replace(/\\r/g, "\r")
14
.replace(/\\t/g, "\t")
15
.replace(/\\\\/g, "\\");
16
}
17
18
function parse(data, on_error) {
19
// Parse a PO file using a state machine (does not work for POT files). Also only extracts data useful
20
// for JSON output.
21
var plural_forms = null;
22
var lines = data.split("\n");
23
var entries = [];
24
var current_entry = create_entry();
25
var lnum = 0;
26
var nplurals = null;
27
var language = null;
28
29
function fatal() {
30
var msg = Array.prototype.slice.call(arguments).join(" ");
31
if (on_error) {
32
on_error(msg);
33
return;
34
}
35
console.error(msg);
36
process.exit(1);
37
}
38
39
function create_entry() {
40
return {
41
msgid: null,
42
fuzzy: false,
43
msgstr: [],
44
msgid_plural: null,
45
lnum: null,
46
};
47
}
48
49
function parse_header() {
50
var raw = current_entry.msgstr[0];
51
if (raw === undefined) fatal("Header has no msgstr");
52
raw.split("\n").forEach(function (line) {
53
if (line.startsWith("Plural-Forms:")) {
54
plural_forms = line.slice("Plural-Forms:".length).trim();
55
var match = /^nplurals\s*=\s*(\d+)\s*;/.exec(plural_forms);
56
if (!match || match[1] === undefined)
57
fatal("Invalid Plural-Forms header:", plural_forms);
58
nplurals = parseInt(match[1]);
59
} else if (line.startsWith("Language:")) {
60
language = line.slice("Language:".length).trim();
61
}
62
});
63
}
64
65
function commit_entry() {
66
if (current_entry.msgid) {
67
if (current_entry.msgid_plural !== null) {
68
if (nplurals === null) fatal("Plural-Forms header missing");
69
for (var i = 0; i < nplurals; i++) {
70
if (current_entry.msgstr[i] === undefined)
71
fatal("Missing plural form for entry at line number:", lnum);
72
}
73
}
74
entries.push(current_entry);
75
} else if (current_entry.msgid === "") parse_header();
76
current_entry = create_entry();
77
}
78
79
function read_string(line) {
80
line = line.trim();
81
if (!line || line[0] !== '"' || line[line.length - 1] !== '"') {
82
fatal("Expecting a string at line number:", lnum);
83
}
84
return unesc(line.slice(1, -1));
85
}
86
87
function continuation(line, lines, append, after) {
88
if (line[0] === '"') append(read_string(line));
89
else {
90
state = after;
91
after(line, lines);
92
}
93
}
94
95
function start(line, lines) {
96
if (line[0] === "#") {
97
if (line[1] === ",") {
98
line
99
.slice(2)
100
.trimLeft()
101
.split(",")
102
.forEach(function (flag) {
103
if (flag.trim().toLowerCase() === "fuzzy")
104
current_entry.fuzzy = true;
105
});
106
}
107
} else if (line.startsWith("msgid ")) {
108
current_entry.msgid = read_string(line.slice("msgid ".length));
109
current_entry.lnum = lnum;
110
state = function (line, lines) {
111
continuation(
112
line,
113
lines,
114
function (x) {
115
current_entry.msgid += x;
116
},
117
after_msgid
118
);
119
};
120
} else {
121
fatal("Expecting msgid at line number:", lnum);
122
}
123
}
124
125
function after_msgid(line, lines) {
126
if (line.startsWith("msgid_plural ")) {
127
current_entry.msgid_plural = read_string(
128
line.slice("msgid_plural ".length)
129
);
130
state = function (line, lines) {
131
continuation(
132
line,
133
lines,
134
function (x) {
135
current_entry.msgid_plural += x;
136
},
137
msgstr
138
);
139
};
140
} else if (line.startsWith("msgstr ") || line.startsWith("msgstr[")) {
141
state = msgstr;
142
msgstr(line, lines);
143
} else
144
fatal("Expecting either msgstr or msgid_plural at line number:", lnum);
145
}
146
147
function msgstr(line, lines) {
148
if (line.startsWith("msgstr ")) {
149
if (current_entry.msgid_plural !== null)
150
fatal("Expecting msgstr[0] at line number:", lnum);
151
current_entry.msgstr.push(read_string(line.slice("msgstr ".length)));
152
state = function (line, lines) {
153
continuation(
154
line,
155
lines,
156
function (x) {
157
current_entry.msgstr[current_entry.msgstr.length - 1] += x;
158
},
159
msgstr
160
);
161
};
162
} else if (line[0] === "#" || line.startsWith("msgid ")) {
163
if (!current_entry.msgstr.length)
164
fatal("Expecting msgstr at line number:", lnum);
165
commit_entry();
166
state = start;
167
start(line, lines);
168
} else if (line.startsWith("msgstr[")) {
169
if (current_entry.msgid_plural === null)
170
fatal("Expecting non-plural msgstr at line number:", lnum);
171
var pnum = /^msgstr\[(\d+)\] /.exec(line);
172
if (!pnum || pnum[1] === undefined)
173
fatal("Malformed msgstr at line number:", lnum);
174
var idx = parseInt(pnum[1]);
175
current_entry.msgstr[idx] = read_string(line.slice(pnum[0].length));
176
state = function (line, lines) {
177
continuation(
178
line,
179
lines,
180
function (x) {
181
current_entry.msgstr[idx] += x;
182
},
183
msgstr
184
);
185
};
186
} else fatal("Expecting msgstr or msgid at line number:", lnum);
187
}
188
189
var state = start;
190
191
while (lines.length) {
192
var line = lines.shift().trim();
193
lnum += 1;
194
if (!line) continue;
195
state(line, lines);
196
}
197
commit_entry();
198
if (language === null)
199
fatal("No language specified in the header of this po file");
200
return {
201
entries: entries,
202
plural_forms: plural_forms,
203
nplurals: nplurals,
204
language: language,
205
};
206
}
207
208
function read_stdin(cont) {
209
var chunks = [];
210
process.stdin.setEncoding("utf8");
211
212
process.stdin.on("readable", function () {
213
var chunk = process.stdin.read();
214
if (chunk) chunks.push(chunk);
215
});
216
217
process.stdin.on("end", function () {
218
cont(chunks.join(""));
219
});
220
}
221
222
function serialize_catalog(catalog, options) {
223
if (!options.use_fuzzy)
224
catalog.entries = catalog.entries.filter(function (e) {
225
return !e.fuzzy;
226
});
227
var entries = {};
228
catalog.entries.forEach(function (entry) {
229
entries[entry.msgid] = entry.msgstr;
230
});
231
return JSON.stringify({
232
plural_forms: catalog.plural_forms,
233
entries: entries,
234
language: catalog.language,
235
});
236
}
237
238
module.exports.cli = function (argv, base_path, src_path, lib_path) {
239
read_stdin(function process(data) {
240
var catalog = parse(data);
241
console.log(serialize_catalog(catalog, argv));
242
});
243
};
244
245
module.exports.parse = parse;
246
module.exports.build = function (data, options) {
247
return serialize_catalog(parse(data), options);
248
};
249
250