
This commit is generated using: % perl misc/devel/tidy.pl *within* ktd, to get the same version of perltidy than what will be used by our CI (currently v20230309). Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
570 lines
16 KiB
JavaScript
570 lines
16 KiB
JavaScript
/* eslint-env node */
|
|
/* eslint no-console:"off" */
|
|
|
|
const { dest, parallel, series, src, watch } = require("gulp");
|
|
|
|
const child_process = require("child_process");
|
|
const fs = require("fs");
|
|
const os = require("os");
|
|
const path = require("path");
|
|
const util = require("util");
|
|
const stream = require("stream/promises");
|
|
|
|
const sass = require("gulp-sass")(require("sass"));
|
|
const tildeImporter = require("node-sass-tilde-importer");
|
|
const rtlcss = require("gulp-rtlcss");
|
|
const sourcemaps = require("gulp-sourcemaps");
|
|
const autoprefixer = require("gulp-autoprefixer");
|
|
const concatPo = require("gulp-concat-po");
|
|
const exec = require("gulp-exec");
|
|
const merge = require("merge-stream");
|
|
const through2 = require("through2");
|
|
const Vinyl = require("vinyl");
|
|
const args = require("minimist")(process.argv.slice(2), {
|
|
default: { "generate-pot": "always" },
|
|
});
|
|
const rename = require("gulp-rename");
|
|
|
|
const STAFF_CSS_BASE = "koha-tmpl/intranet-tmpl/prog/css";
|
|
const OPAC_CSS_BASE = "koha-tmpl/opac-tmpl/bootstrap/css";
|
|
|
|
var CSS_BASE = args.view == "opac" ? OPAC_CSS_BASE : STAFF_CSS_BASE;
|
|
|
|
var sassOptions = {
|
|
importer: tildeImporter,
|
|
includePaths: [__dirname + "/node_modules", __dirname + "/../node_modules"],
|
|
};
|
|
|
|
// CSS processing for development
|
|
function css(css_base) {
|
|
css_base = css_base || CSS_BASE;
|
|
var stream = src(css_base + "/src/**/*.scss", { sourcemaps: true });
|
|
|
|
if (args.view == "opac") {
|
|
stream = stream
|
|
.pipe(sass(sassOptions).on("error", sass.logError))
|
|
.pipe(autoprefixer())
|
|
.pipe(dest(css_base))
|
|
.pipe(rtlcss())
|
|
.pipe(
|
|
rename({
|
|
suffix: "-rtl",
|
|
})
|
|
) // Append "-rtl" to the filename.
|
|
.pipe(dest(css_base, { sourcemaps: "./maps" }));
|
|
} else {
|
|
stream = stream
|
|
.pipe(sass(sassOptions).on("error", sass.logError))
|
|
.pipe(autoprefixer())
|
|
.pipe(dest(css_base))
|
|
.pipe(rtlcss())
|
|
.pipe(
|
|
rename({
|
|
suffix: "-rtl",
|
|
})
|
|
) // Append "-rtl" to the filename.
|
|
.pipe(dest(css_base, { sourcemaps: "./maps" }));
|
|
}
|
|
|
|
return stream;
|
|
}
|
|
|
|
// CSS processing for production
|
|
function build(css_base) {
|
|
css_base = css_base || CSS_BASE;
|
|
sassOptions.outputStyle = "compressed";
|
|
var stream = src(css_base + "/src/**/*.scss")
|
|
.pipe(sass(sassOptions).on("error", sass.logError))
|
|
.pipe(autoprefixer())
|
|
.pipe(dest(css_base))
|
|
.pipe(rtlcss())
|
|
.pipe(
|
|
rename({
|
|
suffix: "-rtl",
|
|
})
|
|
) // Append "-rtl" to the filename.
|
|
.pipe(dest(css_base));
|
|
return stream;
|
|
}
|
|
|
|
function opac_css() {
|
|
return css(OPAC_CSS_BASE);
|
|
}
|
|
|
|
function staff_css() {
|
|
return css(STAFF_CSS_BASE);
|
|
}
|
|
|
|
const poTasks = {
|
|
"marc-MARC21": {
|
|
extract: po_extract_marc_marc21,
|
|
create: po_create_marc_marc21,
|
|
update: po_update_marc_marc21,
|
|
},
|
|
"marc-UNIMARC": {
|
|
extract: po_extract_marc_unimarc,
|
|
create: po_create_marc_unimarc,
|
|
update: po_update_marc_unimarc,
|
|
},
|
|
"staff-prog": {
|
|
extract: po_extract_staff,
|
|
create: po_create_staff,
|
|
update: po_update_staff,
|
|
},
|
|
"opac-bootstrap": {
|
|
extract: po_extract_opac,
|
|
create: po_create_opac,
|
|
update: po_update_opac,
|
|
},
|
|
pref: {
|
|
extract: po_extract_pref,
|
|
create: po_create_pref,
|
|
update: po_update_pref,
|
|
},
|
|
messages: {
|
|
extract: po_extract_messages,
|
|
create: po_create_messages,
|
|
update: po_update_messages,
|
|
},
|
|
"messages-js": {
|
|
extract: po_extract_messages_js,
|
|
create: po_create_messages_js,
|
|
update: po_update_messages_js,
|
|
},
|
|
installer: {
|
|
extract: po_extract_installer,
|
|
create: po_create_installer,
|
|
update: po_update_installer,
|
|
},
|
|
"installer-MARC21": {
|
|
extract: po_extract_installer_marc21,
|
|
create: po_create_installer_marc21,
|
|
update: po_update_installer_marc21,
|
|
},
|
|
"installer-UNIMARC": {
|
|
extract: po_extract_installer_unimarc,
|
|
create: po_create_installer_unimarc,
|
|
update: po_update_installer_unimarc,
|
|
},
|
|
};
|
|
|
|
function getPoTasks() {
|
|
let tasks = [];
|
|
|
|
let all_tasks = Object.keys(poTasks);
|
|
|
|
if (args.task) {
|
|
tasks = [args.task].flat(Infinity);
|
|
} else {
|
|
return all_tasks;
|
|
}
|
|
|
|
let invalid_tasks = tasks.filter(function (el) {
|
|
return all_tasks.indexOf(el) < 0;
|
|
});
|
|
|
|
if (invalid_tasks.length) {
|
|
console.error("Invalid task");
|
|
return [];
|
|
}
|
|
|
|
return tasks;
|
|
}
|
|
const poTypes = getPoTasks();
|
|
|
|
function po_extract_marc(type) {
|
|
return src(`koha-tmpl/*-tmpl/*/en/**/*${type}*`, {
|
|
read: false,
|
|
nocase: true,
|
|
})
|
|
.pipe(
|
|
xgettext(
|
|
"misc/translator/xgettext.pl --charset=UTF-8 -F",
|
|
`Koha-marc-${type}.pot`
|
|
)
|
|
)
|
|
.pipe(dest("misc/translator"));
|
|
}
|
|
|
|
function po_extract_marc_marc21() {
|
|
return po_extract_marc("MARC21");
|
|
}
|
|
function po_extract_marc_unimarc() {
|
|
return po_extract_marc("UNIMARC");
|
|
}
|
|
|
|
function po_extract_staff() {
|
|
const globs = [
|
|
"koha-tmpl/intranet-tmpl/prog/en/**/*.tt",
|
|
"koha-tmpl/intranet-tmpl/prog/en/**/*.inc",
|
|
"koha-tmpl/intranet-tmpl/prog/en/xslt/*.xsl",
|
|
"!koha-tmpl/intranet-tmpl/prog/en/**/*MARC21*",
|
|
"!koha-tmpl/intranet-tmpl/prog/en/**/*UNIMARC*",
|
|
"!koha-tmpl/intranet-tmpl/prog/en/**/*marc21*",
|
|
"!koha-tmpl/intranet-tmpl/prog/en/**/*unimarc*",
|
|
];
|
|
|
|
return src(globs, { read: false, nocase: true })
|
|
.pipe(
|
|
xgettext(
|
|
"misc/translator/xgettext.pl --charset=UTF-8 -F",
|
|
"Koha-staff-prog.pot"
|
|
)
|
|
)
|
|
.pipe(dest("misc/translator"));
|
|
}
|
|
|
|
function po_extract_opac() {
|
|
const globs = [
|
|
"koha-tmpl/opac-tmpl/bootstrap/en/**/*.tt",
|
|
"koha-tmpl/opac-tmpl/bootstrap/en/**/*.inc",
|
|
"koha-tmpl/opac-tmpl/bootstrap/en/xslt/*.xsl",
|
|
"!koha-tmpl/opac-tmpl/bootstrap/en/**/*MARC21*",
|
|
"!koha-tmpl/opac-tmpl/bootstrap/en/**/*UNIMARC*",
|
|
"!koha-tmpl/opac-tmpl/bootstrap/en/**/*marc21*",
|
|
"!koha-tmpl/opac-tmpl/bootstrap/en/**/*unimarc*",
|
|
];
|
|
|
|
return src(globs, { read: false, nocase: true })
|
|
.pipe(
|
|
xgettext(
|
|
"misc/translator/xgettext.pl --charset=UTF-8 -F",
|
|
"Koha-opac-bootstrap.pot"
|
|
)
|
|
)
|
|
.pipe(dest("misc/translator"));
|
|
}
|
|
|
|
const xgettext_options =
|
|
"--from-code=UTF-8 --package-name Koha " +
|
|
"--package-version= -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 " +
|
|
"-k -k$__ -k$__x -k$__n:1,2 -k$__nx:1,2 -k$__xn:1,2 " +
|
|
"--force-po";
|
|
|
|
function po_extract_messages_js() {
|
|
const globs = [
|
|
"koha-tmpl/intranet-tmpl/prog/js/vue/**/*.vue",
|
|
"koha-tmpl/intranet-tmpl/prog/js/**/*.js",
|
|
"koha-tmpl/opac-tmpl/bootstrap/js/**/*.js",
|
|
];
|
|
|
|
return src(globs, { read: false, nocase: true })
|
|
.pipe(
|
|
xgettext(
|
|
`xgettext -L JavaScript ${xgettext_options}`,
|
|
"Koha-messages-js.pot"
|
|
)
|
|
)
|
|
.pipe(dest("misc/translator"));
|
|
}
|
|
|
|
function po_extract_messages() {
|
|
const perlStream = src(["**/*.pl", "**/*.pm"], {
|
|
read: false,
|
|
nocase: true,
|
|
}).pipe(xgettext(`xgettext -L Perl ${xgettext_options}`, "Koha-perl.pot"));
|
|
|
|
const ttStream = src(
|
|
[
|
|
"koha-tmpl/intranet-tmpl/prog/en/**/*.tt",
|
|
"koha-tmpl/intranet-tmpl/prog/en/**/*.inc",
|
|
"koha-tmpl/opac-tmpl/bootstrap/en/**/*.tt",
|
|
"koha-tmpl/opac-tmpl/bootstrap/en/**/*.inc",
|
|
],
|
|
{ read: false, nocase: true }
|
|
).pipe(
|
|
xgettext(
|
|
"misc/translator/xgettext-tt2 --from-code=UTF-8",
|
|
"Koha-tt.pot"
|
|
)
|
|
);
|
|
|
|
const headers = {
|
|
"Project-Id-Version": "Koha",
|
|
"Content-Type": "text/plain; charset=UTF-8",
|
|
};
|
|
|
|
return merge(perlStream, ttStream)
|
|
.pipe(concatPo("Koha-messages.pot", { headers }))
|
|
.pipe(dest("misc/translator"));
|
|
}
|
|
|
|
function po_extract_pref() {
|
|
return src(
|
|
"koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/*.pref",
|
|
{ read: false }
|
|
)
|
|
.pipe(xgettext("misc/translator/xgettext-pref", "Koha-pref.pot"))
|
|
.pipe(dest("misc/translator"));
|
|
}
|
|
|
|
function po_extract_installer() {
|
|
const globs = [
|
|
"installer/data/mysql/en/mandatory/*.yml",
|
|
"installer/data/mysql/en/optional/*.yml",
|
|
];
|
|
|
|
return src(globs, { read: false, nocase: true })
|
|
.pipe(
|
|
xgettext("misc/translator/xgettext-installer", "Koha-installer.pot")
|
|
)
|
|
.pipe(dest("misc/translator"));
|
|
}
|
|
|
|
function po_extract_installer_marc(type) {
|
|
const globs = `installer/data/mysql/en/marcflavour/${type}/**/*.yml`;
|
|
|
|
return src(globs, { read: false, nocase: true })
|
|
.pipe(
|
|
xgettext(
|
|
"misc/translator/xgettext-installer",
|
|
`Koha-installer-${type}.pot`
|
|
)
|
|
)
|
|
.pipe(dest("misc/translator"));
|
|
}
|
|
|
|
function po_extract_installer_marc21() {
|
|
return po_extract_installer_marc("MARC21");
|
|
}
|
|
|
|
function po_extract_installer_unimarc() {
|
|
return po_extract_installer_marc("UNIMARC");
|
|
}
|
|
|
|
function po_create_type(type) {
|
|
const access = util.promisify(fs.access);
|
|
const exec = util.promisify(child_process.exec);
|
|
|
|
const pot = `misc/translator/Koha-${type}.pot`;
|
|
|
|
// Generate .pot only if it doesn't exist or --force-extract is given
|
|
const extract = () => stream.finished(poTasks[type].extract());
|
|
const p =
|
|
args["generate-pot"] === "always"
|
|
? extract()
|
|
: args["generate-pot"] === "auto"
|
|
? access(pot).catch(extract)
|
|
: args["generate-pot"] === "never"
|
|
? Promise.resolve(0)
|
|
: Promise.reject(
|
|
new Error(
|
|
"Invalid value for option --generate-pot: " +
|
|
args["generate-pot"]
|
|
)
|
|
);
|
|
|
|
return p.then(function () {
|
|
const languages = getLanguages();
|
|
const promises = [];
|
|
for (const language of languages) {
|
|
const locale = language
|
|
.split("-")
|
|
.filter(s => s.length !== 4)
|
|
.join("_");
|
|
const po = `misc/translator/po/${language}-${type}.po`;
|
|
|
|
const promise = access(po).catch(() =>
|
|
exec(`msginit -o ${po} -i ${pot} -l ${locale} --no-translator`)
|
|
);
|
|
promises.push(promise);
|
|
}
|
|
|
|
return Promise.all(promises);
|
|
});
|
|
}
|
|
|
|
function po_create_marc_marc21() {
|
|
return po_create_type("marc-MARC21");
|
|
}
|
|
function po_create_marc_unimarc() {
|
|
return po_create_type("marc-UNIMARC");
|
|
}
|
|
function po_create_staff() {
|
|
return po_create_type("staff-prog");
|
|
}
|
|
function po_create_opac() {
|
|
return po_create_type("opac-bootstrap");
|
|
}
|
|
function po_create_pref() {
|
|
return po_create_type("pref");
|
|
}
|
|
function po_create_messages() {
|
|
return po_create_type("messages");
|
|
}
|
|
function po_create_messages_js() {
|
|
return po_create_type("messages-js");
|
|
}
|
|
function po_create_installer() {
|
|
return po_create_type("installer");
|
|
}
|
|
function po_create_installer_marc21() {
|
|
return po_create_type("installer-MARC21");
|
|
}
|
|
function po_create_installer_unimarc() {
|
|
return po_create_type("installer-UNIMARC");
|
|
}
|
|
|
|
function po_update_type(type) {
|
|
const access = util.promisify(fs.access);
|
|
const exec = util.promisify(child_process.exec);
|
|
|
|
const pot = `misc/translator/Koha-${type}.pot`;
|
|
|
|
// Generate .pot only if it doesn't exist or --force-extract is given
|
|
const extract = () => stream.finished(poTasks[type].extract());
|
|
const p =
|
|
args["generate-pot"] === "always"
|
|
? extract()
|
|
: args["generate-pot"] === "auto"
|
|
? access(pot).catch(extract)
|
|
: args["generate-pot"] === "never"
|
|
? Promise.resolve(0)
|
|
: Promise.reject(
|
|
new Error(
|
|
"Invalid value for option --generate-pot: " +
|
|
args["generate-pot"]
|
|
)
|
|
);
|
|
|
|
return p.then(function () {
|
|
const languages = getLanguages();
|
|
const promises = [];
|
|
for (const language of languages) {
|
|
const po = `misc/translator/po/${language}-${type}.po`;
|
|
promises.push(
|
|
exec(
|
|
`msgmerge --backup=off --no-wrap --quiet -F --update ${po} ${pot}`
|
|
)
|
|
);
|
|
}
|
|
|
|
return Promise.all(promises);
|
|
});
|
|
}
|
|
|
|
function po_update_marc_marc21() {
|
|
return po_update_type("marc-MARC21");
|
|
}
|
|
function po_update_marc_unimarc() {
|
|
return po_update_type("marc-UNIMARC");
|
|
}
|
|
function po_update_staff() {
|
|
return po_update_type("staff-prog");
|
|
}
|
|
function po_update_opac() {
|
|
return po_update_type("opac-bootstrap");
|
|
}
|
|
function po_update_pref() {
|
|
return po_update_type("pref");
|
|
}
|
|
function po_update_messages() {
|
|
return po_update_type("messages");
|
|
}
|
|
function po_update_messages_js() {
|
|
return po_update_type("messages-js");
|
|
}
|
|
function po_update_installer() {
|
|
return po_update_type("installer");
|
|
}
|
|
function po_update_installer_marc21() {
|
|
return po_update_type("installer-MARC21");
|
|
}
|
|
function po_update_installer_unimarc() {
|
|
return po_update_type("installer-UNIMARC");
|
|
}
|
|
|
|
/**
|
|
* Gulp plugin that executes xgettext-like command `cmd` on all files given as
|
|
* input, and then outputs the result as a POT file named `filename`.
|
|
* `cmd` should accept -o and -f options
|
|
*/
|
|
function xgettext(cmd, filename) {
|
|
const filenames = [];
|
|
|
|
function transform(file, encoding, callback) {
|
|
filenames.push(path.relative(file.cwd, file.path));
|
|
callback();
|
|
}
|
|
|
|
function flush(callback) {
|
|
fs.mkdtemp(path.join(os.tmpdir(), "koha-"), (err, folder) => {
|
|
const outputFilename = path.join(folder, filename);
|
|
const filesFilename = path.join(folder, "files");
|
|
fs.writeFile(filesFilename, filenames.join(os.EOL), err => {
|
|
if (err) return callback(err);
|
|
|
|
const command = `${cmd} -o ${outputFilename} -f ${filesFilename}`;
|
|
child_process.exec(command, err => {
|
|
if (err) return callback(err);
|
|
|
|
fs.readFile(outputFilename, (err, data) => {
|
|
if (err) return callback(err);
|
|
|
|
const file = new Vinyl();
|
|
file.path = path.join(file.base, filename);
|
|
file.contents = data;
|
|
callback(null, file);
|
|
fs.rmSync(folder, { recursive: true });
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
return through2.obj(transform, flush);
|
|
}
|
|
|
|
/**
|
|
* Return languages selected for PO-related tasks
|
|
*
|
|
* This can be either languages given on command-line with --lang option, or
|
|
* all the languages found in misc/translator/po otherwise
|
|
*/
|
|
function getLanguages() {
|
|
if (Array.isArray(args.lang)) {
|
|
return args.lang;
|
|
}
|
|
|
|
if (args.lang) {
|
|
return [args.lang];
|
|
}
|
|
|
|
const filenames = fs
|
|
.readdirSync("misc/translator/po/")
|
|
.filter(filename => filename.endsWith("-installer.po"))
|
|
.filter(filename => !filename.startsWith("."));
|
|
|
|
const re = new RegExp("-installer.po");
|
|
languages = filenames.map(filename => filename.replace(re, ""));
|
|
|
|
return Array.from(new Set(languages));
|
|
}
|
|
|
|
exports.build = function (next) {
|
|
build();
|
|
next();
|
|
};
|
|
exports.css = function (next) {
|
|
css();
|
|
next();
|
|
};
|
|
exports.opac_css = opac_css;
|
|
exports.staff_css = staff_css;
|
|
exports.watch = function () {
|
|
watch(OPAC_CSS_BASE + "/src/**/*.scss", series("opac_css"));
|
|
watch(STAFF_CSS_BASE + "/src/**/*.scss", series("staff_css"));
|
|
};
|
|
|
|
if (args["_"][0].match("po:") && !fs.existsSync("misc/translator/po")) {
|
|
console.log(
|
|
"misc/translator/po does not exist. You should clone koha-l10n there. See https://wiki.koha-community.org/wiki/Translation_files for more details."
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
exports["po:create"] = parallel(...poTypes.map(type => poTasks[type].create));
|
|
exports["po:update"] = parallel(...poTypes.map(type => poTasks[type].update));
|
|
exports["po:extract"] = parallel(...poTypes.map(type => poTasks[type].extract));
|