Lines 1-369
Link Here
|
1 |
/* eslint-env node */ |
|
|
2 |
/* eslint no-console:"off" */ |
3 |
|
4 |
const { dest, parallel, series, src, watch } = require('gulp'); |
5 |
|
6 |
const child_process = require('child_process'); |
7 |
const fs = require('fs'); |
8 |
const os = require('os'); |
9 |
const path = require('path'); |
10 |
const util = require('util'); |
11 |
|
12 |
const sass = require("gulp-sass"); |
13 |
const cssnano = require("gulp-cssnano"); |
14 |
const rtlcss = require('gulp-rtlcss'); |
15 |
const sourcemaps = require('gulp-sourcemaps'); |
16 |
const autoprefixer = require('gulp-autoprefixer'); |
17 |
const concatPo = require('gulp-concat-po'); |
18 |
const exec = require('gulp-exec'); |
19 |
const merge = require('merge-stream'); |
20 |
const through2 = require('through2'); |
21 |
const Vinyl = require('vinyl'); |
22 |
const args = require('minimist')(process.argv.slice(2)); |
23 |
const rename = require('gulp-rename'); |
24 |
|
25 |
const STAFF_JS_BASE = "koha-tmpl/intranet-tmpl/prog/js"; |
26 |
const STAFF_CSS_BASE = "koha-tmpl/intranet-tmpl/prog/css"; |
27 |
const OPAC_JS_BASE = "koha-tmpl/opac-tmpl/bootstrap/js"; |
28 |
const OPAC_CSS_BASE = "koha-tmpl/opac-tmpl/bootstrap/css"; |
29 |
|
30 |
if (args.view == "opac") { |
31 |
var css_base = OPAC_CSS_BASE; |
32 |
var js_base = OPAC_JS_BASE; |
33 |
} else { |
34 |
var css_base = STAFF_CSS_BASE; |
35 |
var js_base = STAFF_JS_BASE; |
36 |
} |
37 |
|
38 |
var sassOptions = { |
39 |
errLogToConsole: true, |
40 |
precision: 3 |
41 |
} |
42 |
|
43 |
// CSS processing for development |
44 |
function css() { |
45 |
var stream = src(css_base + "/src/**/*.scss") |
46 |
.pipe(sourcemaps.init()) |
47 |
.pipe(sass(sassOptions).on('error', sass.logError)) |
48 |
.pipe(autoprefixer()) |
49 |
.pipe(dest(css_base)); |
50 |
|
51 |
if (args.view == "opac") { |
52 |
stream = stream |
53 |
.pipe(rtlcss()) |
54 |
.pipe(rename({ |
55 |
suffix: '-rtl' |
56 |
})) // Append "-rtl" to the filename. |
57 |
.pipe(dest(css_base)); |
58 |
} |
59 |
|
60 |
stream = stream.pipe(sourcemaps.write('./maps')) |
61 |
.pipe(dest(css_base)); |
62 |
|
63 |
return stream; |
64 |
|
65 |
} |
66 |
|
67 |
// CSS processing for production |
68 |
function build() { |
69 |
var stream = src(css_base + "/src/**/*.scss") |
70 |
.pipe(sass(sassOptions).on('error', sass.logError)) |
71 |
.pipe(autoprefixer()) |
72 |
.pipe(cssnano({ |
73 |
zindex: false |
74 |
})) |
75 |
.pipe(dest(css_base)); |
76 |
|
77 |
if( args.view == "opac" ){ |
78 |
stream = stream.pipe(rtlcss()) |
79 |
.pipe(rename({ |
80 |
suffix: '-rtl' |
81 |
})) // Append "-rtl" to the filename. |
82 |
.pipe(dest(css_base)); |
83 |
} |
84 |
|
85 |
return stream; |
86 |
} |
87 |
|
88 |
const poTasks = { |
89 |
'marc-MARC21': { |
90 |
extract: po_extract_marc_marc21, |
91 |
create: po_create_marc_marc21, |
92 |
update: po_update_marc_marc21, |
93 |
}, |
94 |
'marc-UNIMARC': { |
95 |
extract: po_extract_marc_unimarc, |
96 |
create: po_create_marc_unimarc, |
97 |
update: po_update_marc_unimarc, |
98 |
}, |
99 |
'staff-prog': { |
100 |
extract: po_extract_staff, |
101 |
create: po_create_staff, |
102 |
update: po_update_staff, |
103 |
}, |
104 |
'opac-bootstrap': { |
105 |
extract: po_extract_opac, |
106 |
create: po_create_opac, |
107 |
update: po_update_opac, |
108 |
}, |
109 |
'pref': { |
110 |
extract: po_extract_pref, |
111 |
create: po_create_pref, |
112 |
update: po_update_pref, |
113 |
}, |
114 |
'messages': { |
115 |
extract: po_extract_messages, |
116 |
create: po_create_messages, |
117 |
update: po_update_messages, |
118 |
}, |
119 |
'messages-js': { |
120 |
extract: po_extract_messages_js, |
121 |
create: po_create_messages_js, |
122 |
update: po_update_messages_js, |
123 |
}, |
124 |
'installer': { |
125 |
extract: po_extract_installer, |
126 |
create: po_create_installer, |
127 |
update: po_update_installer, |
128 |
}, |
129 |
'installer-MARC21': { |
130 |
extract: po_extract_installer_marc21, |
131 |
create: po_create_installer_marc21, |
132 |
update: po_update_installer_marc21, |
133 |
}, |
134 |
}; |
135 |
|
136 |
const poTypes = Object.keys(poTasks); |
137 |
|
138 |
function po_extract_marc (type) { |
139 |
return src(`koha-tmpl/*-tmpl/*/en/**/*${type}*`, { read: false, nocase: true }) |
140 |
.pipe(xgettext('misc/translator/xgettext.pl --charset=UTF-8 -s', `Koha-marc-${type}.pot`)) |
141 |
.pipe(dest('misc/translator')) |
142 |
} |
143 |
|
144 |
function po_extract_marc_marc21 () { return po_extract_marc('MARC21') } |
145 |
function po_extract_marc_unimarc () { return po_extract_marc('UNIMARC') } |
146 |
|
147 |
function po_extract_staff () { |
148 |
const globs = [ |
149 |
'koha-tmpl/intranet-tmpl/prog/en/**/*.tt', |
150 |
'koha-tmpl/intranet-tmpl/prog/en/**/*.inc', |
151 |
'koha-tmpl/intranet-tmpl/prog/en/xslt/*.xsl', |
152 |
'koha-tmpl/intranet-tmpl/prog/en/columns.def', |
153 |
'!koha-tmpl/intranet-tmpl/prog/en/**/*MARC21*', |
154 |
'!koha-tmpl/intranet-tmpl/prog/en/**/*UNIMARC*', |
155 |
'!koha-tmpl/intranet-tmpl/prog/en/**/*marc21*', |
156 |
'!koha-tmpl/intranet-tmpl/prog/en/**/*unimarc*', |
157 |
]; |
158 |
|
159 |
return src(globs, { read: false, nocase: true }) |
160 |
.pipe(xgettext('misc/translator/xgettext.pl --charset=UTF-8 -s', 'Koha-staff-prog.pot')) |
161 |
.pipe(dest('misc/translator')) |
162 |
} |
163 |
|
164 |
function po_extract_opac () { |
165 |
const globs = [ |
166 |
'koha-tmpl/opac-tmpl/bootstrap/en/**/*.tt', |
167 |
'koha-tmpl/opac-tmpl/bootstrap/en/**/*.inc', |
168 |
'koha-tmpl/opac-tmpl/bootstrap/en/xslt/*.xsl', |
169 |
'!koha-tmpl/opac-tmpl/bootstrap/en/**/*MARC21*', |
170 |
'!koha-tmpl/opac-tmpl/bootstrap/en/**/*UNIMARC*', |
171 |
'!koha-tmpl/opac-tmpl/bootstrap/en/**/*marc21*', |
172 |
'!koha-tmpl/opac-tmpl/bootstrap/en/**/*unimarc*', |
173 |
]; |
174 |
|
175 |
return src(globs, { read: false, nocase: true }) |
176 |
.pipe(xgettext('misc/translator/xgettext.pl --charset=UTF-8 -s', 'Koha-opac-bootstrap.pot')) |
177 |
.pipe(dest('misc/translator')) |
178 |
} |
179 |
|
180 |
const xgettext_options = '--from-code=UTF-8 --package-name Koha ' |
181 |
+ '--package-version= -k -k__ -k__x -k__n:1,2 -k__nx:1,2 -k__xn:1,2 ' |
182 |
+ '-k__p:1c,2 -k__px:1c,2 -k__np:1c,2,3 -k__npx:1c,2,3 -kN__ ' |
183 |
+ '-kN__n:1,2 -kN__p:1c,2 -kN__np:1c,2,3 --force-po'; |
184 |
|
185 |
function po_extract_messages_js () { |
186 |
const globs = [ |
187 |
'koha-tmpl/intranet-tmpl/prog/js/**/*.js', |
188 |
'koha-tmpl/opac-tmpl/bootstrap/js/**/*.js', |
189 |
]; |
190 |
|
191 |
return src(globs, { read: false, nocase: true }) |
192 |
.pipe(xgettext(`xgettext -L JavaScript ${xgettext_options}`, 'Koha-messages-js.pot')) |
193 |
.pipe(dest('misc/translator')) |
194 |
} |
195 |
|
196 |
function po_extract_messages () { |
197 |
const perlStream = src(['**/*.pl', '**/*.pm'], { read: false, nocase: true }) |
198 |
.pipe(xgettext(`xgettext -L Perl ${xgettext_options}`, 'Koha-perl.pot')) |
199 |
|
200 |
const ttStream = src([ |
201 |
'koha-tmpl/intranet-tmpl/prog/en/**/*.tt', |
202 |
'koha-tmpl/intranet-tmpl/prog/en/**/*.inc', |
203 |
'koha-tmpl/opac-tmpl/bootstrap/en/**/*.tt', |
204 |
'koha-tmpl/opac-tmpl/bootstrap/en/**/*.inc', |
205 |
], { read: false, nocase: true }) |
206 |
.pipe(xgettext('misc/translator/xgettext-tt2 --from-code=UTF-8', 'Koha-tt.pot')) |
207 |
|
208 |
const headers = { |
209 |
'Project-Id-Version': 'Koha', |
210 |
'Content-Type': 'text/plain; charset=UTF-8', |
211 |
}; |
212 |
|
213 |
return merge(perlStream, ttStream) |
214 |
.pipe(concatPo('Koha-messages.pot', { headers })) |
215 |
.pipe(dest('misc/translator')) |
216 |
} |
217 |
|
218 |
function po_extract_pref () { |
219 |
return src('koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/*.pref', { read: false }) |
220 |
.pipe(xgettext('misc/translator/xgettext-pref', 'Koha-pref.pot')) |
221 |
.pipe(dest('misc/translator')) |
222 |
} |
223 |
|
224 |
function po_extract_installer () { |
225 |
const globs = [ |
226 |
'installer/data/mysql/en/mandatory/*.yml', |
227 |
'installer/data/mysql/en/optional/*.yml', |
228 |
]; |
229 |
|
230 |
return src(globs, { read: false, nocase: true }) |
231 |
.pipe(xgettext('misc/translator/xgettext-installer', 'Koha-installer.pot')) |
232 |
.pipe(dest('misc/translator')) |
233 |
} |
234 |
|
235 |
function po_extract_installer_marc (type) { |
236 |
const globs = `installer/data/mysql/en/marcflavour/${type}/**/*.yml`; |
237 |
|
238 |
return src(globs, { read: false, nocase: true }) |
239 |
.pipe(xgettext('misc/translator/xgettext-installer', `Koha-installer-${type}.pot`)) |
240 |
.pipe(dest('misc/translator')) |
241 |
} |
242 |
|
243 |
function po_extract_installer_marc21 () { return po_extract_installer_marc('MARC21') } |
244 |
|
245 |
function po_create_type (type) { |
246 |
const access = util.promisify(fs.access); |
247 |
const exec = util.promisify(child_process.exec); |
248 |
|
249 |
const languages = getLanguages(); |
250 |
const promises = []; |
251 |
for (const language of languages) { |
252 |
const locale = language.split('-').filter(s => s.length !== 4).join('_'); |
253 |
const po = `misc/translator/po/${language}-${type}.po`; |
254 |
const pot = `misc/translator/Koha-${type}.pot`; |
255 |
|
256 |
const promise = access(po) |
257 |
.catch(() => exec(`msginit -o ${po} -i ${pot} -l ${locale} --no-translator`)) |
258 |
promises.push(promise); |
259 |
} |
260 |
|
261 |
return Promise.all(promises); |
262 |
} |
263 |
|
264 |
function po_create_marc_marc21 () { return po_create_type('marc-MARC21') } |
265 |
function po_create_marc_unimarc () { return po_create_type('marc-UNIMARC') } |
266 |
function po_create_staff () { return po_create_type('staff-prog') } |
267 |
function po_create_opac () { return po_create_type('opac-bootstrap') } |
268 |
function po_create_pref () { return po_create_type('pref') } |
269 |
function po_create_messages () { return po_create_type('messages') } |
270 |
function po_create_messages_js () { return po_create_type('messages-js') } |
271 |
function po_create_installer () { return po_create_type('installer') } |
272 |
function po_create_installer_marc21 () { return po_create_type('installer-MARC21') } |
273 |
|
274 |
function po_update_type (type) { |
275 |
const msgmerge_opts = '--backup=off --quiet --sort-output --update'; |
276 |
const cmd = `msgmerge ${msgmerge_opts} <%= file.path %> misc/translator/Koha-${type}.pot`; |
277 |
const languages = getLanguages(); |
278 |
const globs = languages.map(language => `misc/translator/po/${language}-${type}.po`); |
279 |
|
280 |
return src(globs) |
281 |
.pipe(exec(cmd, { continueOnError: true })) |
282 |
.pipe(exec.reporter({ err: false, stdout: false })) |
283 |
} |
284 |
|
285 |
function po_update_marc_marc21 () { return po_update_type('marc-MARC21') } |
286 |
function po_update_marc_unimarc () { return po_update_type('marc-UNIMARC') } |
287 |
function po_update_staff () { return po_update_type('staff-prog') } |
288 |
function po_update_opac () { return po_update_type('opac-bootstrap') } |
289 |
function po_update_pref () { return po_update_type('pref') } |
290 |
function po_update_messages () { return po_update_type('messages') } |
291 |
function po_update_messages_js () { return po_update_type('messages-js') } |
292 |
function po_update_installer () { return po_update_type('installer') } |
293 |
function po_update_installer_marc21 () { return po_update_type('installer-MARC21') } |
294 |
|
295 |
/** |
296 |
* Gulp plugin that executes xgettext-like command `cmd` on all files given as |
297 |
* input, and then outputs the result as a POT file named `filename`. |
298 |
* `cmd` should accept -o and -f options |
299 |
*/ |
300 |
function xgettext (cmd, filename) { |
301 |
const filenames = []; |
302 |
|
303 |
function transform (file, encoding, callback) { |
304 |
filenames.push(path.relative(file.cwd, file.path)); |
305 |
callback(); |
306 |
} |
307 |
|
308 |
function flush (callback) { |
309 |
fs.mkdtemp(path.join(os.tmpdir(), 'koha-'), (err, folder) => { |
310 |
const outputFilename = path.join(folder, filename); |
311 |
const filesFilename = path.join(folder, 'files'); |
312 |
fs.writeFile(filesFilename, filenames.join(os.EOL), err => { |
313 |
if (err) return callback(err); |
314 |
|
315 |
const command = `${cmd} -o ${outputFilename} -f ${filesFilename}`; |
316 |
child_process.exec(command, err => { |
317 |
if (err) return callback(err); |
318 |
|
319 |
fs.readFile(outputFilename, (err, data) => { |
320 |
if (err) return callback(err); |
321 |
|
322 |
const file = new Vinyl(); |
323 |
file.path = path.join(file.base, filename); |
324 |
file.contents = data; |
325 |
callback(null, file); |
326 |
}); |
327 |
}); |
328 |
}); |
329 |
}) |
330 |
} |
331 |
|
332 |
return through2.obj(transform, flush); |
333 |
} |
334 |
|
335 |
/** |
336 |
* Return languages selected for PO-related tasks |
337 |
* |
338 |
* This can be either languages given on command-line with --lang option, or |
339 |
* all the languages found in misc/translator/po otherwise |
340 |
*/ |
341 |
function getLanguages () { |
342 |
if (Array.isArray(args.lang)) { |
343 |
return args.lang; |
344 |
} |
345 |
|
346 |
if (args.lang) { |
347 |
return [args.lang]; |
348 |
} |
349 |
|
350 |
const filenames = fs.readdirSync('misc/translator/po') |
351 |
.filter(filename => filename.endsWith('.po')) |
352 |
.filter(filename => !filename.startsWith('.')) |
353 |
|
354 |
const re = new RegExp('-(' + poTypes.join('|') + ')\.po$'); |
355 |
languages = filenames.map(filename => filename.replace(re, '')) |
356 |
|
357 |
return Array.from(new Set(languages)); |
358 |
} |
359 |
|
360 |
exports.build = build; |
361 |
exports.css = css; |
362 |
|
363 |
exports['po:create'] = parallel(...poTypes.map(type => series(poTasks[type].extract, poTasks[type].create))); |
364 |
exports['po:update'] = parallel(...poTypes.map(type => series(poTasks[type].extract, poTasks[type].update))); |
365 |
exports['po:extract'] = parallel(...poTypes.map(type => poTasks[type].extract)); |
366 |
|
367 |
exports.default = function () { |
368 |
watch(css_base + "/src/**/*.scss", series('css')); |
369 |
} |