[beast] PO: migrated translation support to Makefile.am



commit a27818718ea7cd89fd2904b3fa21a75e2320fdef
Author: Tim Janik <timj gtk org>
Date:   Mon Sep 6 23:03:18 2010 +0200

    PO: migrated translation support to Makefile.am
    
    	* po/Makefile.am: provide rules to build/install/uninstall translation
    	catalogs. Check for unlisted tranlatable files. Provide update-po
    	and pot-file build rules. Support XML, scm, keys, desktop, IDL,
    	proc and C/C++ source files.
    
    	* Makefile.am: beautified make output via echo and printf.
    	Use make function definitions to simplify adding new source file
    	types.
    
    	* po/LINGUAS: list of supported languages.
    
    	* po/POTSCAN: list of project sources with translations.
    
    	* po/POTSKIP: list of translatable project sources to skip.
    
    	* po/POTIGNORE: ERE patterns of project sources to ignore.
    
    	* autotools/intlfix-las.awk: script to prepare I18N strings in
    	line-based assignment files (keys, desktop, INI) for extraction.
    
    	* autotools/intlfix-scm.sed: script to prepare I18N strings in
    	scheme source files for extraction.
    
    	* autotools/intlfix-xml.awk: script to prepare I18N nodes and
    	attribute values for extraction.

 Makefile.am                                     |   10 +-
 acintltool.m4                                   |  204 ----
 autogen.sh                                      |   20 -
 autotools/glib-gettext.m4                       |  432 +++++++
 autotools/intlfix-las.awk                       |   19 +
 autotools/intlfix-scm.sed                       |   16 +
 autotools/intlfix-xml.awk                       |  296 +++++
 autotools/intltool-extract.in                   |  899 --------------
 autotools/{intltool-merge.in => intltool-merge} |  322 ++++--
 autotools/intltool-update.in                    | 1089 -----------------
 configure.in                                    |   79 +-
 data/Makefile.am                                |   18 +-
 po-helper.sh                                    |    1 -
 po-helper.sh.in                                 |    1 -
 po/ChangeLog                                    | 1426 -----------------------
 po/LINGUAS                                      |    3 +-
 po/Makefile.am                                  |  198 ++++
 po/Makefile.intltool                            |  225 ----
 po/POTIGNORE                                    |    4 +
 po/{POTFILES.in => POTSCAN}                     |   16 +-
 po/{POTFILES.skip => POTSKIP}                   |    4 +-
 po/intltool-scm-35.diff                         |  108 --
 po/update.sh                                    |   15 -
 23 files changed, 1269 insertions(+), 4136 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 60df0ad..988f315 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,7 +9,8 @@ SUBDIRS = . data birnet sfi bse plugins shell beast-gtk launchers library tools
 noinst_DATA =
 
 # require automake 1.9
-AUTOMAKE_OPTIONS = 1.9 dist-bzip2 no-dist-gzip
+AUTOMAKE_OPTIONS = 1.9 dist-bzip2 no-dist-gzip -Wno-portability
+ACLOCAL_AMFLAGS = -I autotools
 
 site site-preview site-update site-update-all site-update-pages site-update-galleries:
 	@$(MAKE) -C web/ $(AM_MAKEFLAGS) $@
@@ -18,20 +19,13 @@ site site-preview site-update site-update-all site-update-pages site-update-gall
 configure: birnet/acbirnet.m4 birnet/configure.inc
 
 CLEANFILES += $(strip		\
-	intltool-extract	\
-	intltool-merge		\
-	intltool-update		\
 )
 
 EXTRA_DIST += $(strip		\
 	TODO			\
 	COPYING.GPL		\
 	COPYING.LGPL		\
-	po-helper.sh.in		\
 	topconfig.h		\
-	intltool-extract.in     \
-	intltool-merge.in       \
-	intltool-update.in	\
 )
 
 # check: message
diff --git a/autogen.sh b/autogen.sh
index c889f52..e02d226 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -12,7 +12,6 @@ AUTOCONF=autoconf
 AUTOCONF_POSTFIX=2.50
 AUTOCONF_VERSION=2.57
 AUTOHEADER=autoheader
-GLIB_GETTEXTIZE=glib-gettextize
 LIBTOOLIZE=libtoolize
 LIBTOOLIZE_VERSION=1.5.0
 CONFIGURE_OPTIONS=
@@ -92,13 +91,6 @@ else
 	DIE=1
 fi
 
-# check for gettextize
-$GLIB_GETTEXTIZE --version >/dev/null 2>&1 || {
-	echo "You need to have $GLIB_GETTEXTIZE installed to compile $PROJECT."
-	echo "Get the source tarball at http://www.gtk.org/download/";
-	DIE=1
-}
-
 # check for libtool
 check_version "`$LIBTOOLIZE --version 2>/dev/null | sed 1q`" $LIBTOOLIZE_VERSION || {
 	echo "You need to have $LIBTOOLIZE (version >= $LIBTOOLIZE_VERSION) installed to compile $PROJECT."
@@ -143,18 +135,6 @@ rm -rf autom4te.cache/
 echo "Running: $LIBTOOLIZE"
 $LIBTOOLIZE --force || exit $?
 
-echo "Running: $GLIB_GETTEXTIZE"
-echo "no" | $GLIB_GETTEXTIZE --force || exit $?
-
-
-echo "Providing our own patched intltool..."
-# echo "Running: intltoolize"
-# intltoolize --force --copy || exit $?
-# echo "Patching intltool for SCM and custom Makefile rules"
-# patch -p0 -b <po/intltool-scm-35.diff || exit $?
-echo "Overriding gettext po/Makefile.in.in with intltool version"
-rm -f po/Makefile.in.in && cp -v po/Makefile.intltool po/Makefile.in.in || exit $?
-
 echo "Running: $ACLOCAL $ACLOCAL_FLAGS"
 $ACLOCAL $ACLOCAL_FLAGS	|| exit $?
 
diff --git a/autotools/glib-gettext.m4 b/autotools/glib-gettext.m4
new file mode 100644
index 0000000..68b08b3
--- /dev/null
+++ b/autotools/glib-gettext.m4
@@ -0,0 +1,432 @@
+# Copyright (C) 1995-2002 Free Software Foundation, Inc.
+# Copyright (C) 2001-2003,2004 Red Hat, Inc.
+#
+# This file is free software, distributed under the terms of the GNU
+# General Public License.  As a special exception to the GNU General
+# Public License, this file may be distributed as part of a program
+# that contains a configuration script generated by Autoconf, under
+# the same distribution terms as the rest of that program.
+#
+# This file can be copied and used freely without restrictions.  It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+#
+# Macro to add for using GNU gettext.
+# Ulrich Drepper <drepper cygnus com>, 1995, 1996
+#
+# Modified to never use included libintl. 
+# Owen Taylor <otaylor redhat com>, 12/15/1998
+#
+# Major rework to remove unused code
+# Owen Taylor <otaylor redhat com>, 12/11/2002
+#
+# Added better handling of ALL_LINGUAS from GNU gettext version 
+# written by Bruno Haible, Owen Taylor <otaylor.redhat.com> 5/30/3002
+#
+# Modified to require ngettext
+# Matthias Clasen <mclasen redhat com> 08/06/2004
+#
+# We need this here as well, since someone might use autoconf-2.5x
+# to configure GLib then an older version to configure a package
+# using AM_GLIB_GNU_GETTEXT
+AC_PREREQ(2.53)
+
+dnl
+dnl We go to great lengths to make sure that aclocal won't 
+dnl try to pull in the installed version of these macros
+dnl when running aclocal in the glib directory.
+dnl
+m4_copy([AC_DEFUN],[glib_DEFUN])
+m4_copy([AC_REQUIRE],[glib_REQUIRE])
+dnl
+dnl At the end, if we're not within glib, we'll define the public
+dnl definitions in terms of our private definitions.
+dnl
+
+# GLIB_LC_MESSAGES
+#--------------------
+glib_DEFUN([GLIB_LC_MESSAGES],
+  [AC_CHECK_HEADERS([locale.h])
+    if test $ac_cv_header_locale_h = yes; then
+    AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES,
+      [AC_TRY_LINK([#include <locale.h>], [return LC_MESSAGES],
+       am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)])
+    if test $am_cv_val_LC_MESSAGES = yes; then
+      AC_DEFINE(HAVE_LC_MESSAGES, 1,
+        [Define if your <locale.h> file defines LC_MESSAGES.])
+    fi
+  fi])
+
+# GLIB_PATH_PROG_WITH_TEST
+#----------------------------
+dnl GLIB_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR,
+dnl   TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]])
+glib_DEFUN([GLIB_PATH_PROG_WITH_TEST],
+[# Extract the first word of "$2", so it can be a program name with args.
+set dummy $2; ac_word=[$]2
+AC_MSG_CHECKING([for $ac_word])
+AC_CACHE_VAL(ac_cv_path_$1,
+[case "[$]$1" in
+  /*)
+  ac_cv_path_$1="[$]$1" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in ifelse([$5], , $PATH, [$5]); do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if [$3]; then
+	ac_cv_path_$1="$ac_dir/$ac_word"
+	break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+dnl If no 4th arg is given, leave the cache variable unset,
+dnl so AC_PATH_PROGS will keep looking.
+ifelse([$4], , , [  test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4"
+])dnl
+  ;;
+esac])dnl
+$1="$ac_cv_path_$1"
+if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then
+  AC_MSG_RESULT([$]$1)
+else
+  AC_MSG_RESULT(no)
+fi
+AC_SUBST($1)dnl
+])
+
+# GLIB_WITH_NLS
+#-----------------
+glib_DEFUN([GLIB_WITH_NLS],
+  dnl NLS is obligatory
+  [USE_NLS=yes
+    AC_SUBST(USE_NLS)
+
+    gt_cv_have_gettext=no
+
+    CATOBJEXT=NONE
+    XGETTEXT=:
+    INTLLIBS=
+
+    AC_CHECK_HEADER(libintl.h,
+     [gt_cv_func_dgettext_libintl="no"
+      libintl_extra_libs=""
+
+      #
+      # First check in libc
+      #
+      AC_CACHE_CHECK([for ngettext in libc], gt_cv_func_ngettext_libc,
+        [AC_TRY_LINK([
+#include <libintl.h>
+],
+         [return !ngettext ("","", 1)],
+	  gt_cv_func_ngettext_libc=yes,
+          gt_cv_func_ngettext_libc=no)
+        ])
+  
+      if test "$gt_cv_func_ngettext_libc" = "yes" ; then
+	      AC_CACHE_CHECK([for dgettext in libc], gt_cv_func_dgettext_libc,
+        	[AC_TRY_LINK([
+#include <libintl.h>
+],
+	          [return !dgettext ("","")],
+		  gt_cv_func_dgettext_libc=yes,
+	          gt_cv_func_dgettext_libc=no)
+        	])
+      fi
+  
+      if test "$gt_cv_func_ngettext_libc" = "yes" ; then
+        AC_CHECK_FUNCS(bind_textdomain_codeset)
+      fi
+
+      #
+      # If we don't have everything we want, check in libintl
+      #
+      if test "$gt_cv_func_dgettext_libc" != "yes" \
+	 || test "$gt_cv_func_ngettext_libc" != "yes" \
+         || test "$ac_cv_func_bind_textdomain_codeset" != "yes" ; then
+        
+        AC_CHECK_LIB(intl, bindtextdomain,
+	    [AC_CHECK_LIB(intl, ngettext,
+		    [AC_CHECK_LIB(intl, dgettext,
+			          gt_cv_func_dgettext_libintl=yes)])])
+
+	if test "$gt_cv_func_dgettext_libintl" != "yes" ; then
+	  AC_MSG_CHECKING([if -liconv is needed to use gettext])
+	  AC_MSG_RESULT([])
+  	  AC_CHECK_LIB(intl, ngettext,
+          	[AC_CHECK_LIB(intl, dcgettext,
+		       [gt_cv_func_dgettext_libintl=yes
+			libintl_extra_libs=-liconv],
+			:,-liconv)],
+		:,-liconv)
+        fi
+
+        #
+        # If we found libintl, then check in it for bind_textdomain_codeset();
+        # we'll prefer libc if neither have bind_textdomain_codeset(),
+        # and both have dgettext and ngettext
+        #
+        if test "$gt_cv_func_dgettext_libintl" = "yes" ; then
+          glib_save_LIBS="$LIBS"
+          LIBS="$LIBS -lintl $libintl_extra_libs"
+          unset ac_cv_func_bind_textdomain_codeset
+          AC_CHECK_FUNCS(bind_textdomain_codeset)
+          LIBS="$glib_save_LIBS"
+
+          if test "$ac_cv_func_bind_textdomain_codeset" = "yes" ; then
+            gt_cv_func_dgettext_libc=no
+          else
+            if test "$gt_cv_func_dgettext_libc" = "yes" \
+		&& test "$gt_cv_func_ngettext_libc" = "yes"; then
+              gt_cv_func_dgettext_libintl=no
+            fi
+          fi
+        fi
+      fi
+
+      if test "$gt_cv_func_dgettext_libc" = "yes" \
+	|| test "$gt_cv_func_dgettext_libintl" = "yes"; then
+        gt_cv_have_gettext=yes
+      fi
+  
+      if test "$gt_cv_func_dgettext_libintl" = "yes"; then
+        INTLLIBS="-lintl $libintl_extra_libs"
+      fi
+  
+      if test "$gt_cv_have_gettext" = "yes"; then
+	AC_DEFINE(HAVE_GETTEXT,1,
+	  [Define if the GNU gettext() function is already present or preinstalled.])
+	GLIB_PATH_PROG_WITH_TEST(MSGFMT, msgfmt,
+	  [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl
+	if test "$MSGFMT" != "no"; then
+          glib_save_LIBS="$LIBS"
+          LIBS="$LIBS $INTLLIBS"
+	  AC_CHECK_FUNCS(dcgettext)
+	  MSGFMT_OPTS=
+	  AC_MSG_CHECKING([if msgfmt accepts -c])
+	  GLIB_RUN_PROG([$MSGFMT -c -o /dev/null],[
+msgid ""
+msgstr ""
+"Content-Type: text/plain; charset=UTF-8\n"
+"Project-Id-Version: test 1.0\n"
+"PO-Revision-Date: 2007-02-15 12:01+0100\n"
+"Last-Translator: test <foo bar xx>\n"
+"Language-Team: C <LL li org>\n"
+"MIME-Version: 1.0\n"
+"Content-Transfer-Encoding: 8bit\n"
+], [MSGFMT_OPTS=-c; AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])
+	  AC_SUBST(MSGFMT_OPTS)
+	  AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
+	  GLIB_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+	    [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :)
+	  AC_TRY_LINK(, [extern int _nl_msg_cat_cntr;
+			 return _nl_msg_cat_cntr],
+	    [CATOBJEXT=.gmo 
+             DATADIRNAME=share],
+	    [case $host in
+	    *-*-solaris*)
+	    dnl On Solaris, if bind_textdomain_codeset is in libc,
+	    dnl GNU format message catalog is always supported,
+            dnl since both are added to the libc all together.
+	    dnl Hence, we'd like to go with DATADIRNAME=share and
+	    dnl and CATOBJEXT=.gmo in this case.
+            AC_CHECK_FUNC(bind_textdomain_codeset,
+	      [CATOBJEXT=.gmo 
+               DATADIRNAME=share],
+	      [CATOBJEXT=.mo
+               DATADIRNAME=lib])
+	    ;;
+	    *)
+	    CATOBJEXT=.mo
+            DATADIRNAME=lib
+	    ;;
+	    esac])
+          LIBS="$glib_save_LIBS"
+	  INSTOBJEXT=.mo
+	else
+	  gt_cv_have_gettext=no
+	fi
+      fi
+    ])
+
+    if test "$gt_cv_have_gettext" = "yes" ; then
+      AC_DEFINE(ENABLE_NLS, 1,
+        [always defined to indicate that i18n is enabled])
+    fi
+
+    dnl Test whether we really found GNU xgettext.
+    if test "$XGETTEXT" != ":"; then
+      dnl If it is not GNU xgettext we define it as : so that the
+      dnl Makefiles still can work.
+      if $XGETTEXT --omit-header /dev/null 2> /dev/null; then
+        : ;
+      else
+        AC_MSG_RESULT(
+	  [found xgettext program is not GNU xgettext; ignore it])
+        XGETTEXT=":"
+      fi
+    fi
+
+    # We need to process the po/ directory.
+    POSUB=po
+
+    AC_OUTPUT_COMMANDS(
+      [case "$CONFIG_FILES" in *po/Makefile.in*)
+        sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile
+      esac])
+
+    dnl These rules are solely for the distribution goal.  While doing this
+    dnl we only have to keep exactly one list of the available catalogs
+    dnl in configure.in.
+    for lang in $ALL_LINGUAS; do
+      GMOFILES="$GMOFILES $lang.gmo"
+      POFILES="$POFILES $lang.po"
+    done
+
+    dnl Make all variables we use known to autoconf.
+    AC_SUBST(CATALOGS)
+    AC_SUBST(CATOBJEXT)
+    AC_SUBST(DATADIRNAME)
+    AC_SUBST(GMOFILES)
+    AC_SUBST(INSTOBJEXT)
+    AC_SUBST(INTLLIBS)
+    AC_SUBST(PO_IN_DATADIR_TRUE)
+    AC_SUBST(PO_IN_DATADIR_FALSE)
+    AC_SUBST(POFILES)
+    AC_SUBST(POSUB)
+  ])
+
+# AM_GLIB_GNU_GETTEXT
+# -------------------
+# Do checks necessary for use of gettext. If a suitable implementation 
+# of gettext is found in either in libintl or in the C library,
+# it will set INTLLIBS to the libraries needed for use of gettext
+# and AC_DEFINE() HAVE_GETTEXT and ENABLE_NLS. (The shell variable
+# gt_cv_have_gettext will be set to "yes".) It will also call AC_SUBST()
+# on various variables needed by the Makefile.in.in installed by 
+# glib-gettextize.
+dnl
+glib_DEFUN([GLIB_GNU_GETTEXT],
+  [AC_REQUIRE([AC_PROG_CC])dnl
+   AC_REQUIRE([AC_HEADER_STDC])dnl
+   
+   GLIB_LC_MESSAGES
+   GLIB_WITH_NLS
+
+   if test "$gt_cv_have_gettext" = "yes"; then
+     if test "x$ALL_LINGUAS" = "x"; then
+       LINGUAS=
+     else
+       AC_MSG_CHECKING(for catalogs to be installed)
+       NEW_LINGUAS=
+       for presentlang in $ALL_LINGUAS; do
+         useit=no
+         if test "%UNSET%" != "${LINGUAS-%UNSET%}"; then
+           desiredlanguages="$LINGUAS"
+         else
+           desiredlanguages="$ALL_LINGUAS"
+         fi
+         for desiredlang in $desiredlanguages; do
+ 	   # Use the presentlang catalog if desiredlang is
+           #   a. equal to presentlang, or
+           #   b. a variant of presentlang (because in this case,
+           #      presentlang can be used as a fallback for messages
+           #      which are not translated in the desiredlang catalog).
+           case "$desiredlang" in
+             "$presentlang"*) useit=yes;;
+           esac
+         done
+         if test $useit = yes; then
+           NEW_LINGUAS="$NEW_LINGUAS $presentlang"
+         fi
+       done
+       LINGUAS=$NEW_LINGUAS
+       AC_MSG_RESULT($LINGUAS)
+     fi
+
+     dnl Construct list of names of catalog files to be constructed.
+     if test -n "$LINGUAS"; then
+       for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done
+     fi
+   fi
+
+   dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly
+   dnl find the mkinstalldirs script in another subdir but ($top_srcdir).
+   dnl Try to locate is.
+   MKINSTALLDIRS=
+   if test -n "$ac_aux_dir"; then
+     MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs"
+   fi
+   if test -z "$MKINSTALLDIRS"; then
+     MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs"
+   fi
+   AC_SUBST(MKINSTALLDIRS)
+
+   dnl Generate list of files to be processed by xgettext which will
+   dnl be included in po/Makefile.
+   test -d po || mkdir po
+   if test "x$srcdir" != "x."; then
+     if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then
+       posrcprefix="$srcdir/"
+     else
+       posrcprefix="../$srcdir/"
+     fi
+   else
+     posrcprefix="../"
+   fi
+   rm -f po/POTFILES
+   sed -e "/^#/d" -e "/^\$/d" -e "s,.*,	$posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \
+	< $srcdir/po/POTFILES.in > po/POTFILES
+  ])
+
+# AM_GLIB_DEFINE_LOCALEDIR(VARIABLE)
+# -------------------------------
+# Define VARIABLE to the location where catalog files will
+# be installed by po/Makefile.
+glib_DEFUN([GLIB_DEFINE_LOCALEDIR],
+[glib_REQUIRE([GLIB_GNU_GETTEXT])dnl
+glib_save_prefix="$prefix"
+glib_save_exec_prefix="$exec_prefix"
+glib_save_datarootdir="$datarootdir"
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+test "x$exec_prefix" = xNONE && exec_prefix=$prefix
+datarootdir=`eval echo "${datarootdir}"`
+if test "x$CATOBJEXT" = "x.mo" ; then
+  localedir=`eval echo "${libdir}/locale"`
+else
+  localedir=`eval echo "${datadir}/locale"`
+fi
+prefix="$glib_save_prefix"
+exec_prefix="$glib_save_exec_prefix"
+datarootdir="$glib_save_datarootdir"
+AC_DEFINE_UNQUOTED($1, "$localedir",
+  [Define the location where the catalogs will be installed])
+])
+
+dnl
+dnl Now the definitions that aclocal will find
+dnl
+ifdef(glib_configure_in,[],[
+AC_DEFUN([AM_GLIB_GNU_GETTEXT],[GLIB_GNU_GETTEXT($@)])
+AC_DEFUN([AM_GLIB_DEFINE_LOCALEDIR],[GLIB_DEFINE_LOCALEDIR($@)])
+])dnl
+
+# GLIB_RUN_PROG(PROGRAM, TEST-FILE, [ACTION-IF-PASS], [ACTION-IF-FAIL])
+# 
+# Create a temporary file with TEST-FILE as its contents and pass the
+# file name to PROGRAM.  Perform ACTION-IF-PASS if PROGRAM exits with
+# 0 and perform ACTION-IF-FAIL for any other exit status.
+AC_DEFUN([GLIB_RUN_PROG],
+[cat >conftest.foo <<_ACEOF
+$2
+_ACEOF
+if AC_RUN_LOG([$1 conftest.foo]); then
+  m4_ifval([$3], [$3], [:])
+m4_ifvaln([$4], [else $4])dnl
+echo "$as_me: failed input was:" >&AS_MESSAGE_LOG_FD
+sed 's/^/| /' conftest.foo >&AS_MESSAGE_LOG_FD
+fi])
+
diff --git a/autotools/intlfix-las.awk b/autotools/intlfix-las.awk
new file mode 100644
index 0000000..f1dcfb1
--- /dev/null
+++ b/autotools/intlfix-las.awk
@@ -0,0 +1,19 @@
+
+# AWK file to extract translatable strings from single line assignments
+
+BEGIN { MARKER = ""; if (ENVIRON["INTLFIX"] ~ /:marker:/) MARKER = "__INTLFIX__: "; }
+
+/^#/ { print "// " substr ($0, 2) ; next }
+
+/^[[:space:]]*_([^=]*)=/ {
+    name = $0; value = $0
+    sub (/=.*/, "", name)
+    sub (/[[:space:]]*_/, "", name)
+    sub (/^[^=]*=/, "", value)
+    gsub ("[\\\"]", "\\" "\\&", value)
+    print MARKER " /*" name "*/_(\"" value "\");"
+    next
+}
+
+{ print "\t; " $0 " ;" }
+
diff --git a/autotools/intlfix-scm.sed b/autotools/intlfix-scm.sed
new file mode 100644
index 0000000..ffde8aa
--- /dev/null
+++ b/autotools/intlfix-scm.sed
@@ -0,0 +1,16 @@
+
+
+
+# ignore apostrophes
+: apostrophe
+s ^\(\([^";]\|"\([^"\]\|\\.\)*"\)*\)'@\1.@
+t apostrophe ; # check/fix next apostrophe on same line
+
+# extract gettext function calls, ignore strings and comments
+s/^\(\([^";]\|"\([^"\]\|\\.\)*"\)*\)(\([NUQ]\?\)_/__INTLFIX__: \1\2_(/
+: intlfunc
+s/^\(\([^";]\|"\([^"\]\|\\.\)*"\)*\)(\([NUQ]\?\)_/\1\2_(/
+t intlfunc ; # next intlfunc on same line (omitting marker)
+
+# extract comments, ignore strings
+s ^\(\([^";]\|"\([^"\]\|\\.\)*"\)*\);\+ \1//@
diff --git a/autotools/intlfix-xml.awk b/autotools/intlfix-xml.awk
new file mode 100644
index 0000000..6012b2b
--- /dev/null
+++ b/autotools/intlfix-xml.awk
@@ -0,0 +1,296 @@
+# GNU AWK Script to extract translatable strings from XML files
+# Copyright (C) 2010 Tim Janik
+#
+# The original public domain XML parser was authored by at least:
+# - getXMLEVENT.awk:	Copyright (C) 2007 Juergen Kahrs
+# - getXML.awk:     	Copyright (C) 2005 Jan Weber
+# - xmlparse.awk:   	Copyright (C) 2001 Steve Coile
+
+BEGIN {
+  MARKER = ""; if (ENVIRON["INTLFIX"] ~ /:marker:/) MARKER = "__INTLFIX__:";
+  OLINE = 1
+  TAG = ""
+  while (getXMLEVENT(ARGV[1])) {
+    while (OLINE < XMLROW) { print ""; OLINE++ }
+    next_tag = ""
+    if (XMLEVENT == "STARTELEM") {
+      next_tag = XMLSTARTELEM
+      printf ("%*s<%s>", 2 * XMLDEPTH - 2, "", XMLSTARTELEM)
+      for (i = 1; i <= NF; i++) {
+	if ($i ~ /^_[^_]/) {
+	  aname = $i; avalue = XMLATTR[$i]
+	  sub ("^_", "", aname); gsub ("[\\\"]", "\\" "\\&", avalue)
+          printf ("%s /*%s=*/_(\"%s\"); ", MARKER, aname, avalue)
+	}
+      }
+      #print ""
+    } else if (XMLEVENT == "COMMENT") {
+      gsub ("\\*/", "* /", XMLNAME)
+      ostring = sprintf ("/* %s */\n", XMLNAME)
+      printf ("__XML_LINE__%-3d: %s", OLINE, ostring); gsub (/[^\n]/, "", ostring); OLINE += length (ostring)
+    } else if (XMLEVENT == "CHARDATA" && match (TAG, "^_[^_]")) {
+      sub ("^_", "", TAG); gsub ("[\\\"]", "\\" "\\&", XMLNAME)
+      ostring = sprintf ("%s /*<%s/>*/_(\"%s\");\n", MARKER, TAG, XMLNAME);
+      printf ("__XML_LINE__%-3d: %s", OLINE, ostring); gsub (/[^\n]/, "", ostring); OLINE += length (ostring)
+    } else if (XMLEVENT == "ENDELEM") {
+      printf ("</>")
+    }
+    TAG = next_tag
+  }
+}
+
+
+##
+# getXMLEVENT( file ): # read next xml-data into XMLEVENT,XMLNAME,XMLATTR
+#                      # referenced entities are not resolved
+# Parameters:
+#   file       -- path to xml file
+# External variables:
+#   XMLEVENT   -- type of item read, e.g. "STARTELEM"(tag), "ENDELEM"(end tag),
+#                 "COMMENT"(comment), "CHARDATA"(data)
+#   XMLNAME    -- value of item, e.g. tagname if type is "STARTELEM" or "ENDELEM"
+#   XMLATTR    -- Map of attributes, only set if XMLEVENT=="STARTELEM"
+#   XMLPATH    -- Path to current tag, e.g. /TopLevelTag/SubTag1/SubTag2
+#   XMLROW     -- current line number in input file
+#   XMLERROR   -- error text, set on parse error
+# Returns:
+#    1         on successful read: XMLEVENT, XMLNAME, XMLATTR are set accordingly
+#    ""        at end of file or parse error, XMLERROR is set on error
+# Private Data:
+#   _XMLIO     -- buffer, XMLROW, XMLPATH for open files
+##
+
+function getXMLEVENT( file            ,end,p,q,tag,att,accu,mline,mode,S0,ex,dtd) {
+    XMLEVENT=XMLNAME=XMLERROR=XMLSTARTELEM=XMLENDELEM = ""
+    split("", XMLATTR)
+    S0    = _XMLIO[file,"S0"]
+    XMLROW  = _XMLIO[file,"line"];
+    XMLPATH = _XMLIO[file,"path"];
+    XMLDEPTH=_XMLIO[file,"depth"]+0;
+    dtd   = _XMLIO[file,"dtd"];
+    while (!XMLEVENT) {
+        if (S0 == "") {
+            if (1 != (getline S0 < file))
+                break;
+             XMLROW ++;
+             S0 = S0 RS;
+        }
+        if (mode == "") {
+            mline = XMLROW
+            accu=""
+            p = substr(S0,1,1)
+            if (p != "<" && !(dtd && p=="]"))
+                mode="CHARDATA"
+            else if (p == "]") {
+                S0 = substr(S0,2)
+                mode="ENDDOCT"
+                end=">"
+                dtd=0
+            } else if ( substr(S0,1,4) == "<!--" ) {
+                S0=substr(S0,5)
+                mode="COMMENT"
+                end="-->"
+            } else if ( substr(S0,1,9) == "<!DOCTYPE" ) {
+                S0 = substr(S0,10)
+                mode = "STARTDOCT"
+                end  = ">"
+            } else if (substr(S0,1,9) == "<![CDATA[" ) {
+                S0 = substr(S0,10)
+                mode = "CDA"
+                end = "]]>"
+            } else if ( substr(S0,1,2) == "<!" ) {
+                S0 = substr(S0,3)
+                mode = "DEC"
+                end = ">"
+            } else if (substr(S0,1,2) == "<?") {
+                S0 = substr(S0,3)
+                mode = "PROCINST"
+                end = "?>"
+            } else if ( substr(S0,1,2)=="</" ) {
+                S0 = substr(S0,3)
+                mode = "ENDELEM"
+                end = ">";
+                tag = S0
+                sub(/[ \n\r\t>].*$/,"",tag)
+                S0 = substr(S0,length(tag)+1)
+                ex = XMLPATH
+                sub(/\/[^\/]*$/,"",XMLPATH)
+                ex = substr(ex, length(XMLPATH)+2)
+                if (tag != ex) {
+                    XMLERROR = "unexpected close tag <" ex ">..</" tag ">"
+                    break
+                }
+            } else {
+                S0 = substr(S0,2)
+                mode = "STARTELEM"
+                tag = S0
+                sub(/[ \n\r\t\/>].*$/,"",tag)
+                S0 = substr(S0, length(tag)+1)
+                if (tag !~ /^[A-Za-z:_][0-9A-Za-z:_.-]*$/ ) { # /^[[:alpha:]:_][[:alnum:]:_.-]*$/
+                    XMLERROR = "invalid tag name '" tag "'"
+                    break
+                }
+                XMLPATH = XMLPATH "/" tag;
+            }
+        } else if (mode == "CHARDATA") {                            # terminated by "<" or EOF
+            p = index(S0, "<")
+            if (dtd && (q=index(S0,"]")) && (!p || q<p) )
+                p = q
+            if (p) {
+                XMLEVENT = "CHARDATA"
+                XMLNAME = accu unescapeXML(substr(S0, 1, p-1))
+                S0 = substr(S0, p)
+                mode = ""
+            } else {
+                accu = accu unescapeXML(S0)
+                S0 = ""
+            }
+        } else if ( mode == "STARTELEM" ) {
+            sub(/^[ \n\r\t]*/,"",S0)
+            if (S0 == "")
+                continue
+            if (substr(S0, 1, 2) == "/>" ) {
+                S0 = substr(S0, 3)
+                mode = ""
+                XMLEVENT = "STARTELEM"
+                XMLNAME = XMLSTARTELEM = tag
+                XMLDEPTH ++
+                S0 = "</" tag ">" S0
+            } else if (substr(S0, 1, 1) == ">" ) {
+                S0 = substr(S0, 2)
+                mode = ""
+                XMLEVENT = "STARTELEM"
+                XMLNAME = XMLSTARTELEM = tag
+                XMLDEPTH ++
+            } else {
+                att = S0
+                sub(/[= \n\r\t\/>].*$/,"",att)
+                S0 = substr(S0, length(att) + 1)
+                mode = "ATTR"
+                if (att !~ /^[A-Za-z:_][0-9A-Za-z:_.-]*$/ ) { # /^[[:alpha:]:_][[:alnum:]:_.-]*$/
+                    XMLERROR = "invalid attribute name '" att "'"
+                    break
+                }
+            }
+        } else if (mode == "ATTR") {
+            sub(/^[ \n\r\t]*/, "", S0)
+            if (S0 == "")
+                continue
+            if (substr(S0,1,1) == "=" ) {
+                S0 = substr(S0,2)
+                mode = "EQ"
+            } else {
+                XMLATTR[att] = att
+                mode = "STARTELEM"
+            }
+        } else if (mode == "EQ") {
+            sub(/^[ \n\r\t]*/,"",S0)
+            if (S0 == "")
+              continue
+            end = substr(S0,1,1)
+            if (end == "\"" || end == "'") {
+                S0 = substr(S0,2)
+                accu = ""
+                mode = "VALUE"
+            } else {
+                accu = S0
+                sub(/[ \n\r\t\/>].*$/,"", accu)
+                S0 = substr(S0, length(accu)+1)
+                XMLATTR[att] = unescapeXML(accu)
+                mode = "STARTELEM"
+            }
+        } else if (mode == "VALUE") {                          # terminated by end
+            if (p = index(S0, end)) {
+                XMLATTR[att] = accu unescapeXML(substr(S0,1,p-1))
+                S0 = substr(S0, p+length(end))
+                mode = "STARTELEM"
+            } else {
+                accu = accu unescapeXML(S0)
+                S0=""
+            }
+        } else if (mode == "STARTDOCT") {                      # terminated by "[" or ">"
+            if ((q = index(S0, "[")) && (!(p = index(S0,end)) || q<p )) {
+                XMLEVENT = mode
+                XMLNAME = accu substr(S0, 1, q-1)
+                S0 = substr(S0, q+1)
+                mode = ""
+                dtd = 1
+            } else if (p = index(S0,end)) {
+                XMLEVENT = mode
+                XMLNAME = accu substr(S0, 1, p-1)
+                S0 = "]" substr(S0, p)
+                mode = ""
+                dtd = 1
+            } else {
+                accu = accu S0
+                S0 = ""
+            }
+        } else if (p = index(S0,end)) {  # terminated by end
+            XMLEVENT = mode
+            XMLNAME = XMLENDELEM = ( mode=="ENDELEM" ? tag : accu substr(S0,1,p-1))
+            if (mode=="ENDELEM") XMLDEPTH --
+            S0 = substr(S0, p+length(end))
+            mode = ""
+        } else {
+            accu = accu S0
+            S0 = ""
+        }
+    }
+    _XMLIO[file, "S0"]   = S0;
+    _XMLIO[file, "line"] = XMLROW;
+    _XMLIO[file, "path"] = XMLPATH;
+    _XMLIO[file, "depth"] = XMLDEPTH;
+    _XMLIO[file, "dtd"]  = dtd;
+    if (mode == "CHARDATA") {
+        mode = ""
+        if (accu != "")
+            XMLEVENT = "CHARDATA"
+        XMLNAME = ""
+        $0 = accu
+    }
+    if (XMLEVENT) {
+        if (XMLEVENT == "STARTELEM") {
+            # Copy attributes into $0.
+            NF=0
+            for (ex in XMLATTR) {
+                NF ++
+                $NF = ex
+            }
+        }
+        return 1
+    }
+    close(file);
+    delete _XMLIO[file, "S0"];
+    delete _XMLIO[file, "line"];
+    delete _XMLIO[file, "path"];
+    delete _XMLIO[file, "depth"];
+    delete _XMLIO[file, "dtd"];
+    if (XMLERROR)
+        XMLERROR = file ":" XMLROW": " XMLERROR
+    else if (mode) XMLERROR=file ":" mline ": " "unterminated " mode
+    else if (XMLPATH) XMLERROR=file ":" XMLROW": "  "unclosed tag(s) " XMLPATH
+} # function getXMLEVENT
+
+# unescape data and attribute values, used by getXMLEVENT
+function unescapeXML(text) {
+    gsub( "&apos;", "'",  text )
+    gsub( "&quot;", "\"", text )
+    gsub( "&gt;",   ">",  text )
+    gsub( "&lt;",   "<",  text )
+    gsub( "&amp;",  "\\&",  text)
+    return text
+}
+
+# close xml file
+function closeXMLEVENT(file) {
+    close(file);
+    delete _XMLIO[file,"S0"]
+    delete _XMLIO[file,"line"]
+    delete _XMLIO[file,"path"];
+    delete _XMLIO[file,"depth"];
+    delete _XMLIO[file,"dtd"]
+    delete _XMLIO[file,"open"]
+    delete _XMLIO[file,"IND"]
+}
+
+
diff --git a/autotools/intltool-merge.in b/autotools/intltool-merge
old mode 100644
new mode 100755
similarity index 82%
rename from autotools/intltool-merge.in
rename to autotools/intltool-merge
index d0535ab..5c6f2f2
--- a/autotools/intltool-merge.in
+++ b/autotools/intltool-merge
@@ -1,4 +1,4 @@
-#! INTLTOOL_PERL@ -w
+#!/usr/bin/perl -w
 # -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4  -*-
 
 #
@@ -35,13 +35,14 @@
 ## Release information
 my $PROGRAM = "intltool-merge";
 my $PACKAGE = "intltool";
-my $VERSION = "0.35.0";
+my $VERSION = "0.41.1";
 
 ## Loaded modules
 use strict; 
 use Getopt::Long;
 use Text::Wrap;
 use File::Basename;
+use Encode;
 
 my $must_end_tag      = -1;
 my $last_depth        = -1;
@@ -60,6 +61,8 @@ my $KEYS_STYLE_ARG = 0;
 my $DESKTOP_STYLE_ARG = 0;
 my $SCHEMAS_STYLE_ARG = 0;
 my $RFC822DEB_STYLE_ARG = 0;
+my $QUOTED_STYLE_ARG = 0;
+my $QUOTEDXML_STYLE_ARG = 0;
 my $QUIET_ARG = 0;
 my $PASS_THROUGH_ARG = 0;
 my $UTF8_ARG = 0;
@@ -79,6 +82,8 @@ GetOptions
  "desktop-style|d" => \$DESKTOP_STYLE_ARG,
  "schemas-style|s" => \$SCHEMAS_STYLE_ARG,
  "rfc822deb-style|r" => \$RFC822DEB_STYLE_ARG,
+ "quoted-style" => \$QUOTED_STYLE_ARG,
+ "quotedxml-style" => \$QUOTEDXML_STYLE_ARG,
  "pass-through|p" => \$PASS_THROUGH_ARG,
  "utf8|u" => \$UTF8_ARG,
  "multiple-output|m" => \$MULTIPLE_OUTPUT,
@@ -91,8 +96,6 @@ my $OUTFILE;
 
 my %po_files_by_lang = ();
 my %translations = ();
-my $iconv = $ENV{"ICONV"} || $ENV{"INTLTOOL_ICONV"} || "@INTLTOOL_ICONV@";
-my $devnull = ($^O eq 'MSWin32' ? 'NUL:' : '/dev/null');
 
 # Use this instead of \w for XML files to handle more possible characters.
 my $w = "[-A-Za-z0-9._:]";
@@ -131,7 +134,7 @@ elsif ($KEYS_STYLE_ARG && @ARGV > 2)
 	&utf8_sanity_check;
 	&preparation;
 	&print_message;
-	&keys_merge_translations;
+        &keys_merge_translations;
 	&finalize;
 } 
 elsif ($DESKTOP_STYLE_ARG && @ARGV > 2) 
@@ -157,6 +160,14 @@ elsif ($RFC822DEB_STYLE_ARG && @ARGV > 2)
 	&rfc822deb_merge_translations;
 	&finalize;
 } 
+elsif (($QUOTED_STYLE_ARG || $QUOTEDXML_STYLE_ARG) && @ARGV > 2)
+{
+	&utf8_sanity_check;
+	&preparation;
+	&print_message;
+	&quoted_merge_translations($QUOTEDXML_STYLE_ARG);
+	&finalize;
+} 
 else 
 {
 	&print_help;
@@ -193,6 +204,8 @@ Mandatory options: (exactly one must be specified)
   -k, --keys-style       includes translations in the keys style
   -s, --schemas-style    includes translations in the schemas style
   -r, --rfc822deb-style  includes translations in the RFC822 style
+      --quoted-style     includes translations in the quoted string style
+      --quotedxml-style  includes translations in the quoted xml string style
   -x, --xml-style        includes translations in the standard xml style
 
 Other options:
@@ -207,8 +220,7 @@ Other options:
       --help             display this help and exit
       --version          output version information and exit
 
-Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE")
-or send email to <xml-i18n-tools\ gnome org>.
+Report bugs to http://bugs.launchpad.net/intltool
 _EOF_
     exit;
 }
@@ -249,32 +261,42 @@ sub po_file2lang
 
 sub gather_po_files
 {
-    for my $po_file (glob "$PO_DIR/*.po") {
-	$po_files_by_lang{po_file2lang($po_file)} = $po_file;
+    if (my $linguas = $ENV{"LINGUAS"})
+    {
+        for my $lang (split / /, $linguas) {
+            my $po_file = $PO_DIR . "/" . $lang . ".po";
+            if (-e $po_file) {
+                $po_files_by_lang{$lang} = $po_file;
+            }
+        }
     }
-}
-
-sub get_local_charset
-{
-    my ($encoding) = @_;
-    my $alias_file = $ENV{"G_CHARSET_ALIAS"} || "@INTLTOOL_LIBDIR@/charset.alias";
+    else
+    {
+        if (open LINGUAS_FILE, "$PO_DIR/LINGUAS")
+        {
+            while (<LINGUAS_FILE>)
+            {
+                next if /^#/;
 
-    # seek character encoding aliases in charset.alias (glib)
+                for my $lang (split)
+                {
+                    chomp ($lang);
+                    my $po_file = $PO_DIR . "/" . $lang . ".po";
+                    if (-e $po_file) {
+                        $po_files_by_lang{$lang} = $po_file;
+                    }
+                }
+            }
 
-    if (open CHARSET_ALIAS, $alias_file) 
-    {
-	while (<CHARSET_ALIAS>) 
+            close LINGUAS_FILE;
+        }
+        else
         {
-            next if /^\#/;
-            return $1 if (/^\s*([-._a-zA-Z0-9]+)\s+$encoding\b/i)
+            for my $po_file (glob "$PO_DIR/*.po") {
+                $po_files_by_lang{po_file2lang($po_file)} = $po_file;
+            }
         }
-
-        close CHARSET_ALIAS;
     }
-
-    # if not found, return input string
-
-    return $encoding;
 }
 
 sub get_po_encoding
@@ -300,11 +322,6 @@ sub get_po_encoding
         $encoding = "ISO-8859-1";
     }
 
-    system ("$iconv -f $encoding -t UTF-8 <$devnull 2>$devnull");
-    if ($?) {
-	$encoding = get_local_charset($encoding);
-    }
-
     return $encoding
 }
 
@@ -379,35 +396,43 @@ sub get_cached_translation_database
     &create_cache;
 }
 
+sub add_translation
+{
+    my ($lang, $encoding, $msgctxt, $msgid, $msgstr) = @_;
+
+    return if !($msgid && $msgstr);
+
+    if ($msgctxt) {
+	$msgid = "$msgctxt\004$msgid";
+    }
+    if (uc $encoding ne "UTF-8") {
+        Encode::from_to ($msgid, $encoding, "UTF-8");
+        Encode::from_to ($msgstr, $encoding, "UTF-8");
+    }
+    $translations{$lang, $msgid} = $msgstr;
+}
+
 sub create_translation_database
 {
     for my $lang (keys %po_files_by_lang) 
     {
     	my $po_file = $po_files_by_lang{$lang};
+        my $encoding = "UTF-8";
 
         if ($UTF8_ARG) 
         {
-            my $encoding = get_po_encoding ($po_file);
-
-            if (lc $encoding eq "utf-8") 
-            {
-                open PO_FILE, "<$po_file";	
-            } 
-            else 
-            {
-		print "NOTICE: $po_file is not in UTF-8 but $encoding, converting...\n" unless $QUIET_ARG;;
-
-                open PO_FILE, "$iconv -f $encoding -t UTF-8 $po_file|";	
+            $encoding = get_po_encoding ($po_file);
+            if (uc $encoding ne "UTF-8") {
+                print "NOTICE: $po_file is not in UTF-8 but $encoding, converting...\n" unless $QUIET_ARG;;
             }
-        } 
-        else 
-        {
-            open PO_FILE, "<$po_file";	
         }
+        open PO_FILE, "<$po_file";	
 
 	my $nextfuzzy = 0;
+	my $inmsgctxt = 0;
 	my $inmsgid = 0;
 	my $inmsgstr = 0;
+	my $msgctxt = "";
 	my $msgid = "";
 	my $msgstr = "";
 
@@ -415,36 +440,60 @@ sub create_translation_database
         {
 	    $nextfuzzy = 1 if /^#, fuzzy/;
        
-	    if (/^msgid "((\\.|[^\\])*)"/ ) 
+	    if (/^msgctxt "((\\.|[^\\]+)*)"/ ) 
+            {
+		if ($inmsgstr) {
+		    add_translation ($lang, $encoding,
+                                     $msgctxt, $msgid, $msgstr);
+		    $msgctxt = "";
+		    $msgid = "";
+		    $msgstr = "";
+		}
+
+		$msgctxt = unescape_po_string($1);
+		$inmsgctxt = 1;
+		$inmsgid = 0;
+		$inmsgstr = 0;
+	    }
+
+	    if (/^msgid "((\\.|[^\\]+)*)"/ ) 
             {
-		$translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr;
-		$msgid = "";
-		$msgstr = "";
+		if ($inmsgstr) {
+                    add_translation ($lang, $encoding,
+                                     $msgctxt, $msgid, $msgstr);
+		    $msgctxt = "";
+		    $msgid = "";
+		    $msgstr = "";
+		}
 
 		if ($nextfuzzy) {
 		    $inmsgid = 0;
+		    $nextfuzzy = 0;
 		} else {
 		    $msgid = unescape_po_string($1);
 		    $inmsgid = 1;
 		}
+		$inmsgctxt = 0;
 		$inmsgstr = 0;
-		$nextfuzzy = 0;
 	    }
 
-	    if (/^msgstr "((\\.|[^\\])*)"/) 
+	    if (/^msgstr "((\\.|[^\\]+)*)"/) 
             {
 	        $msgstr = unescape_po_string($1);
 		$inmsgstr = 1;
+		$inmsgctxt = 0;
 		$inmsgid = 0;
 	    }
 
-	    if (/^"((\\.|[^\\])*)"/) 
+	    if (/^"((\\.|[^\\]+)*)"/) 
             {
+	        $msgctxt .= unescape_po_string($1) if $inmsgctxt;
 	        $msgid .= unescape_po_string($1) if $inmsgid;
 	        $msgstr .= unescape_po_string($1) if $inmsgstr;
 	    }
 	}
-	$translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr;
+        add_translation ($lang, $encoding, $msgctxt, $msgid, $msgstr)
+            if ($inmsgstr);
     }
 }
 
@@ -483,16 +532,15 @@ sub unescape_po_string
     return $string;
 }
 
-## NOTE: deal with < - &lt; but not > - &gt;  because it seems its ok to have 
-## > in the entity. For further info please look at #84738.
 sub entity_decode
 {
     local ($_) = @_;
 
     s/&apos;/'/g; # '
     s/&quot;/"/g; # "
-    s/&amp;/&/g;
     s/&lt;/</g;
+    s/&gt;/>/g;
+    s/&amp;/&/g;
 
     return $_;
 }
@@ -517,6 +565,7 @@ sub entity_encode_int_minimalist
     return "&amp;" if $_ == 38;
     return "&apos;" if $_ == 39;
     return "&lt;" if $_ == 60;
+    return "&gt;" if $_ == 62;
     return chr $_;
 }
 
@@ -752,16 +801,23 @@ sub traverse
 
 	print $fh "<$nodename", $outattr;
 	if ($translate) {
-	    $lookup = getXMLstring($content, $spacepreserve);
+	    $content = getXMLstring($content, $spacepreserve);
             if (!$spacepreserve) {
-                $lookup =~ s/^\s+//s;
-                $lookup =~ s/\s+$//s;
+                $content =~ s/^\s+//s;
+                $content =~ s/\s+$//s;
+            }
+            if (exists $attrs->{"msgctxt"}) {
+                my $context = entity_decode ($attrs->{"msgctxt"});
+                $context =~ s/^["'](.*)["']/$1/;
+                $lookup = "$context\004$content";
+            } else {
+                $lookup = $content;
             }
 
 	    if ($lookup || $translate == 2) {
                 my $translation = $translations{$language, $lookup} if isWellFormedXmlFragment($translations{$language, $lookup});
                 if ($MULTIPLE_OUTPUT && ($translation || $translate == 2)) {
-                    $translation = $lookup if (!$translation);
+                    $translation = $content if (!$translation);
                     print $fh " xml:lang=\"", $language, "\"" if $language;
                     print $fh ">";
                     if ($translate == 2) {
@@ -778,7 +834,7 @@ sub traverse
                     if ($translate == 2) {
                         translate_subnodes($fh, \ all, $language, 1, $spacepreserve);
                     } else {
-                        print $fh $lookup;
+                        print $fh $content;
                     }
                     print $fh "</$nodename>";
                 }
@@ -797,7 +853,7 @@ sub traverse
                         my $localattrs = getAttributeString($attrs, 1, $lang, \$translate);
                         my $translation = $translations{$lang, $lookup} if isWellFormedXmlFragment($translations{$lang, $lookup});
                         if ($translate && !$translation) {
-                            $translation = $lookup;
+                            $translation = $content;
                         }
 
                         if ($translation || $translate) {
@@ -1006,8 +1062,8 @@ sub xml_merge_output
 
     if ($MULTIPLE_OUTPUT) {
         for my $lang (sort keys %po_files_by_lang) {
-	    if ( ! -e $lang ) {
-	        mkdir $lang or die "Cannot create subdirectory $lang: $!\n";
+	    if ( ! -d $lang ) {
+	        mkdir $lang or -d $lang or die "Cannot create subdirectory $lang: $!\n";
             }
             open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n";
             binmode (OUTPUT) if $^O eq 'MSWin32';
@@ -1017,43 +1073,74 @@ sub xml_merge_output
             close OUTPUT;
             print "CREATED $lang/$OUTFILE\n" unless $QUIET_ARG;
         }
-    } 
-    open OUTPUT, ">$OUTFILE" or die "Cannot open $OUTFILE: $!\n";
-    binmode (OUTPUT) if $^O eq 'MSWin32';
-    my $tree = readXml($FILE);
-    print_header($FILE, \*OUTPUT);
-    parseTree(\*OUTPUT, $tree);
-    close OUTPUT;
-    print "CREATED $OUTFILE\n" unless $QUIET_ARG;
+        if ( ! -d "C" ) {
+            mkdir "C" or -d "C" or die "Cannot create subdirectory C: $!\n";
+        }
+        open OUTPUT, ">C/$OUTFILE" or die "Cannot open C/$OUTFILE: $!\n";
+        binmode (OUTPUT) if $^O eq 'MSWin32';
+        my $tree = readXml($FILE);
+        print_header($FILE, \*OUTPUT);
+        parseTree(\*OUTPUT, $tree);
+        close OUTPUT;
+        print "CREATED C/$OUTFILE\n" unless $QUIET_ARG;
+    } else {
+        open OUTPUT, ">$OUTFILE" or die "Cannot open $OUTFILE: $!\n";
+        binmode (OUTPUT) if $^O eq 'MSWin32';
+        my $tree = readXml($FILE);
+        print_header($FILE, \*OUTPUT);
+        parseTree(\*OUTPUT, $tree);
+        close OUTPUT;
+        print "CREATED $OUTFILE\n" unless $QUIET_ARG;
+    }
 }
 
-sub keys_merge_translations
+sub keys_merge_translation
 {
-    open INPUT, "<${FILE}" or die;
-    open OUTPUT, ">${OUTFILE}" or die;
+    my ($lang) = @_;
+
+    if ( ! -d $lang && $MULTIPLE_OUTPUT)
+    {
+        mkdir $lang or -d $lang or die "Cannot create subdirectory $lang: $!\n";
+    }
+
+    open INPUT, "<${FILE}" or die "Cannot open ${FILE}: $!\n";
+    open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n";
     binmode (OUTPUT) if $^O eq 'MSWin32';
 
-    while (<INPUT>) 
+    while (<INPUT>)
     {
-        if (s/^(\s*)_(\w+=(.*))/$1$2/)  
+        if (s/^(\s*)_(\w+=(.*))/$1$2/)
         {
-	    my $string = $3;
+            my $string = $3;
 
-            print OUTPUT;
+            if (!$MULTIPLE_OUTPUT)
+            {
+                print OUTPUT;
 
-	    my $non_translated_line = $_;
+                my $non_translated_line = $_;
 
-            for my $lang (sort keys %po_files_by_lang) 
+                for my $lang (sort keys %po_files_by_lang)
+                {
+                    my $translation = $translations{$lang, $string};
+                    next if !$translation;
+
+                    $_ = $non_translated_line;
+                    s/(\w+)=.*/[$lang]$1=$translation/;
+                    print OUTPUT;
+                }
+            }
+            else
             {
-		my $translation = $translations{$lang, $string};
-                next if !$translation;
+                my $non_translated_line = $_;
+                my $translation = $translations{$lang, $string};
+                $translation = $string if !$translation;
 
                 $_ = $non_translated_line;
-		s/(\w+)=.*/[$lang]$1=$translation/;
+                s/(\w+)=.*/$1=$translation/;
                 print OUTPUT;
             }
-	} 
-        else 
+        }
+        else
         {
             print OUTPUT;
         }
@@ -1061,6 +1148,24 @@ sub keys_merge_translations
 
     close OUTPUT;
     close INPUT;
+
+    print "CREATED $lang/$OUTFILE\n" unless $QUIET_ARG;
+}
+
+sub keys_merge_translations
+{
+    if ($MULTIPLE_OUTPUT)
+    {
+        for my $lang (sort keys %po_files_by_lang)
+        {
+            keys_merge_translation ($lang);
+        }
+        keys_merge_translation ("C");
+    }
+    else
+    {
+        keys_merge_translation (".");
+    }
 }
 
 sub desktop_merge_translations
@@ -1071,7 +1176,7 @@ sub desktop_merge_translations
 
     while (<INPUT>) 
     {
-        if (s/^(\s*)_(\w+=(.*))/$1$2/)  
+        if (s/^(\s*)_([A-Za-z0-9\-]+=(.*))/$1$2/)  
         {
 	    my $string = $3;
 
@@ -1354,3 +1459,42 @@ sub rfc822deb_split
     return @list;
 }
 
+sub quoted_translation
+{
+    my ($xml_mode, $lang, $string) = @_;
+
+    $string = entity_decode($string) if $xml_mode;
+    $string =~ s/\\\"/\"/g;
+
+    my $translation = $translations{$lang, $string};
+    $translation = $string if !$translation;
+    $translation = entity_encode($translation) if $xml_mode;
+    $translation =~ s/\"/\\\"/g;
+    return $translation
+}
+
+sub quoted_merge_translations
+{
+    my ($xml_mode) = @_;
+
+    if (!$MULTIPLE_OUTPUT) {
+        print "Quoted only supports Multiple Output.\n";
+        exit(1);
+    }
+
+    for my $lang (sort keys %po_files_by_lang) {
+        if ( ! -d $lang ) {
+            mkdir $lang or -d $lang or die "Cannot create subdirectory $lang: $!\n";
+        }
+        open INPUT, "<${FILE}" or die;
+        open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n";
+        binmode (OUTPUT) if $^O eq 'MSWin32';
+        while (<INPUT>) 
+        {
+            s/\"(([^\"]|\\\")*[^\\\"])\"/"\"" . &quoted_translation($xml_mode, $lang, $1) . "\""/ge;
+            print OUTPUT;
+        }
+        close OUTPUT;
+        close INPUT;
+    }
+}
diff --git a/configure.in b/configure.in
index 726676d..32e1ec3 100644
--- a/configure.in
+++ b/configure.in
@@ -1,8 +1,10 @@
-dnl # Birnet
-dnl # GNU Lesser General Public License version 2 or any later version.
+# Birnet
+# GNU Lesser General Public License version 2 or any later version.
 
-# include BEAST specific macros
+# include various m4 macros
 builtin(include, birnet/acbirnet.m4)dnl
+m4_include(autotools/glib-gettext.m4)
+
 
 #
 # Configure script for BEAST/BSE
@@ -162,39 +164,45 @@ AC_DEFUN([DUMMY_DEFS],
 dnl #
 dnl # Define package requirements.
 dnl #
-dnl ## include acintltool.m4 to provide IT_PROG_INTLTOOL
-builtin(include, acintltool.m4)dnl
 AC_DEFUN([AC_I18N_REQUIREMENTS],
 [
-    ALL_LINGUAS=`cat "$srcdir/po/LINGUAS" | grep -v '^#' | xargs echo -n `
-    AC_SUBST(ALL_LINGUAS)
-    AC_SUBST([CONFIG_STATUS_DEPENDENCIES], ['$(top_srcdir)/po/LINGUAS'])
-
-    dnl # versioned BEAST gettext domain (po/)
-    BST_GETTEXT_DOMAIN=beast-v$BIN_VERSION    # version without -rcZ
-    AC_SUBST(BST_GETTEXT_DOMAIN)
-    AC_DEFINE_UNQUOTED(BST_GETTEXT_DOMAIN, "$BST_GETTEXT_DOMAIN", [Versioned BEAST gettext domain])
-    GETTEXT_PACKAGE=$BST_GETTEXT_DOMAIN
-    AC_SUBST(GETTEXT_PACKAGE)
-
-    dnl # locale directory for all domains
-    dnl # (AM_GLIB_DEFINE_LOCALEDIR() could do this if it would do AC_SUBST())
-    saved_prefix="$prefix"
-    saved_exec_prefix="$exec_prefix"
-    test "x$prefix" = xNONE && prefix=$ac_default_prefix
-    test "x$exec_prefix" = xNONE && exec_prefix=$prefix
-    if test "x$CATOBJEXT" = "x.mo" ; then
-      beastlocaledir=`eval echo "${libdir}/locale"`
-    else
-      beastlocaledir=`eval echo "${datadir}/locale"`
-    fi
-    exec_prefix="$saved_exec_prefix"
-    prefix="$saved_prefix"
-    AC_SUBST(beastlocaledir)
-
-    dnl # do gettext checks and prepare for intltool
-    AM_GLIB_GNU_GETTEXT
-    IT_PROG_INTLTOOL
+  # LINGUAS
+  ALL_LINGUAS=`cat "$srcdir/po/LINGUAS" | grep -v '^#' | xargs echo -n `
+  AC_SUBST(ALL_LINGUAS)
+  AC_SUBST([CONFIG_STATUS_DEPENDENCIES], ['$(top_srcdir)/po/LINGUAS'])
+
+  # versioned BEAST gettext domain (po/)
+  BST_GETTEXT_DOMAIN=beast-v$BIN_VERSION    # version without -rcZ
+  AC_SUBST(BST_GETTEXT_DOMAIN)
+  AC_DEFINE_UNQUOTED(BST_GETTEXT_DOMAIN, "$BST_GETTEXT_DOMAIN", [Versioned BEAST gettext domain])
+  GETTEXT_PACKAGE=$BST_GETTEXT_DOMAIN
+  AC_SUBST(GETTEXT_PACKAGE)
+
+  # locale directory for all domains
+  # (AM_GLIB_DEFINE_LOCALEDIR() could do this if it would do AC_SUBST())
+  saved_prefix="$prefix"		; saved_exec_prefix="$exec_prefix"
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix="$prefix"
+  if test "x$CATOBJEXT" = "x.mo" ; then
+    beastlocaledir=`eval echo "${libdir}/locale"`
+  else
+    beastlocaledir=`eval echo "${datadir}/locale"`
+  fi
+  exec_prefix="$saved_exec_prefix"	; prefix="$saved_prefix"
+  AC_SUBST(beastlocaledir)
+
+  # check for proper gettext support
+  AM_GLIB_GNU_GETTEXT([external])
+  test -z "$ac_cv_path_XGETTEXT" && {
+    AC_MSG_ERROR(["Failed to detect gettext, required for internationalization." \
+      "GNU gettext is available from: http://www.gnu.org/software/gettext/";])
+  }
+
+  # check for gettext utilities
+  AC_PATH_PROG(ICONV, iconv, iconv)
+  AC_PATH_PROG(MSGFMT, msgfmt, msgfmt)
+  AC_PATH_PROG(MSGMERGE, msgmerge, msgmerge)
+  AC_PATH_PROG(XGETTEXT, xgettext, xgettext)
 ])
 AC_DEFUN([AC_SFI_REQUIREMENTS],
 [
@@ -623,8 +631,7 @@ library/skins/Makefile
 library/skins/images/Makefile
 tools/Makefile
 tools/scripts/Makefile
-po/Makefile.in
-po-helper.sh
+po/Makefile
 tests/Makefile
 tests/latency/Makefile
 tests/scripts/Makefile
diff --git a/data/Makefile.am b/data/Makefile.am
index d379421..5d2cc48 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -53,7 +53,11 @@ CLEANFILES += beast-audio-x-bse.png
 EXTRA_DIST += $(sharedpixmaps_DATA)
 
 # generate and install .desktop file
- INTLTOOL_DESKTOP_RULE@
+# FIXME: INTLTOOL_DESKTOP_RULE
+%.desktop: %.desktop.in
+	$(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; \
+	LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache \
+			$(top_srcdir)/po $< $@
 dotdesktopdir = $(datadir)/applications
 dotdesktop_in_files = beast.desktop.in
 dotdesktop_DATA = $(dotdesktop_in_files:.desktop.in=.desktop)
@@ -62,7 +66,11 @@ CLEANFILES += beast.desktop
 EXTRA_DIST += $(dotdesktop_in_files)
 
 # generate and install .xml mime info file
- INTLTOOL_XML_RULE@
+# FIXME: INTLTOOL_XML_RULE
+%.xml: %.xml.in
+	$(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; \
+	LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache \
+		$(top_srcdir)/po $< $@
 sharedmimedir = $(datadir)/mime
 sharedmimepackagedir = $(sharedmimedir)/packages
 sharedmimepackage_in_files = beast.xml.in
@@ -72,7 +80,11 @@ beast.xml: beast.xml.in
 EXTRA_DIST += $(sharedmimepackage_in_files)
 
 # generate and install .mime and .keys files
- INTLTOOL_KEYS_RULE@
+# FIXME: INTLTOOL_KEYS_RULE
+%.keys: %.keys.in
+	$(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; \
+	LC_ALL=C $(INTLTOOL_MERGE) -k -u -c $(top_builddir)/po/.intltool-merge-cache \
+		$(top_srcdir)/po $< $@
 mimedir = $(datadir)/mime-info
 mime_in_file = bse.keys.in bse.mime
 mime_DATA = $(mime_in_file:.keys.in=.keys)
diff --git a/po/LINGUAS b/po/LINGUAS
index bd47a57..f9e1964 100644
--- a/po/LINGUAS
+++ b/po/LINGUAS
@@ -1,5 +1,4 @@
-# please keep this list sorted alphabetically
-#
+#0 please keep this list sorted alphabetically
 ar
 az
 bg
diff --git a/po/Makefile.am b/po/Makefile.am
new file mode 100644
index 0000000..d6629d3
--- /dev/null
+++ b/po/Makefile.am
@@ -0,0 +1,198 @@
+## Process this file with automake to generate Makefile.in
+# Copyright (C) 2010 Tim Janik
+#
+# This work is provided "as is"; see: http://beast.gtk.org/mirror/LICENSE-AS-IS
+include $(top_srcdir)/Makefile.decl
+AUTOMAKE_OPTIONS = -Wno-portability
+
+POSRC_TYPES =
+
+# Variables:
+# ALL_LINGUAS : setup by configure.ac from po/LINGUAS
+# PO_LINGUAS  : command line override for ALL_LINGUAS (subset)
+# GMOFILES    : .gmo files for all TRANSLATIONS (GNU .mo)
+# POFILES     : .po files for all TRANSLATIONS
+# DATADIRNAME : setup by GLIB_GNU_GETTEXT for installation
+# Files:
+# POTSCAN     : list of project sources with translations
+# POTSKIP     : list of translatable project sources to skip
+# POTIGNORE   : ERE patterns of project sources to ignore
+# LINGUAS     : list of supported languages
+# unlisted    : (Makefile target) files missing from POTSCAN
+
+# Translatable file types
+#
+POSRC_TYPES          += XML
+POSRC_XML_PATTERN     = '\.xml\(.in\)\?$$'
+POSRC_XML_FILTER      = gawk -f ./autotools/intlfix-xml.awk
+#
+POSRC_TYPES          += SCM
+POSRC_SCM_PATTERN     = '\.scm\(.in\)\?$$'
+POSRC_SCM_FILTER      = sed -f ./autotools/intlfix-scm.sed
+#
+POSRC_TYPES          += KEYS
+POSRC_KEYS_PATTERN    = '\.keys\(.in\)\?$$'
+POSRC_KEYS_FILTER     = gawk -f ./autotools/intlfix-las.awk
+#
+POSRC_TYPES          += DESKTOP
+POSRC_DESKTOP_PATTERN = '\.desktop\(.in\)\?$$'
+POSRC_DESKTOP_FILTER  = gawk -f ./autotools/intlfix-las.awk
+#
+POSRC_TYPES          += IDL
+POSRC_IDL_PATTERN     = '\.idl\(.in\)\?$$'
+POSRC_IDL_FILTER      =
+#
+POSRC_TYPES          += PROC
+POSRC_PROC_NAME	      = Procedure Files
+POSRC_PROC_PATTERN    = '\.proc\(.in\)\?$$'
+POSRC_PROC_FILTER     =
+#
+POSRC_TYPES          += CCH
+POSRC_CCH_NAME	      = C/C++ Files
+POSRC_CCH_PATTERN     = '\.[hcHC][hcHC]\?\(.in\)\?$$'
+POSRC_CCH_FILTER      =
+
+# FIXME: XML awk needs to \n-escape newlines to avoid unterminated string literals
+
+TRANSLATIONS = $(if ${PO_LINGUAS}, ${PO_LINGUAS}, ${ALL_LINGUAS})
+GMOFILES     = $(patsubst %, %.gmo, $(TRANSLATIONS))
+POFILES      = $(patsubst %, %.po,  $(TRANSLATIONS))
+EXTRA_DIST  += $(POFILES) messages.pot
+CLEANFILES  += $(GMOFILES)
+KEYWORDS     = _ N_ U_ Q_
+TEXTFLAGS    = _:1:pass-c-format
+POTLIST      = $(abs_builddir)/POTLIST
+TMPLIST      = $(abs_builddir)/POTLIST.tmp
+TMPDIR       = tmp-cpots
+I18NPATTERN  = '\b[NUQ]\?_[[:space:]]*([[:space:]]*"'
+INLTFIXPATTERN = '\b__INTLFIX__\b.*'$(I18NPATTERN)
+LOCALEDIR    = $(prefix)/$(DATADIRNAME)/locale
+NEWLINE	    := $(shell echo)
+
+all: $(GMOFILES)
+
+# compile translation catalogs
+%.gmo: %.po
+	@echo $(ECHO_N) "$(@F): " \
+	&& $(GMSGFMT) --statistics --directory=$(srcdir) -o xgen-$(@F) $< \
+	&& mv xgen-$(@F) $@
+
+# install translation catalogs
+install: install-data
+install-data: $(GMOFILES)
+	@echo "Installing localised message files..."
+	@for lang in $(TRANSLATIONS); do \
+	  $(mkinstalldirs) "$(DESTDIR)$(LOCALEDIR)/$$lang/LC_MESSAGES/"; \
+	  test ! -r "$$lang.gmo" || { \
+	    printf "  %-12s -> %s\n" "$$lang.gmo" ".../$$lang/$(BST_GETTEXT_DOMAIN).mo" ; \
+            $(INSTALL_DATA) "$$lang.gmo" \
+	      "$(DESTDIR)$(LOCALEDIR)/$$lang/LC_MESSAGES/$(BST_GETTEXT_DOMAIN).mo" || exit 1 ; \
+	  } ; \
+	done
+uninstall:
+	@echo $(ECHO_N) "Uninstalling message files..."
+	@for lang in $(TRANSLATIONS); do \
+	  test -n "$$c" && test "$$c" -le 6 || { c=0; printf "\n  "; }; c=$$(($$c + 1)) ; \
+	  printf "%-10s" "$$lang" ; \
+	  rm -f "$(DESTDIR)$(LOCALEDIR)/$$lang/LC_MESSAGES/$(BST_GETTEXT_DOMAIN).mo" ; \
+	done ; test "$$c" = 0 || echo
+
+# check for translatable files missing from POTSCAN
+check-local: check-unlisted
+check-unlisted:
+	@echo "Check top source directory for missing translations..."
+	@$(MAKE) unlisted
+	@! test -e unlisted
+
+# force regeneration of all po files
+update-po: Makefile
+	@rm -f $(srcdir)/messages.pot # force rebuild
+	@$(MAKE) --no-print-directory $(srcdir)/messages.pot
+	@echo "Merging messages.pot into po files..."
+	@for i in $(POFILES) ; do \
+	  printf "%12s: " "$$i" ; \
+	  $(MSGMERGE) -qsU --backup=none $(srcdir)/$$i $(srcdir)/messages.pot || exit 1 ; \
+	  $(GMSGFMT) -o /dev/null --verbose $(srcdir)/$$i ; \
+	done
+.PHONY: update-po
+
+$(srcdir)/messages.pot:
+	@echo "Rebuilding $(@F)..."
+	@rm -f $(POTLIST) $(TMPLIST) ; rm -rf $(TMPDIR)/
+	@sed -e '/^#/d' -e 's/^\[[^:]*:[^]]*][[:space:]]*//' -e '/^[[:space:]]*$$/d' < POTSCAN > $(POTLIST) \
+	&& cp $(POTLIST) $(TMPLIST) && mkdir -p $(TMPDIR)/
+	@$(foreach TYPE, $(POSRC_TYPES), \
+	  $(call prepare_pot_source, $(TYPE), $(TMPLIST)))
+	@test `wc -l < $(TMPLIST)` -eq 0 || { \
+	  echo "WARNING: unknown POTSCAN entries:" ; \
+	  sed 's/^/  /' $(TMPLIST) ; \
+	} >&2
+	@echo "  Extracting translatable strings with xgettext..."
+	@$(XGETTEXT) -F -c -n -o $(abs_srcdir)/$(@F) --foreign-user \
+	  --language=C++ --from-code=UTF-8 \
+	  --files-from=$(POTLIST) \
+	  -D $(TMPDIR)/ -D $(abs_top_srcdir) \
+	  $(patsubst %, --keyword=%, $(KEYWORDS)) \
+	  $(patsubst %, --flag=%,    $(TEXTFLAGS)) \
+	  "--package-name=$(PACKAGE)" "--package-version=$(VERSION)"
+	@rm -f $(POTLIST) $(TMPLIST) ; rm -rf $(TMPDIR)/
+# (split_lines, INPUT, OUTPUT, pattern)
+split_lines = test -e $(1) -a -w . && { \
+	grep  -e $(3) < $(1) > $(2) ; \
+	grep -ve $(3) < $(1) > $(1)-$$$$ ; \
+	mv $(1)-$$$$ $(1) ; \
+}
+# (prepare_pot_source, POSRC_TYPE, INFILE)
+define prepare_pot_source
+	DOING=$(if $(POSRC_$(strip $(1))_FILTER),"Preparing","Listing"); \
+	printf "  %-32s" "$$DOING $(strip $(or $(POSRC_$(strip $(1))_NAME), $(1) Files)): " ; \
+	$(call split_lines, $(2), "potlist$$$$.tmp", $(POSRC_$(strip $(1))_PATTERN)) ; \
+	wc -l < "potlist$$$$.tmp" ; \
+	$(if $(POSRC_$(strip $(1))_FILTER), \
+	  cat "potlist$$$$.tmp" | \
+	  while read file ; do \
+	    d=`dirname "$$file"` ; mkdir -p "$(TMPDIR)/$$d" || exit $$? ; \
+	    (cd $(top_srcdir) && $(POSRC_$(strip $(1))_FILTER) "$$file") > "$(TMPDIR)/$$file" \
+	    || exit $$? ; \
+	  done \
+	, \
+	  : \
+	) ; rm -f "potlist$$$$.tmp"
+	$(NEWLINE)
+endef # GNU Make needs an explicit last newline
+
+unlisted:
+	@echo "Creating source file list..."
+	@rm -f unlisted
+	@ # list possible POT sources...
+	@(cd $(top_srcdir) && find . $(FIND_NOHIDDEN) -type f -print) | sed 's,^\./,,' \
+	| if test -e POTSCAN   ; then grep -vFf POTSCAN   ; else cat ; fi \
+	| if test -e POTSKIP   ; then grep -vFf POTSKIP   ; else cat ; fi \
+	| if test -e POTIGNORE ; then grep -vEf POTIGNORE ; else cat ; fi \
+	> "xgen-$(@F)"
+	@ # scanning file types...
+	@$(foreach TYPE, $(POSRC_TYPES), \
+	  $(call test_unlisted, $(TYPE), "xgen-$(@F)", "unlisted"))
+	@rm -f "xgen-$(@F)"
+	@ # report...
+	@test `wc -l <unlisted` -gt 0 || rm -f unlisted
+	@if test -e unlisted ; then \
+	  echo "Found `wc -l <unlisted` untranslated files, see:"; ls -l "`pwd`/unlisted" ; \
+	else echo "Done, all files listed." ; fi
+FIND_NOHIDDEN = \( -name '.?*' -prune -false -o ! -name '.?*' \) # skip .foobar dirs & files
+# (test_unlisted, POSRC_TYPE, INFILE, OUTFILE)
+define test_unlisted
+	printf "  %-32s" "Scanning $(strip $(or $(POSRC_$(strip $(1))_NAME), $(1) Files)): " ; \
+	grep $(POSRC_$(strip $(1))_PATTERN) $(2) | \
+	  $(if $(POSRC_$(strip $(1))_FILTER), \
+	    while read file ; do \
+	      (cd $(top_srcdir) && INTLFIX=:marker: $(POSRC_$(strip $(1))_FILTER) "$$file") | \
+	      grep -q $(INLTFIXPATTERN) && echo "$$file" ; \
+	    done \
+	  , \
+	    (cd $(top_srcdir) && xargs grep -l $(I18NPATTERN) ) \
+	  ) | tee -a $(3) | wc -l
+	$(NEWLINE)
+endef # GNU Make needs an explicit last newline
+.PHONY: unlisted
+CLEANFILES += unlisted
diff --git a/po/POTIGNORE b/po/POTIGNORE
new file mode 100644
index 0000000..64f86fa
--- /dev/null
+++ b/po/POTIGNORE
@@ -0,0 +1,4 @@
+#0 List of source files to scan for translatable strings
+#0 Please keep alphabetically sorted
+.*\.genidl\.hh
+.*\.genprc\.c
diff --git a/po/POTFILES.in b/po/POTSCAN
similarity index 85%
rename from po/POTFILES.in
rename to po/POTSCAN
index dc6d548..beb1f9b 100644
--- a/po/POTFILES.in
+++ b/po/POTSCAN
@@ -1,11 +1,11 @@
-# List of source files containing translatable strings.
-# Please keep this file sorted alphabetically
-[type: gettext/scm-funcs] library/scripts/mixer-splitup-by-track.scm
-[type: gettext/scm-funcs] library/scripts/modules2grid.scm
-[type: gettext/scm-funcs] library/scripts/part-harmonic-transposer.scm
-[type: gettext/scm-funcs] library/scripts/progressor-example.scm
-[type: gettext/scm-funcs] library/scripts/record-midi.scm
-[type: gettext/scm-funcs] library/scripts/song-parts-operations.scm
+#0 List of source files to scan for translatable strings
+#0 Please keep alphabetically sorted
+library/scripts/mixer-splitup-by-track.scm
+library/scripts/modules2grid.scm
+library/scripts/part-harmonic-transposer.scm
+library/scripts/progressor-example.scm
+library/scripts/record-midi.scm
+library/scripts/song-parts-operations.scm
 beast-gtk/bstapp.c
 beast-gtk/bstauxdialogs.c
 beast-gtk/bstbuseditor.c
diff --git a/po/POTFILES.skip b/po/POTSKIP
similarity index 53%
rename from po/POTFILES.skip
rename to po/POTSKIP
index 87f01b9..ea191d4 100644
--- a/po/POTFILES.skip
+++ b/po/POTSKIP
@@ -1,5 +1,5 @@
-# List of source files that should *not* be translated.
-# Please keep this file sorted alphabetically
+#0 List of source files to scan for translatable strings
+#0 Please keep alphabetically sorted
 beast-gtk/bststest.c
 plugins/bsefirfilter.c
 plugins/davguitar.c



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]