* 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.
/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
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.
-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:
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
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
# 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 =
.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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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 || \
$(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
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
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.
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)
# 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
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
@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:
# 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
# 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
# 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
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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)
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
# 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
# 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
# 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
# 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
# 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
# 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
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
pkglibdir = $(libdir)/$(PACKAGE)
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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)
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.
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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# "GNU distributions usually contain some files which are not source files
# ... . Since these files normally appear in the source directory, they
# 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@
# 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)
$(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
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:
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.
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)
pkglibdir = $(libdir)/$(PACKAGE)
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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)
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.
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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# "GNU distributions usually contain some files which are not source files
# ... . Since these files normally appear in the source directory, they
# 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@
# 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)
$(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
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:
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGCAT = msgcat
MSGINIT = msginit
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)
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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
# 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
$(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
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 \
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.
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"; \
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGCAT = msgcat
MSGINIT = msginit
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)
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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
# 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
$(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
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 \
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.
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"; \
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGCAT = msgcat
MSGINIT = msginit
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)
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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
# 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
$(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
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 \
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.
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"; \
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGCAT = msgcat
MSGINIT = msginit
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)
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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
# 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
$(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
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 \
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.
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"; \
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
# 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
XGETTEXT = xgettext
MSGMERGE = msgmerge
-MSGMERGE_UPDATE = msgmerge --update
MSGMERGE_FOR_MSGFMT_OPTION = --for-msgfmt
MSGINIT = msginit
MSGCONV = msgconv
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)
$(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.
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):
# 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
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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)
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.
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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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@
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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)
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.
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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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@
# 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)
$(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
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)
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.
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)
MSGINIT_OPTIONS =
MSGMERGE = @MSGMERGE@
-MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
MSGINIT = msginit
MSGCONV = msgconv
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
# 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
+# <https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html>:
+# "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
+# <https://www.gnu.org/prep/standards/html_node/Releases.html>.
+# 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
# <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>:
# 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,.*/,,'`; \
# 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)
$(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
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)
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.
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)
# 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
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
# 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@
# 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" && \
$(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:
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 \
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):
#!/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
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: .*"$/{
# 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
# 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