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

(-)a/Koha/Database/Columns.pm (-1 / +1 lines)
Lines 306-312 sub columns { Link Here
306
            "datetime"       => __("Statistics date and time"),
306
            "datetime"       => __("Statistics date and time"),
307
            "itemnumber"     => __("Item number"),
307
            "itemnumber"     => __("Item number"),
308
            "itemtype"       => __("Itemtype"),
308
            "itemtype"       => __("Itemtype"),
309
            "other"          => __(""),
309
            "other"          => "",
310
            "type"           => __("Type"),
310
            "type"           => __("Type"),
311
            "value"          => __("Value"),
311
            "value"          => __("Value"),
312
        },
312
        },
(-)a/gulpfile.js (-293 / +31 lines)
Lines 88-157 function staff_css(){ Link Here
88
    return css(STAFF_CSS_BASE);
88
    return css(STAFF_CSS_BASE);
89
}
89
}
90
90
91
const poTasks = {
92
    'marc-MARC21': {
93
        extract: po_extract_marc_marc21,
94
        create: po_create_marc_marc21,
95
        update: po_update_marc_marc21,
96
    },
97
    'marc-UNIMARC': {
98
        extract: po_extract_marc_unimarc,
99
        create: po_create_marc_unimarc,
100
        update: po_update_marc_unimarc,
101
    },
102
    'staff-prog': {
103
        extract: po_extract_staff,
104
        create: po_create_staff,
105
        update: po_update_staff,
106
    },
107
    'opac-bootstrap': {
108
        extract: po_extract_opac,
109
        create: po_create_opac,
110
        update: po_update_opac,
111
    },
112
    'pref': {
113
        extract: po_extract_pref,
114
        create: po_create_pref,
115
        update: po_update_pref,
116
    },
117
    'messages': {
118
        extract: po_extract_messages,
119
        create: po_create_messages,
120
        update: po_update_messages,
121
    },
122
    'messages-js': {
123
        extract: po_extract_messages_js,
124
        create: po_create_messages_js,
125
        update: po_update_messages_js,
126
    },
127
    'installer': {
128
        extract: po_extract_installer,
129
        create: po_create_installer,
130
        update: po_update_installer,
131
    },
132
    'installer-MARC21': {
133
        extract: po_extract_installer_marc21,
134
        create: po_create_installer_marc21,
135
        update: po_update_installer_marc21,
136
    },
137
    'installer-UNIMARC': {
138
        extract: po_extract_installer_unimarc,
139
        create: po_create_installer_unimarc,
140
        update: po_update_installer_unimarc,
141
    },
142
};
143
144
function getPoTasks () {
91
function getPoTasks () {
145
    let tasks = [];
92
    const all_tasks = ['marc-MARC21', 'marc-UNIMARC', 'staff-prog', 'opac-bootstrap', 'pref', 'messages', 'messages-js', 'installer', 'installer-MARC21', 'installer-UNIMARC'];
146
93
    if (!args.task) {
147
    let all_tasks = Object.keys(poTasks);
148
149
    if (args.task) {
150
        tasks = [args.task].flat(Infinity);
151
    } else {
152
        return all_tasks;
94
        return all_tasks;
153
    }
95
    }
154
96
97
    const tasks = [args.task].flat(Infinity);
98
155
    let invalid_tasks = tasks.filter( function( el ) {
99
    let invalid_tasks = tasks.filter( function( el ) {
156
        return all_tasks.indexOf( el ) < 0;
100
        return all_tasks.indexOf( el ) < 0;
157
    });
101
    });
Lines 163-398 function getPoTasks () { Link Here
163
107
164
    return tasks;
108
    return tasks;
165
}
109
}
166
const poTypes = getPoTasks();
167
168
function po_extract_marc (type) {
169
    return src(`koha-tmpl/*-tmpl/*/en/**/*${type}*`, { read: false, nocase: true })
170
        .pipe(xgettext('misc/translator/xgettext.pl --charset=UTF-8 -F', `Koha-marc-${type}.pot`))
171
        .pipe(dest('misc/translator'))
172
}
173
174
function po_extract_marc_marc21 ()  { return po_extract_marc('MARC21') }
175
function po_extract_marc_unimarc () { return po_extract_marc('UNIMARC') }
176
177
function po_extract_staff () {
178
    const globs = [
179
        'koha-tmpl/intranet-tmpl/prog/en/**/*.tt',
180
        'koha-tmpl/intranet-tmpl/prog/en/**/*.inc',
181
        'koha-tmpl/intranet-tmpl/prog/en/xslt/*.xsl',
182
        '!koha-tmpl/intranet-tmpl/prog/en/**/*MARC21*',
183
        '!koha-tmpl/intranet-tmpl/prog/en/**/*UNIMARC*',
184
        '!koha-tmpl/intranet-tmpl/prog/en/**/*marc21*',
185
        '!koha-tmpl/intranet-tmpl/prog/en/**/*unimarc*',
186
    ];
187
188
    return src(globs, { read: false, nocase: true })
189
        .pipe(xgettext('misc/translator/xgettext.pl --charset=UTF-8 -F', 'Koha-staff-prog.pot'))
190
        .pipe(dest('misc/translator'))
191
}
192
193
function po_extract_opac () {
194
    const globs = [
195
        'koha-tmpl/opac-tmpl/bootstrap/en/**/*.tt',
196
        'koha-tmpl/opac-tmpl/bootstrap/en/**/*.inc',
197
        'koha-tmpl/opac-tmpl/bootstrap/en/xslt/*.xsl',
198
        '!koha-tmpl/opac-tmpl/bootstrap/en/**/*MARC21*',
199
        '!koha-tmpl/opac-tmpl/bootstrap/en/**/*UNIMARC*',
200
        '!koha-tmpl/opac-tmpl/bootstrap/en/**/*marc21*',
201
        '!koha-tmpl/opac-tmpl/bootstrap/en/**/*unimarc*',
202
    ];
203
204
    return src(globs, { read: false, nocase: true })
205
        .pipe(xgettext('misc/translator/xgettext.pl --charset=UTF-8 -F', 'Koha-opac-bootstrap.pot'))
206
        .pipe(dest('misc/translator'))
207
}
208
209
const xgettext_options = '--from-code=UTF-8 --package-name Koha '
210
    + '--package-version= -k -k__ -k__x -k__n:1,2 -k__nx:1,2 -k__xn:1,2 '
211
    + '-k__p:1c,2 -k__px:1c,2 -k__np:1c,2,3 -k__npx:1c,2,3 -kN__ '
212
    + '-kN__n:1,2 -kN__p:1c,2 -kN__np:1c,2,3 '
213
    + '-k -k$__ -k$__x -k$__n:1,2 -k$__nx:1,2 -k$__xn:1,2 '
214
    + '--force-po';
215
216
function po_extract_messages_js () {
217
    const globs = [
218
        'koha-tmpl/intranet-tmpl/prog/js/vue/**/*.vue',
219
        'koha-tmpl/intranet-tmpl/prog/js/**/*.js',
220
        'koha-tmpl/opac-tmpl/bootstrap/js/**/*.js',
221
    ];
222
223
    return src(globs, { read: false, nocase: true })
224
        .pipe(xgettext(`xgettext -L JavaScript ${xgettext_options}`, 'Koha-messages-js.pot'))
225
        .pipe(dest('misc/translator'))
226
}
227
228
function po_extract_messages () {
229
    const perlStream = src(['**/*.pl', '**/*.pm'], { read: false, nocase: true })
230
        .pipe(xgettext(`xgettext -L Perl ${xgettext_options}`, 'Koha-perl.pot'))
231
232
    const ttStream = src([
233
            'koha-tmpl/intranet-tmpl/prog/en/**/*.tt',
234
            'koha-tmpl/intranet-tmpl/prog/en/**/*.inc',
235
            'koha-tmpl/opac-tmpl/bootstrap/en/**/*.tt',
236
            'koha-tmpl/opac-tmpl/bootstrap/en/**/*.inc',
237
        ], { read: false, nocase: true })
238
        .pipe(xgettext('misc/translator/xgettext-tt2 --from-code=UTF-8', 'Koha-tt.pot'))
239
240
    const headers = {
241
        'Project-Id-Version': 'Koha',
242
        'Content-Type': 'text/plain; charset=UTF-8',
243
    };
244
245
    return merge(perlStream, ttStream)
246
        .pipe(concatPo('Koha-messages.pot', { headers }))
247
        .pipe(dest('misc/translator'))
248
}
249
250
function po_extract_pref () {
251
    return src('koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/*.pref', { read: false })
252
        .pipe(xgettext('misc/translator/xgettext-pref', 'Koha-pref.pot'))
253
        .pipe(dest('misc/translator'))
254
}
255
256
function po_extract_installer () {
257
    const globs = [
258
        'installer/data/mysql/en/mandatory/*.yml',
259
        'installer/data/mysql/en/optional/*.yml',
260
    ];
261
262
    return src(globs, { read: false, nocase: true })
263
        .pipe(xgettext('misc/translator/xgettext-installer', 'Koha-installer.pot'))
264
        .pipe(dest('misc/translator'))
265
}
266
267
function po_extract_installer_marc (type) {
268
    const globs = `installer/data/mysql/en/marcflavour/${type}/**/*.yml`;
269
270
    return src(globs, { read: false, nocase: true })
271
        .pipe(xgettext('misc/translator/xgettext-installer', `Koha-installer-${type}.pot`))
272
        .pipe(dest('misc/translator'))
273
}
274
275
function po_extract_installer_marc21 ()  { return po_extract_installer_marc('MARC21') }
276
277
function po_extract_installer_unimarc ()  { return po_extract_installer_marc('UNIMARC') }
278
279
function po_create_type (type) {
280
    const access = util.promisify(fs.access);
281
    const exec = util.promisify(child_process.exec);
282
283
    const pot = `misc/translator/Koha-${type}.pot`;
284
285
    // Generate .pot only if it doesn't exist or --force-extract is given
286
    const extract = () => stream.finished(poTasks[type].extract());
287
    const p =
288
        args['generate-pot'] === 'always' ? extract() :
289
        args['generate-pot'] === 'auto' ? access(pot).catch(extract) :
290
        args['generate-pot'] === 'never' ? Promise.resolve(0) :
291
        Promise.reject(new Error('Invalid value for option --generate-pot: ' + args['generate-pot']))
292
293
    return p.then(function () {
294
        const languages = getLanguages();
295
        const promises = [];
296
        for (const language of languages) {
297
            const locale = language.split('-').filter(s => s.length !== 4).join('_');
298
            const po = `misc/translator/po/${language}-${type}.po`;
299
300
            const promise = access(po)
301
                .catch(() => exec(`msginit -o ${po} -i ${pot} -l ${locale} --no-translator`))
302
            promises.push(promise);
303
        }
304
305
        return Promise.all(promises);
306
    });
307
}
308
309
function po_create_marc_marc21 ()       { return po_create_type('marc-MARC21') }
310
function po_create_marc_unimarc ()      { return po_create_type('marc-UNIMARC') }
311
function po_create_staff ()             { return po_create_type('staff-prog') }
312
function po_create_opac ()              { return po_create_type('opac-bootstrap') }
313
function po_create_pref ()              { return po_create_type('pref') }
314
function po_create_messages ()          { return po_create_type('messages') }
315
function po_create_messages_js ()       { return po_create_type('messages-js') }
316
function po_create_installer ()         { return po_create_type('installer') }
317
function po_create_installer_marc21 ()  { return po_create_type('installer-MARC21') }
318
function po_create_installer_unimarc () { return po_create_type('installer-UNIMARC') }
319
320
function po_update_type (type) {
321
    const access = util.promisify(fs.access);
322
    const exec = util.promisify(child_process.exec);
323
324
    const pot = `misc/translator/Koha-${type}.pot`;
325
326
    // Generate .pot only if it doesn't exist or --force-extract is given
327
    const extract = () => stream.finished(poTasks[type].extract());
328
    const p =
329
        args['generate-pot'] === 'always' ? extract() :
330
        args['generate-pot'] === 'auto' ? access(pot).catch(extract) :
331
        args['generate-pot'] === 'never' ? Promise.resolve(0) :
332
        Promise.reject(new Error('Invalid value for option --generate-pot: ' + args['generate-pot']))
333
334
    return p.then(function () {
335
        const languages = getLanguages();
336
        const promises = [];
337
        for (const language of languages) {
338
            const po = `misc/translator/po/${language}-${type}.po`;
339
            promises.push(exec(`msgmerge --backup=off --no-wrap --quiet -F --update ${po} ${pot}`));
340
        }
341
342
        return Promise.all(promises);
343
    });
344
}
345
346
function po_update_marc_marc21 ()       { return po_update_type('marc-MARC21') }
347
function po_update_marc_unimarc ()      { return po_update_type('marc-UNIMARC') }
348
function po_update_staff ()             { return po_update_type('staff-prog') }
349
function po_update_opac ()              { return po_update_type('opac-bootstrap') }
350
function po_update_pref ()              { return po_update_type('pref') }
351
function po_update_messages ()          { return po_update_type('messages') }
352
function po_update_messages_js ()       { return po_update_type('messages-js') }
353
function po_update_installer ()         { return po_update_type('installer') }
354
function po_update_installer_marc21 ()  { return po_update_type('installer-MARC21') }
355
function po_update_installer_unimarc () { return po_update_type('installer-UNIMARC') }
356
357
/**
358
 * Gulp plugin that executes xgettext-like command `cmd` on all files given as
359
 * input, and then outputs the result as a POT file named `filename`.
360
 * `cmd` should accept -o and -f options
361
 */
362
function xgettext (cmd, filename) {
363
    const filenames = [];
364
365
    function transform (file, encoding, callback) {
366
        filenames.push(path.relative(file.cwd, file.path));
367
        callback();
368
    }
369
370
    function flush (callback) {
371
        fs.mkdtemp(path.join(os.tmpdir(), 'koha-'), (err, folder) => {
372
            const outputFilename = path.join(folder, filename);
373
            const filesFilename = path.join(folder, 'files');
374
            fs.writeFile(filesFilename, filenames.join(os.EOL), err => {
375
                if (err) return callback(err);
376
377
                const command = `${cmd} -o ${outputFilename} -f ${filesFilename}`;
378
                child_process.exec(command, err => {
379
                    if (err) return callback(err);
380
381
                    fs.readFile(outputFilename, (err, data) => {
382
                        if (err) return callback(err);
383
384
                        const file = new Vinyl();
385
                        file.path = path.join(file.base, filename);
386
                        file.contents = data;
387
                        callback(null, file);
388
                    });
389
                });
390
            });
391
        })
392
    }
393
394
    return through2.obj(transform, flush);
395
}
396
110
397
/**
111
/**
398
 * Return languages selected for PO-related tasks
112
 * Return languages selected for PO-related tasks
Lines 428-433 exports.watch = function () { Link Here
428
    watch(STAFF_CSS_BASE + "/src/**/*.scss", series('staff_css'));
142
    watch(STAFF_CSS_BASE + "/src/**/*.scss", series('staff_css'));
429
};
143
};
430
144
431
exports['po:create'] = parallel(...poTypes.map(type => poTasks[type].create));
145
exports['po:create'] = function () {
432
exports['po:update'] = parallel(...poTypes.map(type => poTasks[type].update));
146
    const targets = getLanguages();
433
exports['po:extract'] = parallel(...poTypes.map(type => poTasks[type].extract));
147
    const cmdargs = ['--makefile=misc/translator/Makefile', '--jobs'];
148
    if (args['generate-pot'] === 'always') {
149
        cmdargs.push('--always-make');
150
    }
151
    cmdargs.push(`EXTRA_LANGS=${targets.join(' ')}`)
152
153
    return child_process.spawn('make', cmdargs.concat(targets), { stdio: 'inherit' });
154
}
155
156
exports['po:update'] = function () {
157
    const targets = getLanguages();
158
    const cmdargs = ['--makefile=misc/translator/Makefile', '--jobs'];
159
    if (args['generate-pot'] === 'always') {
160
        cmdargs.push('--always-make');
161
    }
162
163
    return child_process.spawn('make', cmdargs.concat(targets), { stdio: 'inherit' });
164
}
165
166
exports['po:extract'] = function () {
167
    const targets = getPoTasks().map(type => `misc/translator/Koha-${type}.pot`);
168
    const cmdargs = ['--makefile=misc/translator/Makefile', '--jobs', '--always-make'];
169
170
    return child_process.spawn('make', cmdargs.concat(targets), { stdio: 'inherit' });
171
};
(-)a/misc/translator/Makefile (-1 / +90 lines)
Line 0 Link Here
0
- 
1
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
2
MAKEFILE_DIR := $(dir $(MAKEFILE_PATH))
3
SRC_DIR := $(abspath $(MAKEFILE_DIR)/../..)
4
ifneq ($(SRC_DIR),$(CURDIR))
5
$(error This makefile should be used from Koha root directory. Use make -C $(SRC_DIR) -f $(MAKEFILE_PATH) $(MAKECMDGOALS))
6
endif
7
8
define help
9
Available targets:
10
    all
11
        Update all PO files
12
    pot
13
        Rebuild all POT files
14
    clean
15
        Delete all POT files
16
    <LANG>, eg. en-GB
17
        Update all PO files for that language
18
    <FILE>, eg. misc/translator/po/en-GB-installer.po or misc/translator/Koha-installer.pot
19
        Update that particular file
20
endef
21
22
TYPES := installer installer-MARC21 installer-UNIMARC marc-MARC21 marc-UNIMARC messages messages-js opac-bootstrap pref staff-prog
23
LANGS := $(patsubst %-installer.po,%,$(notdir $(wildcard misc/translator/po/*-installer.po)))
24
LANGS += $(EXTRA_LANGS)
25
POT_DIR := misc/translator
26
PO_DIR := misc/translator/po
27
POTS := $(foreach TYPE,$(TYPES),$(POT_DIR)/Koha-$(TYPE).pot)
28
XGETTEXT_COMMON_OPTS := --sort-output --from-code=UTF-8 --package-name Koha --package-version= --force-po -k -k__ -k__x -k__n:1,2 -k__nx:1,2 -k__xn:1,2  -k__p:1c,2 -k__px:1c,2 -k__np:1c,2,3 -k__npx:1c,2,3 -kN__ -kN__n:1,2 -kN__p:1c,2 -kN__np:1c,2,3
29
XGETTEXT_PERL_OPTS := $(XGETTEXT_COMMON_OPTS) -L Perl
30
XGETTEXT_JS_OPTS := $(XGETTEXT_COMMON_OPTS) -L JavaScript -k$$__ -k$$__x -k$$__n:1,2 -k$$__nx:1,2 -k$$__xn:1,2
31
32
installer_DEPS := $(shell find installer/data/mysql/en/mandatory installer/data/mysql/en/optional -iname '*.yml' | sort)
33
installer_CMD := misc/translator/xgettext-installer
34
installer-MARC21_DEPS := $(shell find installer/data/mysql/en/marcflavour/marc21 -iname '*.yml' | sort)
35
installer-MARC21_CMD := misc/translator/xgettext-installer
36
installer-UNIMARC_DEPS := $(shell find installer/data/mysql/en/marcflavour/unimarc -iname '*.yml' | sort)
37
installer-UNIMARC_CMD := misc/translator/xgettext-installer
38
marc-MARC21_DEPS := $(shell find koha-tmpl/opac-tmpl/bootstrap/en -iname '*MARC21*' | sort) $(shell find koha-tmpl/intranet-tmpl/prog/en -iname '*MARC21*'| sort -d)
39
marc-MARC21_CMD := misc/translator/xgettext.pl --charset=UTF-8
40
marc-UNIMARC_DEPS := $(shell find koha-tmpl/opac-tmpl/bootstrap/en -iname '*UNIMARC*' | sort) $(shell find koha-tmpl/intranet-tmpl/prog/en -iname '*UNIMARC*'| sort)
41
marc-UNIMARC_CMD := misc/translator/xgettext.pl --charset=UTF-8
42
messages-perl_DEPS := $(shell find -iname '*.pl' -or -iname '*.pm' | sort)
43
messages-perl_CMD := xgettext $(XGETTEXT_PERL_OPTS)
44
messages-tt_DEPS := $(shell find koha-tmpl/opac-tmpl/bootstrap/en koha-tmpl/intranet-tmpl/prog/en -iname *.tt -or -iname *.inc | sort)
45
messages-tt_CMD := misc/translator/xgettext-tt2
46
messages_DEPS := misc/translator/Koha-messages-perl.pot misc/translator/Koha-messages-tt.pot
47
messages_CMD := msgcat --use-first
48
messages-js_DEPS := $(shell find koha-tmpl/intranet-tmpl/prog/js koha-tmpl/opac-tmpl/bootstrap/js -iname '*.js' -or -iname '*.vue' | sort)
49
messages-js_CMD := xgettext $(XGETTEXT_JS_OPTS)
50
opac-bootstrap_DEPS := $(shell find koha-tmpl/opac-tmpl/bootstrap/en \( -iname '*.tt' -or -iname '*.inc' -or -iname '*.xsl' \) -not -iname '*MARC21*' -not -iname '*UNIMARC*' | sort)
51
opac-bootstrap_CMD := misc/translator/xgettext.pl --charset=UTF-8
52
pref_DEPS := $(shell find koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences -iname '*.pref' | sort)
53
pref_CMD := misc/translator/xgettext-pref
54
staff-prog_DEPS := $(shell find koha-tmpl/intranet-tmpl/prog/en \( -iname '*.tt' -or -iname '*.inc' -or -iname '*.xsl' \) -not -iname '*MARC21*' -not -iname '*UNIMARC*' | sort)
55
staff-prog_CMD := misc/translator/xgettext.pl --charset=UTF-8
56
57
.PHONY: all help pot clean $(LANGS)
58
all: $(LANGS)
59
help:; @$(info $(help)) :
60
61
pot: $(POTS)
62
63
clean:
64
	rm -f misc/translator/*.pot
65
66
$(LANGS): %: $(foreach TYPE,$(TYPES),$(PO_DIR)/%-$(TYPE).po)
67
68
define pot-rule-template
69
misc/translator/Koha-$(1).pot: $$($(1)_DEPS)
70
	@echo "Extract: $$@"
71
	$$(file >$$@.in) $$(foreach O,$$^,$$(file >>$$@.in,$$O))
72
	@$$($(1)_CMD) -o $$@.tmp -f $$@.in
73
	@msgcat --sort-by-file --no-wrap -o $$@ $$@.tmp
74
	@rm $$@.tmp $$@.in
75
endef
76
$(foreach TYPE,$(TYPES),$(eval $(call pot-rule-template,$(TYPE))))
77
$(foreach TYPE,messages-perl messages-tt,$(eval $(call pot-rule-template,$(TYPE))))
78
79
define po-rule-template
80
$$(foreach LANG,$$(LANGS),$$(PO_DIR)/$$(LANG)-$(1).po): $$(POT_DIR)/Koha-$(1).pot
81
	@if test -f $$@; then \
82
		echo "Update: $$@"; \
83
		msgmerge --backup=off --quiet --sort-by-file --update $$@ $$< && touch "$$@"; \
84
	else \
85
		echo "Create: $$@"; \
86
		locale=$$$$(basename $$@ .po | perl -nE 'say join("_", grep { (length) < 4 } (split /-/))'); \
87
		msginit --no-translator -o $$@ -i $$< -l $$$$locale ; \
88
	fi
89
endef
90
$(foreach TYPE,$(TYPES),$(eval $(call po-rule-template,$(TYPE))))

Return to bug 35342