View | Details | Raw Unified | Return to bug 29695
Collapse All | Expand All

(-)a/gulpfile.js (-369 lines)
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
}
(-)a/koha-tmpl/intranet-tmpl/prog/en/columns.def (-149 lines)
Lines 1-148 Link Here
1
<field name="borrowers.borrowernumber">Borrower number</field>
2
<field name="borrowers.title">Salutation</field>
3
<field name="borrowers.surname">Surname</field>
4
<field name="borrowers.firstname">First name</field>
5
<field name="borrowers.dateofbirth">Date of birth</field>
6
<field name="borrowers.initials">Initials</field>
7
<field name="borrowers.othernames">Other name</field>
8
<field name="borrowers.sex">Gender</field>
9
<field name="borrowers.relationship">Relationship</field>
10
<field name="borrowers.streetnumber">Street number</field>
11
<field name="borrowers.streettype">Street type</field>
12
<field name="borrowers.address">Address</field>
13
<field name="borrowers.address2">Address 2</field>
14
<field name="borrowers.city">City</field>
15
<field name="borrowers.state">State</field>
16
<field name="borrowers.zipcode">ZIP/Postal code</field>
17
<field name="borrowers.country">Country</field>
18
<field name="borrowers.phone">Primary phone</field>
19
<field name="borrowers.phonepro">Secondary phone</field>
20
<field name="borrowers.mobile">Other phone</field>
21
<field name="borrowers.email">Primary email</field>
22
<field name="borrowers.emailpro">Secondary email</field>
23
<field name="borrowers.fax">Fax</field>
24
<field name="borrowers.B_streetnumber">Alternate address: Street number</field>
25
<field name="borrowers.B_streettype">Alternate address: Street type</field>
26
<field name="borrowers.B_address">Alternate address: Address</field>
27
<field name="borrowers.B_address2">Alternate address: Address 2</field>
28
<field name="borrowers.B_city">Alternate address: City</field>
29
<field name="borrowers.B_state">Alternate address: State</field>
30
<field name="borrowers.B_zipcode">Alternate address: ZIP/Postal code</field>
31
<field name="borrowers.B_country">Alternate address: Country</field>
32
<field name="borrowers.B_phone">Alternate address: Phone</field>
33
<field name="borrowers.B_email">Alternate address: Email</field>
34
<field name="borrowers.contactnote">Alternate contact: Note</field>
35
<field name="borrowers.altcontactfirstname">Alternate contact: First name</field>
36
<field name="borrowers.altcontactsurname">Alternate contact: Surname</field>
37
<field name="borrowers.altcontactaddress1">Alternate contact: Address</field>
38
<field name="borrowers.altcontactaddress2">Alternate contact: Address 2</field>
39
<field name="borrowers.altcontactaddress3">Alternate contact: City</field>
40
<field name="borrowers.contactname">Alternate contact: Surname</field>
41
<field name="borrowers.contactfirstname">Alternate contact: First name</field>
42
<field name="borrowers.contacttitle">Alternate contact: Title</field>
43
<field name="borrowers.altcontactstate">Alternate contact: State</field>
44
<field name="borrowers.altcontactzipcode">Alternate contact: ZIP/Postal code</field>
45
<field name="borrowers.altcontactcountry">Alternate contact: Country</field>
46
<field name="borrowers.altcontactphone">Alternate contact: Phone</field>
47
<field name="borrowers.cardnumber">Card number</field>
48
<field name="borrowers.branchcode">Home library</field>
49
<field name="borrowers.categorycode">Patron category</field>
50
<field name="borrowers.sort1">Sort 1</field>
51
<field name="borrowers.sort2">Sort 2</field>
52
<field name="borrowers.dateenrolled">Registration date</field>
53
<field name="borrowers.dateexpiry">Expiry date</field>
54
<field name="borrowers.opacnote">OPAC note</field>
55
<field name="borrowers.borrowernotes">Circulation note</field>
56
<field name="borrowers.userid">Username</field>
57
<field name="borrowers.password">Password</field>
58
<field name="borrowers.flags">System permissions</field>
59
<field name="borrowers.gonenoaddress">Gone no address flag</field>
60
<field name="borrowers.lost">Lost card flag</field>
61
<field name="borrowers.debarred">Restricted [until] flag</field>
62
<field name="borrowers.debarredcomment">Comment</field>
63
<field name="borrowers.smsalertnumber">Mobile phone number</field>
64
<field name="borrowers.privacy">Privacy settings</field>
65
<field name="items.itemnumber">Item number (internal)</field>
66
<field name="items.biblionumber">Biblio number (internal)</field>
67
<field name="items.biblioitemnumber">Biblioitem number (internal)</field>
68
<field name="items.barcode">Barcode</field>
69
<field name="items.dateaccessioned">Date acquired</field>
70
<field name="items.booksellerid">Source of acquisition</field>
71
<field name="items.homebranch">Permanent library</field>
72
<field name="items.price">Price</field>
73
<field name="items.replacementprice">Replacement price</field>
74
<field name="items.replacementpricedate">Price effective from</field>
75
<field name="items.datelastborrowed">Date last checked out</field>
76
<field name="items.datelastseen">Date last seen</field>
77
<field name="items.stack">Shelving control number</field>
78
<field name="items.onloan">Due date</field>
79
<field name="items.cn_source">Source of classification / shelving scheme</field>
80
<field name="items.cn_sort">Koha normalized classification for sorting</field>
81
<field name="items.notforloan">Not for loan</field>
82
<field name="items.itemlost">Lost status</field>
83
<field name="items.itemlost_on">Lost on</field>
84
<field name="items.withdrawn">Withdrawn status</field>
85
<field name="items.withdrawn_on">Withdrawn on</field>
86
<field name="items.itemcallnumber">Call number</field>
87
<field name="items.issues">Total checkouts</field>
88
<field name="items.renewals">Total renewals</field>
89
<field name="items.reserves">Total holds</field>
90
<field name="items.restricted">Use restrictions</field>
91
<field name="items.itemnotes">Public note</field>
92
<field name="items.itemnotes_nonpublic">Internal note</field>
93
<field name="items.holdingbranch">Current library</field>
94
<field name="items.timestamp">Timestamp</field>
95
<field name="items.location">Shelving location</field>
96
<field name="items.permanent_location">Permanent shelving location</field>
97
<field name="items.ccode">Collection code</field>
98
<field name="items.itype">Koha itemtype</field>
99
<field name="items.stocknumber">Inventory number</field>
100
<field name="items.damaged">Damaged status</field>
101
<field name="items.damaged_on">Damaged on</field>
102
<field name="items.materials">Materials specified</field>
103
<field name="items.uri">Uniform Resource Identifier</field>
104
<field name="items.more_subfields_xml">Additional subfields (XML)</field>
105
<field name="items.enumchron">Serial enumeraton/chronology</field>
106
<field name="items.copynumber">Copy number</field>
107
<field name="statistics.datetime">Statistics date and time</field>
108
<field name="statistics.branch">Library</field>
109
<field name="statistics.value">Value</field>
110
<field name="statistics.type">Type</field>
111
<field name="statistics.other"></field>
112
<field name="statistics.itemnumber">Item number</field>
113
<field name="statistics.itemtype">Itemtype</field>
114
<field name="statistics.borrowernumber">Borrower number</field>
115
<field name="biblio.frameworkcode">Framework code</field>
116
<field name="biblio.author">Author</field>
117
<field name="biblio.datecreated">Creation date</field>
118
<field name="biblio.timestamp">Modification date</field>
119
<field name="biblioitems.biblioitemnumber">Biblioitem number</field>
120
<field name="biblioitems.biblionumber">Biblio number</field>
121
<field name="biblioitems.volume">Volume number</field>
122
<field name="biblioitems.number">Number</field>
123
<field name="biblioitems.classification">Classification</field>
124
<field name="biblioitems.itemtype">Biblio-level item type</field>
125
<field name="biblioitems.isbn">ISBN</field>
126
<field name="biblioitems.issn">ISSN</field>
127
<field name="biblioitems.dewey">Dewey/classification</field>
128
<field name="biblioitems.subclass">Sub classification</field>
129
<field name="biblioitems.publicationyear">Publication date</field>
130
<field name="biblioitems.publishercode">Publisher</field>
131
<field name="biblioitems.volumedate">Volume date</field>
132
<field name="biblioitems.volumedesc">Volume information</field>
133
<field name="biblioitems.timestamp">Timestamp</field>
134
<field name="biblioitems.illus">Illustrations</field>
135
<field name="biblioitems.pages">Number of pages</field>
136
<field name="biblioitems.notes">Notes</field>
137
<field name="biblioitems.size">Size</field>
138
<field name="biblioitems.place">Place of publication</field>
139
<field name="biblioitems.lccn">LCCN</field>
140
<field name="biblioitems.agerestriction">Age restriction</field>
141
<field name="biblioitems.url">URL</field>
142
<field name="biblioitems.title">Title</field>
143
<field name="subscription.startdate">Start date</field>
144
<field name="subscription.enddate">End date</field>
145
<field name="subscription.periodicity">Periodicity</field>
146
<field name="subscription.callnumber">Call number</field>
147
<field name="subscription.location">Location</field>
148
<field name="subscription.branchcode">Library</field>
149
- 

Return to bug 29695