PageSourceSearch

https://jobcluster.jcd.de/libs/pofile/po.js

js jcd.de collected 2026-10-06 01:31:58 UTC 13,468 bytes, 408 lines download raw bytes

1// https://github.com/rubenv/pofile
2// Version 1.1.4
3
4require=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
5
6},{}],"pofile":[function(require,module,exports){
7function trim(string) {
8    return string.replace(/^\s+|\s+$/g, '');
9}
10
11var PO = function () {
12    this.comments = [];
13    this.extractedComments = [];
14    this.headers = {};
15    this.headerOrder = [];
16    this.items = [];
17};
18
19PO.prototype.save = function (filename, callback) {
20    require('fs').writeFile(filename, this.toString(), callback);
21};
22
23PO.prototype.toString = function () {
24    var lines = [];
25
26    if (this.comments) {
27        this.comments.forEach(function (comment) {
28            lines.push(('# ' + comment).trim());
29        });
30    }
31    if (this.extractedComments) {
32        this.extractedComments.forEach(function (comment) {
33            lines.push(('#. ' + comment).trim());
34        });
35    }
36
37    lines.push('msgid ""');
38    lines.push('msgstr ""');
39
40    var self = this;
41    var headerOrder = [];
42
43    this.headerOrder.forEach(function (key) {
44        if (key in self.headers) {
45            headerOrder.push(key);
46        }
47    });
48
49    var keys = Object.keys(this.headers);
50
51    keys.forEach(function (key) {
52        if (headerOrder.indexOf(key) === -1) {
53            headerOrder.push(key);
54        }
55    });
56
57    headerOrder.forEach(function (key) {
58        lines.push('"' + key + ': ' + self.headers[key] + '\\n"');
59    });
60
61    lines.push('');
62
63    this.items.forEach(function (item) {
64        lines.push(item.toString());
65        lines.push('');
66    });
67
68    return lines.join('\n');
69};
70
71PO.load = function (filename, callback) {
72    require('fs').readFile(filename, 'utf-8', function (err, data) {
73        if (err) {
74            return callback(err);
75        }
76        var po = PO.parse(data);
77        callback(null, po);
78    });
79};
80
81PO.parse = function (data) {
82    //support both unix and windows newline formats.
83    data = data.replace(/\r\n/g, '\n');
84    var po = new PO();
85    var sections = data.split(/\n\n/);
86    var headers = [];
87    //everything until the first 'msgid ""' is considered header
88    while (sections[0] && (headers.length === 0 || headers[headers.length - 1].indexOf('msgid ""') < 0)) {
89        if (sections[0].match(/msgid\s+"[^"]/)) {
90            //found first real string, adding a dummy header item
91            headers.push('msgid ""');
92        } else {
93            headers.push(sections.shift());
94        }
95    }
96    headers = headers.join('\n');
97    var lines = sections.join('\n').split(/\n/);
98
99    po.headers = {
100        'Project-Id-Version': '',
101        'Report-Msgid-Bugs-To': '',
102        'POT-Creation-Date': '',
103        'PO-Revision-Date': '',
104        'Last-Translator': '',
105        'Language': '',
106        'Language-Team': '',
107        'Content-Type': '',
108        'Content-Transfer-Encoding': '',
109        'Plural-Forms': '',
110    };
111    po.headerOrder = [];
112
113    headers.split(/\n/).reduce(function (acc, line) {
114        if (acc.merge) {
115            //join lines, remove last resp. first "
116            line = acc.pop().slice(0, -1) + line.slice(1);
117            delete acc.merge;
118        }
119        if (/^".*"$/.test(line) && !/^".*\\n"$/.test(line)) {
120            acc.merge = true;
121        }
122        acc.push(line);
123        return acc;
124    }, []).forEach(function (header) {
125        if (header.match(/^#\./)) {
126            po.extractedComments.push(header.replace(/^#\.\s*/, ''));
127        } else if (header.match(/^#/)) {
128            po.comments.push(header.replace(/^#\s*/, ''));
129        } else if (header.match(/^"/)) {
130            header = header.trim().replace(/^"/, '').replace(/\\n"$/, '');
131            var p = header.split(/:/);
132            var name = p.shift().trim();
133            var value = p.join(':').trim();
134            po.headers[name] = value;
135            po.headerOrder.push(name);
136        }
137    });
138
139    var parsedPluralForms = PO.parsePluralForms(po.headers['Plural-Forms']);
140    var nplurals = parsedPluralForms.nplurals;
141    var item = new PO.Item({ nplurals: nplurals });
142    var context = null;
143    var plural = 0;
144    var obsoleteCount = 0;
145    var noCommentLineCount = 0;
146
147    function finish() {
148        if (item.msgid.length > 0) {
149            if (obsoleteCount >= noCommentLineCount) {
150                item.obsolete = true;
151            }
152            obsoleteCount = 0;
153            noCommentLineCount = 0;
154            po.items.push(item);
155            item = new PO.Item({ nplurals: nplurals });
156        }
157    }
158
159    function extract(string) {
160        string = trim(string);
161        string = string.replace(/^[^"]*"|"$/g, '');
162        string = string.replace(/\\([abtnvfr'"\\?]|([0-7]{3})|x([0-9a-fA-F]{2}))/g, function (match, esc, oct, hex) {
163            if (oct) {
164                return String.fromCharCode(parseInt(oct, 8));
165            }
166            if (hex) {
167                return String.fromCharCode(parseInt(hex, 16));
168            }
169            switch (esc) {
170                case 'a':
171                    return '\x07';
172                case 'b':
173                    return '\b';
174                case 't':
175                    return '\t';
176                case 'n':
177                    return '\n';
178                case 'v':
179                    return '\v';
180                case 'f':
181                    return '\f';
182                case 'r':
183                    return '\r';
184                default:
185                    return esc;
186            }
187        });
188        return string;
189    }
190
191    while (lines.length > 0) {
192        var line = trim(lines.shift());
193        var lineObsolete = false;
194        var add = false;
195
196        if (line.match(/^#\~/)) { // Obsolete item
197            //only remove the obsolte comment mark, here
198            //might be, this is a new item, so
199            //only remember, this line is marked obsolete, count after line is parsed
200            line = trim(line.substring(2));
201            lineObsolete = true;
202        }
203
204        if (line.match(/^#:/)) { // Reference
205            finish();
206            item.references.push(trim(line.replace(/^#:/, '')));
207        } else if (line.match(/^#,/)) { // Flags
208            finish();
209            var flags = trim(line.replace(/^#,/, '')).split(',');
210            for (var i = 0; i < flags.length; i++) {
211                item.flags[flags[i]] = true;
212            }
213        } else if (line.match(/^#($|\s+)/)) { // Translator comment
214            finish();
215            item.comments.push(trim(line.replace(/^#($|\s+)/, '')));
216        } else if (line.match(/^#\./)) { // Extracted comment
217            finish();
218            item.extractedComments.push(trim(line.replace(/^#\./, '')));
219        } else if (line.match(/^msgid_plural/)) { // Plural form
220            item.msgid_plural = extract(line);
221            context = 'msgid_plural';
222            noCommentLineCount++;
223        } else if (line.match(/^msgid/)) { // Original
224            finish();
225            item.msgid = extract(line);
226            context = 'msgid';
227            noCommentLineCount++;
228        } else if (line.match(/^msgstr/)) { // Translation
229            var m = line.match(/^msgstr\[(\d+)\]/);
230            plural = m && m[1] ? parseInt(m[1]) : 0;
231            item.msgstr[plural] = extract(line);
232            context = 'msgstr';
233            noCommentLineCount++;
234        } else if (line.match(/^msgctxt/)) { // Context
235            finish();
236            item.msgctxt = extract(line);
237            context = 'msgctxt';
238            noCommentLineCount++;
239        } else { // Probably multiline string or blank
240            if (line.length > 0) {
241                noCommentLineCount++;
242                if (context === 'msgstr') {
243                    item.msgstr[plural] += extract(line);
244                } else if (context === 'msgid') {
245                    item.msgid += extract(line);
246                } else if (context === 'msgid_plural') {
247                    item.msgid_plural += extract(line);
248                } else if (context === 'msgctxt') {
249                    item.msgctxt += extract(line);
250                }
251            }
252        }
253
254        if (lineObsolete) {
255            // Count obsolete lines for this item
256            obsoleteCount++;
257        }
258    }
259    finish();
260
261    return po;
262};
263
264PO.parsePluralForms = function (pluralFormsString) {
265    var results = (pluralFormsString || '')
266        .split(';')
267        .reduce(function (acc, keyValueString) {
268            var trimmedString = keyValueString.trim();
269            var equalsIndex = trimmedString.indexOf('=');
270            var key = trimmedString.substring(0, equalsIndex).trim();
271            var value = trimmedString.substring(equalsIndex + 1).trim();
272            acc[key] = value;
273            return acc;
274        }, {});
275    return {
276        nplurals: results.nplurals,
277        plural: results.plural
278    };
279};
280
281PO.Item = function (options) {
282    var nplurals = options && options.nplurals;
283
284    this.msgid = '';
285    this.msgctxt = null;
286    this.references = [];
287    this.msgid_plural = null;
288    this.msgstr = [];
289    this.comments = []; // translator comments
290    this.extractedComments = [];
291    this.flags = {};
292    this.obsolete = false;
293    var npluralsNumber = Number(nplurals);
294    this.nplurals = (isNaN(npluralsNumber)) ? 2 : npluralsNumber;
295};
296
297PO.Item.prototype.toString = function () {
298    var lines = [];
299    var self = this;
300
301    // reverse what extract(string) method during PO.parse does
302    var _escape = function (string) {
303        // don't unescape \n, since string can never contain it
304        // since split('\n') is called on it
305        string = string.replace(/[\x07\b\t\v\f\r"\\]/g, function (match) {
306            switch (match) {
307                case '\x07':
308                    return '\\a';
309                case '\b':
310                    return '\\b';
311                case '\t':
312                    return '\\t';
313                case '\v':
314                    return '\\v';
315                case '\f':
316                    return '\\f';
317                case '\r':
318                    return '\\r';
319                default:
320                    return '\\' + match;
321            }
322        });
323        return string;
324    };
325
326    var _process = function (keyword, text, i) {
327        var lines = [];
328        var parts = text.split(/\n/);
329        var index = typeof i !== 'undefined' ? '[' + i + ']' : '';
330        if (parts.length > 1) {
331            lines.push(keyword + index + ' ""');
332            parts.forEach(function (part) {
333                lines.push('"' + _escape(part) + '"');
334            });
335        } else {
336            lines.push(keyword + index + ' "' + _escape(text) + '"');
337        }
338        return lines;
339    };
340
341    //handle \n in single-line texts (can not be handled in _escape)
342    var _processLineBreak = function (keyword, text, index) {
343        var processed = _process(keyword, text, index);
344        for (var i = 1; i < processed.length - 1; i++) {
345            processed[i] = processed[i].slice(0, -1) + '\\n"';
346        }
347        return processed;
348    };
349
350    // https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
351    // says order is translator-comments, extracted-comments, references, flags
352
353    this.comments.forEach(function (c) {
354        lines.push('# ' + c);
355    });
356
357    this.extractedComments.forEach(function (c) {
358        lines.push('#. ' + c);
359    });
360
361    this.references.forEach(function (ref) {
362        lines.push('#: ' + ref);
363    });
364
365    var flags = Object.keys(this.flags).filter(function (flag) {
366        return !!this.flags[flag];
367    }, this);
368    if (flags.length > 0) {
369        lines.push('#, ' + flags.join(','));
370    }
371    var mkObsolete = this.obsolete ? '#~ ' : '';
372
373    ['msgctxt', 'msgid', 'msgid_plural', 'msgstr'].forEach(function (keyword) {
374        var text = self[keyword];
375        if (text != null) {
376            var hasTranslation = false;
377            if (Array.isArray(text)) {
378                hasTranslation = text.some(function (text) {
379                    return text;
380                });
381            }
382
383            if (Array.isArray(text) && text.length > 1) {
384                text.forEach(function (t, i) {
385                    var processed = _processLineBreak(keyword, t, i);
386                    lines = lines.concat(mkObsolete + processed.join('\n' + mkObsolete));
387                });
388            } else if (self.msgid_plural && keyword === 'msgstr' && !hasTranslation) {
389                for (var pluralIndex = 0; pluralIndex < self.nplurals; pluralIndex++) {
390                    lines = lines.concat(mkObsolete + _process(keyword, '', pluralIndex));
391                }
392            } else {
393                var index = (self.msgid_plural && Array.isArray(text)) ?
394                    0 :
395                    undefined;
396                text = Array.isArray(text) ? text.join() : text;
397                var processed = _processLineBreak(keyword, text, index);
398                lines = lines.concat(mkObsolete + processed.join('\n' + mkObsolete));
399            }
400        }
401    });
402
403    return lines.join('\n');
404};
405
406module.exports = PO;
407
408},{"fs":1}]},{},["pofile"]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.