diff --git a/.gitignore b/.gitignore
index dd00fc5ccf..121c2caed1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,7 +37,6 @@
.memdump
.sc-start-sc_*
.ycm_extra_conf.py
-/ABOUT-NLS
/AUTHORS
/ChangeLog
/GNUmakefile
@@ -101,7 +100,7 @@
/maint.mk
/mingw-libvirt.spec
/mkinstalldirs
-/po/*
+/po/*gmo
/proxy/
/python/
/run
@@ -211,6 +210,3 @@ tags
!/gnulib/lib/Makefile.am
!/gnulib/tests/Makefile.am
!/m4/virt-*.m4
-!/po/*.po
-!/po/POTFILES.in
-!/po/libvirt.pot
diff --git a/ABOUT-NLS b/ABOUT-NLS
new file mode 120000
index 0000000000..b583e276a7
--- /dev/null
+++ b/ABOUT-NLS
@@ -0,0 +1 @@
+po/README.md
\ No newline at end of file
diff --git a/autogen.sh b/autogen.sh
index 1183b13083..9afad8f9d5 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -127,8 +127,7 @@ if test -d .git || test -f .git; then
expected_hash=$(cat "$state_file" 2>/dev/null)
actual_hash=$(gnulib_hash "$no_git")
- if test "$actual_hash" = "$expected_hash" && \
- test -f po/Makevars && test -f AUTHORS; then
+ if test "$actual_hash" = "$expected_hash" && test -f AUTHORS; then
# The gnulib hash matches our expectations, and all the files
# that can only be generated through bootstrap are present:
# we just need to run autoreconf. Unless we're performing a
diff --git a/bootstrap.conf b/bootstrap.conf
index 0bfa7941f6..9559922fce 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -58,7 +58,6 @@ getopt-posix
getpass
getpeername
getsockname
-gettext-h
gettimeofday
gitlog-to-changelog
gnumakefile
@@ -132,16 +131,6 @@ waitpid
warnings
'
-# Additional xgettext options to use. Use "\\\newline" to break lines.
-XGETTEXT_OPTIONS=$XGETTEXT_OPTIONS'\\\
- --flag=virAsprintf:2:c-format\\\
- --from-code=UTF-8\\\
-'
-
-# This is not a GNU package, so the default bug address is invalid,
-# and the translation project is not in use.
-MSGID_BUGS_ADDRESS=libvir-list@redhat.com
-COPYRIGHT_HOLDER='Red Hat, Inc.'
SKIP_PO=true
# Enable copy-mode for MSYS/MinGW. MSYS' ln doesn't work well in the way
@@ -150,31 +139,6 @@ if test -n "$MSYSTEM"; then
copy=true
fi
-# If "AM_GNU_GETTEXT(external" or "AM_GNU_GETTEXT([external]"
-# appears in configure.ac, exclude some unnecessary files.
-# Without grep's -E option (not portable enough, pre-configure),
-# the following test is ugly. Also, this depends on the existence
-# of configure.ac, not the obsolescent-named configure.in. But if
-# you're using this infrastructure, you should care about such things.
-
-gettext_external=0
-grep '^[ ]*AM_GNU_GETTEXT(external\>' configure.ac > /dev/null &&
- gettext_external=1
-grep '^[ ]*AM_GNU_GETTEXT(\[external\]' configure.ac > /dev/null &&
- gettext_external=1
-
-if test $gettext_external = 1; then
- # Gettext supplies these files, but we don't need them since
- # we don't have an intl subdirectory.
- excluded_files='
- m4/glibc2.m4
- m4/intdiv0.m4
- m4/lcmessage.m4
- m4/uintmax_t.m4
- m4/ulonglong.m4
- m4/visibility.m4
- '
-fi
# Tell gnulib to:
# require LGPLv2+
@@ -202,8 +166,6 @@ local_gl_dir=gnulib/local
buildreq="\
autoconf 2.59
automake 1.9.6
-autopoint -
-gettext 0.17
git 1.5.5
gzip -
libtool -
diff --git a/configure.ac b/configure.ac
index ae798faa54..0aecf68c38 100644
--- a/configure.ac
+++ b/configure.ac
@@ -257,6 +257,7 @@ LIBVIRT_ARG_LIBSSH
LIBVIRT_ARG_LIBXML
LIBVIRT_ARG_MACVTAP
LIBVIRT_ARG_NETCF
+LIBVIRT_ARG_NLS
LIBVIRT_ARG_NSS
LIBVIRT_ARG_NUMACTL
LIBVIRT_ARG_OPENWSMAN
@@ -298,6 +299,7 @@ LIBVIRT_CHECK_LIBSSH
LIBVIRT_CHECK_LIBXML
LIBVIRT_CHECK_MACVTAP
LIBVIRT_CHECK_NETCF
+LIBVIRT_CHECK_NLS
LIBVIRT_CHECK_NUMACTL
LIBVIRT_CHECK_NWFILTER
LIBVIRT_CHECK_OPENWSMAN
@@ -732,33 +734,7 @@ if test "$enable_test_locking" = "yes"; then
fi
AM_CONDITIONAL([WITH_CIL],[test "$enable_test_locking" = "yes"])
-dnl Check for gettext - don't go any newer than what RHEL 5 supports
-dnl
-dnl save and restore CPPFLAGS around gettext check as the internal iconv
-dnl check might leave -I/usr/local/include in CPPFLAGS on FreeBSD resulting
-dnl in the build picking up previously installed libvirt/libvirt.h instead
-dnl of the correct one from the source tree.
-dnl compute the difference between save_CPPFLAGS and CPPFLAGS and append it
-dnl to INCLUDES in order to preserve changes made by gettext but in a place
-dnl that does not break the build
-save_CPPFLAGS="$CPPFLAGS"
-AM_GNU_GETTEXT_VERSION([0.17])
-AM_GNU_GETTEXT([external])
-GETTEXT_CPPFLAGS=
-if test "x$save_CPPFLAGS" != "x$CPPFLAGS"; then
- set dummy $CPPFLAGS; shift
- for var
- do
- case " $var " in
- " $save_CPPFLAGS ") ;;
- *) GETTEXT_CPPFLAGS="$GETTEXT_CPPFLAGS $var" ;;
- esac
- done
-fi
-CPPFLAGS="$save_CPPFLAGS"
-AC_SUBST([GETTEXT_CPPFLAGS])
-
-ALL_LINGUAS=`cd "$srcdir/po" > /dev/null && ls *.po | sed 's+\.po$++'`
+LIBVIRT_GETTEXT
dnl Cygwin, MinGW and MSVC checks
LIBVIRT_WIN_CHECK_COMMON
@@ -909,7 +885,7 @@ AC_CONFIG_FILES([\
src/libvirt-qemu.pc \
src/libvirt-lxc.pc \
libvirt.spec mingw-libvirt.spec \
- po/Makefile.in \
+ po/Makefile \
include/libvirt/libvirt-common.h \
examples/Makefile \
tests/Makefile \
@@ -990,6 +966,7 @@ LIBVIRT_RESULT_LIBXL
LIBVIRT_RESULT_LIBXML
LIBVIRT_RESULT_MACVTAP
LIBVIRT_RESULT_NETCF
+LIBVIRT_RESULT_NLS
LIBVIRT_RESULT_NSS
LIBVIRT_RESULT_NUMACTL
LIBVIRT_RESULT_OPENWSMAN
diff --git a/m4/virt-nls.m4 b/m4/virt-nls.m4
new file mode 100644
index 0000000000..f9fb27ceb5
--- /dev/null
+++ b/m4/virt-nls.m4
@@ -0,0 +1,71 @@
+dnl gettext utilities
+dnl
+dnl Copyright (C) 2018 Red Hat, Inc.
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library. If not, see
+dnl .
+dnl
+
+AC_DEFUN([LIBVIRT_ARG_NLS],[
+ LIBVIRT_ARG_ENABLE([NLS], [NLS], [check])
+])
+
+AC_DEFUN([LIBVIRT_CHECK_NLS],[
+ if test "x$enable_nls" != "xno"
+ then
+ AC_CHECK_FUNC([gettext], [], [
+ AC_CHECK_LIB([intl], [gettext], [], [
+ if test "x$enable_nls" == "xcheck"
+ then
+ enable_nls=no
+ else
+ AC_MSG_ERROR([gettext() is required to build libvirt]")
+ fi
+ ])
+ ])
+ fi
+
+ if test "x$enable_nls" != "xno"
+ then
+ AC_CHECK_HEADERS([libintl.h], [enable_nls=yes],[
+ if test "x$enable_nls" == "xcheck"
+ then
+ enable_nls=no
+ else
+ AC_MSG_ERROR([libintl.h is required to build libvirt]")
+ fi
+ ])
+ fi
+
+ dnl GNU gettext tools (optional).
+ AC_CHECK_PROG([XGETTEXT], [xgettext], [xgettext], [no])
+ AC_CHECK_PROG([MSGFMT], [msgfmt], [msgfmt], [no])
+ AC_CHECK_PROG([MSGMERGE], [msgmerge], [msgmerge], [no])
+
+ dnl Check they are the GNU gettext tools.
+ AC_MSG_CHECKING([msgfmt is GNU tool])
+ if $MSGFMT --version >/dev/null 2>&1 && $MSGFMT --version | grep -q 'GNU gettext'; then
+ msgfmt_is_gnu=yes
+ else
+ msgfmt_is_gnu=no
+ fi
+ AC_MSG_RESULT([$msgfmt_is_gnu])
+ AM_CONDITIONAL([HAVE_GNU_GETTEXT_TOOLS],
+ [test "x$XGETTEXT" != "xno" && test "x$MSGFMT" != "xno" && \
+ test "x$MSGMERGE" != "xno" && test "x$msgfmt_is_gnu" != "xno"])
+])
+
+AC_DEFUN([LIBVIRT_RESULT_NLS],[
+ LIBVIRT_RESULT([NLS], [$enable_nls])
+])
diff --git a/po/Makefile.am b/po/Makefile.am
new file mode 100644
index 0000000000..95e5ab72bf
--- /dev/null
+++ b/po/Makefile.am
@@ -0,0 +1,97 @@
+DOMAIN = $(PACKAGE_NAME)
+COPYRIGHT_HOLDER = The Libvirt authors
+MSGID_BUGS_ADDRESS = https://libvirt.org/bugs.html
+
+LANGS := \
+ af am anp ar as ast bal be bg bn_IN \
+ bn bo br brx bs ca cs cy da de_CH \
+ de el en_GB eo es et eu fa fi \
+ fr gl gu he hi hr hu ia \
+ id ilo is it ja ka kk km kn ko \
+ kw_GB kw@kkcor kw kw@uccor ky lt lv mai mk ml \
+ mn mr ms nb nds ne nl nn nso \
+ or pa pl pt_BR pt ro ru si sk sl \
+ sq sr@latin sr sv ta te tg th tr tw \
+ uk ur vi wba yo zh_CN zh_HK zh_TW zu
+
+
+POTFILE_DEPS := $(shell $(SED) 's,^,$(top_srcdir)/,' $(srcdir)/POTFILES)
+POTFILE := $(DOMAIN).pot
+POFILES := $(LANGS:%=%.po)
+GMOFILES := $(LANGS:%=%.gmo)
+
+EXTRA_DIST = \
+ POTFILES \
+ $(POTFILE) \
+ $(POFILES) \
+ $(GMOFILES)
+
+if HAVE_GNU_GETTEXT_TOOLS
+
+XGETTEXT_ARGS = \
+ --default-domain=$(DOMAIN) \
+ --from-code=utf-8 \
+ --add-comments=TRANSLATORS: \
+ --keyword=_ --keyword=N_ \
+ --copyright-holder='$(COPYRIGHT_HOLDER)' \
+ --package-name="$(PACKAGE_NAME)" \
+ --package-version="$(PACKAGE_VERSION)" \
+ --msgid-bugs-address="$(MSGID_BUGS_ADDRESS)" \
+ --directory=$(top_srcdir) \
+ $(NULL)
+
+SED_PO_FIXUP_ARGS = \
+ -e "s|text/plain; charset=CHARSET|text/plain; charset=UTF-8|g" \
+ -e "s|SOME DESCRIPTIVE TITLE|Libvirt package strings|g" \
+ -e "s|Copyright (C) YEAR|Copyright (C) $$(date +'%Y')|" \
+ $(NULL)
+
+
+# Although they're in EXTRA_DIST, we still need to
+# copy these again, because update-gmo will change
+# their content, and dist-hook runs after the
+# things in EXTRA_DIST are copied.
+dist-hook: $(GMOFILES)
+ cp -f $(POTFILE:%=$(srcdir)/%) $(distdir)/
+ cp -f $(POFILES:%=$(srcdir)/%) $(distdir)/
+ cp -f $(GMOFILES:%=$(srcdir)/%) $(distdir)/
+
+update-po: $(POFILES)
+
+update-gmo: $(GMOFILES)
+
+$(POTFILE): POTFILES $(POTFILE_DEPS)
+ $(XGETTEXT) -o $(srcdir)/$@-t $(XGETTEXT_ARGS) \
+ --files-from=$(abs_srcdir)/POTFILES
+ $(SED) $(SED_PO_FIXUP_ARGS) < $@-t > $@
+ rm -f $@-t
+
+%.po: $(POTFILE)
+ cd $(srcdir) && \
+ $(MSGMERGE) --backup=off --no-fuzzy-matching --update $@ $(POTFILE)
+
+%.gmo: %.po
+ rm -f $(srcdir)/$@ $@-t
+ $(MSGFMT) -c -o $@-t $(srcdir)/$<
+ mv $@-t $(srcdir)/$@
+
+.PRECIOUS: $(POTFILE) $(POFILES)
+
+endif HAVE_GNU_GETTEXT_TOOLS
+
+# Cannot use 'localedir' since this conflicts with autoconf.
+langinstdir = $(datadir)/locale
+
+install-data-hook: $(GMOFILES)
+ mkdir -p $(DESTDIR)$(langinstdir)
+ for lang in $(LANGS); do \
+ d=$(DESTDIR)$(langinstdir)/$$lang/LC_MESSAGES; \
+ mkdir -p $$d; \
+ install -m 0644 $(srcdir)/$$lang.gmo $$d/$(DOMAIN).mo; \
+ done
+
+uninstall-hook:
+ for lang in $(LANGS); do \
+ d=$(DESTDIR)$(langinstdir)/$$lang/LC_MESSAGES; \
+ rm -f $$d/$(DOMAIN).mo; \
+ done
diff --git a/po/POTFILES.in b/po/POTFILES
similarity index 100%
rename from po/POTFILES.in
rename to po/POTFILES
diff --git a/po/README.md b/po/README.md
new file mode 100644
index 0000000000..ba3d07ccdb
--- /dev/null
+++ b/po/README.md
@@ -0,0 +1,36 @@
+Libvirt Message Translation
+===========================
+
+Libvirt translatable messages are maintained using the GNU Gettext tools and
+file formats, in combination with the Zanata web service.
+
+Source repository
+=================
+
+The libvirt GIT repository stores the master "libvirt.pot" file and full "po"
+files for translations. The master "libvirt.pot" file can be re-generated using
+
+ make libvirt.pot
+
+The full po files can have their source locations and msgids updated using
+
+ make update-po
+
+Normally these updates are only done when either refreshing translations from
+Zanata, or when creating a new release.
+
+Zanata web service
+==================
+
+The translation of libvirt messages has been outsourced to the Fedora
+translation team using the Zanata web service:
+
+ https://fedora.zanata.org/project/view/libvirt
+
+As such, changes to translations will generally NOT be accepted as patches
+directly to libvirt GIT. Any changes made to "$LANG.mini.po" files in libvirt
+GIT will be overwritten and lost the next time content is imported from Zanata.
+
+The master "libvirt.pot" file is periodically pushed to Zanata to provide the
+translation team with content changes. New translated text is then periodically
+pulled down from Zanata to update the po files.
diff --git a/src/internal.h b/src/internal.h
index 1760e3b69c..47ff0479d2 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -26,6 +26,7 @@
# include
# include
# include
+# include
# if STATIC_ANALYSIS
# undef NDEBUG /* Don't let a prior NDEBUG definition cause trouble. */
@@ -45,14 +46,13 @@
/* The library itself needs to know enum sizes. */
# define VIR_ENUM_SENTINELS
-/* All uses of _() within the library should pick up translations from
- * libvirt's message files, rather than from the package that is
- * linking in the library. Setting this macro before including
- * "gettext.h" means that gettext() (and _()) will properly expand to
- * dgettext. */
-# define DEFAULT_TEXT_DOMAIN PACKAGE
-# include "gettext.h"
-# define _(str) gettext(str)
+# ifdef HAVE_LIBINTL_H
+# define DEFAULT_TEXT_DOMAIN PACKAGE
+# include
+# define _(str) dgettext(PACKAGE, str)
+# else /* HAVE_LIBINTL_H */
+# define _(str) str
+# endif /* HAVE_LIBINTL_H */
# define N_(str) str
# include "libvirt/libvirt.h"
diff --git a/src/libvirt-admin.c b/src/libvirt-admin.c
index a1a0d567a6..4d3f241592 100644
--- a/src/libvirt-admin.c
+++ b/src/libvirt-admin.c
@@ -64,8 +64,10 @@ virAdmGlobalInit(void)
virLogSetFromEnv();
+#ifdef HAVE_LIBINTL_H
if (!bindtextdomain(PACKAGE, LOCALEDIR))
goto error;
+#endif /* HAVE_LIBINTL_H */
if (!VIR_CLASS_NEW(remoteAdminPriv, virClassForObjectLockable()))
goto error;
diff --git a/src/libvirt.c b/src/libvirt.c
index 0b6bd6666e..0a81cbfb99 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -363,8 +363,10 @@ virGlobalInit(void)
goto error;
#endif
+#ifdef HAVE_LIBINTL_H
if (!bindtextdomain(PACKAGE, LOCALEDIR))
goto error;
+#endif /* HAVE_LIBINTL_H */
/*
* Note we must avoid everything except 'remote' driver
diff --git a/src/util/virgettext.c b/src/util/virgettext.c
index c0135b4ea4..f583eaf8c4 100644
--- a/src/util/virgettext.c
+++ b/src/util/virgettext.c
@@ -37,6 +37,7 @@
int
virGettextInitialize(void)
{
+#if HAVE_LIBINTL_H
if (!setlocale(LC_ALL, "")) {
perror("setlocale");
/* failure to setup locale is not fatal */
@@ -51,6 +52,6 @@ virGettextInitialize(void)
perror("textdomain");
return -1;
}
-
+#endif /* HAVE_LIBINTL_H */
return 0;
}
diff --git a/tools/virt-host-validate.c b/tools/virt-host-validate.c
index 29d2482b6c..1470bf1c7d 100644
--- a/tools/virt-host-validate.c
+++ b/tools/virt-host-validate.c
@@ -23,7 +23,9 @@
#include
#include
-#include
+#ifdef HAVE_LIBINTL_H
+# include
+#endif /* HAVE_LIBINTL_H */
#include
#include "internal.h"