aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--org/output_hub.org15
-rw-r--r--org/spine.org33
-rw-r--r--org/translation_po4a.org178
-rw-r--r--src/sisudoc/outputs/io_out/hub.d15
-rw-r--r--src/sisudoc/outputs/io_out/po4a_cfg.d173
-rw-r--r--src/sisudoc/spine.d33
6 files changed, 433 insertions, 14 deletions
diff --git a/org/output_hub.org b/org/output_hub.org
index 27e0efc..2456878 100644
--- a/org/output_hub.org
+++ b/org/output_hub.org
@@ -35,6 +35,21 @@ template outputHub() {
@system void outputHub(D)(D doc) {
mixin Msg;
auto msg = Msg!()(doc.matters);
+ /+ ↓ the po4a configuration, printed rather than written.
+ Spine does not write into a source tree, and this belongs beside the
+ catalogues in the pod it describes, so it goes to stdout for the
+ caller to put where they want it:
+ spine --po4a-cfg <pod> > <pod>/tools/po4a/po4a.cfg
+ Once per document, not once per language: it is generated from the
+ source language's files and names every other language itself.
+ +/
+ if (doc.matters.opt.action.po4a_cfg
+ && doc.matters.src.language == doc.matters.pod.manifest_list_of_languages[0]
+ ) {
+ import sisudoc.outputs.io_out.po4a_cfg;
+ mixin spinePo4aConfig;
+ write(po4aConfig(doc.matters));
+ }
enum outTask { source_or_pod, sqlite, sqlite_multi, latex, odt, epub, html_scroll, html_seg, html_stuff, text, skel }
void Scheduled(D)(int sched, D doc) {
auto msg = Msg!()(doc.matters);
diff --git a/org/spine.org b/org/spine.org
index cef324a..5a54d31 100644
--- a/org/spine.org
+++ b/org/spine.org
@@ -325,6 +325,14 @@ enum dAM { abstraction, matters }
static auto rgx = RgxI();
static auto rgx_y = RgxYaml();
static auto rgx_files = RgxFiles();
+/+ ↓ an action whose output is a file's contents, printed to stdout, turns
+ this off: the banner would otherwise be part of what it printed. The
+ round trips do the same by leaving before scope(success) runs, which
+ they can because they leave early; --po4a-cfg prints from inside
+ output processing and so says so here instead. Set where the options
+ are read, below: the banner is declared before they exist.
++/
+bool _run_banner = true;
#+END_SRC
*** scope (run complete) :scope:
@@ -332,13 +340,15 @@ static auto rgx_files = RgxFiles();
#+NAME: spine_init_scope
#+BEGIN_SRC d
scope(success) {
- writefln(
- "~ run complete, ok ~ (%s-%s.%s.%s, %s D:%s, %s %s)",
- program_name,
- _ver.major, _ver.minor, _ver.patch,
- __VENDOR__, __VERSION__,
- bits, os,
- );
+ if (_run_banner) {
+ writefln(
+ "~ run complete, ok ~ (%s-%s.%s.%s, %s D:%s, %s %s)",
+ program_name,
+ _ver.major, _ver.minor, _ver.patch,
+ __VENDOR__, __VERSION__,
+ bits, os,
+ );
+ }
}
scope(failure) {
debug(checkdoc) {
@@ -410,6 +420,7 @@ bool[string] opts = [
"pdf" : false,
"pdf-color-links" : false,
"pdf-init" : false,
+ "po4a-cfg" : false,
"pod" : false,
"pod2" : false,
"serial" : false,
@@ -546,6 +557,7 @@ auto helpInfo = getopt(args,
"pdf", "latex output for pdfs", &opts["pdf"],
"pdf-color-links", "mono or color links for pdfs", &opts["pdf-color-links"],
"pdf-init", "initialise latex shared files (see latex-header-sty)", &opts["pdf-init"],
+ "po4a-cfg", "print the po4a configuration for this document", &opts["po4a-cfg"],
"pod", "spine (doc reform) pod source content bundled", &opts["pod"],
"pod2", "pod with document abstraction (.ssp) bundled", &opts["pod2"],
"quiet|q", "output to terminal", &opts["vox_is1"],
@@ -617,6 +629,10 @@ auto helpInfo = getopt(args,
"debug-stages", "debug stages", &opts["debug-stages"],
// "sqlite-db-filename", "=[filename].sql.db", &settings["sqlite-db-filename"],
);
+/+ ↓ --po4a-cfg prints a file's contents; see the banner above +/
+if (opts["po4a-cfg"]) {
+ _run_banner = false;
+}
if (helpInfo.helpWanted) {
defaultGetoptPrinter("Some information about the program.", helpInfo.options);
}
@@ -882,6 +898,9 @@ struct OptActions {
@trusted bool ocn_off() {
return ((opts["ocn-off"]) || (opts["no-ocn"])) ? true : false;
}
+ @trusted bool po4a_cfg() {
+ return opts["po4a-cfg"];
+ }
@trusted bool pod() {
return (opts["pod"] || opts["pod2"]) ? true : false;
}
diff --git a/org/translation_po4a.org b/org/translation_po4a.org
new file mode 100644
index 0000000..27c3362
--- /dev/null
+++ b/org/translation_po4a.org
@@ -0,0 +1,178 @@
+-*- mode: org -*-
+#+TITLE: sisudoc spine (doc_reform) object-centric document abstraction
+#+DESCRIPTION: documents - structuring, publishing in multiple formats & search
+#+SUMMARY: process markup document, create document abstraction
+#+FILETAGS: :spine:abstraction:
+#+AUTHOR: Ralph Amissah
+#+EMAIL: [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]]
+#+COPYRIGHT: Copyright (C) 2015 (continuously updated, current 2026) Ralph Amissah
+#+LANGUAGE: en
+#+STARTUP: content hideblocks hidestars noindent entitiespretty
+#+PROPERTY: header-args+ :eval never-export :exports code
+#+PROPERTY: header-args+ :noweb yes :padline no
+#+PROPERTY: header-args+ :results silent :cache no
+#+PROPERTY: header-args+ :mkdirp yes
+#+OPTIONS: H:3 num:nil toc:t \n:t ::t |:t ^:nil -:t f:t *:t
+- magic single double-quote → " ← FIX changes hilighting behavior (occuring
+ after it) in org document. INVESTIGATE (org-mode CONFIG?) FIND & FIX
+
+- [[./doc-reform.org][doc-reform.org]] [[./][org/]]
+
+* (translation) po4a setup
+
+#+HEADER: :tangle "../src/sisudoc/outputs/io_out/po4a_cfg.d"
+#+HEADER: :noweb yes
+#+BEGIN_SRC d
+<<doc_header_including_copyright_and_license>>
+/++
+ module po4a_cfg;<BR>
+ - the po4a configuration for a document, generated from its manifest and
+ the files its markup names<BR>
+ - written for tools/po4a/po4a.cfg, so its paths are relative to there
++/
+module sisudoc.outputs.io_out.po4a_cfg;
+@system:
+/+ ↓ po4a's configuration, derived rather than kept
+
+ The sample this replaces kept a Makefile that built po4a.cfg by globbing
+ a language directory and listing what it found. Spine already knows both
+ halves without looking: the manifest says which languages a document
+ has, and the markup says which files it is made of, through the << lines
+ the parser follows. Deriving the configuration from those two means it
+ cannot disagree with the document, which a hand-kept file eventually
+ does: a language added to the manifest and forgotten in the Makefile
+ produces a translation nobody updates.
+ .
+ It is derived, so it is not kept in git. The sample repository's
+ whitelist admits pot/ and po/ and not this.
+ .
+ neverwrap is deliberately NOT set, and the reason is worth keeping.
+ .
+ Without it po4a rewraps its output at about 75 columns, so a document
+ whose markup keeps one paragraph on one long line comes back reflowed.
+ That is untidy: it changes no object, since sisu delimits on blank
+ lines, but it churns every translated file in a diff and leaves the
+ source language and its translations formatted unlike each other. The
+ obvious thing is to turn wrapping off.
+ .
+ Measured on live-manual, same catalogues and same English, the option
+ the only difference:
+ .
+ fuzzy before with neverwrap without
+ ca 1 889 5
+ de 8 103 10
+ it 149 804 152
+ .
+ of 1126 strings. po4a will not use a fuzzy translation, so each one
+ renders as the source language: Catalan's coverage would fall from about
+ 46% to about 12%, and Spanish, French and Japanese with it. Setting the
+ option re-extracts the strings in a form the existing catalogues do not
+ match, and four fifths of nine languages' work stops being used.
+ .
+ Tidy formatting is not worth that. The wrapping stays.
++/
+template spinePo4aConfig() {
+ string po4aConfig(M)(M doc_matters) {
+ import std.algorithm : sort;
+ import std.array : array, join;
+ import std.conv : to;
+ import std.file : exists;
+ import std.path : baseName;
+ string _src_lang = doc_matters.src.language;
+ /+ ↓ the languages po4a is to produce, which is every language the
+ manifest lists except the one being translated from
+ +/
+ string[] _targets;
+ foreach (_lang; doc_matters.pod.manifest_list_of_languages) {
+ if (_lang != _src_lang) {
+ _targets ~= _lang;
+ }
+ }
+ /+ ↓ the files the document is made of: its master, and every insert the
+ markup names. In manifest order rather than directory order, so the
+ configuration is the same however a filesystem chooses to list a
+ directory.
+ +/
+ string[] _files;
+ _files ~= doc_matters.src.filename;
+ string[] _inserts;
+ foreach (_insert; doc_matters.srcs.file_insert_list) {
+ _inserts ~= _insert.baseName;
+ }
+ _inserts = _inserts.sort.array;
+ _files ~= _inserts;
+ /+ ↓ paths are relative to tools/po4a/, where this file belongs +/
+ enum string _to_text = "../../media/text";
+ string _o;
+ _o ~= "# po4a configuration for " ~ doc_matters.src.filename_base ~ "\n";
+ _o ~= "# generated by spine from pod.manifest and the markup; not kept in git\n";
+ _o ~= "# run from the directory this file is in\n";
+ _o ~= "\n";
+ /+ ↓ --keep 0 is not optional here, it is the difference between
+ regenerating a document and destroying it.
+ .
+ po4a will not write a translated file that falls below a
+ completeness threshold, and that threshold defaults to 80%. A
+ partially translated document is the normal state of one being
+ worked on, and sisu's own behaviour covers it: an untranslated
+ string falls back to the source text, so a file at 3% is mostly the
+ source language and entirely readable. (Measured on live-manual at
+ the default: 181 of its 189 translated files would be discarded, and
+ nine languages would collapse to eight surviving files. It would not
+ look like a failure either, because what remains reads as the
+ document reverting to its source language.)
+ .
+ The Makefile this replaces passed --keep 0 for exactly this reason.
+ +/
+ _o ~= "[options] --keep 0 --package-name " ~ doc_matters.src.filename_base ~ "\n";
+ _o ~= "\n";
+ _o ~= "[po4a_langs] " ~ _targets.join(" ") ~ "\n";
+ _o ~= "[po4a_paths] pot/$master.pot $lang:po/$lang/$master.po\n";
+ _o ~= "\n";
+ foreach (_f; _files) {
+ _o ~= "[type: text] " ~ _to_text ~ "/" ~ _src_lang ~ "/" ~ _f
+ ~ " $lang:" ~ _to_text ~ "/$lang/" ~ _f ~ "\n";
+ }
+ /+ ↓ index.html.in is not markup and no << line names it, so it is found
+ by asking whether the source language has one. live-manual does, the
+ Makefile it replaces carried it as xhtml, and the sample
+ repository's whitelist admits index.html.in.pot and .po by name.
+ Left out, regenerating would quietly drop those catalogue entries.
+ +/
+ string _index_in = doc_matters.pod.manifest_path
+ ~ "/media/text/" ~ _src_lang ~ "/index.html.in";
+ if (_index_in.exists) {
+ _o ~= "[type: xhtml] " ~ _to_text ~ "/" ~ _src_lang ~ "/index.html.in"
+ ~ " $lang:" ~ _to_text ~ "/$lang/index.html.in\n";
+ }
+ return _o;
+ }
+}
+#+END_SRC
+
+* org includes
+** project version
+
+#+NAME: spine_version
+#+HEADER: :noweb yes
+#+BEGIN_SRC emacs-lisp
+<<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:spine_project_version()>>
+#+END_SRC
+
+** year
+
+#+NAME: year
+#+HEADER: :noweb yes
+#+BEGIN_SRC emacs-lisp
+<<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:year()>>
+#+END_SRC
+
+** document header including copyright & license
+
+#+NAME: doc_header_including_copyright_and_license
+#+HEADER: :noweb yes
+#+BEGIN_SRC emacs-lisp
+<<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:spine_doc_header_including_copyright_and_license()>>
+#+END_SRC
+
+* __END__
diff --git a/src/sisudoc/outputs/io_out/hub.d b/src/sisudoc/outputs/io_out/hub.d
index 0973097..254eaa5 100644
--- a/src/sisudoc/outputs/io_out/hub.d
+++ b/src/sisudoc/outputs/io_out/hub.d
@@ -62,6 +62,21 @@ template outputHub() {
@system void outputHub(D)(D doc) {
mixin Msg;
auto msg = Msg!()(doc.matters);
+ /+ ↓ the po4a configuration, printed rather than written.
+ Spine does not write into a source tree, and this belongs beside the
+ catalogues in the pod it describes, so it goes to stdout for the
+ caller to put where they want it:
+ spine --po4a-cfg <pod> > <pod>/tools/po4a/po4a.cfg
+ Once per document, not once per language: it is generated from the
+ source language's files and names every other language itself.
+ +/
+ if (doc.matters.opt.action.po4a_cfg
+ && doc.matters.src.language == doc.matters.pod.manifest_list_of_languages[0]
+ ) {
+ import sisudoc.outputs.io_out.po4a_cfg;
+ mixin spinePo4aConfig;
+ write(po4aConfig(doc.matters));
+ }
enum outTask { source_or_pod, sqlite, sqlite_multi, latex, odt, epub, html_scroll, html_seg, html_stuff, text, skel }
void Scheduled(D)(int sched, D doc) {
auto msg = Msg!()(doc.matters);
diff --git a/src/sisudoc/outputs/io_out/po4a_cfg.d b/src/sisudoc/outputs/io_out/po4a_cfg.d
new file mode 100644
index 0000000..ddcc1ef
--- /dev/null
+++ b/src/sisudoc/outputs/io_out/po4a_cfg.d
@@ -0,0 +1,173 @@
+/+
+- Name: SisuDoc Spine, Doc Reform [a part of]
+ - Description: documents, structuring, processing, publishing, search
+ - static content generator
+
+ - Author: Ralph Amissah
+ [ralph.amissah@gmail.com]
+
+ - Copyright: (C) 2015 (continuously updated, current 2026) Ralph Amissah, All Rights Reserved.
+
+ - License: AGPL 3 or later:
+
+ Spine (SiSU), a framework for document structuring, publishing and
+ search
+
+ Copyright (C) Ralph Amissah
+
+ This program is free software: you can redistribute it and/or modify it
+ under the terms of the GNU AFERO General Public License as published by the
+ Free Software Foundation, either version 3 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program. If not, see [https://www.gnu.org/licenses/].
+
+ If you have Internet connection, the latest version of the AGPL should be
+ available at these locations:
+ [https://www.fsf.org/licensing/licenses/agpl.html]
+ [https://www.gnu.org/licenses/agpl.html]
+
+ - Spine (by Doc Reform, related to SiSU) uses standard:
+ - docReform markup syntax
+ - standard SiSU markup syntax with modified headers and minor modifications
+ - docReform object numbering
+ - standard SiSU object citation numbering & system
+
+ - Homepages:
+ [https://www.sisudoc.org]
+ [https://www.doc-reform.org]
+
+ - Git
+ [https://git.sisudoc.org/]
+
++/
+/++
+ module po4a_cfg;<BR>
+ - the po4a configuration for a document, generated from its manifest and
+ the files its markup names<BR>
+ - written for tools/po4a/po4a.cfg, so its paths are relative to there
++/
+module sisudoc.outputs.io_out.po4a_cfg;
+@system:
+/+ ↓ po4a's configuration, derived rather than kept
+
+ The sample this replaces kept a Makefile that built po4a.cfg by globbing
+ a language directory and listing what it found. Spine already knows both
+ halves without looking: the manifest says which languages a document
+ has, and the markup says which files it is made of, through the << lines
+ the parser follows. Deriving the configuration from those two means it
+ cannot disagree with the document, which a hand-kept file eventually
+ does: a language added to the manifest and forgotten in the Makefile
+ produces a translation nobody updates.
+ .
+ It is derived, so it is not kept in git. The sample repository's
+ whitelist admits pot/ and po/ and not this.
+ .
+ neverwrap is deliberately NOT set, and the reason is worth keeping.
+ .
+ Without it po4a rewraps its output at about 75 columns, so a document
+ whose markup keeps one paragraph on one long line comes back reflowed.
+ That is untidy: it changes no object, since sisu delimits on blank
+ lines, but it churns every translated file in a diff and leaves the
+ source language and its translations formatted unlike each other. The
+ obvious thing is to turn wrapping off.
+ .
+ Measured on live-manual, same catalogues and same English, the option
+ the only difference:
+ .
+ fuzzy before with neverwrap without
+ ca 1 889 5
+ de 8 103 10
+ it 149 804 152
+ .
+ of 1126 strings. po4a will not use a fuzzy translation, so each one
+ renders as the source language: Catalan's coverage would fall from about
+ 46% to about 12%, and Spanish, French and Japanese with it. Setting the
+ option re-extracts the strings in a form the existing catalogues do not
+ match, and four fifths of nine languages' work stops being used.
+ .
+ Tidy formatting is not worth that. The wrapping stays.
++/
+template spinePo4aConfig() {
+ string po4aConfig(M)(M doc_matters) {
+ import std.algorithm : sort;
+ import std.array : array, join;
+ import std.conv : to;
+ import std.file : exists;
+ import std.path : baseName;
+ string _src_lang = doc_matters.src.language;
+ /+ ↓ the languages po4a is to produce, which is every language the
+ manifest lists except the one being translated from
+ +/
+ string[] _targets;
+ foreach (_lang; doc_matters.pod.manifest_list_of_languages) {
+ if (_lang != _src_lang) {
+ _targets ~= _lang;
+ }
+ }
+ /+ ↓ the files the document is made of: its master, and every insert the
+ markup names. In manifest order rather than directory order, so the
+ configuration is the same however a filesystem chooses to list a
+ directory.
+ +/
+ string[] _files;
+ _files ~= doc_matters.src.filename;
+ string[] _inserts;
+ foreach (_insert; doc_matters.srcs.file_insert_list) {
+ _inserts ~= _insert.baseName;
+ }
+ _inserts = _inserts.sort.array;
+ _files ~= _inserts;
+ /+ ↓ paths are relative to tools/po4a/, where this file belongs +/
+ enum string _to_text = "../../media/text";
+ string _o;
+ _o ~= "# po4a configuration for " ~ doc_matters.src.filename_base ~ "\n";
+ _o ~= "# generated by spine from pod.manifest and the markup; not kept in git\n";
+ _o ~= "# run from the directory this file is in\n";
+ _o ~= "\n";
+ /+ ↓ --keep 0 is not optional here, it is the difference between
+ regenerating a document and destroying it.
+ .
+ po4a will not write a translated file that falls below a
+ completeness threshold, and that threshold defaults to 80%. A
+ partially translated document is the normal state of one being
+ worked on, and sisu's own behaviour covers it: an untranslated
+ string falls back to the source text, so a file at 3% is mostly the
+ source language and entirely readable. (Measured on live-manual at
+ the default: 181 of its 189 translated files would be discarded, and
+ nine languages would collapse to eight surviving files. It would not
+ look like a failure either, because what remains reads as the
+ document reverting to its source language.)
+ .
+ The Makefile this replaces passed --keep 0 for exactly this reason.
+ +/
+ _o ~= "[options] --keep 0 --package-name " ~ doc_matters.src.filename_base ~ "\n";
+ _o ~= "\n";
+ _o ~= "[po4a_langs] " ~ _targets.join(" ") ~ "\n";
+ _o ~= "[po4a_paths] pot/$master.pot $lang:po/$lang/$master.po\n";
+ _o ~= "\n";
+ foreach (_f; _files) {
+ _o ~= "[type: text] " ~ _to_text ~ "/" ~ _src_lang ~ "/" ~ _f
+ ~ " $lang:" ~ _to_text ~ "/$lang/" ~ _f ~ "\n";
+ }
+ /+ ↓ index.html.in is not markup and no << line names it, so it is found
+ by asking whether the source language has one. live-manual does, the
+ Makefile it replaces carried it as xhtml, and the sample
+ repository's whitelist admits index.html.in.pot and .po by name.
+ Left out, regenerating would quietly drop those catalogue entries.
+ +/
+ string _index_in = doc_matters.pod.manifest_path
+ ~ "/media/text/" ~ _src_lang ~ "/index.html.in";
+ if (_index_in.exists) {
+ _o ~= "[type: xhtml] " ~ _to_text ~ "/" ~ _src_lang ~ "/index.html.in"
+ ~ " $lang:" ~ _to_text ~ "/$lang/index.html.in\n";
+ }
+ return _o;
+ }
+}
diff --git a/src/sisudoc/spine.d b/src/sisudoc/spine.d
index 9013c3e..9424e02 100644
--- a/src/sisudoc/spine.d
+++ b/src/sisudoc/spine.d
@@ -97,14 +97,24 @@ string program_name = "spine";
static auto rgx = RgxI();
static auto rgx_y = RgxYaml();
static auto rgx_files = RgxFiles();
+ /+ ↓ an action whose output is a file's contents, printed to stdout, turns
+ this off: the banner would otherwise be part of what it printed. The
+ round trips do the same by leaving before scope(success) runs, which
+ they can because they leave early; --po4a-cfg prints from inside
+ output processing and so says so here instead. Set where the options
+ are read, below: the banner is declared before they exist.
+ +/
+ bool _run_banner = true;
scope(success) {
- writefln(
- "~ run complete, ok ~ (%s-%s.%s.%s, %s D:%s, %s %s)",
- program_name,
- _ver.major, _ver.minor, _ver.patch,
- __VENDOR__, __VERSION__,
- bits, os,
- );
+ if (_run_banner) {
+ writefln(
+ "~ run complete, ok ~ (%s-%s.%s.%s, %s D:%s, %s %s)",
+ program_name,
+ _ver.major, _ver.minor, _ver.patch,
+ __VENDOR__, __VERSION__,
+ bits, os,
+ );
+ }
}
scope(failure) {
debug(checkdoc) {
@@ -166,6 +176,7 @@ string program_name = "spine";
"pdf" : false,
"pdf-color-links" : false,
"pdf-init" : false,
+ "po4a-cfg" : false,
"pod" : false,
"pod2" : false,
"serial" : false,
@@ -288,6 +299,7 @@ string program_name = "spine";
"pdf", "latex output for pdfs", &opts["pdf"],
"pdf-color-links", "mono or color links for pdfs", &opts["pdf-color-links"],
"pdf-init", "initialise latex shared files (see latex-header-sty)", &opts["pdf-init"],
+ "po4a-cfg", "print the po4a configuration for this document", &opts["po4a-cfg"],
"pod", "spine (doc reform) pod source content bundled", &opts["pod"],
"pod2", "pod with document abstraction (.ssp) bundled", &opts["pod2"],
"quiet|q", "output to terminal", &opts["vox_is1"],
@@ -359,6 +371,10 @@ string program_name = "spine";
"debug-stages", "debug stages", &opts["debug-stages"],
// "sqlite-db-filename", "=[filename].sql.db", &settings["sqlite-db-filename"],
);
+ /+ ↓ --po4a-cfg prints a file's contents; see the banner above +/
+ if (opts["po4a-cfg"]) {
+ _run_banner = false;
+ }
if (helpInfo.helpWanted) {
defaultGetoptPrinter("Some information about the program.", helpInfo.options);
}
@@ -611,6 +627,9 @@ string program_name = "spine";
@trusted bool ocn_off() {
return ((opts["ocn-off"]) || (opts["no-ocn"])) ? true : false;
}
+ @trusted bool po4a_cfg() {
+ return opts["po4a-cfg"];
+ }
@trusted bool pod() {
return (opts["pod"] || opts["pod2"]) ? true : false;
}