summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xautogen.sh214
-rw-r--r--install/Makefile.am1
-rw-r--r--install/configure.ac30
-rw-r--r--install/po/LINGUAS0
-rw-r--r--install/po/Makefile.in217
-rw-r--r--install/po/README123
-rw-r--r--install/po/ipa.pot605
-rw-r--r--ipa.spec.in6
8 files changed, 991 insertions, 205 deletions
diff --git a/autogen.sh b/autogen.sh
index 2956e51cd..99b4805d0 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,208 +1,14 @@
#!/bin/sh
-# Run this to generate all the initial makefiles, etc.
-set -e
-PACKAGE=freeipa
-
-LIBTOOLIZE=${LIBTOOLIZE-libtoolize}
-LIBTOOLIZE_FLAGS="--copy --force"
-AUTOHEADER=${AUTOHEADER-autoheader}
-AUTOMAKE_FLAGS="--add-missing --gnu"
-AUTOCONF=${AUTOCONF-autoconf}
-
-# automake 1.8 requires autoconf 2.58
-# automake 1.7 requires autoconf 2.54
-automake_min_vers=1.7
-aclocal_min_vers=$automake_min_vers
-autoconf_min_vers=2.54
-libtoolize_min_vers=1.4
-
-# The awk-based string->number conversion we use needs a C locale to work
-# as expected. Setting LC_ALL overrides whether the user set LC_ALL,
-# LC_NUMERIC, or LANG.
-LC_ALL=C
-
-ARGV0=$0
-
-# Allow invocation from a separate build directory; in that case, we change
-# to the source directory to run the auto*, then change back before running configure
-#srcdir=`dirname $ARGV0`
-#test -z "$srcdir" && srcdir=.
-srcdir="."
-
-#ORIGDIR=`pwd`
-
-#cd $srcdir
-
-# Usage:
-# compare_versions MIN_VERSION ACTUAL_VERSION
-# returns true if ACTUAL_VERSION >= MIN_VERSION
-compare_versions() {
- ch_min_version=$1
- ch_actual_version=$2
- ch_status=0
- IFS="${IFS= }"; ch_save_IFS="$IFS"; IFS="."
- set $ch_actual_version
- for ch_min in $ch_min_version; do
- ch_cur=`echo $1 | sed 's/[^0-9].*$//'`; shift # remove letter suffixes
- if [ -z "$ch_min" ]; then break; fi
- if [ -z "$ch_cur" ]; then ch_status=1; break; fi
- if [ $ch_cur -gt $ch_min ]; then break; fi
- if [ $ch_cur -lt $ch_min ]; then ch_status=1; break; fi
- done
- IFS="$ch_save_IFS"
- return $ch_status
-}
-
-if ($AUTOCONF --version) < /dev/null > /dev/null 2>&1 ; then
- if ($AUTOCONF --version | head -n 1 | awk 'NR==1 { if( $(NF) >= '$autoconf_min_vers') \
- exit 1; exit 0; }');
- then
- echo "$ARGV0: ERROR: \`$AUTOCONF' is too old."
- $AUTOCONF --version
- echo " (version $autoconf_min_vers or newer is required)"
- DIE="yes"
- fi
-else
- echo $AUTOCONF: command not found
- echo
- echo "$ARGV0: ERROR: You must have \`autoconf' installed to compile $PACKAGE."
- echo " (version $autoconf_min_vers or newer is required)"
- DIE="yes"
-fi
-
-#
-# Hunt for an appropriate version of automake and aclocal; we can't
-# assume that 'automake' is necessarily the most recent installed version
-#
-# We check automake first to allow it to be a newer version than we know about.
-#
-if test x"$AUTOMAKE" = x || test x"$ACLOCAL" = x ; then
- am_ver=""
- for ver in "" "-1.9" "-1.8" "-1.7" ; do
- am="automake$ver"
- if ($am --version) < /dev/null > /dev/null 2>&1 ; then
- if ($am --version | head -n 1 | awk 'NR==1 { if( $(NF) >= '$automake_min_vers') \
- exit 1; exit 0; }'); then : ; else
- am_ver=$ver
- break;
- fi
- fi
- done
-
- AUTOMAKE=${AUTOMAKE-automake$am_ver}
- ACLOCAL=${ACLOCAL-aclocal$am_ver}
-fi
-
-#
-# Now repeat the tests with the copies we decided upon and error out if they
-# aren't sufficiently new.
-#
-if ($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 ; then
- automake_actual_version=`$AUTOMAKE --version | head -n 1 | \
- sed 's/^.*[ ]\([0-9.]*[a-z]*\).*$/\1/'`
- if ! compare_versions $automake_min_vers $automake_actual_version; then
- echo "$ARGV0: ERROR: \`$AUTOMAKE' is too old."
- $AUTOMAKE --version
- echo " (version $automake_min_vers or newer is required)"
- DIE="yes"
- fi
- if ($ACLOCAL --version) < /dev/null > /dev/null 2>&1; then
- aclocal_actual_version=`$ACLOCAL --version | head -n 1 | \
- sed 's/^.*[ ]\([0-9.]*[a-z]*\).*$/\1/'`
-
- if ! compare_versions $aclocal_min_vers $aclocal_actual_version; then
- echo "$ARGV0: ERROR: \`$ACLOCAL' is too old."
- $ACLOCAL --version
- echo " (version $aclocal_min_vers or newer is required)"
- DIE="yes"
- fi
- else
- echo $ACLOCAL: command not found
- echo
- echo "$ARGV0: ERROR: Missing \`$ACLOCAL'"
- echo " The version of $AUTOMAKE installed doesn't appear recent enough."
- DIE="yes"
- fi
-else
- echo $AUTOMAKE: command not found
- echo
- echo "$ARGV0: ERROR: You must have \`automake' installed to compile $PACKAGE."
- echo " (version $automake_min_vers or newer is required)"
- DIE="yes"
-fi
-
-if ($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 ; then
- if ($LIBTOOLIZE --version | awk 'NR==1 { if( $4 >= '$libtoolize_min_vers') \
- exit 1; exit 0; }');
- then
- echo "$ARGV0: ERROR: \`$LIBTOOLIZE' is too old."
- echo " (version $libtoolize_min_vers or newer is required)"
- DIE="yes"
+# automake demands these files exist when run in gnu mode which is the default,
+# automake can be run in foreign mode to avoid failing on the absence of these
+# files, but unfortunately there is no way to pass the --foreign flag to
+# automake when run from autoreconf.
+for f in NEWS README AUTHORS ChangeLog; do
+ if [ ! -e $f ]; then
+ touch $f
fi
-else
- echo $LIBTOOLIZE: command not found
- echo
- echo "$ARGV0: ERROR: You must have \`libtoolize' installed to compile $PACKAGE."
- echo " (version $libtoolize_min_vers or newer is required)"
- DIE="yes"
-fi
-
-if test -z "$ACLOCAL_FLAGS"; then
- acdir=`$ACLOCAL --print-ac-dir`
- if [ ! -f $acdir/pkg.m4 ]; then
- echo "$ARGV0: Error: Could not find pkg-config macros."
- echo " (Looked in $acdir/pkg.m4)"
- echo " If pkg.m4 is available in /another/directory, please set"
- echo " ACLOCAL_FLAGS=\"-I /another/directory\""
- echo " Otherwise, please install pkg-config."
- echo ""
- echo "pkg-config is available from:"
- echo "http://www.freedesktop.org/software/pkgconfig/"
- DIE=yes
- fi
-fi
-
-if test "X$DIE" != X; then
- exit 1
-fi
-
-
-if test -z "$*"; then
- echo "$ARGV0: Note: \`./configure' will be run with no arguments."
- echo " If you wish to pass any to it, please specify them on the"
- echo " \`$0' command line."
- echo
-fi
-
-do_cmd() {
- echo "$ARGV0: running \`$@'"
- $@
-}
-
-# I don't want a tool telling me what files I need to have
-remauto=0
-if [ ! -e AUTHORS ]; then
- touch AUTHORS ChangeLog NEWS README
- remauto=1
-fi
-
-do_cmd $LIBTOOLIZE $LIBTOOLIZE_FLAGS
-
-do_cmd $ACLOCAL $ACLOCAL_FLAGS
-
-do_cmd $AUTOHEADER
-
-do_cmd $AUTOMAKE $AUTOMAKE_FLAGS
-
-do_cmd $AUTOCONF
-
-if [ $remauto -eq 1 ]; then
- rm -f AUTHORS ChangeLog NEWS README
-fi
-
-#cd $ORIGDIR || exit 1
-
-rm -f config.cache
+done
-do_cmd $srcdir/configure --cache-file=config.cache --disable-static --enable-maintainer-mode --enable-gtk-doc ${1+"$@"} && echo "Now type \`make' to compile" || exit 1
+autoreconf -i
+./configure ${1+"$@"}
diff --git a/install/Makefile.am b/install/Makefile.am
index 68a3c2655..bc1dff147 100644
--- a/install/Makefile.am
+++ b/install/Makefile.am
@@ -11,6 +11,7 @@ SUBDIRS = \
share \
tools \
updates \
+ po \
$(NULL)
install-exec-local:
diff --git a/install/configure.ac b/install/configure.ac
index 826eeb047..83579ac66 100644
--- a/install/configure.ac
+++ b/install/configure.ac
@@ -19,6 +19,35 @@ AM_MAINTAINER_MODE
AC_SUBST(VERSION)
+AC_PROG_MKDIR_P
+
+AC_PATH_PROG(XGETTEXT, xgettext, [no])
+if test "x$XGETTEXT" = "xno"; then
+ AC_MSG_ERROR([xgettext not found, install gettext])
+fi
+
+AC_PATH_PROG(MSGFMT, msgfmt, [no])
+if test "x$MSGFMT" = "xno"; then
+ AC_MSG_ERROR([msgfmt not found, install gettext])
+fi
+
+AC_PATH_PROG(MSGINIT, msginit, [no])
+if test "x$MSGINIT" = "xno"; then
+ AC_MSG_ERROR([msginit not found, install gettext])
+fi
+
+AC_PATH_PROG(MSGMERGE, msgmerge, [no])
+if test "x$MSGMERGE" = "xno"; then
+ AC_MSG_ERROR([msgmerge not found, install gettext])
+fi
+
+AC_ARG_WITH([gettext_domain],
+ [AS_HELP_STRING([--with-gettext-domain=name],
+ [set the name of the i18n message catalog])],
+ [],
+ [with_gettext_domain=ipa])
+AC_SUBST(GETTEXT_DOMAIN, $with_gettext_domain)
+
dnl ---------------------------------------------------------------------------
dnl - Set the data install directory since we don't use pkgdatadir
dnl ---------------------------------------------------------------------------
@@ -39,6 +68,7 @@ AC_CONFIG_FILES([
tools/Makefile
tools/man/Makefile
updates/Makefile
+ po/Makefile
])
AC_OUTPUT
diff --git a/install/po/LINGUAS b/install/po/LINGUAS
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/install/po/LINGUAS
diff --git a/install/po/Makefile.in b/install/po/Makefile.in
new file mode 100644
index 000000000..7a8631aff
--- /dev/null
+++ b/install/po/Makefile.in
@@ -0,0 +1,217 @@
+prefix = @prefix@
+exec_prefix = ${prefix}
+datarootdir = ${prefix}/share
+datadir = ${datarootdir}
+localedir = ${datarootdir}/locale
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL@ -m 644
+MKDIR_P = @MKDIR_P@
+XGETTEXT = @XGETTEXT@
+MSGFMT = @MSGFMT@
+MSGINIT = @MSGINIT@
+MSGMERGE = @MSGMERGE@
+
+DOMAIN = @GETTEXT_DOMAIN@
+MSGMERGE_UPDATE = $(MSGMERGE) --update
+
+COPYRIGHT_HOLDER = Red Hat
+PACKAGE_NAME = $(DOMAIN)
+PACKAGE_BUGREPORT = https://hosted.fedoraproject.org/projects/freeipa/newticket
+XGETTEXT_OPTIONS = \
+--add-comments="TRANSLATORS:" \
+--copyright-holder="$(COPYRIGHT_HOLDER)" \
+--package-name="$(PACKAGE_NAME)" \
+--msgid-bugs-address="$(PACKAGE_BUGREPORT)"
+
+languages = $(shell sed 's/\#.*//' LINGUAS)
+po_files = $(patsubst %, %.po, $(languages))
+mo_files = $(patsubst %.po, %.mo, $(po_files))
+
+PYTHON_POTFILES = \
+ ../../ipa \
+ ../../lite-server.py \
+ ../../ipapython/config.py \
+ ../../ipapython/sysrestore.py \
+ ../../ipapython/ipasslfile.py \
+ ../../ipapython/__init__.py \
+ ../../ipapython/ipautil.py \
+ ../../ipapython/certdb.py \
+ ../../ipapython/ipavalidate.py \
+ ../../ipapython/dnsclient.py \
+ ../../ipapython/dogtag.py \
+ ../../ipapython/nsslib.py \
+ ../../ipapython/entity.py \
+ ../../install/tools/ipa-replica-manage \
+ ../../install/tools/ipa-server-certinstall \
+ ../../install/tools/ipa-replica-install \
+ ../../install/tools/ipa-nis-manage \
+ ../../install/tools/ipa-upgradeconfig \
+ ../../install/tools/ipa-replica-prepare \
+ ../../install/tools/ipa-compat-manage \
+ ../../install/tools/ipa-server-install \
+ ../../install/tools/ipa-ldap-updater \
+ ../../install/migration/migration.py \
+ ../../ipalib/config.py \
+ ../../ipalib/parameters.py \
+ ../../ipalib/request.py \
+ ../../ipalib/output.py \
+ ../../ipalib/__init__.py \
+ ../../ipalib/backend.py \
+ ../../ipalib/pkcs10.py \
+ ../../ipalib/x509.py \
+ ../../ipalib/plugable.py \
+ ../../ipalib/constants.py \
+ ../../ipalib/aci.py \
+ ../../ipalib/base.py \
+ ../../ipalib/ipauuid.py \
+ ../../ipalib/crud.py \
+ ../../ipalib/cli.py \
+ ../../ipalib/text.py \
+ ../../ipalib/compat.py \
+ ../../ipalib/frontend.py \
+ ../../ipalib/rpc.py \
+ ../../ipalib/errors.py \
+ ../../ipalib/encoder.py \
+ ../../ipalib/util.py \
+ ../../ipalib/plugins/config.py \
+ ../../ipalib/plugins/rolegroup.py \
+ ../../ipalib/plugins/host.py \
+ ../../ipalib/plugins/group.py \
+ ../../ipalib/plugins/migration.py \
+ ../../ipalib/plugins/xmlclient.py \
+ ../../ipalib/plugins/service.py \
+ ../../ipalib/plugins/passwd.py \
+ ../../ipalib/plugins/__init__.py \
+ ../../ipalib/plugins/virtual.py \
+ ../../ipalib/plugins/hbac.py \
+ ../../ipalib/plugins/cert.py \
+ ../../ipalib/plugins/baseldap.py \
+ ../../ipalib/plugins/aci.py \
+ ../../ipalib/plugins/kerberos.py \
+ ../../ipalib/plugins/krbtpolicy.py \
+ ../../ipalib/plugins/dns.py \
+ ../../ipalib/plugins/automount.py \
+ ../../ipalib/plugins/netgroup.py \
+ ../../ipalib/plugins/misc.py \
+ ../../ipalib/plugins/user.py \
+ ../../ipalib/plugins/taskgroup.py \
+ ../../ipalib/plugins/hostgroup.py \
+ ../../ipalib/plugins/pwpolicy.py \
+ ../../ipaserver/__init__.py \
+ ../../ipaserver/servercore.py \
+ ../../ipaserver/ipautil.py \
+ ../../ipaserver/rpcserver.py \
+ ../../ipaserver/conn.py \
+ ../../ipaserver/ipaldap.py \
+ ../../ipaserver/install/installutils.py \
+ ../../ipaserver/install/service.py \
+ ../../ipaserver/install/ldapupdate.py \
+ ../../ipaserver/install/__init__.py \
+ ../../ipaserver/install/cainstance.py \
+ ../../ipaserver/install/ntpinstance.py \
+ ../../ipaserver/install/bindinstance.py \
+ ../../ipaserver/install/krbinstance.py \
+ ../../ipaserver/install/certs.py \
+ ../../ipaserver/install/dsinstance.py \
+ ../../ipaserver/install/replication.py \
+ ../../ipaserver/install/httpinstance.py \
+ ../../ipaserver/plugins/ldap2.py \
+ ../../ipaserver/plugins/rabase.py \
+ ../../ipaserver/plugins/selfsign.py \
+ ../../ipaserver/plugins/__init__.py \
+ ../../ipaserver/plugins/join.py \
+ ../../ipaserver/plugins/ldapapi.py \
+ ../../ipaserver/plugins/xmlserver.py \
+ ../../ipaserver/plugins/dogtag.py \
+ ../../contrib/RHEL4/ipachangeconf.py \
+ ../../ipawebui/engine.py \
+ ../../ipawebui/__init__.py \
+ ../../ipawebui/widgets.py \
+ ../../ipawebui/controllers.py \
+ ../../ipa-client/ipaclient/ntpconf.py \
+ ../../ipa-client/ipaclient/__init__.py \
+ ../../ipa-client/ipaclient/ipachangeconf.py \
+ ../../ipa-client/ipaclient/ipadiscovery.py \
+ ../../ipa-client/ipa-install/ipa-client-install
+
+C_POTFILES = \
+ ../../daemons/ipa-kpasswd/ipa_kpasswd.c \
+ ../../daemons/ipa-slapi-plugins/ipa-enrollment/ipa_enrollment.c \
+ ../../daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof.c \
+ ../../daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof.h \
+ ../../daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof_config.c \
+ ../../daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c \
+ ../../daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-config.c \
+ ../../daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync.c \
+ ../../daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync.h \
+ ../../ipa-client/config.c \
+ ../../ipa-client/ipa-getkeytab.c \
+ ../../ipa-client/ipa-join.c \
+ ../../ipa-client/ipa-rmkeytab.c
+
+POTFILES = $(PYTHON_POTFILES) $(C_POTFILES)
+
+.SUFFIXES:
+.SUFFIXES: .po .mo
+
+all: $(po_files)
+ @
+
+SUFFIXES = .po .mo
+
+.po.mo:
+ @echo Creating $@; \
+ $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@
+
+$(po_files): $(DOMAIN).pot
+ @if [ ! -f @a ]; then \
+ echo Creating nonexistent $@, you should add this file to your SCM repository; \
+ $(MSGINIT) --locale en_US --no-translator -i $(DOMAIN).pot -o $@; \
+ fi; \
+ $(MSGMERGE) $@ -o $@ $(DOMAIN).pot
+
+create-po: $(DOMAIN).pot
+ @for po_file in $(po_files); do \
+ if [ ! -e $$po_file ]; then \
+ echo Creating nonexistent $$po_file, you should add this file to your SCM repository; \
+ $(MSGINIT) --locale en_US --no-translator -i $(DOMAIN).pot -o $$po_file; \
+ fi; \
+ done
+
+$(DOMAIN).pot: $(POTFILES)
+ $(MAKE) update-pot
+
+update-po: update-pot
+ $(MAKE) all
+
+update-pot:
+ rm -f $(DOMAIN).pot.update
+ $(XGETTEXT) $(XGETTEXT_OPTIONS) \
+ --output $(DOMAIN).pot.update \
+ --language="python" \
+ $(PYTHON_POTFILES) \
+ && \
+ $(XGETTEXT) $(XGETTEXT_OPTIONS) \
+ --output $(DOMAIN).pot.update \
+ --join-existing \
+ --language="c" \
+ $(C_POTFILES) \
+ && \
+ mv $(DOMAIN).pot.update $(DOMAIN).pot
+
+install: $(mo_files)
+ @for lang in $(languages); do \
+ dstdir=$(DESTDIR)$(localedir)/$$lang/LC_MESSAGES; \
+ $(MKDIR_P) $$dstdir; \
+ $(INSTALL) $$lang.mo $$dstdir/$(DOMAIN).mo; \
+ done
+
+mostlyclean:
+ rm -f *.mo
+
+clean: mostlyclean
+
+distclean: clean
+ rm -f Makefile
+
diff --git a/install/po/README b/install/po/README
new file mode 100644
index 000000000..e032e3529
--- /dev/null
+++ b/install/po/README
@@ -0,0 +1,123 @@
+Q: I've added a new source file, how do I make sure it's strings get translated?
+
+A: Edit Makefile.in and add the source file to the appropriate *_POTFILES list.
+ Then run "make update-po".
+
+Q: How do I pick up new strings to translate from the source files after the
+ source have been modified?
+
+A: make update-po
+ This regenerates the pot template file by scanning all the source files.
+ Then the new strings are merged into each .po file from the new pot file.
+
+Q: How do I just regenerate the pot template file without regenerating all the
+ .po files?
+
+A: make update-pot
+
+Q: How do I add a new language for translation?
+
+A: Edit the LINGUAS file and add the new language. Then run "make create-po".
+ This will generate a new .po file for each language which doesn't have one
+ yet. Be sure to add the new .po file(s) to the source code repository.
+
+Q: What files must be under source code control?
+
+A: The files Makefile.in, LINGUAS control the build, they must be in the SCM.
+ The *.pot and *.po files are used by translators, they must be in SCM so the
+ translator can checkout out a .po files, add the translations, and then check
+ the .po file back in.
+
+ Be careful, .po files may be automatically updated when the source files
+ change (or the .pot changes, usually the .pot file changes only as a result
+ of rescanning the source files). This mean a .po file might be automatically
+ updated while a translator has the file out for editing, all the caveats
+ about SCM merging apply.
+
+Q: Which are automatically generated and thus do not need to be in SCM?
+
+A: The *.mo files are automatically generated on demand from their corresponding
+ .po file.
+
+Q: What role does the .pot file play?
+
+A: The .pot file is called a template file. It is generated by scanning all the
+ source files (e.g. *.py *.c *.h) in the project using xgettext. xgettext
+ locates every translatable string (e.g. strings marked with _()) and adds
+ that string along with metadata about it's location to the .pot file. Thus
+ the .pot file is a collection of every translatable string in the project. If
+ you edit a source file and add a translatable string you will have to
+ regenerate the .pot file in order to pick up the new string.
+
+Q: What is the relationship between a .po file and the .pot file?
+
+A: A .po file contains the translations for particular language. It derives from
+ the .pot file. When the .pot file is updated with new strings to translate
+ each .po will merge the new strings in. The .po file is where translators
+ work providing translations for their language. Thus it's important the .po
+ not be recreated from scratch and is kept in SCM, otherwise the translators
+ work will be lost.
+
+ Let's use an example for French, it's .po file will be fr.po.
+
+ 1) Developer creates main.c with one translatable sting _("Begin").
+
+ 2) Produce the .pot file by running xgettext on main.c
+
+ 3) .pot file contains one msgid, "Begin"
+
+ 4) fr.po is created from the .pot file, it also contains one msgid, "Begin"
+
+ 5) Translator edits fr.po and provide the French translation of "Begin".
+
+ 6) Developer adds new translatable sting _("End") to main.c
+
+ 7) Generate a new .pot file by running xgettext on main.c
+
+ 8) .pot file contains two msgid's, "Begin", and "End"
+
+ 9) fr.po is missing the new msgid in the .pot file, so the .pot is merged
+ into fr.po by running msgmerge. This copies into fr.po the new "End" msgid
+ but preserves the existing translations in fr.po (e.g. "Begin"). The fr.po
+ will now have 2 msgid's one which is translated already (e.g. "Begin") and
+ one that untranslated (e.g. "End").
+
+ 10) Sometime later the French translator comes back to see if he/she needs to
+ add more translations to fr.po. They see there is a missing translation,
+ they check fr.po out from SCM, add the missing translation, and then
+ check fr.po back into SCM.
+
+ This means at any given moment the set of .po files will have varying degrees
+ of translation completeness. Because the .po files are merged when the source
+ code files are updated existing translations are not lost. It also means a
+ .po file which was fully translated may need new translations after a .pot
+ update. It is permissible to have incomplete translations in a message
+ catalog, at run time if a translation for a particular string is available in
+ the message catalog the user will be presented with the string in their
+ language. However if the string is not yet translated in the .po file then
+ they just get the original string (typically in English).
+
+Q: What are .mo files?
+
+A: .mo files are the content of a .po file but in "machine" format for fast
+ run time access (mo = Machine Object, po = Portable Object). .mo files are
+ what gets installed along with the package. Think of a .po as a source file
+ which is compiled into a object file for run time use.
+
+Q: Why don't we use gettexize and autopoint?
+
+A: Because the framework they produce is too limited. Specifically there is no
+ way to pass the source language to xgettext when it scans a file. xgettext
+ only knows how to automatically determine the language from the source files
+ extension. However we have many files without extensions, thus we have to
+ group all Python (et. al.) files together and run xgettext on every file *we*
+ know to Python (because xgettext can't figure this out itself if there is no
+ file extension). There is another added benefit of avoiding gettextize and
+ autopoint, simplicity. Managing translations is complex and hard enough as it
+ is, gettextize and autopoint adds another whole layer of complexity which
+ just further obscures things.
+
+Q: Who created the awful mess and who do I ask when things don't work as I
+ expect or I have further questions?
+
+A: John Dennis <jdennis@redhat.com>
diff --git a/install/po/ipa.pot b/install/po/ipa.pot
new file mode 100644
index 000000000..5662807ba
--- /dev/null
+++ b/install/po/ipa.pot
@@ -0,0 +1,605 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Red Hat
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: ipa\n"
+"Report-Msgid-Bugs-To: https://hosted.fedoraproject.org/projects/freeipa/"
+"newticket\n"
+"POT-Creation-Date: 2010-02-09 12:59-0500\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+
+#: ../../ipalib/parameters.py:228
+msgid "incorrect type"
+msgstr ""
+
+#: ../../ipalib/parameters.py:231
+msgid "Only one value is allowed"
+msgstr ""
+
+#: ../../ipalib/parameters.py:795
+msgid "must be True or False"
+msgstr ""
+
+#: ../../ipalib/parameters.py:896
+msgid "must be an integer"
+msgstr ""
+
+#: ../../ipalib/parameters.py:947
+#, python-format
+msgid "must be at least %(minvalue)d"
+msgstr ""
+
+#: ../../ipalib/parameters.py:957
+#, python-format
+msgid "can be at most %(maxvalue)d"
+msgstr ""
+
+#: ../../ipalib/parameters.py:967
+msgid "must be a decimal number"
+msgstr ""
+
+#: ../../ipalib/parameters.py:989
+#, python-format
+msgid "must be at least %(minvalue)f"
+msgstr ""
+
+#: ../../ipalib/parameters.py:999
+#, python-format
+msgid "can be at most %(maxvalue)f"
+msgstr ""
+
+#: ../../ipalib/parameters.py:1059
+#, python-format
+msgid "must match pattern \"%(pattern)s\""
+msgstr ""
+
+#: ../../ipalib/parameters.py:1077
+msgid "must be binary data"
+msgstr ""
+
+#: ../../ipalib/parameters.py:1092
+#, python-format
+msgid "must be at least %(minlength)d bytes"
+msgstr ""
+
+#: ../../ipalib/parameters.py:1102
+#, python-format
+msgid "can be at most %(maxlength)d bytes"
+msgstr ""
+
+#: ../../ipalib/parameters.py:1112
+#, python-format
+msgid "must be exactly %(length)d bytes"
+msgstr ""
+
+#: ../../ipalib/parameters.py:1130
+msgid "must be Unicode text"
+msgstr ""
+
+#: ../../ipalib/parameters.py:1160
+#, python-format
+msgid "must be at least %(minlength)d characters"
+msgstr ""
+
+#: ../../ipalib/parameters.py:1170
+#, python-format
+msgid "can be at most %(maxlength)d characters"
+msgstr ""
+
+#: ../../ipalib/parameters.py:1180
+#, python-format
+msgid "must be exactly %(length)d characters"
+msgstr ""
+
+#: ../../ipalib/parameters.py:1219
+#, python-format
+msgid "must be one of %(values)r"
+msgstr ""
+
+#: ../../ipalib/cli.py:505
+#, python-format
+msgid "Enter %(label)s again to verify: "
+msgstr ""
+
+#: ../../ipalib/cli.py:509
+msgid "Passwords do not match!"
+msgstr ""
+
+#: ../../ipalib/cli.py:514
+msgid "Cancelled."
+msgstr ""
+
+#: ../../ipalib/frontend.py:377
+msgid "Results are truncated, try a more specific search"
+msgstr ""
+
+#: ../../ipalib/errors.py:297
+#, python-format
+msgid "%(cver)s client incompatible with %(sver)s server at %(server)r"
+msgstr ""
+
+#: ../../ipalib/errors.py:315
+#, python-format
+msgid "unknown error %(code)d from %(server)s: %(error)s"
+msgstr ""
+
+#: ../../ipalib/errors.py:331
+msgid "an internal error has occurred"
+msgstr ""
+
+#: ../../ipalib/errors.py:353
+#, python-format
+msgid "an internal error has occurred on server at %(server)r"
+msgstr ""
+
+#: ../../ipalib/errors.py:369
+#, python-format
+msgid "unknown command %(name)r"
+msgstr ""
+
+#: ../../ipalib/errors.py:386 ../../ipalib/errors.py:411
+#, python-format
+msgid "error on server %(server)r: %(error)s"
+msgstr ""
+
+#: ../../ipalib/errors.py:402
+#, python-format
+msgid "cannot connect to %(uri)r: %(error)s"
+msgstr ""
+
+#: ../../ipalib/errors.py:420
+#, python-format
+msgid "Invalid JSON-RPC request: %(error)s"
+msgstr ""
+
+#: ../../ipalib/errors.py:448
+#, python-format
+msgid "Kerberos error: %(major)s/%(minor)s"
+msgstr ""
+
+#: ../../ipalib/errors.py:465
+msgid "did not receive Kerberos credentials"
+msgstr ""
+
+#: ../../ipalib/errors.py:481
+#, python-format
+msgid "Service %(service)r not found in Kerberos database"
+msgstr ""
+
+#: ../../ipalib/errors.py:497
+msgid "No credentials cache found"
+msgstr ""
+
+#: ../../ipalib/errors.py:513
+msgid "Ticket expired"
+msgstr ""
+
+#: ../../ipalib/errors.py:529
+msgid "Credentials cache permissions incorrect"
+msgstr ""
+
+#: ../../ipalib/errors.py:545
+msgid "Bad format in credentials cache"
+msgstr ""
+
+#: ../../ipalib/errors.py:561
+msgid "Cannot resolve KDC for requested realm"
+msgstr ""
+
+#: ../../ipalib/errors.py:580
+#, python-format
+msgid "Insufficient access: %(info)s"
+msgstr ""
+
+#: ../../ipalib/errors.py:624
+#, python-format
+msgid "command %(name)r takes no arguments"
+msgstr ""
+
+#: ../../ipalib/errors.py:644
+#, python-format
+msgid "command %(name)r takes at most %(count)d argument"
+msgid_plural "command %(name)r takes at most %(count)d arguments"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../../ipalib/errors.py:674
+#, python-format
+msgid "overlapping arguments and options: %(names)r"
+msgstr ""
+
+#: ../../ipalib/errors.py:690
+#, python-format
+msgid "%(name)r is required"
+msgstr ""
+
+#: ../../ipalib/errors.py:706 ../../ipalib/errors.py:722
+#, python-format
+msgid "invalid %(name)r: %(error)s"
+msgstr ""
+
+#: ../../ipalib/errors.py:738
+#, python-format
+msgid "api has no such namespace: %(name)r"
+msgstr ""
+
+#: ../../ipalib/errors.py:747
+msgid "Passwords do not match"
+msgstr ""
+
+#: ../../ipalib/errors.py:755
+msgid "Command not implemented"
+msgstr ""
+
+#: ../../ipalib/errors.py:783 ../../ipalib/errors.py:1023
+#, python-format
+msgid "%(reason)s"
+msgstr ""
+
+#: ../../ipalib/errors.py:799
+msgid "This entry already exists"
+msgstr ""
+
+#: ../../ipalib/errors.py:815
+msgid "You must enroll a host in order to create a host service"
+msgstr ""
+
+#: ../../ipalib/errors.py:831
+#, python-format
+msgid ""
+"Service principal is not of the form: service/fully-qualified host name: %"
+"(reason)s"
+msgstr ""
+
+#: ../../ipalib/errors.py:847
+msgid ""
+"The realm for the principal does not match the realm for this IPA server"
+msgstr ""
+
+#: ../../ipalib/errors.py:863
+msgid "This command requires root access"
+msgstr ""
+
+#: ../../ipalib/errors.py:879
+msgid "This is already a posix group"
+msgstr ""
+
+#: ../../ipalib/errors.py:895
+#, python-format
+msgid "Principal is not of the form user@REALM: %(principal)r"
+msgstr ""
+
+#: ../../ipalib/errors.py:911
+msgid "This entry is already unlocked"
+msgstr ""
+
+#: ../../ipalib/errors.py:927
+msgid "This entry is already locked"
+msgstr ""
+
+#: ../../ipalib/errors.py:943
+msgid "This entry has nsAccountLock set, it cannot be locked or unlocked"
+msgstr ""
+
+#: ../../ipalib/errors.py:959
+msgid "This entry is not a member of the group"
+msgstr ""
+
+#: ../../ipalib/errors.py:975
+msgid "A group may not be a member of itself"
+msgstr ""
+
+#: ../../ipalib/errors.py:991
+msgid "This entry is already a member of the group"
+msgstr ""
+
+#: ../../ipalib/errors.py:1007
+#, python-format
+msgid "Base64 decoding failed: %(reason)s"
+msgstr ""
+
+#: ../../ipalib/errors.py:1039
+msgid "A group may not be added as a member of itself"
+msgstr ""
+
+#: ../../ipalib/errors.py:1055
+msgid "The default users group cannot be removed"
+msgstr ""
+
+#: ../../ipalib/errors.py:1078
+#, python-format
+msgid "no command nor help topic %(topic)r"
+msgstr ""
+
+#: ../../ipalib/errors.py:1102
+msgid "change collided with another change"
+msgstr ""
+
+#: ../../ipalib/errors.py:1118
+msgid "no modifications to be performed"
+msgstr ""
+
+#: ../../ipalib/errors.py:1134
+#, python-format
+msgid "%(desc)s:%(info)s"
+msgstr ""
+
+#: ../../ipalib/errors.py:1150
+msgid "limits exceeded for this query"
+msgstr ""
+
+#: ../../ipalib/errors.py:1165
+#, python-format
+msgid "%(info)s"
+msgstr ""
+
+#: ../../ipalib/errors.py:1190
+#, python-format
+msgid "Certificate operation cannot be completed: %(error)s"
+msgstr ""
+
+#: ../../ipalib/plugins/rolegroup.py:73
+#, python-format
+msgid "Added rolegroup \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/rolegroup.py:83
+#, python-format
+msgid "Deleted rolegroup \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/rolegroup.py:93
+#, python-format
+msgid "Modified rolegroup \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/rolegroup.py:104
+#, python-format
+msgid "%(count)d rolegroup matched"
+msgid_plural "%(count)d rolegroups matched"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../../ipalib/plugins/host.py:149
+#, python-format
+msgid "Added host \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/host.py:178
+#, python-format
+msgid "Deleted host \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/host.py:206
+#, python-format
+msgid "Modified host \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/host.py:255
+#, python-format
+msgid "%(count)d host matched"
+msgid_plural "%(count)d hosts matched"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../../ipalib/plugins/group.py:85
+#, python-format
+msgid "Added group \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/group.py:108
+#, python-format
+msgid "Deleted group \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/group.py:134
+#, python-format
+msgid "Modified group \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/group.py:163
+#, python-format
+msgid "%(count)d group matched"
+msgid_plural "%(count)d groups matched"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../../ipalib/plugins/cert.py:63 ../../ipalib/plugins/cert.py:84
+msgid "Unable to decode certificate in entry"
+msgstr ""
+
+#: ../../ipalib/plugins/cert.py:106 ../../ipalib/plugins/cert.py:120
+#: ../../ipalib/plugins/cert.py:137
+msgid "Failure decoding Certificate Signing Request"
+msgstr ""
+
+#: ../../ipalib/plugins/cert.py:139
+#, python-format
+msgid "Failure decoding Certificate Signing Request: %s"
+msgstr ""
+
+#: ../../ipalib/plugins/aci.py:109
+msgid "type, filter, subtree and targetgroup are mutually exclusive"
+msgstr ""
+
+#: ../../ipalib/plugins/aci.py:112
+msgid ""
+"at least one of: type, filter, subtree, targetgroup, attrs or memberof are "
+"required"
+msgstr ""
+
+#: ../../ipalib/plugins/aci.py:117
+msgid "group and taskgroup are mutually exclusive"
+msgstr ""
+
+#: ../../ipalib/plugins/aci.py:119
+msgid "One of group or taskgroup is required"
+msgstr ""
+
+#: ../../ipalib/plugins/aci.py:140
+#, python-format
+msgid "Group '%s' does not exist"
+msgstr ""
+
+#: ../../ipalib/plugins/aci.py:184
+#, python-format
+msgid "ACI with name \"%s\" not found"
+msgstr ""
+
+#: ../../ipalib/plugins/aci.py:255
+#, python-format
+msgid "Created ACI \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/aci.py:305
+#, python-format
+msgid "Deleted ACI \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/aci.py:345
+#, python-format
+msgid "Modified ACI \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/aci.py:405
+#, python-format
+msgid "%(count)d ACI matched"
+msgid_plural "%(count)d ACIs matched"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../../ipalib/plugins/misc.py:37
+#, python-format
+msgid "%(count)d variables"
+msgstr ""
+
+#: ../../ipalib/plugins/misc.py:96
+#, python-format
+msgid "%(count)d plugin loaded"
+msgid_plural "%(count)d plugins loaded"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../../ipalib/plugins/user.py:139
+#, python-format
+msgid "Added user \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/user.py:184
+#, python-format
+msgid "Deleted user \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/user.py:203
+#, python-format
+msgid "Modified user \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/user.py:214
+#, python-format
+msgid "%(count)d user matched"
+msgid_plural "%(count)d users matched"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../../ipalib/plugins/user.py:234
+#, python-format
+msgid "Locked user \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/user.py:260
+#, python-format
+msgid "Unlocked user \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/taskgroup.py:73
+#, python-format
+msgid "Added taskgroup \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/taskgroup.py:83
+#, python-format
+msgid "Deleted taskgroup \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/taskgroup.py:93
+#, python-format
+msgid "Modified taskgroup \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/taskgroup.py:104
+#, python-format
+msgid "%(count)d taskgroup matched"
+msgid_plural "%(count)d taskgroups matched"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../../ipalib/plugins/hostgroup.py:72
+#, python-format
+msgid "Added hostgroup \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/hostgroup.py:82
+#, python-format
+msgid "Deleted hostgroup \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/hostgroup.py:92
+#, python-format
+msgid "Modified hostgroup \"%(value)s\""
+msgstr ""
+
+#: ../../ipalib/plugins/hostgroup.py:103
+#, python-format
+msgid "%(count)d hostgroup matched"
+msgid_plural "%(count)d hostgroups matched"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../../ipalib/plugins/pwpolicy.py:231
+msgid "priority cannot be set on global policy"
+msgstr ""
+
+#: ../../ipaserver/install/certs.py:571 ../../ipaserver/plugins/dogtag.py:1313
+#: ../../ipaserver/plugins/dogtag.py:1398
+#: ../../ipaserver/plugins/dogtag.py:1463
+#: ../../ipaserver/plugins/dogtag.py:1543
+#: ../../ipaserver/plugins/dogtag.py:1602
+#, python-format
+msgid "Unable to communicate with CMS (%s)"
+msgstr ""
+
+#: ../../ipaserver/plugins/selfsign.py:102
+#, python-format
+msgid ""
+"Request subject \"%(request_subject)s\" does not match the form \"%"
+"(subject_base)s\""
+msgstr ""
+
+#: ../../ipaserver/plugins/selfsign.py:107
+#, python-format
+msgid "unable to decode csr: %s"
+msgstr ""
+
+#: ../../ipaserver/plugins/selfsign.py:128
+#: ../../ipaserver/plugins/selfsign.py:143
+msgid "file operation"
+msgstr ""
+
+#: ../../ipaserver/plugins/selfsign.py:157
+msgid "cannot obtain next serial number"
+msgstr ""
+
+#: ../../ipaserver/plugins/selfsign.py:192
+msgid "certutil failure"
+msgstr ""
diff --git a/ipa.spec.in b/ipa.spec.in
index c264de143..3de1a2a7f 100644
--- a/ipa.spec.in
+++ b/ipa.spec.in
@@ -9,6 +9,7 @@
%{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
%{!?python_sitearch: %global python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
%global POLICYCOREUTILSVER 1.33.12-1
+%global gettext_domain ipa
Name: ipa
Version: __VERSION__
@@ -44,6 +45,7 @@ BuildRequires: python-setuptools
BuildRequires: python-krbV
BuildRequires: xmlrpc-c-devel
BuildRequires: libcurl-devel
+BuildRequires: gettext
%endif
%description
@@ -251,6 +253,8 @@ cd ..
%else
make client-install DESTDIR=%{buildroot}
%endif
+%find_lang %{gettext_domain}
+
%if ! %{ONLY_CLIENT}
# Remove .la files from libtool - we don't want to package
@@ -461,7 +465,7 @@ fi
%{_sysconfdir}/bash_completion.d
%endif
-%files python
+%files python -f %{gettext_domain}.lang
%doc LICENSE README
%defattr(-,root,root,-)
%dir %{python_sitelib}/ipapython