=head1 TRANSLATION

=head2 Introduction

The translation system in Zonemaster is a two-step process, where internal
message tags are first replaced by English strings with argument
placeholders, and a second step where GNU gettext is used to translate the
strings to other languages and fill in the placeholders based on provided data.

All translation files live in the F<share> directory in the
L<Zonemaster::Engine> source directory and all commands described here are
executed from that directory.

=head2 For developers of Zonemaster test modules

The test module code should produce log messages with message tags, as documented
elsewhere. These tags will be used for translation to human language, for
determining the severity of the event logged and to make the events easily used
by other software.

Each test module must also have a method named C<tag_descriptions()>.
This method must return a reference to a hash whose entries are expected to look
like this, where C<MESSAGE_TAG> is a message, C<TEST_MODULE> is the name of a
test module tag and C<"Hello, {name}!"> is a message id:

    MESSAGE_TAG => sub {
        __x    # TEST_MODULE:MESSAGE_TAG
          "Hello, {name}!", @_;
    },

A number of things are important here.
Keys in the hashref are message tags and values are coderefs.
The coderef calls Locale::TextDomain::__x() with a Perl brace format string
(a.k.a. message id) and passes along its own @_).
The coderef propagates the return value of Locale::TextDomain::__x().
The line immediately before the format string contains a comment consisting of
the module name, a colon and the message tag.

The format strings themselves, the comments and the line numbers of the __x
calls are used by the gettext tooling when updating the PO files with new
message ids and old message strings.

Every time you add, remove or modify a tag or its message id, re-run
C<make update-po> as descibed in the next section.
Make sure the message tag comments are properly added and up to date.

=head2 For translators

=head3 Software preparation

For the steps below you need to work on a computer with Git, Perl and Xgettext.
Select what OS you want to work on. Other OSs will also work, but you will
have to find instructions elsewhere.

=head4 FreeBSD

Install the following:

C<pkg install git-lite devel/p5-Locale-XGettext devel/p5-Locale-Msgfmt devel/gmake>

=head4 CentOS

To be written.

=head4 Ubuntu

To be written.

=head4 Debian

To be written

=head3 Background

The first step in updating the translations is to generate a new template file
(F<Zonemaster-Engine.pot>).
In practice you rarely need to think about generating it as it is generally
performed as an implicit intermediate step.
If you do want to generate it, the command is C<make extract-pot>
(C<gmake extract-pot> on FreeBSD).

The translated strings are maintained in files named C<{language_code}.po>
(currently F<en.po>, F<sv.po>, F<da.po> or F<fr.po>).
Execute C<make update-po> (C<gmake update-po> on FreeBSD) to update these
files with new message ids from the
source code (C<make extract-pot> will be infoked behind the scenes).
This should only be necessary to do when a developer has added or changed a test
module.

By default C<make update-po> suggests translations for new message ids based on
fuzzy matching of similar strings.
This is not always desirable and you can disable fuzzy matching by executing
C<make update-po MSGMERGE_OPTS=--no-fuzzy-mathing> instead.

=head3 Github preparation

For full integration with Zonemaster translation you need a Github account
and a fork of F<Zonemaster-Engine>. If you do not have a Github account you
can easily create one at L<https://github.com/>. If you are not prepared to
create one, contact the Zonemaster work group for instructions, either by
creating an issue in L<https://github.com/zonemaster/zonemaster-engine/issues>
or by sending an email to L<mailto:contact@zonemaster.net>.

To create a fork of F<Zonemaster-Engine> go to
L<https://github.com/zonemaster/zonemaster-engine>, make sure you are logged
in at Github and press the "Fork" button.

Make sure you have your public C<ssh> key uploaded to Github and its
private key available on the computer you are going to work from.

=head3 Tools

The ".po" can be edited with a plain text editor, but then it is important
to keep the database structur of the file. There are tools that makes
editing of the ".po" files easier. When using those, the ".po" file is
handled rather as a database then a plain file.

=over

=item * There is an add-on to Emacs,
L<https://www.gnu.org/software/gettext/manual/html_node/PO-Mode.html#PO-Mode>,
which makes updating and searching in the ".po" file easier and more robust.

=item * There is also "GNOME Translation Editor",
L<https://wiki.gnome.org/Apps/Gtranslator>, a ".po" graphical editor available
for at least Windows and Linux.

=item * There are more tools available, either cloud services or programs
for download, and they could be found by searching for "po editor".

=back

=head3 Steps

For normal translation work, follow the steps below.

=over

=item * Clone the Zonemaster-Engine repository with
C<git clone https://github.com/zonemaster/zonemaster-engine.git>
and enter the direcory created, C<cd zonemaster-engine>.

=item * Check-out the F<develop> branch and create a new branch to work in,
C<git checkout origin/develop; git checkout -b translation-update>

=item * Now it is time to add your own fork of F<Zonemaster-Engine> to the
created clone. Run
C<git remote add XXXXX git@github.com:XXXXX/zonemaster-engine.git>
where F<XXXXX> is your Github user name.

=item * Go to the F<share> directory with C<cd share> and execute
C<make update-po> (C<gmake update-po> on FreeBSD).

=item * Update the po file the language to be updated. The F<en.po> file should
not be updated in this way. Instead, create an issue or a pull request
to have the message updated in the Perl module.

=item * When doing the update, do not change the F<msgid>, only update
F<msgstr>. Instead, create an issue or a pull request to have the message
updated in the Perl module.

=item * Inspect every F<fuzzy entry> (tagged with "fuzzy"). Update F<msgstr>
if needed and remove the "fuzzy" tag.

=item * Search for F<untranslated entries> (empty F<msgstr>) and add a
translation. At the end of the file there could be F<obsolete entries>
(lines starting with "#~") and those could have matching translations.

=item * Any remaining F<obsolete entries> (lines at the end of the file
starting with "#~") could be removed.

=item * When the update is completed, it is time to commit the changes. First do
a C<git add xx.po> where F<xx> is the language code of the po file you
have updated. Make sure not to "add" any other file that might have been
changed.

=item * Run C<git status> to verify that only the ".po" file as been added for
commit.

=item * Create a commit, C<git commit -m 'Write a description of the change'>.

=item * Other changed files could be reset by C<git checkout FILE-NAME>.

=item * Added files not needed can just be removed by C<rm FILE-NAME>.

=item * Now push the branch to your fork at Github. Run
C<git push -u XXXXX translation-update> where F<XXXXX> is your
Github user name and "translation-update" is name of the branch
you created above and have been working on.

=item * Go to your fork at Github, https://github.com/XXXXX/zonemaster-engine
where F<XXXXX> is your Github user name.

=item * Select to create a new F<pull request> where the base directory
should be F<zonemaster-engine> and the base should be F<develop> (not
"master"). The "head" should be your fork and "compare" the same
branch as you created above and pushed to your fork.

=item * Inspect what Github says that will change by the pull request. It should
only be the F<po> file that you have updated and nothing else. If additional
files are listed, please correct or request for help.

=item * Press "create pull request", write a nice description and press "create"
again.

=item * If you go back to your own computer and just save the clone as it is, you
can easily update the pull request if needed with more changes to the same
po file. When the pull request has been merged by the Zonemaster work group,
you can delete the local clone and on your Github fork you can remove the branch.

=back

=head2 For Zonemaster package maintainers

In order to make a new translation usable, it must be compiled to C<mo> format
and installed. The first step needs the C<msgfmt> program from the GNU gettext
package to be installed and available in the shell path. As long as it is, it
should be enough to go to the F<share> directory and run C<make> (C<gmake> on
FreeBSD). This is automatically done when following the release instructions.

For the new translation to actually be installed, the C<mo> file must be added
to the F<MANIFEST> file. At the end of the C<make> run, it should have printed
a list of all the paths that has to be there. Just open F<MANIFEST> in a text
editor, check that all the lines are in there and add any that are missing (if
you just added a new translation, that will be missing, for example).

Once the new translation is compiled and added to F<MANIFEST>, the normal Perl
C<make install> process will install it.
