From: Bruno Haible Date: Mon, 13 Oct 2025 22:55:27 +0000 (+0200) Subject: po: Don't msgmerge the PO files through Makefile.in.in. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=75a5c466169446d1100eecebeafdbacad631223c;p=thirdparty%2Fgettext.git po: Don't msgmerge the PO files through Makefile.in.in. * gettext-runtime/po/Makefile.in.in (MSGMERGE_UPDATE): Remove variable. (UPDATEPOFILES): Remove variable. (POFILESDEPS*): Remove variables. (.SUFFIXES): Add '.gpo'. Remove '.po-update'. (.po.gpo): New rule. ($(POFILES)): Remove dependencies. Don't invoke MSGMERGE_UPDATE. (mostlyclean): Add *.gpo. (update-po): Don't make $(UPDATEPOFILES). (.nop.po-update): Remove rule. * gettext-runtime/po/Makevars (PO_DEPENDS_ON_POT): Remove variable. * gettext-tools/po/Makevars (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/po/Makevars.template (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/examples/hello-c/po/Makevars (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/examples/hello-c-gnome2/po/Makevars (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/examples/hello-c-gnome3/po/Makevars (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/examples/hello-c-http/po/Makevars (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/examples/hello-c++/po/Makevars (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/examples/hello-c++20/po/Makevars (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/examples/hello-c++-gnome2/po/Makevars (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/examples/hello-c++-gnome3/po/Makevars (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/examples/hello-c++-kde/po/Makevars (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/examples/hello-objc/po/Makevars (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/examples/hello-objc-gnome2/po/Makevars (PO_DEPENDS_ON_POT): Likewise. * gettext-tools/examples/hello-c++-wxwidgets/po/Makefile.am (MSGMERGE_UPDATE): Remove variable. (UPDATEPOFILES): Remove variable. (.SUFFIXES): Add '.gpo'. Remove '.po-update'. (.po.gpo): New rule. ($(POFILES)): Remove dependencies. Don't invoke MSGMERGE_UPDATE. (MOSTLYCLEANFILES): Add *.gpo. (update-po): Don't make $(UPDATEPOFILES). (.nop.po-update): Remove rule. * gettext-tools/examples/hello-python/po/Makefile.am: Likewise. * gettext-tools/examples/hello-guile/po/Makefile.am: Likewise. * gettext-tools/examples/hello-clisp/po/Makefile.am: Likewise. * gettext-tools/examples/hello-librep/po/Makefile.am: Likewise. * gettext-tools/examples/hello-rust/po/Makefile.am: Likewise. * gettext-tools/examples/hello-go/po/Makefile.am: Likewise. * gettext-tools/examples/hello-go-http/po/Makefile.am: Likewise. * gettext-tools/examples/hello-ruby/po/Makefile.am: Likewise. * gettext-tools/examples/hello-sh/po/Makefile.am: Likewise. * gettext-tools/examples/hello-gawk/po/Makefile.am: Likewise. * gettext-tools/examples/hello-pascal/po/Makefile.am: Likewise. * gettext-tools/examples/hello-modula2/po/Makefile.am: Likewise. * gettext-tools/examples/hello-d/po/Makefile.am: Likewise. * gettext-tools/examples/hello-ocaml/po/Makefile.am: Likewise. * gettext-tools/examples/hello-smalltalk/po/Makefile.am: Likewise. * gettext-tools/examples/hello-perl/po/Makefile.am: Likewise. * gettext-tools/examples/hello-php/po/Makefile.am: Likewise. * gettext-tools/examples/hello-ycp/po/Makefile.am: Likewise. * gettext-tools/examples/hello-c++-qt/po/Makefile.am: Likewise. * gettext-tools/examples/hello-java/po/Makefile.am: Likewise. * gettext-tools/examples/hello-java-awt/po/Makefile.am: Likewise. * gettext-tools/examples/hello-java-swing/po/Makefile.am: Likewise. * gettext-tools/examples/hello-java-qtjambi/po/Makefile.am: Likewise. * gettext-tools/examples/hello-csharp/po/Makefile.am (MSGMERGE_UPDATE): Remove variable. (UPDATEPOFILES): Remove variable. (RESOURCESDLLFILES): Change emitted commands to use an intermediate .gpo file. (.SUFFIXES): Add '.gpo'. Remove '.po-update'. (.po.gpo): New rule. ($(POFILES)): Remove dependencies. Don't invoke MSGMERGE_UPDATE. (MOSTLYCLEANFILES): Add *.gpo. (update-po): Don't make $(UPDATEPOFILES). (.nop.po-update): Remove rule. * gettext-tools/examples/hello-csharp-forms/po/Makefile.am: Likewise. * gettext-tools/examples/hello-tcl/po/Makefile.am (MSGMERGE_UPDATE): Remove variable. (UPDATEPOFILES): Remove variable. (MSGFILES): Change emitted commands to use an intermediate .gpo file. (.SUFFIXES): Add '.gpo'. Remove '.po-update'. (.po.gpo): New rule. ($(POFILES)): Remove dependencies. Don't invoke MSGMERGE_UPDATE. (MOSTLYCLEANFILES): Add *.gpo. (update-po): Don't make $(UPDATEPOFILES). (.nop.po-update): Remove rule. * gettext-tools/examples/hello-tcl-tk/po/Makefile.am: Likewise. * gettext-tools/examples/hello-objc-gnustep/po/GNUmakefile (MSGMERGE_UPDATE): Remove variable. (UPDATEPOFILES): Remove variable. (.SUFFIXES): Add '.gpo'. Remove '.po-update'. ($(POFILES)): Remove dependencies. Don't invoke MSGMERGE_UPDATE. (update-po): Don't make $(UPDATEPOFILES). (.nop.po-update): Remove rule. * gettext-tools/examples/po/Makefile.am (MSGMERGE_OPTIONS): Add --no-fuzzy-matching --quiet. (MSGMERGE_UPDATE): Remove variable. (UPDATEPOFILES): Remove variable. (GPOFILES): New variable. (.SUFFIXES): Add '.gpo'. Remove '.nop', '.po-update'. (.po.gpo): New rule. ($(POFILES)): Remove rule. (DISTCLEANFILES): New variable. (update-po): Don't make $(UPDATEPOFILES). Make the small PO files. (.nop.po-update): Remove rule. * gettext-tools/examples/po/mmsmallpo.sh: Use $language.gpo instead of $language.po. * gettext-tools/doc/gettext.texi (Translations under Version Control): Remove documentation of PO_DEPENDS_ON_POT. (Release Management): Update wording. * Admin/release-steps: Don't msgmerge the PO files from translationproject.org. * NEWS: Mention the change. --- diff --git a/.gitignore b/.gitignore index 3d67145d3..f0f6c678e 100644 --- a/.gitignore +++ b/.gitignore @@ -901,6 +901,7 @@ core /gettext-tools/doc/gettext.pgs /gettext-tools/doc/gettext.vr /gettext-tools/doc/gettext.vrs +/gettext-tools/examples/po/*.gpo /gettext-tools/libgettextpo/config.h /gettext-tools/libgettextpo/alloca.h /gettext-tools/libgettextpo/assert.h diff --git a/Admin/release-steps b/Admin/release-steps index a0fc0c7c8..b10de4ac9 100644 --- a/Admin/release-steps +++ b/Admin/release-steps @@ -171,31 +171,22 @@ We assume that the following environment variables are set: https://translationproject.org/latest/gettext-runtime/ Optionally merge: cd gettext-runtime/po - make update-po - cd new - for f in *.po; do msgmerge --update --lang=${f%.po} --previous --width=80 $f ../gettext-runtime.pot; done - mv *.po ../ - cd ..; rm -rf new + mv new/*.po . + rm -rf new wget --mirror --level=1 -nd -nv -A.po -P gettext-tools/po/new \ https://translationproject.org/latest/gettext-tools/ Optionally merge: cd gettext-tools/po - make update-po - cd new - for f in *.po; do msgmerge --update --lang=${f%.po} --previous --width=80 $f ../gettext-tools.pot; done - mv *.po ../ - cd ..; rm -rf new + mv new/*.po . + rm -rf new wget --mirror --level=1 -nd -nv -A.po -P gettext-tools/examples/po/new \ https://translationproject.org/latest/gettext-examples/ Optionally merge: cd gettext-tools/examples/po - make update-po - cd new - for f in *.po; do msgmerge --update --lang=${f%.po} --previous --width=80 $f ../gettext-examples.pot; done - mv *.po ../ - cd ..; rm -rf new + mv new/*.po . + rm -rf new Adjust LINGUAS files if any of the languages has been added or removed since the last release. Commit the changes. diff --git a/NEWS b/NEWS index bb7c4dc77..3b192432f 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,26 @@ -Version 0.27 - October 2025 +Version 1.0 - October 2025 + +# Improvements for maintainers and distributors: + * In a po/ directory, the PO files are now exactly those that the + translators submitted or committed in version control, or a + translation project's daemon committed on behalf of the translators. + They are no longer regularly updated with respect to the POT file + in the same directory. + + The advantage for maintainers is that the maintainer may commit the + PO files in version control, without getting + - lots of modified files shown by "git status", + - frequent merge conflicts when merging between branches, + - a voluminous version control history. + + The advantage for distributors is that the role of files in a + release tarball are clearer: The PO files are source code, whereas + the POT file and the *.gmo files are generated files. + + ATTENTION translators! + Translators who work directly on a package's source code (without + going through a translation project) now need to run "msginit" + before starting work on a PO file. # Improvements for translators: * msginit: diff --git a/gettext-runtime/po/Makefile.in.in b/gettext-runtime/po/Makefile.in.in index c4a828b07..f0ef23ae1 100644 --- a/gettext-runtime/po/Makefile.in.in +++ b/gettext-runtime/po/Makefile.in.in @@ -70,7 +70,6 @@ XGETTEXT_no = @XGETTEXT@ XGETTEXT_yes = @XGETTEXT_015@ XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -91,8 +90,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -131,11 +128,6 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -POFILESDEPS_ = $(srcdir)/$(DOMAIN).pot -POFILESDEPS_yes = $(POFILESDEPS_) -POFILESDEPS_no = -POFILESDEPS = $(POFILESDEPS_$(PO_DEPENDS_ON_POT)) - DISTFILESDEPS_ = update-po DISTFILESDEPS_yes = $(DISTFILESDEPS_) DISTFILESDEPS_no = @@ -148,8 +140,63 @@ all: all-@USE_NLS@ .SUFFIXES: -.SUFFIXES: .po .gmo .nop .po-create .po-update +.SUFFIXES: .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -160,10 +207,16 @@ all: all-@USE_NLS@ # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -200,8 +253,12 @@ CHECK_MACRO_VERSION = \ # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot @$(CHECK_MACRO_VERSION) test ! -f $(srcdir)/$(DOMAIN).pot || \ @@ -288,27 +345,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/POTFILES.in $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(POFILESDEPS) - @test -f $(srcdir)/$(DOMAIN).pot || $(MAKE) $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - if test "$(PACKAGE)" = "gettext-tools" && test "$(CROSS_COMPILING)" != "yes"; then PATH=`pwd`/../src:$$PATH; fi; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -445,7 +486,7 @@ install-dvi install-ps install-pdf install-html: mostlyclean: rm -f $(srcdir)/stamp-poT - rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po + rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po rm -fr *.o clean: mostlyclean @@ -493,9 +534,11 @@ dist2: $(srcdir)/stamp-po $(DISTFILES) fi; \ done +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -505,42 +548,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - if test "$(PACKAGE)" = "gettext-tools" && test "$(CROSS_COMPILING)" != "yes"; then PATH=`pwd`/../src:$$PATH; fi; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-runtime/po/Makevars b/gettext-runtime/po/Makevars index 3cd4ded67..bf501d01a 100644 --- a/gettext-runtime/po/Makevars +++ b/gettext-runtime/po/Makevars @@ -72,12 +72,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/doc/gettext.texi b/gettext-tools/doc/gettext.texi index 7b31eeceb..71b55d88a 100644 --- a/gettext-tools/doc/gettext.texi +++ b/gettext-tools/doc/gettext.texi @@ -9983,13 +9983,6 @@ $(DOMAIN).pot-update}, and commit it at certain point. Special advices for particular version control systems: @itemize @bullet -@item -Recent version control systems, Git for instance, ignore file's -timestamp. In that case, PO files can be accidentally updated even if -a POT file is not updated. To prevent this, you can set -@samp{PO_DEPENDS_ON_POT} variable to @code{no} in the @file{Makevars} -file and do @code{make update-po} manually. - @item Location comments such as @code{#: lib/error.c:116} are sometimes annoying, since these comments are volatile and may introduce unwanted @@ -10016,7 +10009,8 @@ recover the location comments by running @code{msgmerge} again. @cindex distribution tarball In projects that use GNU @code{automake}, the usual commands for creating a distribution tarball, @samp{make dist} or @samp{make distcheck}, -automatically update the PO files as needed. +automatically update the generated files in the @file{po/} directories +as needed. If GNU @code{automake} is not used, the maintainer needs to perform this update before making a release: diff --git a/gettext-tools/examples/hello-c++-gnome2/po/Makevars b/gettext-tools/examples/hello-c++-gnome2/po/Makevars index c3f465c68..895aef2eb 100644 --- a/gettext-tools/examples/hello-c++-gnome2/po/Makevars +++ b/gettext-tools/examples/hello-c++-gnome2/po/Makevars @@ -82,12 +82,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/examples/hello-c++-gnome3/po/Makevars b/gettext-tools/examples/hello-c++-gnome3/po/Makevars index c3f465c68..895aef2eb 100644 --- a/gettext-tools/examples/hello-c++-gnome3/po/Makevars +++ b/gettext-tools/examples/hello-c++-gnome3/po/Makevars @@ -82,12 +82,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/examples/hello-c++-kde/po/Makevars b/gettext-tools/examples/hello-c++-kde/po/Makevars index 225e74167..b656a9aa2 100644 --- a/gettext-tools/examples/hello-c++-kde/po/Makevars +++ b/gettext-tools/examples/hello-c++-kde/po/Makevars @@ -78,12 +78,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/examples/hello-c++-qt/po/Makefile.am b/gettext-tools/examples/hello-c++-qt/po/Makefile.am index 9a0c28404..a405151a0 100644 --- a/gettext-tools/examples/hello-c++-qt/po/Makefile.am +++ b/gettext-tools/examples/hello-c++-qt/po/Makefile.am @@ -65,7 +65,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -82,8 +81,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ fi # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).qm) @@ -111,8 +108,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).qm) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.qm; done -SUFFIXES = .po .qm .nop .po-create .po-update +SUFFIXES = .po .qm .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .qm files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .qm files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .qm files, and it would be a bad +# idea to include the (generated) .qm files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .qm files appear in release tarballs. # The GNU Coding Standards say in # : @@ -123,10 +175,16 @@ SUFFIXES = .po .qm .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .qm conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(QMFILES): $(srcdir)/$(DOMAIN).pot .po.qm: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -157,8 +215,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(QMFILES)" || $(MAKE) $(QMFILES) @@ -244,25 +306,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -298,7 +346,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(QMFILES) @@ -322,9 +370,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -334,41 +384,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(QMFILES) diff --git a/gettext-tools/examples/hello-c++-wxwidgets/po/Makefile.am b/gettext-tools/examples/hello-c++-wxwidgets/po/Makefile.am index 0243bf6be..848fd7c5e 100644 --- a/gettext-tools/examples/hello-c++-wxwidgets/po/Makefile.am +++ b/gettext-tools/examples/hello-c++-wxwidgets/po/Makefile.am @@ -68,7 +68,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -87,8 +86,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -114,8 +111,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -126,10 +178,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -160,8 +218,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -247,25 +309,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -363,7 +411,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -387,9 +435,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -399,41 +449,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-c++/po/Makevars b/gettext-tools/examples/hello-c++/po/Makevars index 307bf0336..e0527a338 100644 --- a/gettext-tools/examples/hello-c++/po/Makevars +++ b/gettext-tools/examples/hello-c++/po/Makevars @@ -71,12 +71,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/examples/hello-c++20/po/Makevars b/gettext-tools/examples/hello-c++20/po/Makevars index 307bf0336..e0527a338 100644 --- a/gettext-tools/examples/hello-c++20/po/Makevars +++ b/gettext-tools/examples/hello-c++20/po/Makevars @@ -71,12 +71,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/examples/hello-c-gnome2/po/Makevars b/gettext-tools/examples/hello-c-gnome2/po/Makevars index c3f465c68..895aef2eb 100644 --- a/gettext-tools/examples/hello-c-gnome2/po/Makevars +++ b/gettext-tools/examples/hello-c-gnome2/po/Makevars @@ -82,12 +82,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/examples/hello-c-gnome3/po/Makevars b/gettext-tools/examples/hello-c-gnome3/po/Makevars index c3f465c68..895aef2eb 100644 --- a/gettext-tools/examples/hello-c-gnome3/po/Makevars +++ b/gettext-tools/examples/hello-c-gnome3/po/Makevars @@ -82,12 +82,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/examples/hello-c-http/po/Makevars b/gettext-tools/examples/hello-c-http/po/Makevars index 097db7f95..62edf52ae 100644 --- a/gettext-tools/examples/hello-c-http/po/Makevars +++ b/gettext-tools/examples/hello-c-http/po/Makevars @@ -70,12 +70,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/examples/hello-c/po/Makevars b/gettext-tools/examples/hello-c/po/Makevars index 097db7f95..62edf52ae 100644 --- a/gettext-tools/examples/hello-c/po/Makevars +++ b/gettext-tools/examples/hello-c/po/Makevars @@ -70,12 +70,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/examples/hello-clisp/po/Makefile.am b/gettext-tools/examples/hello-clisp/po/Makefile.am index bcc190bd5..ff21c1cd9 100644 --- a/gettext-tools/examples/hello-clisp/po/Makefile.am +++ b/gettext-tools/examples/hello-clisp/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-csharp-forms/po/Makefile.am b/gettext-tools/examples/hello-csharp-forms/po/Makefile.am index 3d2b1934e..e90ade686 100644 --- a/gettext-tools/examples/hello-csharp-forms/po/Makefile.am +++ b/gettext-tools/examples/hello-csharp-forms/po/Makefile.am @@ -60,7 +60,6 @@ MSGINIT_OPTIONS = pkglibdir = $(libdir)/$(PACKAGE) MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -77,8 +76,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ fi # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang))/$(DOMAIN).resources.dll) @@ -86,9 +83,9 @@ DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done RESOURCESDLLFILES != tab=`printf '\t'`; \ for lang in $(ALL_LINGUAS); do \ frobbedlang=`echo $$lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$$/-Latn/' -e 's/@cyrillic$$/-Cyrl/' -e 's/^sr-SP$$/sr-SP-Latn/' -e 's/^uz-UZ$$/uz-UZ-Latn/'`; \ - echo 1>&3 "$$frobbedlang/\$$(DOMAIN).resources.dll: $$lang.po"; \ - echo 1>&3 "$${tab}@echo \"\$$(MSGFMT) -c --csharp -d \$$(srcdir) -l $$lang \$$(srcdir)/$$lang.po -r \$$(DOMAIN)\"; \\"; \ - echo 1>&3 "$${tab}\$$(MSGFMT) -c --csharp -d \"\$$(srcdir)\" -l $$lang \$$(srcdir)/$$lang.po -r \"\$$(DOMAIN)\" || { rm -f \"\$$(srcdir)/$$frobbedlang/\$$(DOMAIN).resources.dll\"; exit 1; }"; \ + echo 1>&3 "$$frobbedlang/\$$(DOMAIN).resources.dll: $$lang.po \$$(srcdir)/\$$(DOMAIN).pot"; \ + echo 1>&3 "$${tab}@echo \"\$$(MSGMERGE) \$$(MSGMERGE_FOR_MSGFMT_OPTION) -o $$lang.gpo \$$(srcdir)/$$lang.po \$$(srcdir)/\$$(DOMAIN).pot && \$$(MSGFMT) -c --csharp -d \$$(srcdir) -l $$lang $$lang.gpo -r \$$(DOMAIN); rm -f $$lang.gpo\"; \\"; \ + echo 1>&3 "$${tab}\$$(MSGMERGE) \$$(MSGMERGE_FOR_MSGFMT_OPTION) -o $$lang.gpo \$$(srcdir)/$$lang.po \$$(srcdir)/\$$(DOMAIN).pot && \$$(MSGFMT) -c --csharp -d \"\$$(srcdir)\" -l $$lang $$lang.gpo -r \"\$$(DOMAIN)\" || { rm -f \"\$$(srcdir)/$$frobbedlang/\$$(DOMAIN).resources.dll\"; exit 1; }; rm -f $$lang.gpo"; \ echo $(srcdir)/$$frobbedlang/$(DOMAIN).resources.dll; \ done 3> .csharp-rules # Include the generated rules that cannot be formulated as a simple rule. @@ -119,11 +116,65 @@ CATALOGS != for lang in $(INST_LINGUAS); do \ echo $$lang/$(DOMAIN).resources.dll; \ done -SUFFIXES = .nop .po-create .po-update +SUFFIXES = .po .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .resources.dll files appear in release tarballs, because the GNU Coding +# Standards say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .resources.dll files. The only way to achieve this is to include +# them in the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .resources.dll files, and it would +# be a bad idea to include the (generated) .resources.dll files without +# their corresponding source code. Even if the .po files can be found on +# some translation project's site or in some separate git repository, users +# and distributors should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .resources.dll files appear in release -# tarballs. -# The GNU Coding Standards say in +# tarballs. The GNU Coding Standards say in # : # "GNU distributions usually contain some files which are not source files # ... . Since these files normally appear in the source directory, they @@ -132,6 +183,13 @@ SUFFIXES = .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + all-local: all-local-@USE_NLS@ @@ -150,8 +208,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(RESOURCESDLLFILES)" || $(MAKE) $(RESOURCESDLLFILES) @@ -237,25 +299,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -296,7 +344,7 @@ DISTCLEANFILES = .csharp-rules MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po maintainer-clean-local: @@ -327,9 +375,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-resourcesdll # General rule for creating PO files. @@ -339,41 +389,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-resourcesdll: Makefile $(RESOURCESDLLFILES) diff --git a/gettext-tools/examples/hello-csharp/po/Makefile.am b/gettext-tools/examples/hello-csharp/po/Makefile.am index 3d2b1934e..e90ade686 100644 --- a/gettext-tools/examples/hello-csharp/po/Makefile.am +++ b/gettext-tools/examples/hello-csharp/po/Makefile.am @@ -60,7 +60,6 @@ MSGINIT_OPTIONS = pkglibdir = $(libdir)/$(PACKAGE) MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -77,8 +76,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ fi # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang))/$(DOMAIN).resources.dll) @@ -86,9 +83,9 @@ DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done RESOURCESDLLFILES != tab=`printf '\t'`; \ for lang in $(ALL_LINGUAS); do \ frobbedlang=`echo $$lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$$/-Latn/' -e 's/@cyrillic$$/-Cyrl/' -e 's/^sr-SP$$/sr-SP-Latn/' -e 's/^uz-UZ$$/uz-UZ-Latn/'`; \ - echo 1>&3 "$$frobbedlang/\$$(DOMAIN).resources.dll: $$lang.po"; \ - echo 1>&3 "$${tab}@echo \"\$$(MSGFMT) -c --csharp -d \$$(srcdir) -l $$lang \$$(srcdir)/$$lang.po -r \$$(DOMAIN)\"; \\"; \ - echo 1>&3 "$${tab}\$$(MSGFMT) -c --csharp -d \"\$$(srcdir)\" -l $$lang \$$(srcdir)/$$lang.po -r \"\$$(DOMAIN)\" || { rm -f \"\$$(srcdir)/$$frobbedlang/\$$(DOMAIN).resources.dll\"; exit 1; }"; \ + echo 1>&3 "$$frobbedlang/\$$(DOMAIN).resources.dll: $$lang.po \$$(srcdir)/\$$(DOMAIN).pot"; \ + echo 1>&3 "$${tab}@echo \"\$$(MSGMERGE) \$$(MSGMERGE_FOR_MSGFMT_OPTION) -o $$lang.gpo \$$(srcdir)/$$lang.po \$$(srcdir)/\$$(DOMAIN).pot && \$$(MSGFMT) -c --csharp -d \$$(srcdir) -l $$lang $$lang.gpo -r \$$(DOMAIN); rm -f $$lang.gpo\"; \\"; \ + echo 1>&3 "$${tab}\$$(MSGMERGE) \$$(MSGMERGE_FOR_MSGFMT_OPTION) -o $$lang.gpo \$$(srcdir)/$$lang.po \$$(srcdir)/\$$(DOMAIN).pot && \$$(MSGFMT) -c --csharp -d \"\$$(srcdir)\" -l $$lang $$lang.gpo -r \"\$$(DOMAIN)\" || { rm -f \"\$$(srcdir)/$$frobbedlang/\$$(DOMAIN).resources.dll\"; exit 1; }; rm -f $$lang.gpo"; \ echo $(srcdir)/$$frobbedlang/$(DOMAIN).resources.dll; \ done 3> .csharp-rules # Include the generated rules that cannot be formulated as a simple rule. @@ -119,11 +116,65 @@ CATALOGS != for lang in $(INST_LINGUAS); do \ echo $$lang/$(DOMAIN).resources.dll; \ done -SUFFIXES = .nop .po-create .po-update +SUFFIXES = .po .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .resources.dll files appear in release tarballs, because the GNU Coding +# Standards say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .resources.dll files. The only way to achieve this is to include +# them in the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .resources.dll files, and it would +# be a bad idea to include the (generated) .resources.dll files without +# their corresponding source code. Even if the .po files can be found on +# some translation project's site or in some separate git repository, users +# and distributors should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .resources.dll files appear in release -# tarballs. -# The GNU Coding Standards say in +# tarballs. The GNU Coding Standards say in # : # "GNU distributions usually contain some files which are not source files # ... . Since these files normally appear in the source directory, they @@ -132,6 +183,13 @@ SUFFIXES = .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + all-local: all-local-@USE_NLS@ @@ -150,8 +208,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(RESOURCESDLLFILES)" || $(MAKE) $(RESOURCESDLLFILES) @@ -237,25 +299,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -296,7 +344,7 @@ DISTCLEANFILES = .csharp-rules MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po maintainer-clean-local: @@ -327,9 +375,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-resourcesdll # General rule for creating PO files. @@ -339,41 +389,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-resourcesdll: Makefile $(RESOURCESDLLFILES) diff --git a/gettext-tools/examples/hello-d/po/Makefile.am b/gettext-tools/examples/hello-d/po/Makefile.am index cc988084d..927f0c921 100644 --- a/gettext-tools/examples/hello-d/po/Makefile.am +++ b/gettext-tools/examples/hello-d/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-gawk/po/Makefile.am b/gettext-tools/examples/hello-gawk/po/Makefile.am index 6f2038ce4..5ddb939fb 100644 --- a/gettext-tools/examples/hello-gawk/po/Makefile.am +++ b/gettext-tools/examples/hello-gawk/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-go-http/po/Makefile.am b/gettext-tools/examples/hello-go-http/po/Makefile.am index 4460d5060..f106f8cc7 100644 --- a/gettext-tools/examples/hello-go-http/po/Makefile.am +++ b/gettext-tools/examples/hello-go-http/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-go/po/Makefile.am b/gettext-tools/examples/hello-go/po/Makefile.am index 25470f214..970badb3c 100644 --- a/gettext-tools/examples/hello-go/po/Makefile.am +++ b/gettext-tools/examples/hello-go/po/Makefile.am @@ -65,7 +65,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -84,8 +83,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -111,8 +108,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -123,10 +175,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -157,8 +215,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -244,25 +306,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -360,7 +408,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -384,9 +432,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -396,41 +446,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-guile/po/Makefile.am b/gettext-tools/examples/hello-guile/po/Makefile.am index 38a52b350..9d7264e30 100644 --- a/gettext-tools/examples/hello-guile/po/Makefile.am +++ b/gettext-tools/examples/hello-guile/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-java-awt/po/Makefile.am b/gettext-tools/examples/hello-java-awt/po/Makefile.am index 3c08f8323..e4b41b36b 100644 --- a/gettext-tools/examples/hello-java-awt/po/Makefile.am +++ b/gettext-tools/examples/hello-java-awt/po/Makefile.am @@ -58,7 +58,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGCAT = msgcat MSGINIT = msginit @@ -76,8 +75,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ fi # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(DOMAIN)_$(lang).properties) @@ -107,8 +104,64 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(DOMAIN)_$(lang).properties) CATALOGS != for lang in $(INST_LINGUAS); do echo $(DOMAIN)_$$lang.properties; done -SUFFIXES = .po .nop .po-create .po-update +SUFFIXES = .po .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .properties or .class files appear in release tarballs, because the GNU +# Coding Standards say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .properties or .class files. The only way to achieve this is to +# include them in the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .properties or .class files, and +# it would be a bad idea to include the (generated) .properties or .class +# files without their corresponding source code. Even if the .po files can +# be found on some translation project's site or in some separate git +# repository, users and distributors should not have to go that far, to hunt +# them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .properties or .class files appear # in release tarballs. The GNU Coding Standards say in # : @@ -119,6 +172,13 @@ SUFFIXES = .po .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + all-local: $(srcdir)/stamp-po @@ -134,8 +194,12 @@ all-local: $(srcdir)/stamp-po # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ $(MAKE) update-properties @@ -221,25 +285,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -249,7 +299,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MAINTAINERCLEANFILES = \ $(DOMAIN).pot stamp-po \ @@ -274,9 +324,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-properties # General rule for creating PO files. @@ -286,47 +338,11 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): # During .po -> .properties or .class conversion, take into account the most # recent changes to the .pot file. This eliminates the need to update the .po -# files when the .pot file has changed, which would be troublesome if the .po -# files are put under version control. +# files when the .pot file has changed (see above). update-properties: Makefile $(srcdir)/$(DOMAIN).pot $(POFILES) @echo "$(MSGINIT) -i $(srcdir)/$(DOMAIN).pot --no-translator -l en --properties-output -o $(srcdir)/$(DOMAIN).properties"; \ diff --git a/gettext-tools/examples/hello-java-qtjambi/po/Makefile.am b/gettext-tools/examples/hello-java-qtjambi/po/Makefile.am index 3c08f8323..e4b41b36b 100644 --- a/gettext-tools/examples/hello-java-qtjambi/po/Makefile.am +++ b/gettext-tools/examples/hello-java-qtjambi/po/Makefile.am @@ -58,7 +58,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGCAT = msgcat MSGINIT = msginit @@ -76,8 +75,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ fi # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(DOMAIN)_$(lang).properties) @@ -107,8 +104,64 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(DOMAIN)_$(lang).properties) CATALOGS != for lang in $(INST_LINGUAS); do echo $(DOMAIN)_$$lang.properties; done -SUFFIXES = .po .nop .po-create .po-update +SUFFIXES = .po .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .properties or .class files appear in release tarballs, because the GNU +# Coding Standards say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .properties or .class files. The only way to achieve this is to +# include them in the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .properties or .class files, and +# it would be a bad idea to include the (generated) .properties or .class +# files without their corresponding source code. Even if the .po files can +# be found on some translation project's site or in some separate git +# repository, users and distributors should not have to go that far, to hunt +# them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .properties or .class files appear # in release tarballs. The GNU Coding Standards say in # : @@ -119,6 +172,13 @@ SUFFIXES = .po .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + all-local: $(srcdir)/stamp-po @@ -134,8 +194,12 @@ all-local: $(srcdir)/stamp-po # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ $(MAKE) update-properties @@ -221,25 +285,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -249,7 +299,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MAINTAINERCLEANFILES = \ $(DOMAIN).pot stamp-po \ @@ -274,9 +324,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-properties # General rule for creating PO files. @@ -286,47 +338,11 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): # During .po -> .properties or .class conversion, take into account the most # recent changes to the .pot file. This eliminates the need to update the .po -# files when the .pot file has changed, which would be troublesome if the .po -# files are put under version control. +# files when the .pot file has changed (see above). update-properties: Makefile $(srcdir)/$(DOMAIN).pot $(POFILES) @echo "$(MSGINIT) -i $(srcdir)/$(DOMAIN).pot --no-translator -l en --properties-output -o $(srcdir)/$(DOMAIN).properties"; \ diff --git a/gettext-tools/examples/hello-java-swing/po/Makefile.am b/gettext-tools/examples/hello-java-swing/po/Makefile.am index 3c08f8323..e4b41b36b 100644 --- a/gettext-tools/examples/hello-java-swing/po/Makefile.am +++ b/gettext-tools/examples/hello-java-swing/po/Makefile.am @@ -58,7 +58,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGCAT = msgcat MSGINIT = msginit @@ -76,8 +75,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ fi # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(DOMAIN)_$(lang).properties) @@ -107,8 +104,64 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(DOMAIN)_$(lang).properties) CATALOGS != for lang in $(INST_LINGUAS); do echo $(DOMAIN)_$$lang.properties; done -SUFFIXES = .po .nop .po-create .po-update +SUFFIXES = .po .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .properties or .class files appear in release tarballs, because the GNU +# Coding Standards say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .properties or .class files. The only way to achieve this is to +# include them in the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .properties or .class files, and +# it would be a bad idea to include the (generated) .properties or .class +# files without their corresponding source code. Even if the .po files can +# be found on some translation project's site or in some separate git +# repository, users and distributors should not have to go that far, to hunt +# them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .properties or .class files appear # in release tarballs. The GNU Coding Standards say in # : @@ -119,6 +172,13 @@ SUFFIXES = .po .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + all-local: $(srcdir)/stamp-po @@ -134,8 +194,12 @@ all-local: $(srcdir)/stamp-po # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ $(MAKE) update-properties @@ -221,25 +285,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -249,7 +299,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MAINTAINERCLEANFILES = \ $(DOMAIN).pot stamp-po \ @@ -274,9 +324,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-properties # General rule for creating PO files. @@ -286,47 +338,11 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): # During .po -> .properties or .class conversion, take into account the most # recent changes to the .pot file. This eliminates the need to update the .po -# files when the .pot file has changed, which would be troublesome if the .po -# files are put under version control. +# files when the .pot file has changed (see above). update-properties: Makefile $(srcdir)/$(DOMAIN).pot $(POFILES) @echo "$(MSGINIT) -i $(srcdir)/$(DOMAIN).pot --no-translator -l en --properties-output -o $(srcdir)/$(DOMAIN).properties"; \ diff --git a/gettext-tools/examples/hello-java/po/Makefile.am b/gettext-tools/examples/hello-java/po/Makefile.am index 3c08f8323..e4b41b36b 100644 --- a/gettext-tools/examples/hello-java/po/Makefile.am +++ b/gettext-tools/examples/hello-java/po/Makefile.am @@ -58,7 +58,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGCAT = msgcat MSGINIT = msginit @@ -76,8 +75,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ fi # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(DOMAIN)_$(lang).properties) @@ -107,8 +104,64 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(DOMAIN)_$(lang).properties) CATALOGS != for lang in $(INST_LINGUAS); do echo $(DOMAIN)_$$lang.properties; done -SUFFIXES = .po .nop .po-create .po-update +SUFFIXES = .po .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .properties or .class files appear in release tarballs, because the GNU +# Coding Standards say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .properties or .class files. The only way to achieve this is to +# include them in the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .properties or .class files, and +# it would be a bad idea to include the (generated) .properties or .class +# files without their corresponding source code. Even if the .po files can +# be found on some translation project's site or in some separate git +# repository, users and distributors should not have to go that far, to hunt +# them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .properties or .class files appear # in release tarballs. The GNU Coding Standards say in # : @@ -119,6 +172,13 @@ SUFFIXES = .po .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + all-local: $(srcdir)/stamp-po @@ -134,8 +194,12 @@ all-local: $(srcdir)/stamp-po # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ $(MAKE) update-properties @@ -221,25 +285,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -249,7 +299,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MAINTAINERCLEANFILES = \ $(DOMAIN).pot stamp-po \ @@ -274,9 +324,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-properties # General rule for creating PO files. @@ -286,47 +338,11 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): # During .po -> .properties or .class conversion, take into account the most # recent changes to the .pot file. This eliminates the need to update the .po -# files when the .pot file has changed, which would be troublesome if the .po -# files are put under version control. +# files when the .pot file has changed (see above). update-properties: Makefile $(srcdir)/$(DOMAIN).pot $(POFILES) @echo "$(MSGINIT) -i $(srcdir)/$(DOMAIN).pot --no-translator -l en --properties-output -o $(srcdir)/$(DOMAIN).properties"; \ diff --git a/gettext-tools/examples/hello-librep/po/Makefile.am b/gettext-tools/examples/hello-librep/po/Makefile.am index 03e90b5ab..e31baf86a 100644 --- a/gettext-tools/examples/hello-librep/po/Makefile.am +++ b/gettext-tools/examples/hello-librep/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-modula2/po/Makefile.am b/gettext-tools/examples/hello-modula2/po/Makefile.am index a1282f20d..2d9eb0b88 100644 --- a/gettext-tools/examples/hello-modula2/po/Makefile.am +++ b/gettext-tools/examples/hello-modula2/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-objc-gnome2/po/Makevars b/gettext-tools/examples/hello-objc-gnome2/po/Makevars index c3f465c68..895aef2eb 100644 --- a/gettext-tools/examples/hello-objc-gnome2/po/Makevars +++ b/gettext-tools/examples/hello-objc-gnome2/po/Makevars @@ -82,12 +82,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/examples/hello-objc-gnustep/po/GNUmakefile b/gettext-tools/examples/hello-objc-gnustep/po/GNUmakefile index 5479b2024..eb9ffa697 100644 --- a/gettext-tools/examples/hello-objc-gnustep/po/GNUmakefile +++ b/gettext-tools/examples/hello-objc-gnustep/po/GNUmakefile @@ -68,7 +68,6 @@ PACKAGE_VERSION = 0 XGETTEXT = xgettext MSGMERGE = msgmerge -MSGMERGE_UPDATE = msgmerge --update MSGMERGE_FOR_MSGFMT_OPTION = --for-msgfmt MSGINIT = msginit MSGCONV = msgconv @@ -85,13 +84,19 @@ include LocaleAliases POTFILES_DEPS = $(foreach file, $(POTFILES), $(top_srcdir)/$(file)) POFILES = $(foreach lang, $(LINGUAS), $(lang).po) -UPDATEPOFILES = $(foreach lang, $(LINGUAS), $(lang).po-update) DUMMYPOFILES = $(foreach lang, $(LINGUAS), $(lang).nop) STRINGSFILES = $(foreach lang, $(LINGUAS), $(top_srcdir)/$(NSLOCALE_$(lang)).lproj/Localizable.strings) ENSTRINGSFILES = $(foreach lang, $(ENLINGUAS), $(top_srcdir)/$(NSLOCALE_$(lang)).lproj/Localizable.strings) CATALOGS = $(STRINGSFILES) $(ENSTRINGSFILES) -.SUFFIXES: .po .nop .po-create .po-update +.SUFFIXES: .po .gpo .nop .po-create + +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $${lang}.po $(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $${lang}.po $(DOMAIN).pot internal-all:: all-local-$(USE_NLS) @@ -171,29 +176,20 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ - if test -f $${lang}.po; then \ - echo "$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ + if test -f "$${lang}.po"; then \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-strings # General rule for creating PO files. @@ -203,37 +199,6 @@ update-po: echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - echo "$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-7] | 0.1[1-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): diff --git a/gettext-tools/examples/hello-objc/po/Makevars b/gettext-tools/examples/hello-objc/po/Makevars index 097db7f95..62edf52ae 100644 --- a/gettext-tools/examples/hello-objc/po/Makevars +++ b/gettext-tools/examples/hello-objc/po/Makevars @@ -70,12 +70,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/examples/hello-ocaml/po/Makefile.am b/gettext-tools/examples/hello-ocaml/po/Makefile.am index 6759d699c..b14be32ef 100644 --- a/gettext-tools/examples/hello-ocaml/po/Makefile.am +++ b/gettext-tools/examples/hello-ocaml/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-pascal/po/Makefile.am b/gettext-tools/examples/hello-pascal/po/Makefile.am index 0d0de0720..f9d70377e 100644 --- a/gettext-tools/examples/hello-pascal/po/Makefile.am +++ b/gettext-tools/examples/hello-pascal/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-perl/po/Makefile.am b/gettext-tools/examples/hello-perl/po/Makefile.am index 0e3b0ca27..7dd4265f1 100644 --- a/gettext-tools/examples/hello-perl/po/Makefile.am +++ b/gettext-tools/examples/hello-perl/po/Makefile.am @@ -72,7 +72,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -91,8 +90,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -118,8 +115,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -130,10 +182,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -164,8 +222,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -251,25 +313,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -367,7 +415,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -391,9 +439,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -403,41 +453,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-php/po/Makefile.am b/gettext-tools/examples/hello-php/po/Makefile.am index b9cb205d4..32e97bf84 100644 --- a/gettext-tools/examples/hello-php/po/Makefile.am +++ b/gettext-tools/examples/hello-php/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-python/po/Makefile.am b/gettext-tools/examples/hello-python/po/Makefile.am index d1d82a688..8afec3d0c 100644 --- a/gettext-tools/examples/hello-python/po/Makefile.am +++ b/gettext-tools/examples/hello-python/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-ruby/po/Makefile.am b/gettext-tools/examples/hello-ruby/po/Makefile.am index a5492990f..1a20e34d9 100644 --- a/gettext-tools/examples/hello-ruby/po/Makefile.am +++ b/gettext-tools/examples/hello-ruby/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-rust/po/Makefile.am b/gettext-tools/examples/hello-rust/po/Makefile.am index 29d4e014a..e1e13c25b 100644 --- a/gettext-tools/examples/hello-rust/po/Makefile.am +++ b/gettext-tools/examples/hello-rust/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-sh/po/Makefile.am b/gettext-tools/examples/hello-sh/po/Makefile.am index 131be9267..0b1e69365 100644 --- a/gettext-tools/examples/hello-sh/po/Makefile.am +++ b/gettext-tools/examples/hello-sh/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-smalltalk/po/Makefile.am b/gettext-tools/examples/hello-smalltalk/po/Makefile.am index f6cd3e3b6..f75c386b7 100644 --- a/gettext-tools/examples/hello-smalltalk/po/Makefile.am +++ b/gettext-tools/examples/hello-smalltalk/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/hello-tcl-tk/po/Makefile.am b/gettext-tools/examples/hello-tcl-tk/po/Makefile.am index 2eac09697..88873929f 100644 --- a/gettext-tools/examples/hello-tcl-tk/po/Makefile.am +++ b/gettext-tools/examples/hello-tcl-tk/po/Makefile.am @@ -58,7 +58,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -75,8 +74,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ fi # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang)).msg) @@ -84,9 +81,9 @@ DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done MSGFILES != tab=`printf '\t'`; \ for lang in $(ALL_LINGUAS); do \ frobbedlang=`echo $$lang | sed -e 's/\..*$$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`; \ - echo 1>&3 "$$frobbedlang.msg: $$lang.po"; \ - echo 1>&3 "$${tab}@echo \"\$$(MSGFMT) -c --tcl -d \$$(srcdir) -l $$lang \$$(srcdir)/$$lang.po\"; \\"; \ - echo 1>&3 "$${tab}\$$(MSGFMT) -c --tcl -d \"\$$(srcdir)\" -l $$lang \$$(srcdir)/$$lang.po || { rm -f \"\$$(srcdir)/$$frobbedlang.msg\"; exit 1; }"; \ + echo 1>&3 "$$frobbedlang.msg: $$lang.po \$$(srcdir)/\$$(DOMAIN).pot"; \ + echo 1>&3 "$${tab}@echo \"\$$(MSGMERGE) \$$(MSGMERGE_FOR_MSGFMT_OPTION) -o $$lang.gpo \$$(srcdir)/$$lang.po \$$(srcdir)/\$$(DOMAIN).pot && \$$(MSGFMT) -c --tcl -d \$$(srcdir) -l $$lang $$lang.gpo; rm -f $$lang.gpo\"; \\"; \ + echo 1>&3 "$${tab}\$$(MSGMERGE) \$$(MSGMERGE_FOR_MSGFMT_OPTION) -o $$lang.gpo \$$(srcdir)/$$lang.po \$$(srcdir)/\$$(DOMAIN).pot && \$$(MSGFMT) -c --tcl -d \"\$$(srcdir)\" -l $$lang $$lang.gpo || { rm -f \"\$$(srcdir)/$$frobbedlang.msg\"; exit 1; }; rm -f $$lang.gpo"; \ echo $(srcdir)/$$frobbedlang.msg; \ done 3> .tcl-rules # Include the generated rules that cannot be formulated as a simple rule. @@ -117,8 +114,63 @@ CATALOGS != for lang in $(INST_LINGUAS); do \ echo $$frobbedlang.msg; \ done -SUFFIXES = .nop .po-create .po-update +SUFFIXES = .po .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .msg files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .msg files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .msg files, and it would be a bad +# idea to include the (generated) .msg files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .msg files appear in release tarballs. # The GNU Coding Standards say in # : @@ -129,6 +181,13 @@ SUFFIXES = .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + all-local: all-local-@USE_NLS@ @@ -147,8 +206,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(MSGFILES)" || $(MAKE) $(MSGFILES) @@ -234,25 +297,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -290,7 +339,7 @@ DISTCLEANFILES = .tcl-rules MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(MSGFILES) @@ -314,9 +363,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-msg # General rule for creating PO files. @@ -326,41 +377,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-msg: Makefile $(MSGFILES) diff --git a/gettext-tools/examples/hello-tcl/po/Makefile.am b/gettext-tools/examples/hello-tcl/po/Makefile.am index 2eac09697..88873929f 100644 --- a/gettext-tools/examples/hello-tcl/po/Makefile.am +++ b/gettext-tools/examples/hello-tcl/po/Makefile.am @@ -58,7 +58,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -75,8 +74,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ fi # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang)).msg) @@ -84,9 +81,9 @@ DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done MSGFILES != tab=`printf '\t'`; \ for lang in $(ALL_LINGUAS); do \ frobbedlang=`echo $$lang | sed -e 's/\..*$$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`; \ - echo 1>&3 "$$frobbedlang.msg: $$lang.po"; \ - echo 1>&3 "$${tab}@echo \"\$$(MSGFMT) -c --tcl -d \$$(srcdir) -l $$lang \$$(srcdir)/$$lang.po\"; \\"; \ - echo 1>&3 "$${tab}\$$(MSGFMT) -c --tcl -d \"\$$(srcdir)\" -l $$lang \$$(srcdir)/$$lang.po || { rm -f \"\$$(srcdir)/$$frobbedlang.msg\"; exit 1; }"; \ + echo 1>&3 "$$frobbedlang.msg: $$lang.po \$$(srcdir)/\$$(DOMAIN).pot"; \ + echo 1>&3 "$${tab}@echo \"\$$(MSGMERGE) \$$(MSGMERGE_FOR_MSGFMT_OPTION) -o $$lang.gpo \$$(srcdir)/$$lang.po \$$(srcdir)/\$$(DOMAIN).pot && \$$(MSGFMT) -c --tcl -d \$$(srcdir) -l $$lang $$lang.gpo; rm -f $$lang.gpo\"; \\"; \ + echo 1>&3 "$${tab}\$$(MSGMERGE) \$$(MSGMERGE_FOR_MSGFMT_OPTION) -o $$lang.gpo \$$(srcdir)/$$lang.po \$$(srcdir)/\$$(DOMAIN).pot && \$$(MSGFMT) -c --tcl -d \"\$$(srcdir)\" -l $$lang $$lang.gpo || { rm -f \"\$$(srcdir)/$$frobbedlang.msg\"; exit 1; }; rm -f $$lang.gpo"; \ echo $(srcdir)/$$frobbedlang.msg; \ done 3> .tcl-rules # Include the generated rules that cannot be formulated as a simple rule. @@ -117,8 +114,63 @@ CATALOGS != for lang in $(INST_LINGUAS); do \ echo $$frobbedlang.msg; \ done -SUFFIXES = .nop .po-create .po-update +SUFFIXES = .po .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .msg files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .msg files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .msg files, and it would be a bad +# idea to include the (generated) .msg files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .msg files appear in release tarballs. # The GNU Coding Standards say in # : @@ -129,6 +181,13 @@ SUFFIXES = .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + all-local: all-local-@USE_NLS@ @@ -147,8 +206,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(MSGFILES)" || $(MAKE) $(MSGFILES) @@ -234,25 +297,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -290,7 +339,7 @@ DISTCLEANFILES = .tcl-rules MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(MSGFILES) @@ -314,9 +363,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-msg # General rule for creating PO files. @@ -326,41 +377,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-msg: Makefile $(MSGFILES) diff --git a/gettext-tools/examples/hello-ycp/po/Makefile.am b/gettext-tools/examples/hello-ycp/po/Makefile.am index 657a33457..b14304827 100644 --- a/gettext-tools/examples/hello-ycp/po/Makefile.am +++ b/gettext-tools/examples/hello-ycp/po/Makefile.am @@ -62,7 +62,6 @@ MSGMERGE_OPTIONS = MSGINIT_OPTIONS = MSGMERGE = @MSGMERGE@ -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ MSGINIT = msginit MSGCONV = msgconv @@ -81,8 +80,6 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) GMOFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.gmo; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done @@ -108,8 +105,63 @@ INST_LINGUAS != for presentlang in $(ALL_LINGUAS); do \ # This is computed as $(foreach lang, $(INST_LINGUAS), $(lang).gmo) CATALOGS != for lang in $(INST_LINGUAS); do echo $$lang.gmo; done -SUFFIXES = .po .gmo .nop .po-create .po-update +SUFFIXES = .po .gmo .gpo .nop .po-create +# Which files appear in release tarballs? +# +# The .gmo files appear in release tarballs, because the GNU Coding Standards +# say in +# : +# "The configure script and the Makefile rules for building and installation +# should not use any utilities directly except these: +# awk ... true" +# and 'msgfmt' is not in this list. In other words, when a user - who does not +# have the GNU gettext tools installed - does "make && make install", it should +# install the .gmo files. The only way to achieve this is to include them in +# the release tarballs. +# +# The .pot file appears in release tarballs, because it is needed when a +# translator runs "msginit" to start working on a PO file or when a web-based +# PO editor prepares the initial PO file for a translator. Translators and +# translation projects should not have to run 'xgettext' on some source code; +# that's not their business, and they would not be in a good position to deal +# with errors. +# +# The .po files appear in release tarballs, because +# - They are part of the source code of the .gmo files, and it would be a bad +# idea to include the (generated) .gmo files without their corresponding +# source code. Even if the .po files can be found on some translation +# project's site or in some separate git repository, users and distributors +# should not have to go that far, to hunt them down. +# - The .po file is needed when a translator runs "msginit" to continue +# working on a PO file (in packages that do not use a web-based translation +# project). +# These .po files are those that the translators submitted or committed in +# version control, or a translation project's daemon committed on behalf of the +# translators. +# Up until 2025, we included the *merged* .po files in the release tarballs. +# These merged .po files, that we now name .gpo files in this Makefile, +# are neither source code nor entirely generated files: They are a mix of +# source code (from the translators) and generated parts (from the .pot file). +# This caused two problems: +# * Regarding the tarballs: They are "non-source" files in the sense of +# . +# Distributors who want to make sure that they rebuild everything from +# source had a problem here. +# Also, small changes in the package caused massive line number changes +# in the .po files. +# * Regarding version control: +# Packages that put the .po files under version control had changes in +# all .po files nearly each time "make dist" was invoked. Leading to +# - Lots of modified files shown by "git status", +# - Frequent merge conflicts when merging between branches, +# - A voluminous version control history. +# Whereas packages that do not put the .po files under version control +# had to fetch them from somewhere (usually a translation project), +# meaning that an 'autopull.sh' step was needed before the 'autogen.sh' +# step of the package's build system. +# Instead, now, we include the original .po files in the release tarballs. +# # The .pot file, stamp-po, .po files, and .gmo files appear in release tarballs. # The GNU Coding Standards say in # : @@ -120,10 +172,16 @@ SUFFIXES = .po .gmo .nop .po-create .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file (mostly for debugging purposes). +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_FOR_MSGFMT_OPTION) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + # During .po -> .gmo conversion, take into account the most recent changes to # the .pot file. This eliminates the need to update the .po files when the -# .pot file has changed, which would be troublesome if the .po files are put -# under version control. +# .pot file has changed (see above). $(GMOFILES): $(srcdir)/$(DOMAIN).pot .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ @@ -154,8 +212,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @@ -241,25 +303,11 @@ $(DOMAIN).pot-update: $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot +# This target attempts to build a PO file. +$(POFILES): @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --previous $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ + : ; \ else \ $(MAKE) $${lang}.po-create; \ fi @@ -357,7 +405,7 @@ html ID: MOSTLYCLEANFILES = MOSTLYCLEANFILES += stamp-poT -MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po +MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.gpo *.new.po MOSTLYCLEANFILES += *.o MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(GMOFILES) @@ -381,9 +429,11 @@ distdir1: esac; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. @@ -393,41 +443,6 @@ update-po: Makefile echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.10 | 0.10.*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[1-5] | 0.1[1-5].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - 0.1[6-7] | 0.1[6-7].*) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$$lang --previous -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) diff --git a/gettext-tools/examples/po/Makefile.am b/gettext-tools/examples/po/Makefile.am index e440e3684..4b1860019 100644 --- a/gettext-tools/examples/po/Makefile.am +++ b/gettext-tools/examples/po/Makefile.am @@ -164,10 +164,9 @@ EXTRA_LOCALE_CATEGORIES = # These options get passed to msgmerge. # Useful options are in particular: # --previous to keep previous msgids of translated messages -MSGMERGE_OPTIONS = +MSGMERGE_OPTIONS = --no-fuzzy-matching --quiet MSGMERGE = msgmerge -MSGMERGE_UPDATE = @MSGMERGE@ --update MSGINIT = msginit MSGCONV = msgconv MSGFILTER = msgfilter @@ -183,12 +182,12 @@ ALL_LINGUAS != if test -f $(srcdir)/LINGUAS; then \ fi # This is computed as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) POFILES != for lang in $(ALL_LINGUAS); do echo $(srcdir)/$$lang.po; done -# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) -UPDATEPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.po-update; done +# This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).gpo) +GPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.gpo; done # This is computed as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) DUMMYPOFILES != for lang in $(ALL_LINGUAS); do echo $$lang.nop; done -SUFFIXES = .po .nop .po-update +SUFFIXES = .po .gpo # The .pot file, stamp-po, and .po files appear in release tarballs. # The GNU Coding Standards say in @@ -200,6 +199,14 @@ SUFFIXES = .po .nop .po-update # source directory." # Therefore we put these files in the source directory, not the build directory. +# This target creates a merged PO file. +$(GPOFILES): $(srcdir)/$(DOMAIN).pot +.po.gpo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + echo "rm -f $${lang}.gpo && $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot"; \ + rm -f $${lang}.gpo && \ + $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $${lang}.gpo $(srcdir)/$${lang}.po $(srcdir)/$(DOMAIN).pot + all-local: all-local-@USE_NLS@ @@ -218,8 +225,12 @@ all-local-no: # file is not under version control, "make" will update the $(DOMAIN).pot and # the $(CATALOGS), but subsequent invocations of "make" will do nothing. This # timestamp would not be necessary if updating the $(CATALOGS) would always -# touch them; however, the rule for $(POFILES) has been designed to not touch -# files that don't need to be changed. +# touch them; however, the rule for $(DOMAIN).pot-update has been designed to +# not touch $(srcdir)/$(DOMAIN).pot if it doesn't need to be changed. +# +# Note: The name 'stamp-po' is a bit misleading. It does *not* designate a +# timestamp for the *.po files. Rather it is a timestamp for all generated +# files in this directory. $(srcdir)/stamp-po: $(srcdir)/$(DOMAIN).pot @test ! -f $(srcdir)/$(DOMAIN).pot || { \ echo "touch $(srcdir)/stamp-po" && \ @@ -394,14 +405,6 @@ hello-ycp.pot : $(POTFILES_DEPS) $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot - @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) && $(MSGMERGE_UPDATE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $${lang}.po $(DOMAIN).pot - html ID: @@ -410,6 +413,8 @@ MOSTLYCLEANFILES += stamp-poT MOSTLYCLEANFILES += core core.* *.stackdump $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po MOSTLYCLEANFILES += *.o +DISTCLEANFILES = $(GPOFILES) + MAINTAINERCLEANFILES = $(DOMAIN).pot stamp-po $(SMALLPOTS) EXTRA_DIST = remove-potcdate.sed xsmallpot.sh mmsmallpo.sh LINGUAS \ @@ -425,36 +430,16 @@ distdir1: $(srcdir)/$(DOMAIN).pot done; \ fi +# This rule updates all generated files in this directory. +# Note: The name 'update-po' is a bit misleading. It does *not* modify the *.po +# files. But we can't rename it easily, because it's a documented target. update-po: Makefile $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) - -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - (cd $(srcdir) && \ - if $(MSGMERGE) --quiet $(MSGMERGE_OPTIONS) --lang=$${lang} --previous $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - exit 1; \ - fi) && \ - $(MAKE) $(SMALLPOFILES_FOR_lang) LL=$$lang + test -z "$(GPOFILES)" || $(MAKE) $(GPOFILES) + for file in $(GPOFILES); do \ + lang=`echo $$file | sed -e 's,.*/,,' -e 's,\.gpo$$,,'`; \ + $(MAKE) $(SMALLPOFILES_FOR_lang) LL=$$lang || exit 1; \ + done $(DUMMYPOFILES): diff --git a/gettext-tools/examples/po/mmsmallpo.sh b/gettext-tools/examples/po/mmsmallpo.sh index c268684f1..ebf6be2eb 100755 --- a/gettext-tools/examples/po/mmsmallpo.sh +++ b/gettext-tools/examples/po/mmsmallpo.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (C) 2003-2004, 2009 Free Software Foundation, Inc. +# Copyright (C) 2003-2025 Free Software Foundation, Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -23,7 +23,7 @@ test $# = 2 || { echo "Usage: mmsmallpo.sh hello-foo ll" 1>&2; exit 1; } directory=$1 language=$2 -msgmerge --quiet --force-po $language.po $directory.pot -o - | \ +msgmerge --quiet --force-po $language.gpo $directory.pot -o - | \ msgattrib --no-obsolete | \ sed -e "s, $directory/, ,g" | sed -e "s,gettext-examples,$directory," | \ sed -e '/^"POT-Creation-Date: .*"$/{ diff --git a/gettext-tools/po/Makevars b/gettext-tools/po/Makevars index 3df320a35..d612bb0db 100644 --- a/gettext-tools/po/Makevars +++ b/gettext-tools/po/Makevars @@ -77,12 +77,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained diff --git a/gettext-tools/po/Makevars.template b/gettext-tools/po/Makevars.template index d1532a95c..e2117b867 100644 --- a/gettext-tools/po/Makevars.template +++ b/gettext-tools/po/Makevars.template @@ -69,12 +69,6 @@ MSGMERGE_OPTIONS = # MSGINIT_OPTIONS. MSGINIT_OPTIONS = -# This tells whether or not to regenerate a PO file when $(DOMAIN).pot -# has changed. Possible values are "yes" and "no". Set this to no if -# the POT file is checked in the repository and the version control -# program ignores timestamps. -PO_DEPENDS_ON_POT = yes - # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained