@@ -6,6 +6,7 @@ var path = require('path');
6
6
var _ = require ( 'lodash' ) ;
7
7
var flat = require ( 'flat' ) ;
8
8
var gutil = require ( 'gulp-util' ) ;
9
+ var he = require ( 'he' ) ;
9
10
var through = require ( 'through2' ) ;
10
11
11
12
@@ -38,49 +39,67 @@ var defaults = {
38
39
ignoreErrors : false ,
39
40
dryRun : false ,
40
41
includeOriginal : false ,
41
- ignoreTokens : false
42
+ ignoreTokens : false ,
43
+ encodeEntities : true
42
44
} ;
43
45
46
+ /**
47
+ * A helper function to test whether an option was set to true or the value matches the options regular expression.
48
+ * @param {boolean|string|RegExp } needle
49
+ * @param {String } haystack
50
+ * @returns {boolean }
51
+ */
52
+ function trueOrMatch ( needle , haystack ) {
53
+ if ( needle === true ) {
54
+ return true ;
55
+ }
56
+ if ( needle instanceof RegExp && needle . test ( haystack ) ) {
57
+ return true ;
58
+ }
59
+ return ! ! ( needle instanceof String && haystack . indexOf ( needle ) !== - 1 ) ;
60
+
61
+ }
62
+
63
+
44
64
/**
45
65
* Loads the dictionaries from the locale directory.
46
66
* @param {Object } options
47
67
*/
48
68
function load ( options ) {
49
69
if ( cache [ options . locales ] ) {
50
- dictionaries = cache [ options . locales ] ;
51
- } else {
52
- try {
53
- var files = fs . readdirSync ( options . locales ) ;
54
- for ( var i in files ) {
55
- var file = files [ i ] ;
56
- switch ( path . extname ( file ) ) {
57
- case '.json' :
58
- case '.js' :
59
- dictionaries [ path . basename ( file , path . extname ( file ) ) ] = flat ( require ( path . join ( process . cwd ( ) , options . locales , file ) ) ) ;
60
- break ;
61
- case '.ini' :
62
- var iniData = fs . readFileSync ( path . join ( process . cwd ( ) , options . locales , file ) ) ;
63
- dictionaries [ path . basename ( file , path . extname ( file ) ) ] = flat ( ini2json ( iniData ) ) ;
64
- break ;
65
- case '.csv' :
66
- var csvData = fs . readFileSync ( path . join ( process . cwd ( ) , options . locales , file ) ) ;
67
- dictionaries [ path . basename ( file , path . extname ( file ) ) ] = csv2json ( csvData ) ;
68
- break ;
69
- }
70
- }
71
- if ( options . cache ) {
72
- cache [ options . locales ] = dictionaries ;
70
+ return dictionaries = cache [ options . locales ] ;
71
+ }
72
+ try {
73
+ var files = fs . readdirSync ( options . locales ) ;
74
+ for ( var i in files ) {
75
+ var file = files [ i ] ;
76
+ switch ( path . extname ( file ) ) {
77
+ case '.json' :
78
+ case '.js' :
79
+ dictionaries [ path . basename ( file , path . extname ( file ) ) ] = flat ( require ( path . join ( process . cwd ( ) , options . locales , file ) ) ) ;
80
+ break ;
81
+ case '.ini' :
82
+ var iniData = fs . readFileSync ( path . join ( process . cwd ( ) , options . locales , file ) ) ;
83
+ dictionaries [ path . basename ( file , path . extname ( file ) ) ] = flat ( ini2json ( iniData ) ) ;
84
+ break ;
85
+ case '.csv' :
86
+ var csvData = fs . readFileSync ( path . join ( process . cwd ( ) , options . locales , file ) ) ;
87
+ dictionaries [ path . basename ( file , path . extname ( file ) ) ] = csv2json ( csvData ) ;
88
+ break ;
73
89
}
74
- } catch ( e ) {
75
- throw new Error ( 'No translation dictionaries have been found!' ) ;
76
90
}
91
+ if ( options . cache ) {
92
+ cache [ options . locales ] = dictionaries ;
93
+ }
94
+ } catch ( e ) {
95
+ throw new Error ( 'No translation dictionaries have been found!' ) ;
77
96
}
78
97
}
79
98
80
99
/**
81
100
* Splits a line from an ini file into 2. Any subsequent '=' are ignored.
82
- * @param {string } line
83
- * @returns {string [] }
101
+ * @param {String } line
102
+ * @returns {String [] }
84
103
*/
85
104
function splitIniLine ( line ) {
86
105
var separator = line . indexOf ( '=' ) ;
@@ -95,7 +114,7 @@ function splitIniLine(line) {
95
114
96
115
/**
97
116
* Simple conversion helper to get a json file from an ini file.
98
- * @param {string } iniData
117
+ * @param {String } iniData
99
118
* @returns {{} }
100
119
*/
101
120
function ini2json ( iniData ) {
@@ -127,8 +146,8 @@ function ini2json(iniData) {
127
146
128
147
/**
129
148
* Converts a line of a CSV file to an array of strings, omitting empty fields.
130
- * @param {string } line
131
- * @returns {string [] }
149
+ * @param {String } line
150
+ * @returns {String [] }
132
151
*/
133
152
function splitCsvLine ( line ) {
134
153
if ( ! line . trim ( ) . length ) {
@@ -163,7 +182,7 @@ function splitCsvLine(line) {
163
182
164
183
/**
165
184
* Simple conversion helper to get a json file from a csv file.
166
- * @param {string } csvData
185
+ * @param {String } csvData
167
186
* @returns {Object }
168
187
*/
169
188
function csv2json ( csvData ) {
@@ -187,9 +206,9 @@ function csv2json(csvData) {
187
206
/**
188
207
* Performs the actual translation from a tokenized source to the final content.
189
208
* @param {Object } options
190
- * @param {string } contents
209
+ * @param {String } contents
191
210
* @param {number } copied
192
- * @param {string } filePath
211
+ * @param {String } filePath
193
212
* @returns {Object }
194
213
*/
195
214
function translate ( options , contents , copied , filePath ) {
@@ -205,7 +224,7 @@ function translate(options, contents, copied, filePath) {
205
224
throw new Error ( 'No translation dictionaries available to create any files!' ) ;
206
225
}
207
226
var i = contents . indexOf ( options . delimiter . prefix ) ;
208
- if ( ! ( options . ignoreTokens === true || options . ignoreTokens instanceof RegExp && options . ignoreTokens . test ( filePath ) ) ) {
227
+ if ( ! trueOrMatch ( options . ignoreTokens , filePath ) ) {
209
228
while ( ( i !== - 1 ) ) {
210
229
var endMatch , length , token , key ;
211
230
var tail = contents . substr ( i ) ;
@@ -226,8 +245,12 @@ function translate(options, contents, copied, filePath) {
226
245
for ( var lang in processed ) {
227
246
processed [ lang ] += contents . substring ( copied , i ) ;
228
247
if ( dictionaries [ lang ] [ key ] !== undefined ) {
229
- processed [ lang ] += dictionaries [ lang ] [ key ] ;
230
- } else if ( options . warn ) {
248
+ if ( trueOrMatch ( options . encodeEntities , filePath ) ) {
249
+ processed [ lang ] += he . encode ( dictionaries [ lang ] [ key ] , { useNamedReferences : true } ) ;
250
+ } else {
251
+ processed [ lang ] += dictionaries [ lang ] [ key ] ;
252
+ }
253
+ } else if ( trueOrMatch ( options . warn , filePath ) ) {
231
254
gutil . log ( 'Missing translation of language' , lang , 'for key' , key , 'in file' , filePath ) ;
232
255
}
233
256
processed [ lang ] += contents . substring ( i + length , next == - 1 ? contents . length : next ) ;
@@ -315,18 +338,18 @@ module.exports = function(options) {
315
338
316
339
try {
317
340
var files = replace ( file , options ) ;
318
- if ( options . dryRun === true || options . dryRun instanceof RegExp && options . dryRun . test ( file . path ) ) {
341
+ if ( trueOrMatch ( options . dryRun , file . path ) ) {
319
342
this . push ( file ) ;
320
343
} else {
321
- if ( options . includeOriginal === true || options . includeOriginal instanceof RegExp && options . includeOriginal . test ( file . path ) ) {
344
+ if ( trueOrMatch ( options . includeOriginal , file . path ) ) {
322
345
this . push ( file ) ;
323
346
}
324
347
for ( var i in files ) {
325
348
this . push ( files [ i ] ) ;
326
349
}
327
350
}
328
351
} catch ( err ) {
329
- if ( ! options . ignoreErrors ) {
352
+ if ( ! trueOrMatch ( options . ignoreErrors , file . path ) ) {
330
353
this . emit ( 'error' , new gutil . PluginError ( 'gulp-international' , err ) ) ;
331
354
}
332
355
}
0 commit comments