@tim-greller/xgettext-regex 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.travis.yml +3 -0
- package/LICENCE +5 -0
- package/README.md +53 -0
- package/bin/usage.txt +17 -0
- package/bin/xgettext-regex.js +39 -0
- package/index.js +186 -0
- package/package.json +45 -0
- package/test/fixtures/index.jade +2 -0
- package/test/fixtures/index.php +3 -0
- package/test/fixtures/js/app.js +5 -0
- package/test/fixtures/js/plugin.js +3 -0
- package/test/test.js +110 -0
package/.travis.yml
ADDED
package/LICENCE
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Copyright (c) 2014, Alan Shaw
|
|
2
|
+
|
|
3
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
|
4
|
+
|
|
5
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# xgettext-regex
|
|
2
|
+
|
|
3
|
+
Minimum viable xgettext .pot file generator. Uses a configurable regex to get translation keys.
|
|
4
|
+
|
|
5
|
+
## Examples
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
cat foo.js | xgettext-regex # Output to stdout
|
|
9
|
+
xgettext-regex foo.js -o foo.po # Output to foo.po
|
|
10
|
+
xgettext-regex app-dir -o app.po # Recursive read directory
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
var fs = require('fs')
|
|
15
|
+
var xgettext = require('xgettext-regex')
|
|
16
|
+
|
|
17
|
+
var src = '/path/to/file'
|
|
18
|
+
var dest = '/path/to/en-GB.po'
|
|
19
|
+
var opts = {}
|
|
20
|
+
|
|
21
|
+
fs.createReadStream(src)
|
|
22
|
+
.pipe(xgettext(src, opts))
|
|
23
|
+
.pipe(fs.createWriteStream(dest))
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
var fs = require('fs')
|
|
28
|
+
var xgettext = require('xgettext-regex')
|
|
29
|
+
|
|
30
|
+
var files = ['/path/to/file.js', '/path/to/html/dir']
|
|
31
|
+
var opts = {}
|
|
32
|
+
|
|
33
|
+
xgettext.createReadStream(files, opts))
|
|
34
|
+
.pipe(fs.createWriteStream('/path/to/en-GB.po'))
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Options
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
opts = {
|
|
41
|
+
/* i18n function name */
|
|
42
|
+
fn: '_',
|
|
43
|
+
/* The regex used to match i18n function calls */
|
|
44
|
+
regex: /_\(((["'])(?:(?=(\\?))\3.)*?\2)\)/g,
|
|
45
|
+
/* Capture index for the i18n text in the above regex */
|
|
46
|
+
regexTextCaptureIndex: 1,
|
|
47
|
+
/* readdirp filters etc. */
|
|
48
|
+
readdirp: {
|
|
49
|
+
fileFilter: ['!.*', '!*.png', '!*.jpg', '!*.gif', , '!*.zip', , '!*.gz'],
|
|
50
|
+
directoryFilter: ['!.*', '!node_modules', '!coverage']
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
package/bin/usage.txt
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Usage: xgettext-regex [files] {OPTIONS}
|
|
2
|
+
|
|
3
|
+
Standard Options:
|
|
4
|
+
|
|
5
|
+
--outfile, -o Write the .pot formatted output to this file.
|
|
6
|
+
If unspecified, xgettext-regex prints to stdout.
|
|
7
|
+
|
|
8
|
+
--fn, -f Name of the i18n translation function.
|
|
9
|
+
Defaults to "_" if unspecified.
|
|
10
|
+
|
|
11
|
+
--help, -h Show this message.
|
|
12
|
+
|
|
13
|
+
--regex, -r Complete regex that matches string literals in translation functions.
|
|
14
|
+
Defaults to the name of the i18n function followed by "\(((["'])(?:(?=(\\?))\3.)*?\2)\)".
|
|
15
|
+
|
|
16
|
+
--index, -i The index of the capturing group that contains the match's string literal.
|
|
17
|
+
Defaults to 1 if unspecified.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var fs = require('fs')
|
|
3
|
+
var argv = require('minimist')(process.argv.slice(2))
|
|
4
|
+
var path = require('path')
|
|
5
|
+
var xgettext = require('../')
|
|
6
|
+
|
|
7
|
+
if (argv.v || argv.version) {
|
|
8
|
+
return console.log(require('../package.json').version)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (argv.h || argv.help) {
|
|
12
|
+
return fs.createReadStream(__dirname + '/usage.txt').pipe(process.stdout)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
var outFile = argv.o || argv.outfile
|
|
16
|
+
var opts = {
|
|
17
|
+
fn: (argv.f || argv.fn)
|
|
18
|
+
}
|
|
19
|
+
if (argv.r || argv.regex) opts.regex = new RegExp(argv.r || argv.regex, 'g')
|
|
20
|
+
if (argv.i || argv.index) opts.regexTextCaptureIndex = argv.i || argv.index
|
|
21
|
+
|
|
22
|
+
if (argv._.length) {
|
|
23
|
+
var files = argv._.map(function (filename) { return path.resolve(filename) })
|
|
24
|
+
var readable = xgettext.createReadStream(files, opts)
|
|
25
|
+
|
|
26
|
+
if (outFile) {
|
|
27
|
+
readable.pipe(fs.createWriteStream(outFile))
|
|
28
|
+
} else {
|
|
29
|
+
readable.pipe(process.stdout)
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
var duplex = xgettext('process.stdin', opts)
|
|
33
|
+
|
|
34
|
+
if (outFile) {
|
|
35
|
+
process.stdin.pipe(duplex).pipe(fs.createWriteStream(outFile))
|
|
36
|
+
} else {
|
|
37
|
+
process.stdin.pipe(duplex).pipe(process.stdout)
|
|
38
|
+
}
|
|
39
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
var fs = require('fs')
|
|
2
|
+
var path = require('path')
|
|
3
|
+
var Readable = require('stream').Readable
|
|
4
|
+
var through = require('through2')
|
|
5
|
+
var readdirp = require('readdirp')
|
|
6
|
+
var once = require('once')
|
|
7
|
+
var split = require('split')
|
|
8
|
+
var xtend = require('xtend')
|
|
9
|
+
var combine = require('stream-combiner')
|
|
10
|
+
|
|
11
|
+
function createDuplexStream (filename, opts) {
|
|
12
|
+
filename = filename || ''
|
|
13
|
+
opts = opts || {}
|
|
14
|
+
opts.fn = opts.fn || '_'
|
|
15
|
+
/*
|
|
16
|
+
* RegExp explaination
|
|
17
|
+
*
|
|
18
|
+
* (?<= begin of a positive lookbehind that makes sure that the string literal is an argument of the i18n function
|
|
19
|
+
* opts.fn i18n function name
|
|
20
|
+
* \(\s* opening paranthesis followed by optional whitespace
|
|
21
|
+
* (?: non capturing group matching individual prior arguments to the function and their delimeters
|
|
22
|
+
* (?: non capturing group matching a single prior argument
|
|
23
|
+
* "(?:[^"]|\\.)*" possible argument: a string literal quoted with double quotes, containing only escaped quotes if any
|
|
24
|
+
* | or
|
|
25
|
+
* '(?:[^']|\\.)*' same with single quotes
|
|
26
|
+
* ) end of single argument
|
|
27
|
+
* \s*,\s* delimeter: the arguments are seperated by commas and optional whitespace
|
|
28
|
+
* )* end of argument list, ending with a delimeter
|
|
29
|
+
* ) end of positive lookbehind and therefore everything that comes before the actual string literal that should be matched
|
|
30
|
+
*
|
|
31
|
+
* ( begin first capturing group containing the string value including its quotes (stripped away later via text.slice(1, -1))
|
|
32
|
+
* (["']) second capturing group containing the quote character
|
|
33
|
+
* (?: begin non capturing group containing a single (escaped or unescaped) character of the string literal's text content
|
|
34
|
+
* (?= begin of a positive lookahead matching and capturing a backslash, if there is one at the current position
|
|
35
|
+
* (\\?) capturing the backslash (or an empty string) in \3
|
|
36
|
+
* )
|
|
37
|
+
* \3. matches any character, optionally preceeded by a backslash.
|
|
38
|
+
* )*? end of the character. The lazy repetition ensures, that no quotes (\2) are included. Escaped quotes are included, because the character immediately after a backslash is always included, since \3 is followed by a dot and therefore the string cannot end with a backslash, but automatically matches the next character as well.
|
|
39
|
+
* \2 the quote character, closing the string literal
|
|
40
|
+
* ) end of the capturing group containing the string literal
|
|
41
|
+
*
|
|
42
|
+
* (?= begin of a positive lookahead matching any paramters that might follow after the target string literal
|
|
43
|
+
* (?: analogous to the beginning: non capturing group matching arguments and their delimeters
|
|
44
|
+
* \s*,\s* now we start with the delimeter
|
|
45
|
+
* (?: match single argument
|
|
46
|
+
* "(?:[^"]|\\.)*" string literal with double quotes
|
|
47
|
+
* |'(?:[^']|\\.)*' or with single quotes
|
|
48
|
+
* |[^"')]+ or without any quotes (numbers, object references, variables, ...). Cannot contain any paranthesis either, as it is not possible to ensure that every closing bracket has a preceding opening one with regex (would require at least a context free language)
|
|
49
|
+
* )
|
|
50
|
+
* )* end of argument list
|
|
51
|
+
* \s* optional whitespace
|
|
52
|
+
* \) closing paranthesis
|
|
53
|
+
* ) end of positive lookahead
|
|
54
|
+
*/
|
|
55
|
+
opts.regex = opts.regex || new RegExp("(?<=" + opts.fn + "\\(\\s*(?:(?:\"(?:[^\"]|\\\\.)*\"|'(?:[^']|\\\\.)*')\\s*,\\s*)*)(([\"'])(?:(?=(\\\\?))\\3.)*?\\2)(?=(?:\\s*,\\s*(?:\"(?:[^\"]|\\\\.)*\"|'(?:[^']|\\\\.)*'|[^\"')]+))*\\s*\\))", 'g')
|
|
56
|
+
opts.regexTextCaptureIndex = opts.regexTextCaptureIndex || 1
|
|
57
|
+
|
|
58
|
+
var lineNum = 1
|
|
59
|
+
|
|
60
|
+
return combine(
|
|
61
|
+
split(),
|
|
62
|
+
through(function (line, enc, cb) {
|
|
63
|
+
line = line.toString()
|
|
64
|
+
|
|
65
|
+
var matches
|
|
66
|
+
var first = true
|
|
67
|
+
|
|
68
|
+
while ((matches = opts.regex.exec(line)) !== null) {
|
|
69
|
+
var entry = '\n'
|
|
70
|
+
|
|
71
|
+
if (first) {
|
|
72
|
+
const relativeFilename = path.relative(process.cwd(), filename)
|
|
73
|
+
entry += '#: ' + relativeFilename + ':' + lineNum + '\n'
|
|
74
|
+
first = false
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
var text = matches[opts.regexTextCaptureIndex]
|
|
78
|
+
|
|
79
|
+
if (text[0] == "'") {
|
|
80
|
+
text = text.slice(1, -1)
|
|
81
|
+
text = text.replace(/\\'/g, "'")
|
|
82
|
+
text = '"' + text.replace(/"/g, '\\"') + '"'
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
entry += 'msgid ' + text + '\n'
|
|
86
|
+
entry += 'msgstr ' + text + '\n'
|
|
87
|
+
|
|
88
|
+
this.push(entry)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
lineNum++
|
|
92
|
+
opts.regex.lastIndex = 0
|
|
93
|
+
cb()
|
|
94
|
+
})
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = createDuplexStream
|
|
99
|
+
|
|
100
|
+
module.exports.createReadStream = function (files, opts) {
|
|
101
|
+
if (!Array.isArray(files)) files = [files]
|
|
102
|
+
|
|
103
|
+
var index = 0
|
|
104
|
+
var readable = new Readable()
|
|
105
|
+
|
|
106
|
+
readable._read = function () {
|
|
107
|
+
var push = true
|
|
108
|
+
|
|
109
|
+
while (push && index < files.length) {
|
|
110
|
+
push = this.push(files[index])
|
|
111
|
+
index++
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this.push(null)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return readable.pipe(createDuplexFileStream(opts))
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function getText (filename, opts) {
|
|
121
|
+
return fs.createReadStream(filename).pipe(createDuplexStream(filename, opts))
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
var READDIRP_OPTS = {
|
|
125
|
+
fileFilter: ['!.*', '!*.png', '!*.jpg', '!*.gif', '!*.zip', '!*.gz'],
|
|
126
|
+
directoryFilter: ['!.*', '!node_modules', '!coverage']
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function createDuplexFileStream (opts) {
|
|
130
|
+
opts = opts || {}
|
|
131
|
+
opts.readdirp = opts.readdirp || {}
|
|
132
|
+
|
|
133
|
+
return through(function (filename, enc, cb) {
|
|
134
|
+
var self = this
|
|
135
|
+
filename = filename.toString()
|
|
136
|
+
cb = once(cb)
|
|
137
|
+
|
|
138
|
+
self.push('#, fuzzy\n')
|
|
139
|
+
self.push('msgid ""\n')
|
|
140
|
+
self.push('msgstr ""\n')
|
|
141
|
+
self.push('"Content-Type: text/plain; charset=UTF-8\\n"\n')
|
|
142
|
+
|
|
143
|
+
fs.stat(filename, function (er, stats) {
|
|
144
|
+
if (er) return cb(er)
|
|
145
|
+
|
|
146
|
+
if (stats.isFile()) {
|
|
147
|
+
getText(filename, opts)
|
|
148
|
+
.on('data', function (entry) {self.push(entry)})
|
|
149
|
+
.on('error', function (er) {
|
|
150
|
+
console.error('File getText error', filename, er)
|
|
151
|
+
cb(er)
|
|
152
|
+
})
|
|
153
|
+
.on('end', function () {
|
|
154
|
+
cb()
|
|
155
|
+
})
|
|
156
|
+
} else if (stats.isDirectory()) {
|
|
157
|
+
var total = 0
|
|
158
|
+
var complete = 0
|
|
159
|
+
var readdirpComplete = false
|
|
160
|
+
|
|
161
|
+
readdirp(filename, xtend(READDIRP_OPTS, opts.readdirp))
|
|
162
|
+
.on('data', function (entry) {
|
|
163
|
+
total++
|
|
164
|
+
|
|
165
|
+
getText(entry.fullPath, opts)
|
|
166
|
+
.on('data', function (entry) {self.push(entry)})
|
|
167
|
+
.on('error', function (er) {
|
|
168
|
+
console.error('Directory getText error', entry.fullPath, er)
|
|
169
|
+
cb(er)
|
|
170
|
+
})
|
|
171
|
+
.on('end', function () {
|
|
172
|
+
complete++
|
|
173
|
+
if (total == complete && readdirpComplete) cb()
|
|
174
|
+
})
|
|
175
|
+
})
|
|
176
|
+
.on('error', function (er) {
|
|
177
|
+
console.error('Directory error', filename, er)
|
|
178
|
+
cb(er)
|
|
179
|
+
})
|
|
180
|
+
.on('end', function () {
|
|
181
|
+
readdirpComplete = true
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tim-greller/xgettext-regex",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Minimum viable xgettext .po file generator. Uses a configurable regex to get translation keys.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "istanbul cover node_modules/.bin/tape test/test.js"
|
|
8
|
+
},
|
|
9
|
+
"author": "Alan Shaw",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"minimist": "^1.1.0",
|
|
13
|
+
"once": "^1.3.1",
|
|
14
|
+
"readdirp": "^3.1.3",
|
|
15
|
+
"split": "^1.0.1",
|
|
16
|
+
"stream-combiner": "^0.2.1",
|
|
17
|
+
"through2": "^3.0.1",
|
|
18
|
+
"xtend": "^4.0.0"
|
|
19
|
+
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"xgettext-regex": "bin/xgettext-regex.js"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"concat-stream": "^2.0.0",
|
|
25
|
+
"istanbul": "^0.4.5",
|
|
26
|
+
"tape": "^4.11.0"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/alanshaw/xgettext-regex.git"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"xgettext",
|
|
34
|
+
"gettext",
|
|
35
|
+
"i18n",
|
|
36
|
+
"l18n"
|
|
37
|
+
],
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/alanshaw/xgettext-regex/issues"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/alanshaw/xgettext-regex",
|
|
42
|
+
"directories": {
|
|
43
|
+
"test": "test"
|
|
44
|
+
}
|
|
45
|
+
}
|
package/test/test.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
var fs = require('fs')
|
|
2
|
+
var Readable = require('stream').Readable
|
|
3
|
+
var test = require('tape')
|
|
4
|
+
var concat = require('concat-stream')
|
|
5
|
+
var xgettext = require('../')
|
|
6
|
+
|
|
7
|
+
test('Can create .pot from code', function (t) {
|
|
8
|
+
t.plan(1)
|
|
9
|
+
|
|
10
|
+
var src = new Readable
|
|
11
|
+
src._read = function () {
|
|
12
|
+
this.push('_("foobar")\n\n')
|
|
13
|
+
this.push(null)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
src
|
|
17
|
+
.pipe(xgettext())
|
|
18
|
+
.pipe(concat({encoding: 'string'}, function (pot) {
|
|
19
|
+
t.ok(pot.indexOf('msgid "foobar"') > -1, 'msgid "foobar" exists')
|
|
20
|
+
t.end()
|
|
21
|
+
}))
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('Can deal with single quotes', function (t) {
|
|
25
|
+
t.plan(1)
|
|
26
|
+
|
|
27
|
+
var src = new Readable
|
|
28
|
+
src._read = function () {
|
|
29
|
+
this.push("blah;\n_('foobar')")
|
|
30
|
+
this.push(null)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
src
|
|
34
|
+
.pipe(xgettext())
|
|
35
|
+
.pipe(concat({encoding: 'string'}, function (pot) {
|
|
36
|
+
t.ok(pot.indexOf('msgid "foobar"') > -1, 'msgid "foobar" exists')
|
|
37
|
+
t.end()
|
|
38
|
+
}))
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('Can deal with escaped quotes', function (t) {
|
|
42
|
+
t.plan(2)
|
|
43
|
+
|
|
44
|
+
var src = new Readable
|
|
45
|
+
src._read = function () {
|
|
46
|
+
this.push("\n_('foobar\\'s');\nif(true){_(\"air \\\"quotes\\\"\")}")
|
|
47
|
+
this.push(null)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
src
|
|
51
|
+
.pipe(xgettext())
|
|
52
|
+
.pipe(concat({encoding: 'string'}, function (pot) {
|
|
53
|
+
t.ok(pot.indexOf('msgid "foobar\'s"') > -1, 'msgid "foobar\'s" exists')
|
|
54
|
+
t.ok(pot.indexOf('msgid "air \\"quotes\\""') > -1, 'msgid "air \\"quotes\\"" exists')
|
|
55
|
+
t.end()
|
|
56
|
+
}))
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('Can create .pot from single file', function (t) {
|
|
60
|
+
t.plan(1)
|
|
61
|
+
|
|
62
|
+
xgettext.createReadStream(__dirname + '/fixtures/index.jade')
|
|
63
|
+
.pipe(concat({encoding: 'string'}, function (pot) {
|
|
64
|
+
t.ok(pot.indexOf('msgid "index.js"') > -1, 'msgid "index.js" exists')
|
|
65
|
+
t.end()
|
|
66
|
+
}))
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('Can change i18n function', function (t) {
|
|
70
|
+
t.plan(1)
|
|
71
|
+
|
|
72
|
+
var src = new Readable
|
|
73
|
+
src._read = function () {
|
|
74
|
+
this.push("blah;\ni18n('foobar')")
|
|
75
|
+
this.push(null)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
src
|
|
79
|
+
.pipe(xgettext('src', {fn: 'i18n'}))
|
|
80
|
+
.pipe(concat({encoding: 'string'}, function (pot) {
|
|
81
|
+
t.ok(pot.indexOf('msgid "foobar"') > -1, 'msgid "foobar" exists')
|
|
82
|
+
t.end()
|
|
83
|
+
}))
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('Can create .pot from multiple files/directories', function (t) {
|
|
87
|
+
t.plan(6)
|
|
88
|
+
|
|
89
|
+
fs.readdir(__dirname + '/fixtures', function (er, files) {
|
|
90
|
+
t.ifError(er, 'No error getting fixtures dir listing')
|
|
91
|
+
|
|
92
|
+
files = files.map(function (f) {
|
|
93
|
+
return __dirname + '/fixtures/' + f
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
xgettext.createReadStream(files)
|
|
97
|
+
.pipe(concat({encoding: 'string'}, function (pot) {
|
|
98
|
+
// app.js
|
|
99
|
+
t.ok(pot.indexOf('msgid "app.js"') > -1, 'msgid "app.js" exists')
|
|
100
|
+
t.ok(pot.indexOf('msgid "There\'s pie in them hills"') > -1, 'msgid "There\'s pie in them hills" exists')
|
|
101
|
+
// plugin.js
|
|
102
|
+
t.ok(pot.indexOf('msgid "w00t!"') > -1, 'msgid "w00t!" exists')
|
|
103
|
+
// index.jade
|
|
104
|
+
t.ok(pot.indexOf('msgid "index.js"') > -1, 'msgid "index.js" exists')
|
|
105
|
+
// index.php
|
|
106
|
+
t.ok(pot.indexOf('msgid "php hypertext preprocessor"') > -1, 'msgid "php hypertext preprocessor" exists')
|
|
107
|
+
t.end()
|
|
108
|
+
}))
|
|
109
|
+
})
|
|
110
|
+
})
|