Hello Marc,

I am currently new as Debian Maintainer, but I have more experience
from upstream-side.

As I understand your question about a general workflow of translations
in all your email-cases correct, I think the short answer maybe to use
`quilt` to patch the .PO files instead of committing them directly via
Git.  Also consider `gbp-pq`, could be useful, but not sure.

The reason is, that you can merge (aka. apply) your patch-series
(patch-series: something like a branch in Git) at any time during
source-package building.  As I'm new to Debian packaging I'm not sure
if it is possible to use "debian/patches"; but I think no, because the
step is hard-coded during `dpkg-buildpackage` -- and that is not what
we want.

I would recommend to use another quilt directory, like
`debian/patches-intl`.  I don't know if there exist some other
recommended directory in any Debian Policy or Debian Guide.  Then you
can call in `debian/rules` at the time you wish to apply your patch
series

  ```
  $> QUILT_PATCHES=debian/patches-intl quilt push -a
  ```

The manual call in `debian/rules` ensures that you can decide yourself
at which step to apply your patches -- and decide if the
`dpkg-buildpackage` should break with an error on fail-patching, or
not.  If the package maintainer changes, it should be easy to comment
out the one `quilt` command in `debian/rules` and remove the
patch-series `debian/patches-intl` from the package-repository.

To commit your changes to upstream you just need to apply (or ask to
apply) the patch-series into theres repository.  Make sure to have
many small patches, then the chance is greater that some patches are
going to upstream, and maybe others not.

If these patches coming down from upstream `quilt push -a` stops with
a message like:

  ```
  Applying patch debian/patches-intl/<PATCHNAME>.patch
  patching file <FILE.EXT>
  Hunk #1 FAILED at <LINE_NUMBER>.
  1 out of 1 hunk FAILED -- rejects in file <FILE.EXT>
  Patch debian/patches-intl/<PATCHNAME>.patch can be reverse-applied
  ```

Quilt detects with the message 'can be reverse-applied' that it was
already applied by third-party.  Then you can delete the patch in the
patch series with:

  ```
  $> QUILT_PATCHES=debian/patches-intl quilt delete -nr
  ```

followed by completing to apply the patch series with a second `quilt
push -a` -- and repeatly so on, if more than one patches where
accepted by upstream.

Quilt also allows adapting your patches, in contrast to Git, at which
commits are forever or are needed to be reverted with a revert-commit
(see backport work-flows).  That was also an issue you reported.

This workflow should also work if upstream already have translations
committed -- and/or you begin a fresh one.  Maybe, not sure, that it
also solve the issue of the multiple calls of `msgmerge`; as I
understand, `msgmerge` was used as a kind of `patch`.

Hopefully this helps you for progression,
Dirk =)


On 3/11/25 12:03 PM, Marc Haber wrote:
tl;dr: We need more docs about best practices to handle translations as
a package maintainer


My fellow developers,

there are two things in being a DD that I truly despise. The one is
keeping the machine readable debian/copyright up to date, the other is
handling of translations, regardless of whether it's po-debconf, manpage
translations or program translations (when I am also the upstream).

I might rant about debian/copyright when I blow my fuse next time, but
today it's going to be translations. For me, it seems impossible to
support translator's work without putting a significant burden of
additional work to put on oneself. Especially when one uses version
control and does not do all development in Mast^wdebian/latest, dealing
with translations is a nightmare when it comes to merge. As the Newbie¹
DD I am, I keep running into either nightmare merges, or unnecessarily
fuzzed or even destroyed translations, in all cases feeling even more
stupid and incompetent when some translator points out my mistakes. I
have felt being sent back and forth between different workflows (all of
them wrong) by following random advice without being able to find
authoritative explanation.

I might have a fundamantal misunderstandig of procedures, but all
documentation one finds, including Chapter 8 in the Developer's
Reference (which links to a document by Tomohiro KUBOTA which is no
longer there), elaborate on how one would do actual translations, but
doesn't go as far as giving best practice documentation about what a
package maintainer is supposed to do to make translation blend into a
normal packaging workflow without being a nuisance ("put them into the
po directory and build the package" doesn't fit a modern packaging
workflow using version control).

My example package is adduser, but I think that my questions might apply
to other packages as well. adduser has both its program messages and the
manual pages translatable, the latter being done with po4a. I am aware
that there are also translations for debconf templates, but adduser
doesn't have those (any more). I think the problems that show with
debconf template translations are similar to the pain one feels with
documentation and program translations. I actively avoid using debconf
in my packages because I don't want to go through the pain that handling
translations causes, and many parts of Debian consider it bad practice
to use debconf. But that's an entirely different rant.

Handling translations does hurt when the sources are stored in version
control because I constantly end up having changes to pot and po files
in commits where they don't belong, or uncommitted changes that prevent
me, for example, from doing rebases. I have tried to build a workflow
that doesn't hurt me as package maintainer as much, but it has turned
out that this doesn't work because many translators don't care.

Please don't take me wrong, I know this is a rant, and I know that
you'll notice that I am typing this with my fists clenched. But my time
and my nerves and my mental health as as important as it is to be nice
to my translators. I do care, but sometimes it's really hard to maintain
a straight and friendly face while cursing our tools and docs inside.

Whenever I am angry about something in Debian, I start writing docs. So
I try this here, but here I don't know enough to be really helpful. I
hope that this rant will start a positive discussion with actual results
that I could pour into a Wiki page that might actually help with the
pain I am feeling, assuming that many other maintainers feel as well.

Let me try to summarize what I have understood regarding translations
and what my problems are with that.

(1)
When writing software, docs or debconf templates, the respective author
marks certain strings as translateable. There is a number of conventions
to do so which are language dependent. Let's assume that has been done
the right way, there are docs about this.

(2)
There is some point in the development process when it is time to ask
for translations. Translators need a POT file which contains all the
translatable strings, and they make a PO file from that which contains
the actual translation.

(3)
Some program (xgettext for program translations, po4a for manual pages
and some podebconf tool for debconf templates) is used to pull the
translatable strings from the source code and to create a POT file.

xgettext doesn't even try to create a meaningful header and overwrites
whatever one has written into the previous version of the POT file, so a
wrapper is already needed to have a header that translators can fill
(which they usually don't do).

For Adduser's program translations, my call to xgettext is:
xgettext --keyword=mtx --keyword=gtx --omit-header -o "$TEMP_FILE"
--from-code=UTF-8 -L perl adduser deluser $(find . -name "*.pm")².
TEMP_FILE then gets the generated header prepended to result in
adduser.pot.

I have seen this being done in debian/rules' clean target which, in
in-tree builds, causes the POT file to be changed as well and I don't
understand at which step of the packaging process it would be a good
idea to commit that POT file. If I build my package out of tree (like I
do out of tradition of svn-buildpackage, I have gbp configured to use
../build-area), the POT file ends up newly generated in the source
package but never gets updated in git. Adduser had POT files from 2022
in git until just recently because I just never noticed. There is no
lintian check and no check inside tracker.d.o for this.

In other packages, there is a dedicated m4 macro to call xgettext which
doesn't make things easier to understand.

(4)
Then,
msgmerge --update --backup=none --no-fuzzy-matching "${PO_FILE}" "${POT_FILE}"
is called for every existing PO file. This doesn't move the header from
the POT file to the existing PO file so stupidities like "# COPYRIGHT
THE PACKAGE CREATOR" just never get fixed because the translators don't
seem to care.

If a po file for a language already exists during this step, the already
existing translation gets merged into the new po file. In some
circumstances that I have not understood yet, the translation gets
"fuzzied", which I have been told causes a lot of unnecessary and
repeated work for the translators which I am supposed to avoid by doing
manual work myself which I don't understand. Not doing this work is
condemned as "not being nice to translators".

Basically the same applies for this step than for the POT generation
step, with the additional hardship that the PO files are generated,
being written to by a program AND STILL contain a significant part of
human work. I never know how much work of other people I am destroying
by calling msgmerge out of line. In which stage of package build do I do
msgmerge? Do I commit the merged po files, when do I commit them, what
do I do with them during git merge when a feature branch is merged?

(5)
podebconf-report-po is used to generate the calls for translation. One
message is sent to this mailing list with the pot file attached, and for
each existing po file, the translators listed in that file get an
individual mail with just the respective po file attached.

If the msgmerge step is forgotten, they get an already translated po
file that doesn't match the pot and therefore is useless.

In theory, for an already existing package, the POT file is not needed,
right?

(6)
Depending on the age of the existing translations, about half of the
messages I send to individual translators are going to bounce. Am I
supposed to report that to debian-i18n@l.d.o as a followup to the
general translation request so that new translators can take up the
outdated translatorless translations? Or am I supposed to send the
general translation request to debian-i18n last so that I can explicitly
mention the translatorless languages there?

(8)
When a translator does a translation, they send me a new po file
containing the actual translation. If it's a new language, they start
with the pot file that hopefully has the correct header, and if it's an
existing language, they start with the old po file, which almost always
has a historically grown header that is in more or less dire need of
streamlining and cleaning. They either take the PO/POT file from the
e-mail attachment, use a package the pulled from the archive³ or they
pull the PO/POT file from git.

They usually don't bother about the header or copyright, so things like
package name, licenseª, Project-ID-Version and PO-Revision-Date are
often questionable, unclear, just plain wrong or cause extra work to
package maintainer because, for example, a different license was chosen
than the actual package is licensed under either out of incompetence or
not caring.

Am I supposed to fix those headers in the po file myself? Am I supposed
to ask the translator to fix the headers? Or am I supposed to just
ignore all of that and just accept whatever I get sent? I often feel
like a smart-mouthed know-it-all when I ask a translator to improve the
headers of their PO file.

(9)
I then commit the po file the translator sent me to version control

(10)
And then I eventually release the package.

In theory, it would probably be good to do all that regeneration when
preparing a package for release. Why don't we have a debian/rules target
like debian/rules prepare-release that might be useful for that? How
could we protect us against uploading a package with outdated POT/PO
files? People make mistakes.

How am I supposed to handle the unavoidable differences between git
branches, that are probably easier to solve when I am just merging a
feature branch but can be a major pain when merging suite branches like
experimental, stable, unstable where translation work has already been
done?

There must be some smarter method when merging to mas^wdebian/unstable
than (1) move away all po files, (2) merge, (3) ignore all merge
conflicts in po files, (4) regenerate POT, (5) restore po files moved
away in step 1, (6) msgmerge, (7) do a dedicated translation commit
(one? or one per file?).

I have caused enough breakage in adduser in the last weeks and have
wasted enough time of both translators and myself. For the time being, I
am halting all my efforts to be "nice to translators" to avoid breaking
more things and to keep the chaos in my package trees and version
control low. You can read from my git histories pretty well that I don't
know zilch about what I am doing.

This has to stop as long as being nice on translators means multiplying
my own degree of unthanked busy work.

This happens through a crucial part of adduser development since we are
nearing the freeze, but first I need to build knowledge that I should
have built 25 years ago but noone bothered to document. I really don't
know how translations in Debian have come up to THIS point in the
absence of serious docs. Maybe my fellow DDs are smarter than I am with
all tools involved.

Thanks for reading up to this point. Writing this message alone has cost
me three hours of my time that I'd rather have put in productive
packaging work, and a sleepless night. You know, when I blow a fuse, I
rant, and then I start writing docs. I guess when I put the result of
this discussion in a wiki page, it should be under i18n, right? I am
inclined to put on https://wiki.debian.org/I18n a dedicated chapter
titled "for package maintainers", probably between "Keyboard input
infrastructure support" and "Meetings" as this is a matter beyond
interna of the translation teams and the i18n effort. Am I on the
correct track with that?

Ich habe fertigǂ. Thanks in advance,
Marc Haber

¹ I have only been a DD for a bit more than two decades
² adduser has strings that get used in both translated and untranslated
form, making sure that messages written to the console are translated
and messages written to syslog are written in English to make handling
bug repors easier
³ I have received translations that were obviously done against the POT
file from stable.
ª I have received translations that placed the translation under the
same copyright as $SOME_OTHER_PACKAGE.
ǂ https://en.wikipedia.org/wiki/Giovanni_Trapattoni#In_popular_culture


Attachment: OpenPGP_0xE2A3766F21F02BD5.asc
Description: OpenPGP public key

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature

Reply via email to