summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorptomulik <ptomulik@meil.pw.edu.pl>2012-06-06 22:14:26 +0200
committerptomulik <ptomulik@meil.pw.edu.pl>2012-06-06 22:14:26 +0200
commit8bb5b81da48b79298f6c122ac4e03727f2733051 (patch)
treece81b8f9455c354c8a85e77134b0ece9b5903c66
parentec74799028d501d7e49e0fbae5a56b7744c0826e (diff)
downloadscons-8bb5b81da48b79298f6c122ac4e03727f2733051.tar.gz
Added gettext tools
-rw-r--r--doc/user/MANIFEST1
-rw-r--r--doc/user/gettext.in351
-rw-r--r--doc/user/gettext.xml335
-rw-r--r--doc/user/main.in6
-rw-r--r--src/engine/MANIFEST.in11
-rw-r--r--src/engine/SCons/Tool/GettextCommon.py444
-rw-r--r--src/engine/SCons/Tool/gettext.py47
-rw-r--r--src/engine/SCons/Tool/gettext.xml239
-rw-r--r--src/engine/SCons/Tool/msgfmt.py101
-rw-r--r--src/engine/SCons/Tool/msgfmt.xml101
-rw-r--r--src/engine/SCons/Tool/msginit.py111
-rw-r--r--src/engine/SCons/Tool/msginit.xml167
-rw-r--r--src/engine/SCons/Tool/msgmerge.py97
-rw-r--r--src/engine/SCons/Tool/msgmerge.xml157
-rw-r--r--src/engine/SCons/Tool/xgettext.py331
-rw-r--r--src/engine/SCons/Tool/xgettext.xml288
-rw-r--r--test/GETTEXT/Translate_doc_user_examples1.py74
-rw-r--r--test/GETTEXT/Translate_doc_user_examples2.py86
-rw-r--r--test/GETTEXT/Translate_doc_user_examples3.py108
-rw-r--r--test/GETTEXT/doc_user_examples1.py58
-rw-r--r--test/MSGFMT/MOFile_doc_user_examples1.py114
-rw-r--r--test/MSGFMT/MOFile_doc_user_examples2.py114
-rw-r--r--test/MSGFMT/MOFile_doc_user_examples3.py163
-rw-r--r--test/MSGFMT/MOFile_doc_user_examples4.py115
-rw-r--r--test/MSGINIT/POinit_doc_user_examples1.py87
-rw-r--r--test/MSGINIT/POinit_doc_user_examples2.py87
-rw-r--r--test/MSGINIT/POinit_doc_user_examples3.py87
-rw-r--r--test/MSGINIT/POinit_doc_user_examples4.py91
-rw-r--r--test/MSGINIT/POinit_doc_user_examples5.py93
-rw-r--r--test/MSGINIT/POinit_doc_user_examples6.py93
-rw-r--r--test/MSGMERGE/POUpdate_doc_user_examples1.py137
-rw-r--r--test/MSGMERGE/POUpdate_doc_user_examples2.py137
-rw-r--r--test/MSGMERGE/POUpdate_doc_user_examples3.py138
-rw-r--r--test/MSGMERGE/POUpdate_doc_user_examples4.py144
-rw-r--r--test/MSGMERGE/POUpdate_doc_user_examples5.py143
-rw-r--r--test/MSGMERGE/POUpdate_doc_user_examples6.py194
-rw-r--r--test/MSGMERGE/POUpdate_doc_user_examples8.py74
-rw-r--r--test/XGETTEXT/POTUpdate_doc_user_examples1.py82
-rw-r--r--test/XGETTEXT/POTUpdate_doc_user_examples2.py70
-rw-r--r--test/XGETTEXT/POTUpdate_doc_user_examples3.py67
-rw-r--r--test/XGETTEXT/POTUpdate_doc_user_examples4.py67
-rw-r--r--test/XGETTEXT/POTUpdate_doc_user_examples5.py81
42 files changed, 5491 insertions, 0 deletions
diff --git a/doc/user/MANIFEST b/doc/user/MANIFEST
index 0994f2b0..21c63b01 100644
--- a/doc/user/MANIFEST
+++ b/doc/user/MANIFEST
@@ -18,6 +18,7 @@ example.xml
factories.xml
file-removal.xml
functions.xml
+gettext.xml
hierarchy.xml
install.xml
java.xml
diff --git a/doc/user/gettext.in b/doc/user/gettext.in
new file mode 100644
index 00000000..63c1d201
--- /dev/null
+++ b/doc/user/gettext.in
@@ -0,0 +1,351 @@
+<!--
+
+ __TOOL_COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+ <para>
+ The &t-link-gettext; toolset supports internationalization and localization
+ of SCons-based projects. The tools provided within &t-link-gettext; by
+ automatize generation and updates of translation files. You can manage
+ translations and translation templates simillary as it was done with
+ autotools.
+ </para>
+
+ <section>
+ <title>Prerequisites</title>
+ <para>
+ Setup your operating system, so you can use several languages. In following
+ examples we use locales <literal>en_US</literal>, <literal>de_DE</literal>,
+ and <literal>pl_PL</literal>.
+ </para>
+
+ <para>
+ Ensure, that you have <ulink
+ url="http://www.gnu.org/software/gettext/manual/gettext.html">GNU gettext
+ utilities</ulink> installed on your system.
+ </para>
+
+ <para>
+ To edit translation files, you may install <ulink
+ url="http://www.poedit.net/">poedit</ulink> editor.
+ </para>
+ </section>
+
+ <section>
+ <title>Simple project</title>
+ <para>
+ Let's start with some simple project, the "Hello world" program
+ for example
+ <scons_example name="ex1">
+ <file name="hello.c" printme="1">
+ /* hello.c */
+ #include &lt;stdio.h&gt;
+ int main(int argc, char* argv[])
+ {
+ printf("Hello world\n");
+ return 0;
+ }
+ </file>
+ </scons_example>
+
+ Prepare simple <filename>SConstruct</filename> script to compile the
+ program.
+ <scons_example name="ex2">
+ <file name="SConstruct" printme="1">
+ # SConstruct
+ env = Environment()
+ hello = Program(["hello.c"])
+ </file>
+ </scons_example>
+ </para>
+
+ <para>
+ Now we'll convert the project to multi-lingual one. I assume, that you
+ already have <ulink
+ url="http://www.gnu.org/software/gettext/manual/gettext.html">GNU gettext
+ utilities</ulink> installed. If not, install it from repository, or
+ download from <ulink url="http://ftp.gnu.org/gnu/gettext/">
+ http://ftp.gnu.org/gnu/gettext/</ulink>. For the purpose of this example,
+ you should have following three locales installed on your system
+ <literal>en_US</literal>, <literal>de_DE</literal> and
+ <literal>pl_PL</literal>. On debian, for example, you may enable certain
+ locales through <command>dpkg-reconfigure locales</command>.
+ </para>
+
+ <para>
+ We first prepare the <filename>hello.c</filename> program, for
+ internationalization. Change the previous code so it reads as follows:
+ <scons_example name="ex3">
+ <file name="hello.c" printme="1">
+ /* hello.c */
+ #include &lt;stdio.h&gt;
+ #include &lt;libintl.h&gt;
+ #include &lt;locale.h&gt;
+ int main(int argc, char* argv[])
+ {
+ bindtextdomain("hello", "locale");
+ setlocale(LC_ALL, "");
+ textdomain("hello");
+ printf(gettext("Hello world\n"));
+ return 0;
+ }
+ </file>
+ </scons_example>
+ This way we prepared source code. Detailed recipes for such preparation can
+ be found at <ulink
+ url="http://www.gnu.org/software/gettext/manual/gettext.html#Sources">
+ http://www.gnu.org/software/gettext/manual/gettext.html#Sources</ulink>.
+ The <function>gettext("...")</function> in above source has two purposes.
+ First is is recognized by the <command>xgettext(1)</command> program, which
+ we will use to extract from the sources the messages for localization.
+ Second, it calls the <literal>gettext</literal> library internals to
+ translate the message at runtime.
+ </para>
+
+ <para>
+ Now we shall instruct SCons how to generate and maintain translation files.
+ For that, we use &b-link-Translate; builder and &b-link-MOFiles; builder.
+ First one takes a couple of source files, extracts internationalized
+ messages from them, creates so-called <literal>POT</literal> file
+ (translation template), and then creates <literal>PO</literal> translation
+ files, one for each requested language. Later, during the development
+ lifecycle, the builder keeps all these files up-to date. The
+ &b-link-MOFiles; builder compiles the <literal>PO</literal> files to binary
+ form. After all, we install the <literal>MO</literal> files under directory
+ called <filename>locale</filename>.
+ </para>
+
+ <para> The complete code of
+ <filename>SConstruct</filename> script for multi-lingual "Hello world" will
+ be following:
+ <scons_example name="ex4">
+ <file name="SConstruct" printme="1">
+ # SConstruct
+ env = Environment( tools = ['default', 'gettext'] )
+ hello = env.Program(["hello.c"])
+ env['XGETTEXTFLAGS'] = [
+ '--package-name=%s' % 'hello',
+ '--package-version=%s' % '1.0',
+ ]
+ po = env.Translate(["pl","en", "de"], ["hello.c"], POAUTOINIT = 1)
+ mo = env.MOFiles(po)
+ InstallAs(["locale/en/LC_MESSAGES/hello.mo"], ["en.mo"])
+ InstallAs(["locale/pl/LC_MESSAGES/hello.mo"], ["pl.mo"])
+ InstallAs(["locale/de/LC_MESSAGES/hello.mo"], ["de.mo"])
+ </file>
+ </scons_example>
+ </para>
+ <para>
+ Generate translation files with <command>scons po-update</command>.
+ You should see the output from SCons simillar to this:
+ <screen>
+ ptomulik@:$ scons po-update
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ Entering '/home/ptomulik/projects/tmp'
+ xgettext --package-name=hello --package-version=1.0 -o - hello.c
+ Leaving '/home/ptomulik/projects/tmp'
+ Writting 'messages.pot' (new file)
+ msginit --no-translator -l pl -i messages.pot -o pl.po
+ Created pl.po.
+ msginit --no-translator -l en -i messages.pot -o en.po
+ Created en.po.
+ msginit --no-translator -l de -i messages.pot -o de.po
+ Created de.po.
+ scons: done building targets.
+ </screen>
+ </para>
+
+ <para>
+ If everything is right, you shall see following new files.
+ <screen>
+ ptomulik@:$ ls *.po*
+ de.po en.po messages.pot pl.po
+ </screen>
+ </para>
+
+ <para>
+ Open <filename>en.po</filename> in <command>poedit</command> and provide
+ english "translation" to message <literal>"Hello world\n"</literal>. Do the
+ same for <filename>de.po</filename> (deutsch) and
+ <filename>pl.po</filename> (polish). Let the translations be, for example:
+ <itemizedlist>
+ <listitem><para>
+ <literal>en: "Welcome to beautiful world!\n"</literal>
+ </para></listitem>
+ <listitem><para>
+ <literal>de: "Hallo Welt!\n"</literal>
+ </para></listitem>
+ <listitem><para>
+ <literal>pl: "Witaj swiecie!\n"</literal>
+ </para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Now compile the project by executing <command>scons</command> command. The
+ output should be similar to this:
+ <screen>
+ ptomulik@:$ scons
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ msgfmt -c -o de.mo de.po
+ msgfmt -c -o en.mo en.po
+ gcc -o hello.o -c hello.c
+ gcc -o hello hello.o
+ Install file: "de.mo" as "locale/de/LC_MESSAGES/hello.mo"
+ Install file: "en.mo" as "locale/en/LC_MESSAGES/hello.mo"
+ msgfmt -c -o pl.mo pl.po
+ Install file: "pl.mo" as "locale/pl/LC_MESSAGES/hello.mo"
+ scons: done building targets.
+ </screen>
+ SCons automatically compiled <literal>PO</literal> files to binary format
+ <literal>MO</literal>, and the <literal>InstallAs</literal> lines installed
+ these files under <filename>locale</filename> folder.
+ </para>
+ <para>
+ Your program should be now ready. You may try it as follows (linux):
+ <screen>
+ ptomulik@:$ LANG=en_US.UTF-8 ./hello
+ Welcome to beautiful world
+ </screen>
+ <screen>
+ ptomulik@:$ LANG=de_DE.UTF-8 ./hello
+ Hallo Welt
+ </screen>
+ <screen>
+ ptomulik@:$ LANG=pl_PL.UTF-8 ./hello
+ Witaj swiecie
+ </screen>
+ </para>
+ <para>
+ To demonstrate further life of translation files, let's change polish
+ translation (<command>poedit pl.po</command>) to <literal>"Witaj drogi
+ swiecie\n"</literal>. Run <command>scons</command> to see how scons
+ reacts to this
+ <screen>
+ ptomulik@:$scons
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ msgfmt -c -o pl.mo pl.po
+ Install file: "pl.mo" as "locale/pl/LC_MESSAGES/hello.mo"
+ scons: done building targets.
+ </screen>
+ </para>
+ <para>
+ Now, open <filename>hello.c</filename> and add another one
+ <literal>printf</literal> line with new message.
+ <scons_example name="ex5">
+ <file name="hello.c" printme="1">
+ /* hello.c */
+ #include &lt;stdio.h&gt;
+ #include &lt;libintl.h&gt;
+ #include &lt;locale.h&gt;
+ int main(int argc, char* argv[])
+ {
+ bindtextdomain("hello", "locale");
+ setlocale(LC_ALL, "");
+ textdomain("hello");
+ printf(gettext("Hello world\n"));
+ printf(gettext("and good bye\n"));
+ return 0;
+ }
+ </file>
+ </scons_example>
+ </para>
+ <para>
+ Compile project with <command>scons</command>. This time, the
+ <command>msgmerge(1)</command> program is used by SCons to update
+ <literal>PO</literal> file. The output from compilation is like:
+ <screen>
+ ptomulik@:$scons
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ Entering '/home/ptomulik/projects/tmp'
+ xgettext --package-name=hello --package-version=1.0 -o - hello.c
+ Leaving '/home/ptomulik/projects/tmp'
+ Writting 'messages.pot' (messages in file were outdated)
+ msgmerge --update de.po messages.pot
+ ... done.
+ msgfmt -c -o de.mo de.po
+ msgmerge --update en.po messages.pot
+ ... done.
+ msgfmt -c -o en.mo en.po
+ gcc -o hello.o -c hello.c
+ gcc -o hello hello.o
+ Install file: "de.mo" as "locale/de/LC_MESSAGES/hello.mo"
+ Install file: "en.mo" as "locale/en/LC_MESSAGES/hello.mo"
+ msgmerge --update pl.po messages.pot
+ ... done.
+ msgfmt -c -o pl.mo pl.po
+ Install file: "pl.mo" as "locale/pl/LC_MESSAGES/hello.mo"
+ scons: done building targets.
+ </screen>
+ </para>
+ <para>
+ The last example demonstrates what happens, if we change the source code
+ in such way, that the internationalized messages do not change. The answer
+ is, that none of translation files (<literal>POT</literal>,
+ <literal>PO</literal>) is touched (i.e. no content changes, no
+ creation/modification time changed and so on). Let's append another one
+ instruction to the program (after the last printf), so its code becomes:
+ <scons_example name="ex6">
+ <file name="hello.c" printme="1">
+ /* hello.c */
+ #include &lt;stdio.h&gt;
+ #include &lt;libintl.h&gt;
+ #include &lt;locale.h&gt;
+ int main(int argc, char* argv[])
+ {
+ bindtextdomain("hello", "locale");
+ setlocale(LC_ALL, "");
+ textdomain("hello");
+ printf(gettext("Hello world\n"));
+ printf(gettext("and good bye\n"));
+ printf("----------------\n");
+ return a;
+ }
+ </file>
+ </scons_example>
+ Compile project. You'll see on your screen
+ <screen>
+ ptomulik@:$scons
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ Entering '/home/ptomulik/projects/tmp'
+ xgettext --package-name=hello --package-version=1.0 -o - hello.c
+ Leaving '/home/ptomulik/projects/tmp'
+ Not writting 'messages.pot' (messages in file found to be up-to-date)
+ gcc -o hello.o -c hello.c
+ gcc -o hello hello.o
+ scons: done building targets.
+ </screen>
+ As you see, the internationalized messages ditn't change, so the
+ <literal>POT</literal> and the rest of translation files have not
+ even been touched.
+ </para>
+ </section>
diff --git a/doc/user/gettext.xml b/doc/user/gettext.xml
new file mode 100644
index 00000000..9b1b6313
--- /dev/null
+++ b/doc/user/gettext.xml
@@ -0,0 +1,335 @@
+<!--
+
+ __TOOL_COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+ <para>
+ The &t-link-gettext; toolset supports internationalization and localization
+ of SCons-based projects. The tools provided within &t-link-gettext; by
+ automatize generation and updates of translation files. You can manage
+ translations and translation templates simillary as it was done with
+ autotools.
+ </para>
+
+ <section>
+ <title>Prerequisites</title>
+ <para>
+ Setup your operating system, so you can use several languages. In following
+ examples we use locales <literal>en_US</literal>, <literal>de_DE</literal>,
+ and <literal>pl_PL</literal>.
+ </para>
+
+ <para>
+ Ensure, that you have <ulink url="http://www.gnu.org/software/gettext/manual/gettext.html">GNU gettext
+ utilities</ulink> installed on your system.
+ </para>
+
+ <para>
+ To edit translation files, you may install <ulink url="http://www.poedit.net/">poedit</ulink> editor.
+ </para>
+ </section>
+
+ <section>
+ <title>Simple project</title>
+ <para>
+ Let's start with some simple project, the "Hello world" program
+ for example
+ <programlisting>
+ /* hello.c */
+ #include &lt;stdio.h&gt;
+ int main(int argc, char* argv[])
+ {
+ printf("Hello world\n");
+ return 0;
+ }
+ </programlisting>
+
+ Prepare simple <filename>SConstruct</filename> script to compile the
+ program.
+ <programlisting>
+ # SConstruct
+ env = Environment()
+ hello = Program(["hello.c"])
+ </programlisting>
+ </para>
+
+ <para>
+ Now we'll convert the project to multi-lingual one. I assume, that you
+ already have <ulink url="http://www.gnu.org/software/gettext/manual/gettext.html">GNU gettext
+ utilities</ulink> installed. If not, install it from repository, or
+ download from <ulink url="http://ftp.gnu.org/gnu/gettext/">
+ http://ftp.gnu.org/gnu/gettext/</ulink>. For the purpose of this example,
+ you should have following three locales installed on your system
+ <literal>en_US</literal>, <literal>de_DE</literal> and
+ <literal>pl_PL</literal>. On debian, for example, you may enable certain
+ locales through <command>dpkg-reconfigure locales</command>.
+ </para>
+
+ <para>
+ We first prepare the <filename>hello.c</filename> program, for
+ internationalization. Change the previous code so it reads as follows:
+ <programlisting>
+ /* hello.c */
+ #include &lt;stdio.h&gt;
+ #include &lt;libintl.h&gt;
+ #include &lt;locale.h&gt;
+ int main(int argc, char* argv[])
+ {
+ bindtextdomain("hello", "locale");
+ setlocale(LC_ALL, "");
+ textdomain("hello");
+ printf(gettext("Hello world\n"));
+ return 0;
+ }
+ </programlisting>
+ This way we prepared source code. Detailed recipes for such preparation can
+ be found at <ulink url="http://www.gnu.org/software/gettext/manual/gettext.html#Sources">
+ http://www.gnu.org/software/gettext/manual/gettext.html#Sources</ulink>.
+ The <function>gettext("...")</function> in above source has two purposes.
+ First is is recognized by the <command>xgettext(1)</command> program, which
+ we will use to extract from the sources the messages for localization.
+ Second, it calls the <literal>gettext</literal> library internals to
+ translate the message at runtime.
+ </para>
+
+ <para>
+ Now we shall instruct SCons how to generate and maintain translation files.
+ For that, we use &b-link-Translate; builder and &b-link-MOFiles; builder.
+ First one takes a couple of source files, extracts internationalized
+ messages from them, creates so-called <literal>POT</literal> file
+ (translation template), and then creates <literal>PO</literal> translation
+ files, one for each requested language. Later, during the development
+ lifecycle, the builder keeps all these files up-to date. The
+ &b-link-MOFiles; builder compiles the <literal>PO</literal> files to binary
+ form. After all, we install the <literal>MO</literal> files under directory
+ called <filename>locale</filename>.
+ </para>
+
+ <para> The complete code of
+ <filename>SConstruct</filename> script for multi-lingual "Hello world" will
+ be following:
+ <programlisting>
+ # SConstruct
+ env = Environment( tools = ['default', 'gettext'] )
+ hello = env.Program(["hello.c"])
+ env['XGETTEXTFLAGS'] = [
+ '--package-name=%s' % 'hello',
+ '--package-version=%s' % '1.0',
+ ]
+ po = env.Translate(["pl","en", "de"], ["hello.c"], POAUTOINIT = 1)
+ mo = env.MOFiles(po)
+ InstallAs(["locale/en/LC_MESSAGES/hello.mo"], ["en.mo"])
+ InstallAs(["locale/pl/LC_MESSAGES/hello.mo"], ["pl.mo"])
+ InstallAs(["locale/de/LC_MESSAGES/hello.mo"], ["de.mo"])
+ </programlisting>
+ </para>
+ <para>
+ Generate translation files with <command>scons po-update</command>.
+ You should see the output from SCons simillar to this:
+ <screen>
+ ptomulik@:$ scons po-update
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ Entering '/home/ptomulik/projects/tmp'
+ xgettext --package-name=hello --package-version=1.0 -o - hello.c
+ Leaving '/home/ptomulik/projects/tmp'
+ Writting 'messages.pot' (new file)
+ msginit --no-translator -l pl -i messages.pot -o pl.po
+ Created pl.po.
+ msginit --no-translator -l en -i messages.pot -o en.po
+ Created en.po.
+ msginit --no-translator -l de -i messages.pot -o de.po
+ Created de.po.
+ scons: done building targets.
+ </screen>
+ </para>
+
+ <para>
+ If everything is right, you shall see following new files.
+ <screen>
+ ptomulik@:$ ls *.po*
+ de.po en.po messages.pot pl.po
+ </screen>
+ </para>
+
+ <para>
+ Open <filename>en.po</filename> in <command>poedit</command> and provide
+ english "translation" to message <literal>"Hello world\n"</literal>. Do the
+ same for <filename>de.po</filename> (deutsch) and
+ <filename>pl.po</filename> (polish). Let the translations be, for example:
+ <itemizedlist>
+ <listitem><para>
+ <literal>en: "Welcome to beautiful world!\n"</literal>
+ </para></listitem>
+ <listitem><para>
+ <literal>de: "Hallo Welt!\n"</literal>
+ </para></listitem>
+ <listitem><para>
+ <literal>pl: "Witaj swiecie!\n"</literal>
+ </para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Now compile the project by executing <command>scons</command> command. The
+ output should be similar to this:
+ <screen>
+ ptomulik@:$ scons
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ msgfmt -c -o de.mo de.po
+ msgfmt -c -o en.mo en.po
+ gcc -o hello.o -c hello.c
+ gcc -o hello hello.o
+ Install file: "de.mo" as "locale/de/LC_MESSAGES/hello.mo"
+ Install file: "en.mo" as "locale/en/LC_MESSAGES/hello.mo"
+ msgfmt -c -o pl.mo pl.po
+ Install file: "pl.mo" as "locale/pl/LC_MESSAGES/hello.mo"
+ scons: done building targets.
+ </screen>
+ SCons automatically compiled <literal>PO</literal> files to binary format
+ <literal>MO</literal>, and the <literal>InstallAs</literal> lines installed
+ these files under <filename>locale</filename> folder.
+ </para>
+ <para>
+ Your program should be now ready. You may try it as follows (linux):
+ <screen>
+ ptomulik@:$ LANG=en_US.UTF-8 ./hello
+ Welcome to beautiful world
+ </screen>
+ <screen>
+ ptomulik@:$ LANG=de_DE.UTF-8 ./hello
+ Hallo Welt
+ </screen>
+ <screen>
+ ptomulik@:$ LANG=pl_PL.UTF-8 ./hello
+ Witaj swiecie
+ </screen>
+ </para>
+ <para>
+ To demonstrate further life of translation files, let's change polish
+ translation (<command>poedit pl.po</command>) to <literal>"Witaj drogi
+ swiecie\n"</literal>. Run <command>scons</command> to see how scons
+ reacts to this
+ <screen>
+ ptomulik@:$scons
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ msgfmt -c -o pl.mo pl.po
+ Install file: "pl.mo" as "locale/pl/LC_MESSAGES/hello.mo"
+ scons: done building targets.
+ </screen>
+ </para>
+ <para>
+ Now, open <filename>hello.c</filename> and add another one
+ <literal>printf</literal> line with new message.
+ <programlisting>
+ /* hello.c */
+ #include &lt;stdio.h&gt;
+ #include &lt;libintl.h&gt;
+ #include &lt;locale.h&gt;
+ int main(int argc, char* argv[])
+ {
+ bindtextdomain("hello", "locale");
+ setlocale(LC_ALL, "");
+ textdomain("hello");
+ printf(gettext("Hello world\n"));
+ printf(gettext("and good bye\n"));
+ return 0;
+ }
+ </programlisting>
+ </para>
+ <para>
+ Compile project with <command>scons</command>. This time, the
+ <command>msgmerge(1)</command> program is used by SCons to update
+ <literal>PO</literal> file. The output from compilation is like:
+ <screen>
+ ptomulik@:$scons
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ Entering '/home/ptomulik/projects/tmp'
+ xgettext --package-name=hello --package-version=1.0 -o - hello.c
+ Leaving '/home/ptomulik/projects/tmp'
+ Writting 'messages.pot' (messages in file were outdated)
+ msgmerge --update de.po messages.pot
+ ... done.
+ msgfmt -c -o de.mo de.po
+ msgmerge --update en.po messages.pot
+ ... done.
+ msgfmt -c -o en.mo en.po
+ gcc -o hello.o -c hello.c
+ gcc -o hello hello.o
+ Install file: "de.mo" as "locale/de/LC_MESSAGES/hello.mo"
+ Install file: "en.mo" as "locale/en/LC_MESSAGES/hello.mo"
+ msgmerge --update pl.po messages.pot
+ ... done.
+ msgfmt -c -o pl.mo pl.po
+ Install file: "pl.mo" as "locale/pl/LC_MESSAGES/hello.mo"
+ scons: done building targets.
+ </screen>
+ </para>
+ <para>
+ The last example demonstrates what happens, if we change the source code
+ in such way, that the internationalized messages do not change. The answer
+ is, that none of translation files (<literal>POT</literal>,
+ <literal>PO</literal>) is touched (i.e. no content changes, no
+ creation/modification time changed and so on). Let's append another one
+ instruction to the program (after the last printf), so its code becomes:
+ <programlisting>
+ /* hello.c */
+ #include &lt;stdio.h&gt;
+ #include &lt;libintl.h&gt;
+ #include &lt;locale.h&gt;
+ int main(int argc, char* argv[])
+ {
+ bindtextdomain("hello", "locale");
+ setlocale(LC_ALL, "");
+ textdomain("hello");
+ printf(gettext("Hello world\n"));
+ printf(gettext("and good bye\n"));
+ printf("----------------\n");
+ return a;
+ }
+ </programlisting>
+ Compile project. You'll see on your screen
+ <screen>
+ ptomulik@:$scons
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ Entering '/home/ptomulik/projects/tmp'
+ xgettext --package-name=hello --package-version=1.0 -o - hello.c
+ Leaving '/home/ptomulik/projects/tmp'
+ Not writting 'messages.pot' (messages in file found to be up-to-date)
+ gcc -o hello.o -c hello.c
+ gcc -o hello hello.o
+ scons: done building targets.
+ </screen>
+ As you see, the internationalized messages ditn't change, so the
+ <literal>POT</literal> and the rest of translation files have not
+ even been touched.
+ </para>
+ </section>
diff --git a/doc/user/main.in b/doc/user/main.in
index 4b0807da..0f8e3053 100644
--- a/doc/user/main.in
+++ b/doc/user/main.in
@@ -65,6 +65,7 @@
<!ENTITY factories SYSTEM "factories.xml">
<!ENTITY file-removal SYSTEM "file-removal.xml">
<!ENTITY functions SYSTEM "functions.xml">
+ <!ENTITY gettext SYSTEM "gettext.xml">
<!ENTITY hierarchy SYSTEM "hierarchy.xml">
<!ENTITY java SYSTEM "java.xml">
<!ENTITY install SYSTEM "install.xml">
@@ -253,6 +254,11 @@
&variants;
</chapter>
+ <chapter id="chap-gettext">
+ <title>Internaionalization and Localization with Gettext</title>
+ &gettext;
+ </chapter>
+
<!--
<chapter id="chap-builders-built-in">
diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in
index 377b7b77..15b3cb48 100644
--- a/src/engine/MANIFEST.in
+++ b/src/engine/MANIFEST.in
@@ -183,3 +183,14 @@ SCons/Variables/ListVariable.py
SCons/Variables/PackageVariable.py
SCons/Variables/PathVariable.py
SCons/Warnings.py
+SCons/Tool/msgfmt.py
+SCons/Tool/GettextCommon.py
+SCons/Tool/gettext.py
+SCons/Tool/msginit.py
+SCons/Tool/msgmerge.py
+SCons/Tool/xgettext.py
+SCons/Tool/msgfmt.xml
+SCons/Tool/xgettext.xml
+SCons/Tool/msgmerge.xml
+SCons/Tool/msginit.xml
+SCons/Tool/gettext.xml
diff --git a/src/engine/SCons/Tool/GettextCommon.py b/src/engine/SCons/Tool/GettextCommon.py
new file mode 100644
index 00000000..d786015b
--- /dev/null
+++ b/src/engine/SCons/Tool/GettextCommon.py
@@ -0,0 +1,444 @@
+"""SCons.Tool.GettextCommon module
+
+Used by several tools of `gettext` toolset.
+"""
+
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import SCons.Warnings
+import re
+
+#############################################################################
+class XgettextToolWarning(SCons.Warnings.Warning): pass
+class XgettextNotFound(XgettextToolWarning): pass
+class MsginitToolWarning(SCons.Warnings.Warning): pass
+class MsginitNotFound(MsginitToolWarning): pass
+class MsgmergeToolWarning(SCons.Warnings.Warning): pass
+class MsgmergeNotFound(MsgmergeToolWarning): pass
+class MsgfmtToolWarning(SCons.Warnings.Warning): pass
+class MsgfmtNotFound(MsgfmtToolWarning): pass
+#############################################################################
+SCons.Warnings.enableWarningClass(XgettextToolWarning)
+SCons.Warnings.enableWarningClass(XgettextNotFound)
+SCons.Warnings.enableWarningClass(MsginitToolWarning)
+SCons.Warnings.enableWarningClass(MsginitNotFound)
+SCons.Warnings.enableWarningClass(MsgmergeToolWarning)
+SCons.Warnings.enableWarningClass(MsgmergeNotFound)
+SCons.Warnings.enableWarningClass(MsgfmtToolWarning)
+SCons.Warnings.enableWarningClass(MsgfmtNotFound)
+#############################################################################
+
+#############################################################################
+class _POTargetFactory(object):
+ """ A factory of `PO` target files.
+
+ Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious`
+ (this is required by builders and actions in `SConsToolGettext`) and
+ `noclean` flags by default for all produced nodes.
+ """
+ def __init__( self, env, nodefault = True, alias = None, precious = True
+ , noclean = True ):
+ """ Object constructor.
+
+ **Arguments**
+
+ - *env* (`SCons.Environment.Environment`)
+ - *nodefault* (`boolean`) - if `True`, produced nodes will be ignored
+ from default target `'.'`
+ - *alias* (`string`) - if provided, produced nodes will be automatically
+ added to this alias, and alias will be set as `AlwaysBuild`
+ - *precious* (`boolean`) - if `True`, the produced nodes will be set as
+ `Precious`.
+ - *noclen* (`boolean`) - if `True`, the produced nodes will be excluded
+ from `Clean`.
+ """
+ self.env = env
+ self.alias = alias
+ self.precious = precious
+ self.noclean = noclean
+ self.nodefault = nodefault
+
+ def _create_node(self, name, factory, directory = None, create = 1):
+ """ Create node, and set it up to factory settings. """
+ import SCons.Util
+ node = factory(name, directory, create)
+ node.set_noclean(self.noclean)
+ node.set_precious(self.precious)
+ if self.nodefault:
+ self.env.Ignore('.', node)
+ if self.alias:
+ self.env.AlwaysBuild(self.env.Alias(self.alias, node))
+ return node
+
+ def Entry(self, name, directory = None, create = 1):
+ """ Create `SCons.Node.FS.Entry` """
+ return self._create_node(name, self.env.fs.Entry, directory, create)
+
+ def File(self, name, directory = None, create = 1):
+ """ Create `SCons.Node.FS.File` """
+ return self._create_node(name, self.env.fs.File, directory, create)
+#############################################################################
+
+#############################################################################
+_re_comment = re.compile(r'(#[^\n\r]+)$', re.M)
+_re_lang = re.compile(r'([a-zA-Z0-9_]+)', re.M)
+#############################################################################
+def _read_linguas_from_files(env, linguas_files = None):
+ """ Parse `LINGUAS` file and return list of extracted languages """
+ import SCons.Util
+ import SCons.Environment
+ global _re_comment
+ global _re_lang
+ if not SCons.Util.is_List(linguas_files) \
+ and not SCons.Util.is_String(linguas_files) \
+ and not isinstance(linguas_files, SCons.Node.FS.Base) \
+ and linguas_files:
+ # If, linguas_files==True or such, then read 'LINGUAS' file.
+ linguas_files = [ 'LINGUAS' ]
+ if linguas_files is None:
+ return []
+ fnodes = env.arg2nodes(linguas_files)
+ linguas = []
+ for fnode in fnodes:
+ contents = _re_comment.sub("", fnode.get_text_contents())
+ ls = [ l for l in _re_lang.findall(contents) if l ]
+ linguas.extend(ls)
+ return linguas
+#############################################################################
+
+#############################################################################
+from SCons.Builder import BuilderBase
+#############################################################################
+class _POFileBuilder(BuilderBase):
+ """ `PO` file builder.
+
+ This is multi-target single-source builder. In typical situation the source
+ is single `POT` file, e.g. `messages.pot`, and there are multiple `PO`
+ targets to be updated from this `POT`. We must run
+ `SCons.Builder.BuilderBase._execute()` separatelly for each target to track
+ dependencies separatelly for each target file.
+
+ **NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)`
+ with target being list of all targets, all targets would be rebuilt each time
+ one of the targets from this list is missing. This would happen, for example,
+ when new language `ll` enters `LINGUAS_FILE` (at this moment there is no
+ `ll.po` file yet). To avoid this, we override
+ `SCons.Builder.BuilerBase._execute()` and call it separatelly for each
+ target. Here we also append to the target list the languages read from
+ `LINGUAS_FILE`.
+ """
+ #
+ #* The argument for overriding _execute(): We must use environment with
+ # builder overrides applied (see BuilderBase.__init__(). Here it comes for
+ # free.
+ #* The argument against using 'emitter': The emitter is called too late
+ # by BuilderBase._execute(). If user calls, for example:
+ #
+ # env.POUpdate(LINGUAS_FILE = 'LINGUAS')
+ #
+ # the builder throws error, because it is called with target=None,
+ # source=None and is trying to "generate" sources or target list first.
+ # If user calls
+ #
+ # env.POUpdate(['foo', 'baz'], LINGUAS_FILE = 'LINGUAS')
+ #
+ # the env.BuilderWrapper() calls our builder with target=None,
+ # source=['foo', 'baz']. The BuilderBase._execute() then splits execution
+ # and execute iterativelly (recursion) self._execute(None, source[i]).
+ # After that it calls emitter (which is quite too late). The emitter is
+ # also called in each iteration, what makes things yet worse.
+ def __init__(self, env, **kw):
+ if not 'suffix' in kw:
+ kw['suffix'] = '$POSUFFIX'
+ if not 'src_suffix' in kw:
+ kw['src_suffix'] = '$POTSUFFIX'
+ if not 'src_builder' in kw:
+ kw['src_builder'] = '_POTUpdateBuilder'
+ if not 'single_source' in kw:
+ kw['single_source'] = True
+ alias = None
+ if 'target_alias' in kw:
+ alias = kw['target_alias']
+ del kw['target_alias']
+ if not 'target_factory' in kw:
+ kw['target_factory'] = _POTargetFactory(env, alias=alias).File
+ BuilderBase.__init__(self, **kw)
+
+ def _execute(self, env, target, source, *args, **kw):
+ """ Execute builder's actions.
+
+ Here we append to `target` the languages read from `$LINGUAS_FILE` and
+ apply `SCons.Builder.BuilderBase._execute()` separatelly to each target.
+ The arguments and return value are same as for
+ `SCons.Builder.BuilderBase._execute()`.
+ """
+ import SCons.Util
+ import SCons.Node
+ linguas_files = None
+ if env.has_key('LINGUAS_FILE') and env['LINGUAS_FILE']:
+ linguas_files = env['LINGUAS_FILE']
+ # This prevents endless recursion loop (we'll be invoked once for
+ # each target appended here, we must not extend the list again).
+ env['LINGUAS_FILE'] = None
+ linguas = _read_linguas_from_files(env,linguas_files)
+ if SCons.Util.is_List(target):
+ target.extend(linguas)
+ elif target is not None:
+ target = [target] + linguas
+ else:
+ target = linguas
+ if not target:
+ # Let the SCons.BuilderBase to handle this patologic situation
+ return BuilderBase._execute( self, env, target, source, *args, **kw)
+ # The rest is ours
+ if not SCons.Util.is_List(target):
+ target = [ target ]
+ result = []
+ for tgt in target:
+ r = BuilderBase._execute( self, env, [tgt], source, *args, **kw)
+ result.extend(r)
+ if linguas_files is not None:
+ env['LINGUAS_FILE'] = linguas_files
+ return SCons.Node.NodeList(result)
+#############################################################################
+
+import SCons.Environment
+#############################################################################
+def _translate(env, target=[], source=SCons.Environment._null, *args, **kw):
+ """ Function for `Translate()` pseudo-builder """
+ pot = env.POTUpdate(None, source, *args, **kw)
+ po = env.POUpdate(target, pot, *args, **kw)
+ return po
+#############################################################################
+
+#############################################################################
+class RPaths(object):
+ """ Callable object, which returns pathnames relative to SCons current
+ working directory.
+
+ It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths
+ for nodes that are outside of current working directory (`env.fs.getcwd()`).
+ In `SConsToolGettext` way we often have `SConscript`, `POT` and `PO` files
+ within `po/` directory and source files (e.g. `*.c`) outside of it. When
+ generating `POT` template file, references to source files are written to
+ `POT` template, so a translator may later quickly jump to appropriate source
+ file and line from its `PO` editor (e.g. `poedit`). Relative paths in
+ `PO` file are usually interpreted by `PO` editor as paths relative to the
+ place, where `PO` file lives. The absolute paths would make resultant `POT`
+ file nonportable, as the references would be correct only on the machine,
+ where `POT` file was recently re-created. For such reason, we need a
+ function, which always returns relative paths. This is the purpose of
+ `RPaths` callable object.
+
+ The `__call__` method returns paths relative to current woking directory, but
+ we assume, that *xgettext(1)* is run from the directory, where target file is
+ going to be created.
+
+ Note, that this may not work for files distributed over several hosts or
+ across different drives on windows. We assume here, that single local
+ filesystem holds both source files and target `POT` templates.
+
+ Intended use of `RPaths` - in `xgettext.py`::
+
+ def generate(env):
+ from GettextCommon import RPaths
+ ...
+ sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET, SOURCES)} $)'
+ env.Append(
+ ...
+ XGETTEXTCOM = 'XGETTEXT ... ' + sources,
+ ...
+ XgettextRPaths = RPaths(env)
+ )
+ """
+ # NOTE: This callable object returns pathnames of dirs/files relative to
+ # current working directory. The pathname remains relative also for entries
+ # that are outside of current working directory (node, that
+ # SCons.Node.FS.File and siblings return absolute path in such case). For
+ # simplicity we compute path relative to current working directory, this
+ # seems be enough for our purposes (don't need TARGET variable and
+ # SCons.Defaults.Variable_Caller stuff).
+
+ def __init__(self, env):
+ """ Initialize `RPaths` callable object.
+
+ **Arguments**:
+
+ - *env* - a `SCons.Environment.Environment` object, defines *current
+ working dir*.
+ """
+ self.env = env
+
+ # FIXME: I'm not sure, how it should be implemented (what the *args are in
+ # general, what is **kw).
+ def __call__(self, nodes, *args, **kw):
+ """ Return nodes' paths (strings) relative to current working directory.
+
+ **Arguments**:
+
+ - *nodes* ([`SCons.Node.FS.Base`]) - list of nodes.
+ - *args* - currently unused.
+ - *kw* - currently unused.
+
+ **Returns**:
+
+ - Tuple of strings, which represent paths relative to current working
+ directory (for given environment).
+ """
+ # os.path.relpath is available only on python >= 2.6. We use our own
+ # implementation. It's taken from BareNecessities package:
+ # http://jimmyg.org/work/code/barenecessities/index.html
+ from posixpath import curdir
+ def relpath(path, start=curdir):
+ import posixpath
+ """Return a relative version of a path"""
+ if not path:
+ raise ValueError("no path specified")
+ start_list = posixpath.abspath(start).split(posixpath.sep)
+ path_list = posixpath.abspath(path).split(posixpath.sep)
+ # Work out how much of the filepath is shared by start and path.
+ i = len(posixpath.commonprefix([start_list, path_list]))
+ rel_list = [posixpath.pardir] * (len(start_list)-i) + path_list[i:]
+ if not rel_list:
+ return posixpath.curdir
+ return posixpath.join(*rel_list)
+ import os
+ import SCons.Node.FS
+ rpaths = ()
+ cwd = self.env.fs.getcwd().get_abspath()
+ for node in nodes:
+ rpath = None
+ if isinstance(node, SCons.Node.FS.Base):
+ rpath = relpath(node.get_abspath(), cwd)
+ # FIXME: Other types possible here?
+ if rpath is not None:
+ rpaths += (rpath,)
+ return rpaths
+#############################################################################
+
+#############################################################################
+def _init_po_files(target, source, env):
+ """ Action function for `POInit` builder. """
+ nop = lambda target, source, env : 0
+ if env.has_key('POAUTOINIT'):
+ autoinit = env['POAUTOINIT']
+ else:
+ autoinit = False
+ # Well, if everything outside works well, this loop should do single
+ # iteration. Otherwise we are rebuilding all the targets even, if just
+ # one has changed (but is this out fault?).
+ for tgt in target:
+ if not tgt.exists():
+ if autoinit:
+ action = SCons.Action.Action('$MSGINITCOM', '$MSGINITCOMSTR')
+ else:
+ msg = 'File ' + repr(str(tgt)) + ' does not exist. ' \
+ + 'If you are a translator, you can create it through: \n' \
+ + '$MSGINITCOM'
+ action = SCons.Action.Action(nop, msg)
+ status = action([tgt], source, env)
+ if status: return status
+ return 0
+#############################################################################
+
+#############################################################################
+def _install_mo_files( env, localedir, source, domain, category="LC_MESSAGES"
+ , *args, **kw):
+ """ Function for `InstallMOFiles` pseudo-builder """
+ import SCons.Util
+ import os
+ nodes = []
+ for src in source:
+ lang = SCons.Util.splitext(os.path.basename(str(src)))[0]
+ tgt = os.path.join(localedir, lang, category, domain + "$MOSUFFIX")
+ nodes.extend(env.InstallAs(tgt, src, *args, **kw))
+ return nodes
+#############################################################################
+
+#############################################################################
+def _detect_xgettext(env):
+ """ Detects *xgettext(1)* binary """
+ if env.has_key('XGETTEXT'):
+ return env['XGETTEXT']
+ xgettext = env.Detect('xgettext');
+ if xgettext:
+ return xgettext
+ raise SCons.Errors.StopError(XgettextNotFound,"Could not detect xgettext")
+ return None
+#############################################################################
+def _xgettext_exists(env):
+ return _detect_xgettext(env)
+#############################################################################
+
+#############################################################################
+def _detect_msginit(env):
+ """ Detects *msginit(1)* program. """
+ if env.has_key('MSGINIT'):
+ return env['MSGINIT']
+ msginit = env.Detect('msginit');
+ if msginit:
+ return msginit
+ raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit")
+ return None
+#############################################################################
+def _msginit_exists(env):
+ return _detect_msginit(env)
+#############################################################################
+
+#############################################################################
+def _detect_msgmerge(env):
+ """ Detects *msgmerge(1)* program. """
+ if env.has_key('MSGMERGE'):
+ return env['MSGMERGE']
+ msgmerge = env.Detect('msgmerge');
+ if msgmerge:
+ return msgmerge
+ raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge")
+ return None
+#############################################################################
+def _msgmerge_exists(env):
+ return _detect_msgmerge(env)
+#############################################################################
+
+#############################################################################
+def _detect_msgfmt(env):
+ """ Detects *msgmfmt(1)* program. """
+ if env.has_key('MSGFMT'):
+ return env['MSGFMT']
+ msgfmt = env.Detect('msgfmt');
+ if msgfmt:
+ return msgfmt
+ raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt")
+ return None
+#############################################################################
+def _msgfmt_exists(env):
+ return _detect_msgfmt(env)
+#############################################################################
+
+#############################################################################
+def tool_list(platform, env):
+ """ List tools that shall be generated by top-level `gettext` tool """
+ return [ 'xgettext', 'msginit', 'msgmerge', 'msgfmt' ]
+#############################################################################
+
diff --git a/src/engine/SCons/Tool/gettext.py b/src/engine/SCons/Tool/gettext.py
new file mode 100644
index 00000000..1055087a
--- /dev/null
+++ b/src/engine/SCons/Tool/gettext.py
@@ -0,0 +1,47 @@
+"""gettext tool
+"""
+
+
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+#############################################################################
+def generate(env,**kw):
+ import SCons.Tool
+ from SConsToolGettext.GettextCommon \
+ import _translate, _install_mo_files, tool_list
+ for t in tool_list(env['PLATFORM'], env):
+ env.Tool(t)
+ env.AddMethod(_translate, 'Translate')
+ # This is not ready yet
+ # env.AddMethod(_install_mo_files, 'InstallMOFiles')
+#############################################################################
+
+#############################################################################
+def exists(env):
+ from SConsToolGettext.GettextCommon \
+ import _xgettext_exists, _msginit_exists, \
+ _msgmerge_exists, _msgfmt_exists
+ return _xgettext_exists(env) and _msginit_exists(env) \
+ and _msgmerge_exists(env) and _msgfmt_exists(env)
+#############################################################################
diff --git a/src/engine/SCons/Tool/gettext.xml b/src/engine/SCons/Tool/gettext.xml
new file mode 100644
index 00000000..db76cc97
--- /dev/null
+++ b/src/engine/SCons/Tool/gettext.xml
@@ -0,0 +1,239 @@
+<!--
+__TOOL_COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
+<tool name="gettext">
+<summary>
+This is actually a toolset, which supports internationalization and
+localization of sofware being constructed with SCons. The toolset loads
+following tools:
+
+<itemizedlist mark='opencircle'>
+ <listitem><para>
+ &t-link-xgettext; - to extract internationalized messages from source code to
+ <literal>POT</literal> file(s),
+ </para></listitem>
+ <listitem><para>
+ &t-link-msginit; - may be optionally used to initialize <literal>PO</literal>
+ files,
+ </para></listitem>
+ <listitem><para>
+ &t-link-msgmerge; - to update <literal>PO</literal> files, that already contain
+ translated messages,</para></listitem>
+ <listitem><para>
+ &t-link-msgfmt; - to compile textual <literal>PO</literal> file to binary
+ installable <literal>MO</literal> file.
+ </para></listitem>
+</itemizedlist>
+
+When you enable &t-gettext;, it internally loads all abovementioned tools,
+so you're encouraged to see their individual documentation.
+
+Each of the above tools provides its own builder(s) which may be used to
+perform particular activities related to software internationalization. You
+may be however interested in <emphasis>top-level</emphasis> builders
+&b-Translate; and &b-InstallMOFiles; described few paragraphs later.
+
+To use &t-gettext; tools, copy <filename>SConsToolGettext</filename>
+folder to your <filename>site_scons/</filename> and simply add
+<literal>'gettext'</literal> tool to your environment:
+<example>
+ env = Environment( tools = ['default', 'gettext'] )
+</example>
+</summary>
+<sets>
+</sets>
+<uses>
+<!-- PLATFORM -->
+</uses>
+</tool>
+
+<builder name="Translate">
+<summary>
+This pseudo-builder belongs to &t-link-gettext; toolset. The builder extracts
+internationalized messages from source files, updates <literal>POT</literal>
+template (if necessary) and then updates <literal>PO</literal> translations (if
+necessary). If &cv-link-POAUTOINIT; is set, missing <literal>PO</literal> files
+will be automatically created (i.e. without translator person intervention).
+The variables &cv-link-LINGUAS_FILE; and &cv-link-POTDOMAIN; are taken into
+acount too. All other construction variables used by &b-link-POTUpdate;, and
+&b-link-POUpdate; work here too.
+
+<emphasis>Example 1</emphasis>.
+The simplest way is to specify input files and output languages inline in
+a SCons script when invoking &b-Translate;
+<example>
+# SConscript in 'po/' directory
+env = Environment( tools = ["default", "gettext"] )
+env['POAUTOINIT'] = 1
+env.Translate(['en','pl'], ['../a.cpp','../b.cpp'])
+</example>
+
+<emphasis>Example 2</emphasis>.
+If you wish, you may also stick to conventional style known from
+<productname>autotools</productname>, i.e. using
+<filename>POTFILES.in</filename> and <filename>LINGUAS</filename> files
+<example>
+# LINGUAS
+en pl
+#end
+</example>
+
+<example>
+# POTFILES.in
+a.cpp
+b.cpp
+# end
+</example>
+
+<example>
+# SConscript
+env = Environment( tools = ["default", "gettext"] )
+env['POAUTOINIT'] = 1
+env['XGETTEXTPATH'] = ['../']
+env.Translate(LINGUAS_FILE = 1, XGETTEXTFROM = 'POTFILES.in')
+</example>
+
+The last approach is perhaps the recommended one. It allows easily split
+internationalization/localization onto separate SCons scripts, where a script
+in source tree is responsible for translations (from sources to
+<literal>PO</literal> files) and script(s) under variant directories are
+responsible for compilation of <literal>PO</literal> to <literal>MO</literal>
+files to and for installation of <literal>MO</literal> files. The "gluing
+factor" synchronizing these two scripts is then the content of
+<filename>LINGUAS</filename> file. Note, that the updated
+<literal>POT</literal> and <literal>PO</literal> files are usually going to be
+committed back to the repository, so they must be updated within the source
+directory (and not in variant directories). Additionaly, the file listing of
+<filename>po/</filename> directory contains <filename>LINGUAS</filename> file,
+so the source tree looks familiar to translators, and they may work with the
+project in their usual way.
+
+<emphasis>Example 3</emphasis>.
+Let's prepare a development tree as below
+<example>
+ project/
+ + SConstruct
+ + build/
+ + src/
+ + po/
+ + SConscript
+ + SConscript.i18n
+ + POTFILES.in
+ + LINGUAS
+</example>
+with <filename>build</filename> being variant directory. Write the top-level
+<filename>SConstruct</filename> script as follows
+<example>
+ # SConstruct
+ env = Environment( tools = ["default", "gettext"] )
+ VariantDir('build', 'src', duplicate = 0)
+ env['POAUTOINIT'] = 1
+ SConscript('src/po/SConscript.i18n', exports = 'env')
+ SConscript('build/po/SConscript', exports = 'env')
+</example>
+the <filename>src/po/SConscript.i18n</filename> as
+<example>
+ # src/po/SConscript.i18n
+ Import('env')
+ env.Translate(LINGUAS_FILE=1, XGETTEXTFROM='POTFILES.in', XGETTEXTPATH=['../'])
+</example>
+and the <filename>src/po/SConscript</filename>
+<example>
+ # src/po/SConscript
+ Import('env')
+ env.MOFiles(LINGUAS_FILE = 1)
+</example>
+Such setup produces <literal>POT</literal> and <literal>PO</literal> files
+under source tree in <filename>src/po/</filename> and binary
+<literal>MO</literal> files under variant tree in
+<filename>build/po/</filename>. This way the <literal>POT</literal> and
+<literal>PO</literal> files are separated from other output files, which must
+not be committed back to source repositories (e.g. <literal>MO</literal>
+files).
+
+<note><para>In above example, the <literal>PO</literal> files are not updated,
+nor created automatically when you issue <command>scons '.'</command> command.
+The files must be updated (created) by hand via <command>scons
+po-update</command> and then <literal>MO</literal> files can be compiled by
+running <command>scons '.'</command>.</para></note>
+
+</summary>
+</builder>
+
+<!--
+<builder name="InstallMOFiles">
+<summary>
+This is not implemented yet.
+Install <literal>MO</literal> catalog files into system directories.
+
+The parameters are:
+- <literal>localedir</literal> - system locale base directory, e.g. <literal>/usr/share/locale</literal>
+- <literal>source</literal> - list of <literal>MO</literal> files to install
+- <literal>domain</literal> - domain, i.e. your package/program name
+- <literal>category</literal> - locale category, e.g. <literal>LC_MESSAGES</literal>
+
+The installation goes in standard way. For example, if
+<literal>localedir="/usr/share/locale"</literal>, <literal>domain="program1"</literal>,
+<literal>category="LC_MESSAGES"</literal>, <literal>sources=['en.mo', 'fr.mo']</literal>, then the
+installation goes as follows:
+<example>
+en.mo ===&gt; /usr/share/locale/en/LC_MESSAGES/program1.mo
+fr.mo ===&gt; /usr/share/locale/fr/LC_MESSAGES/program1.mo
+</example>
+The <literal>InstallMOFiles</literal> builder uses internaly <literal>InstallAs</literal> builder, so all
+the features of <literal>InstallAs</literal> (e.g. <literal>xxinstall-sandbox</literal>) should work.
+<example>
+TODO:
+</example>
+</summary>
+</builder>
+-->
+
+<cvar name="POTDOMAIN">
+<summary>
+The &cv-POTDOMAIN; defines default domain, used to generate
+<literal>POT</literal> filename as <filename>&cv-POTDOMAIN;.pot</filename> when
+no <literal>POT</literal> file name is provided by the user. This applies to
+&b-link-POTUpdate;, &b-link-POInit; and &b-link-POUpdate; builders (and
+builders, that use them, e.g. &b-Translate;). Normally (if &cv-POTDOMAIN; is
+not defined), the builders use <filename>messages.pot</filename> as default
+<literal>POT</literal> file name.
+</summary>
+</cvar>
+
+<cvar name="POAUTOINIT">
+<summary>
+The &cv-POAUTOINIT; variable, if set to <literal>True</literal> (on non-zero
+numeric value), let the SConsToolGettext to automatically initialize
+<emphasis>missing</emphasis> <literal>PO</literal> files with
+<command>msginit(1)</command>. This applies to both,
+&b-link-POInit; and &b-link-POUpdate; builders (and others that use any of
+them).
+</summary>
+</cvar>
+
+<cvar name="LINGUAS_FILE">
+<summary>
+The &cv-LINGUAS_FILE; defines file(s) containing list of additional linguas
+to be processed by &b-link-POInit;, &b-link-POUpdate; or &b-link-MOFiles;
+builders. It also affects &b-link-Translate; builder. If the variable contains
+a string, it defines name of the list file. The &cv-LINGUAS_FILE; may be a
+list of file names as well. If &cv-LINGUAS_FILE; is set to
+<literal>True</literal> (or non-zero numeric value), the list will be read from
+default file named
+<filename>LINGUAS</filename>.
+
+</summary>
+</cvar>
+
+<scons_function name="Dummy">
+<arguments>
+TODO: Try to remove me.
+</arguments>
+<summary>
+TODO: Try to remove me.
+</summary>
+</scons_function>
diff --git a/src/engine/SCons/Tool/msgfmt.py b/src/engine/SCons/Tool/msgfmt.py
new file mode 100644
index 00000000..ce8cff8d
--- /dev/null
+++ b/src/engine/SCons/Tool/msgfmt.py
@@ -0,0 +1,101 @@
+""" msgfmt tool """
+
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from SCons.Builder import BuilderBase
+#############################################################################
+class _MOFileBuilder(BuilderBase):
+ """ The builder class for `MO` files.
+
+ The reason for this builder to exists and its purpose is quite simillar
+ as for `SConsToolGettext._POFileBuilder`. This time, we extend list of
+ sources, not targets, and call `BuilderBase._execute()` only once (as we
+ assume single-target here).
+ """
+
+ def _execute(self, env, target, source, *args, **kw):
+ # Here we add support for 'LINGUAS_FILE' keyword. Emitter is not suitable
+ # in this case, as it is called too late (after multiple sources
+ # are handled single_source builder.
+ import SCons.Util
+ from SCons.Tool.GettextCommon import _read_linguas_from_files
+ linguas_files = None
+ if env.has_key('LINGUAS_FILE') and env['LINGUAS_FILE'] is not None:
+ linguas_files = env['LINGUAS_FILE']
+ # This should prevent from endless recursion.
+ env['LINGUAS_FILE'] = None
+ # We read only languages. Suffixes shall be added automatically.
+ linguas = _read_linguas_from_files(env, linguas_files)
+ if SCons.Util.is_List(source):
+ source.extend(linguas)
+ elif source is not None:
+ source = [source] + linguas
+ else:
+ source = linguas
+ result = BuilderBase._execute(self,env,target,source,*args, **kw)
+ if linguas_files is not None:
+ env['LINGUAS_FILE'] = linguas_files
+ return result
+#############################################################################
+
+#############################################################################
+def _create_mo_file_builder(env, **kw):
+ """ Create builder object for `MOFiles` builder """
+ import SCons.Action
+ # FIXME: What factory use for source? Ours or their?
+ kw['action'] = SCons.Action.Action('$MSGFMTCOM','$MSGFMTCOMSTR')
+ kw['suffix'] = '$MOSUFFIX'
+ kw['src_suffix'] = '$POSUFFIX'
+ kw['src_builder'] = '_POUpdateBuilder'
+ kw['single_source'] = True
+ return _MOFileBuilder(**kw)
+#############################################################################
+
+#############################################################################
+def generate(env,**kw):
+ """ Generate `msgfmt` tool """
+ import SCons.Util
+ from SCons.Tool.GettextCommon import _detect_msgfmt
+ env['MSGFMT'] = _detect_msgfmt(env)
+ env.SetDefault(
+ MSGFMTFLAGS = [ SCons.Util.CLVar('-c') ],
+ MSGFMTCOM = '$MSGFMT $MSGFMTFLAGS -o $TARGET $SOURCE',
+ MSGFMTCOMSTR = '',
+ MOSUFFIX = '.mo'
+ )
+ env.Append( BUILDERS = { 'MOFiles' : _create_mo_file_builder(env) } )
+#############################################################################
+
+#############################################################################
+def exists(env):
+ """ Check if the tool exists """
+ from SCons.Tool.GettextCommon import _msgfmt_exists
+ return _msgfmt_exists(env)
+#############################################################################
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Tool/msgfmt.xml b/src/engine/SCons/Tool/msgfmt.xml
new file mode 100644
index 00000000..93e6e02c
--- /dev/null
+++ b/src/engine/SCons/Tool/msgfmt.xml
@@ -0,0 +1,101 @@
+<!--
+__TOOL_COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
+<tool name="msgfmt">
+<summary>
+This scons tool is a part of scons &t-link-gettext; toolset. It provides scons
+interface to <command>msgfmt(1)</command> command, which generates binary
+message catalog (<literal>MO</literal>) from a textual translation description
+(<literal>PO</literal>).
+</summary>
+<sets>
+MOSUFFIX
+MSGFMT
+MSGFMTCOM
+MSGFMTCOMSTR
+MSGFMTFLAGS
+</sets>
+<uses>
+LINGUAS_FILE
+</uses>
+</tool>
+
+<builder name="MOFiles">
+<summary>
+This builder belongs to &t-link-msgfmt; tool. The builder compiles
+<literal>PO</literal> files to <literal>MO</literal> files.
+
+<emphasis>Example 1</emphasis>.
+Create <filename>pl.mo</filename> and <filename>en.mo</filename> by compiling
+<filename>pl.po</filename> and <filename>en.po</filename>:
+<example>
+ # ...
+ env.MOFiles(['pl', 'en'])
+</example>
+
+<emphasis>Example 2</emphasis>.
+Compile files for languages defined in <filename>LINGUAS</filename> file:
+<example>
+ # ...
+ env.MOFiles(LINGUAS_FILE = 1)
+</example>
+
+<emphasis>Example 3</emphasis>.
+Create <filename>pl.mo</filename> and <filename>en.mo</filename> by compiling
+<filename>pl.po</filename> and <filename>en.po</filename> plus files for
+languages defined in <filename>LINGUAS</filename> file:
+<example>
+ # ...
+ env.MOFiles(['pl', 'en'], LINGUAS_FILE = 1)
+</example>
+
+<emphasis>Example 4</emphasis>.
+Compile files for languages defined in <filename>LINGUAS</filename> file
+(another version):
+<example>
+ # ...
+ env['LINGUAS_FILE'] = 1
+ env.MOFiles()
+</example>
+</summary>
+</builder>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MOSUFFIX">
+<summary>
+Suffix used for <literal>MO</literal> files (default: <literal>'.mo'</literal>).
+See &t-link-msgfmt; tool and &b-link-MOFiles; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MSGFMT">
+<summary>
+Absolute path to <command>msgfmt(1)</command> binary, found by
+<function>Detect()</function>.
+See &t-link-msgfmt; tool and &b-link-MOFiles; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MSGFMTCOM">
+<summary>
+Complete command line to run <command>msgfmt(1)</command> program.
+See &t-link-msgfmt; tool and &b-link-MOFiles; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MSGFMTCOMSTR">
+<summary>
+String to display when <command>msgfmt(1)</command> is invoked
+(default: <literal>''</literal>, which means ``print &cv-link-MSGFMTCOM;'').
+See &t-link-msgfmt; tool and &b-link-MOFiles; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MSGFMTFLAGS">
+<summary>
+Additional flags to <command>msgfmt(1)</command>.
+See &t-link-msgfmt; tool and &b-link-MOFiles; builder.
+</summary>
+</cvar>
diff --git a/src/engine/SCons/Tool/msginit.py b/src/engine/SCons/Tool/msginit.py
new file mode 100644
index 00000000..164215b0
--- /dev/null
+++ b/src/engine/SCons/Tool/msginit.py
@@ -0,0 +1,111 @@
+""" msginit tool
+
+Tool specific initialization of msginit tool.
+"""
+
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import SCons.Warnings
+import SCons.Builder
+import re
+
+#############################################################################
+def _optional_no_translator_flag(env):
+ """ Return '--no-translator' flag if we run *msginit(1)* in non-interactive
+ mode."""
+ import SCons.Util
+ if env.has_key('POAUTOINIT'):
+ autoinit = env['POAUTOINIT']
+ else:
+ autoinit = False
+ if autoinit:
+ return [SCons.Util.CLVar('--no-translator')]
+ else:
+ return [SCons.Util.CLVar('')]
+#############################################################################
+
+#############################################################################
+def _POInitBuilder(env, **kw):
+ """ Create builder object for `POInit` builder. """
+ import SCons.Action
+ from SCons.Tool.GettextCommon import _init_po_files, _POFileBuilder
+ action = SCons.Action.Action(_init_po_files, None)
+ return _POFileBuilder(env, action=action, target_alias='$POCREATE_ALIAS')
+#############################################################################
+
+#############################################################################
+from SCons.Environment import _null
+#############################################################################
+def _POInitBuilderWrapper(env, target=None, source=_null, **kw):
+ """ Wrapper for _POFileBuilder. We use it to make user's life easier.
+
+ This wrapper checks for `$POTDOMAIN` construction variable (or override in
+ `**kw`) and treats it appropriatelly.
+ """
+ if source is _null:
+ if 'POTDOMAIN' in kw:
+ domain = kw['POTDOMAIN']
+ elif env.has_key('POTDOMAIN'):
+ domain = env['POTDOMAIN']
+ else:
+ domain = 'messages'
+ source = [ domain ] # NOTE: Suffix shall be appended automatically
+ return env._POInitBuilder(target, source, **kw)
+#############################################################################
+
+#############################################################################
+def generate(env,**kw):
+ """ Generate the `msginit` tool """
+ import SCons.Util
+ from SCons.Tool.GettextCommon import _detect_msginit
+ env['MSGINIT'] = _detect_msginit(env)
+ msginitcom = '$MSGINIT ${_MSGNoTranslator(__env__)} -l ${_MSGINITLOCALE}' \
+ + ' $MSGINITFLAGS -i $SOURCE -o $TARGET'
+ env.SetDefault(
+ POSUFFIX = '.po',
+ _MSGINITLOCALE = '${TARGET.filebase}',
+ _MSGNoTranslator = _optional_no_translator_flag,
+ MSGINITCOM = msginitcom,
+ MSGINITCOMSTR = '',
+ MSGINITFLAGS = [ ],
+ POAUTOINIT = False,
+ POCREATE_ALIAS = 'po-create'
+ )
+ env.Append( BUILDERS = { '_POInitBuilder' : _POInitBuilder(env) } )
+ env.AddMethod(_POInitBuilderWrapper, 'POInit')
+ env.AlwaysBuild(env.Alias('$POCREATE_ALIAS'))
+#############################################################################
+
+#############################################################################
+def exists(env):
+ """ Check if the tool exists """
+ from SCons.Tool.GettextCommon import _msginit_exists
+ return _msginit_exists(env)
+#############################################################################
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Tool/msginit.xml b/src/engine/SCons/Tool/msginit.xml
new file mode 100644
index 00000000..527a1682
--- /dev/null
+++ b/src/engine/SCons/Tool/msginit.xml
@@ -0,0 +1,167 @@
+<!--
+__TOOL_COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
+<tool name="msginit">
+<summary>
+This scons tool is a part of scons &t-link-gettext; toolset. It provides
+scons interface to <command>msginit(1)</command> program, which creates new
+<literal>PO</literal> file, initializing the meta information with values from
+user's environment (or options).
+</summary>
+<sets>
+MSGINIT
+MSGINITCOM
+MSGINITCOMSTR
+MSGINITFLAGS
+POAUTOINIT
+POCREATE_ALIAS
+POSUFFIX
+_MSGINITLOCALE
+</sets>
+<uses>
+POTDOMAIN
+LINGUAS_FILE
+POAUTOINIT
+</uses>
+</tool>
+
+<builder name="POInit">
+<summary>
+This builder belongs to &t-link-msginit; tool. The builder initializes missing
+<literal>PO</literal> file(s) if &cv-link-POAUTOINIT; is set. If
+&cv-link-POAUTOINIT; is not set (default), &b-POInit; prints instruction for
+user (that is supposed to be a translator), telling how the
+<literal>PO</literal> file should be initialized. In normal projects
+<emphasis>you should not use &b-POInit; and use &b-link-POUpdate;
+instead</emphasis>. &b-link-POUpdate; chooses intelligently between
+<command>msgmerge(1)</command> and <command>msginit(1)</command>. &b-POInit;
+always uses <command>msginit(1)</command> and should be regarded as builder for
+special purposes or for temporary use (e.g. for quick, one time initialization
+of a bunch of <literal>PO</literal> files) or for tests.
+
+Target nodes defined through &b-POInit; are not built by default (they're
+<literal>Ignore</literal>d from <literal>'.'</literal> node) but are added to
+special <literal>Alias</literal> (<literal>'po-create'</literal> by default).
+The alias name may be changed through the &cv-link-POCREATE_ALIAS;
+construction variable. All <literal>PO</literal> files defined through
+&b-POInit; may be easily initialized by <command>scons po-create</command>.
+
+<emphasis>Example 1</emphasis>.
+Initialize <filename>en.po</filename> and <filename>pl.po</filename> from
+<filename>messages.pot</filename>:
+<example>
+ # ...
+ env.POInit(['en', 'pl']) # messages.pot --&gt; [en.po, pl.po]
+</example>
+
+<emphasis>Example 2</emphasis>.
+Initialize <filename>en.po</filename> and <filename>pl.po</filename> from
+<filename>foo.pot</filename>:
+<example>
+ # ...
+ env.POInit(['en', 'pl'], ['foo']) # foo.pot --&gt; [en.po, pl.po]
+</example>
+
+<emphasis>Example 3</emphasis>.
+Initialize <filename>en.po</filename> and <filename>pl.po</filename> from
+<filename>foo.pot</filename> but using &cv-link-POTDOMAIN; construction
+variable:
+<example>
+ # ...
+ env.POInit(['en', 'pl'], POTDOMAIN='foo') # foo.pot --&gt; [en.po, pl.po]
+</example>
+
+<emphasis>Example 4</emphasis>.
+Initialize <literal>PO</literal> files for languages defined in
+<filename>LINGUAS</filename> file. The files will be initialized from template
+<filename>messages.pot</filename>:
+<example>
+ # ...
+ env.POInit(LINGUAS_FILE = 1) # needs 'LINGUAS' file
+</example>
+
+<emphasis>Example 5</emphasis>.
+Initialize <filename>en.po</filename> and <filename>pl.pl</filename>
+<literal>PO</literal> files plus files for languages defined in
+<filename>LINGUAS</filename> file. The files will be initialized from template
+<filename>messages.pot</filename>:
+<example>
+ # ...
+ env.POInit(['en', 'pl'], LINGUAS_FILE = 1)
+</example>
+
+<emphasis>Example 6</emphasis>.
+You may preconfigure your environment first, and then initialize
+<literal>PO</literal> files:
+<example>
+ # ...
+ env['POAUTOINIT'] = 1
+ env['LINGUAS_FILE'] = 1
+ env['POTDOMAIN'] = 'foo'
+ env.POInit()
+</example>
+which has same efect as:
+<example>
+ # ...
+ env.POInit(POAUTOINIT = 1, LINGUAS_FILE = 1, POTDOMAIN = 'foo')
+</example>
+</summary>
+</builder>
+
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="POCREATE_ALIAS">
+<summary>
+Common alias for all <literal>PO</literal> files created with &b-POInit;
+builder (default: <literal>'po-create'</literal>).
+See &t-link-msginit; tool and &b-link-POInit; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="POSUFFIX">
+<summary>
+Suffix used for <literal>PO</literal> files (default: <literal>'.po'</literal>)
+See &t-link-msginit; tool and &b-link-POInit; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MSGINIT">
+<summary>
+Path to <command>msginit(1)</command> program (found via
+<literal>Detect()</literal>).
+See &t-link-msginit; tool and &b-link-POInit; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MSGINITCOM">
+<summary>
+Complete command line to run <command>msginit(1)</command> program.
+See &t-link-msginit; tool and &b-link-POInit; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MSGINITCOMSTR">
+<summary>
+String to display when <command>msginit(1)</command> is invoked
+(default: <literal>''</literal>, which means ``print &cv-link-MSGINITCOM;'').
+See &t-link-msginit; tool and &b-link-POInit; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MSGINITFLAGS">
+<summary>
+List of additional flags to <command>msginit(1)</command> (default:
+<literal>[]</literal>).
+See &t-link-msginit; tool and &b-link-POInit; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="_MSGINITLOCALE">
+<summary>
+Internal ``macro''. Computes locale (language) name based on target filename
+(default: <literal>'${TARGET.filebase}' </literal>).
+</summary>
+See &t-link-msginit; tool and &b-link-POInit; builder.
+</cvar>
diff --git a/src/engine/SCons/Tool/msgmerge.py b/src/engine/SCons/Tool/msgmerge.py
new file mode 100644
index 00000000..19db36c2
--- /dev/null
+++ b/src/engine/SCons/Tool/msgmerge.py
@@ -0,0 +1,97 @@
+""" msgmerget tool
+
+Tool specific initialization for `msgmerge` tool.
+"""
+
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+#############################################################################
+def _update_or_init_po_files(target, source, env):
+ """ Action function for `POUpdate` builder """
+ import SCons.Action
+ from SCons.Tool.GettextCommon import _init_po_files
+ for tgt in target:
+ if tgt.rexists():
+ action = SCons.Action.Action('$MSGMERGECOM', '$MSGMERGECOMSTR')
+ else:
+ action = _init_po_files
+ status = action([tgt], source, env)
+ if status : return status
+ return 0
+#############################################################################
+
+#############################################################################
+def _POUpdateBuilder(env, **kw):
+ """ Create an object of `POUpdate` builder """
+ import SCons.Action
+ from SCons.Tool.GettextCommon import _POFileBuilder
+ action = SCons.Action.Action(_update_or_init_po_files, None)
+ return _POFileBuilder(env, action=action, target_alias='$POUPDATE_ALIAS')
+#############################################################################
+
+#############################################################################
+from SCons.Environment import _null
+#############################################################################
+def _POUpdateBuilderWrapper(env, target=None, source=_null, **kw):
+ """ Wrapper for `POUpdate` builder - make user's life easier """
+ if source is _null:
+ if 'POTDOMAIN' in kw:
+ domain = kw['POTDOMAIN']
+ elif env.has_key('POTDOMAIN') and env['POTDOMAIN']:
+ domain = env['POTDOMAIN']
+ else:
+ domain = 'messages'
+ source = [ domain ] # NOTE: Suffix shall be appended automatically
+ return env._POUpdateBuilder(target, source, **kw)
+#############################################################################
+
+#############################################################################
+def generate(env,**kw):
+ """ Generate the `xgettext` tool """
+ from SCons.Tool.GettextCommon import _detect_msgmerge
+ env['MSGMERGE'] = _detect_msgmerge(env)
+ env.SetDefault(
+ POSUFFIX = '.po',
+ MSGMERGECOM = '$MSGMERGE $MSGMERGEFLAGS --update $TARGET $SOURCE',
+ MSGMERGECOMSTR = '',
+ MSGMERGEFLAGS = [ ],
+ POUPDATE_ALIAS = 'po-update'
+ )
+ env.Append(BUILDERS = { '_POUpdateBuilder':_POUpdateBuilder(env) })
+ env.AddMethod(_POUpdateBuilderWrapper, 'POUpdate')
+ env.AlwaysBuild(env.Alias('$POUPDATE_ALIAS'))
+#############################################################################
+
+#############################################################################
+def exists(env):
+ """ Check if the tool exists """
+ from SCons.Tool.GettextCommon import _msgmerge_exists
+ return _msgmerge_exists(env)
+#############################################################################
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Tool/msgmerge.xml b/src/engine/SCons/Tool/msgmerge.xml
new file mode 100644
index 00000000..1c567a1f
--- /dev/null
+++ b/src/engine/SCons/Tool/msgmerge.xml
@@ -0,0 +1,157 @@
+<!--
+__TOOL_COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
+<tool name="msgmerge">
+<summary>
+This scons tool is a part of scons &t-link-gettext; toolset. It provides
+scons interface to <command>msgmerge(1)</command> command, which merges two
+Uniform style <filename>.po</filename> files together.
+</summary>
+<sets>
+MSGMERGE
+MSGMERGECOM
+MSGMERGECOMSTR
+MSGMERGEFLAGS
+POSUFFIX
+POUPDATE_ALIAS
+</sets>
+<uses>
+POTDOMAIN
+LINGUAS_FILE
+POAUTOINIT
+</uses>
+</tool>
+
+<builder name="POUpdate">
+<summary>
+The builder belongs to &t-link-msgmerge; tool. The builder updates
+<literal>PO</literal> files with <command>msgmerge(1)</command>, or initializes
+missing <literal>PO</literal> files as described in documentation of
+&t-link-msginit; tool and &b-link-POInit; builder (see also
+&cv-link-POAUTOINIT;). Note, that &b-POUpdate; <emphasis>does not add its
+targets to <literal>po-create</literal> alias</emphasis> as &b-link-POInit;
+does.
+
+Target nodes defined through &b-POUpdate; are not built by default
+(they're <literal>Ignore</literal>d from <literal>'.'</literal> node). Instead,
+they are added automatically to special <literal>Alias</literal>
+(<literal>'po-update'</literal> by default). The alias name may be changed
+through the &cv-link-POUPDATE_ALIAS; construction variable. You can easilly
+update <literal>PO</literal> files in your project by <command>scons
+po-update</command>.
+
+<emphasis>Example 1.</emphasis>
+Update <filename>en.po</filename> and <filename>pl.po</filename> from
+<filename>messages.pot</filename> template (see also &cv-link-POTDOMAIN;),
+assuming that the later one exists or there is rule to build it (see
+&b-link-POTUpdate;):
+<example>
+ # ...
+ env.POUpdate(['en','pl']) # messages.pot --&gt; [en.po, pl.po]
+</example>
+
+<emphasis>Example 2.</emphasis>
+Update <filename>en.po</filename> and <filename>pl.po</filename> from
+<filename>foo.pot</filename> template:
+<example>
+ # ...
+ env.POUpdate(['en', 'pl'], ['foo']) # foo.pot --&gt; [en.po, pl.pl]
+</example>
+
+<emphasis>Example 3.</emphasis>
+Update <filename>en.po</filename> and <filename>pl.po</filename> from
+<filename>foo.pot</filename> (another version):
+<example>
+ # ...
+ env.POUpdate(['en', 'pl'], POTDOMAIN='foo') # foo.pot -- &gt; [en.po, pl.pl]
+</example>
+
+<emphasis>Example 4.</emphasis>
+Update files for languages defined in <filename>LINGUAS</filename> file. The
+files are updated from <filename>messages.pot</filename> template:
+<example>
+ # ...
+ env.POUpdate(LINGUAS_FILE = 1) # needs 'LINGUAS' file
+</example>
+
+<emphasis>Example 5.</emphasis>
+Same as above, but update from <filename>foo.pot</filename> template:
+<example>
+ # ...
+ env.POUpdate(LINGUAS_FILE = 1, source = ['foo'])
+</example>
+
+<emphasis>Example 6.</emphasis>
+Update <filename>en.po</filename> and <filename>pl.po</filename> plus files for
+languages defined in <filename>LINGUAS</filename> file. The files are updated
+from <filename>messages.pot</filename> template:
+<example>
+ # produce 'en.po', 'pl.po' + files defined in 'LINGUAS':
+ env.POUpdate(['en', 'pl' ], LINGUAS_FILE = 1)
+</example>
+
+<emphasis>Example 7.</emphasis>
+Use &cv-link-POAUTOINIT; to automatically initialize <literal>PO</literal> file
+if it doesn't exist:
+<example>
+ # ...
+ env.POUpdate(LINGUAS_FILE = 1, POAUTOINIT = 1)
+</example>
+
+<emphasis>Example 8.</emphasis>
+Update <literal>PO</literal> files for languages defined in
+<filename>LINGUAS</filename> file. The files are updated from
+<filename>foo.pot</filename> template. All necessary settings are
+pre-configured via environment.
+<example>
+ # ...
+ env['POAUTOINIT'] = 1
+ env['LINGUAS_FILE'] = 1
+ env['POTDOMAIN'] = 'foo'
+ env.POUpdate()
+</example>
+
+</summary>
+</builder>
+
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="POUPDATE_ALIAS">
+<summary>
+Common alias for all <literal>PO</literal> files being defined with
+&b-link-POUpdate; builder (default: <literal>'po-update'</literal>).
+See &t-link-msgmerge; tool and &b-link-POUpdate; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MSGMERGE">
+<summary>
+Absolute path to <command>msgmerge(1)</command> binary as found by
+<function>Detect()</function>.
+See &t-link-msgmerge; tool and &b-link-POUpdate; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MSGMERGECOM">
+<summary>
+Complete command line to run <command>msgmerge(1)</command> command.
+See &t-link-msgmerge; tool and &b-link-POUpdate; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MSGMERGECOMSTR">
+<summary>
+String to be displayed when <command>msgmerge(1)</command> is invoked
+(default: <literal>''</literal>, which means ``print &cv-link-MSGMERGECOM;'').
+See &t-link-msgmerge; tool and &b-link-POUpdate; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="MSGMERGEFLAGS">
+<summary>
+Additional flags to <command>msgmerge(1)</command> command.
+See &t-link-msgmerge; tool and &b-link-POUpdate; builder.
+</summary>
+</cvar>
diff --git a/src/engine/SCons/Tool/xgettext.py b/src/engine/SCons/Tool/xgettext.py
new file mode 100644
index 00000000..04951748
--- /dev/null
+++ b/src/engine/SCons/Tool/xgettext.py
@@ -0,0 +1,331 @@
+""" xgettext tool
+
+Tool specific initialization of `xgettext` tool.
+"""
+
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+#############################################################################
+class _CmdRunner(object):
+ """ Callabe object, which runs shell command storing its stdout and stderr to
+ variables. It also provides `strfunction()` method, which shall be used by
+ scons Action objects to print command string. """
+
+ def __init__( self, command, commandstr = None):
+ self.out = None
+ self.err = None
+ self.status = None
+ self.command = command
+ self.commandstr = commandstr
+
+ def __call__(self, target, source, env):
+ import SCons.Action
+ import subprocess
+ import os
+ import sys
+ kw = {
+ 'stdin' : 'devnull',
+ 'stdout' : subprocess.PIPE,
+ 'stderr' : subprocess.PIPE,
+ 'universal_newlines' : True,
+ 'shell' : True
+ }
+ command = env.subst(self.command, target = target, source = source)
+ proc = SCons.Action._subproc(env, command, **kw)
+ self.out, self.err = proc.communicate()
+ self.status = proc.wait()
+ if self.err: sys.stderr.write(unicode(self.err))
+ return self.status
+
+ def strfunction(self, target, source, env):
+ import os
+ comstr = self.commandstr
+ if env.subst(comstr, target = target, source = source) == "":
+ comstr = self.command
+ s = env.subst(comstr, target = target, source = source)
+ return s
+#############################################################################
+
+#############################################################################
+def _update_pot_file(target, source, env):
+ """ Action function for `POTUpdate` builder """
+ import re
+ import os
+ import SCons.Action
+ nop = lambda target, source, env : 0
+
+ # Save scons cwd and os cwd (NOTE: they may be different. After the job, we
+ # revert ech one to its original state).
+ save_cwd = env.fs.getcwd()
+ save_os_cwd = os.getcwd()
+ chdir = target[0].dir
+ chdir_str = repr(chdir.get_abspath())
+ # Print chdir message (employ SCons.Action.Action for that. It knows better
+ # than me how to to this correctly).
+ env.Execute(SCons.Action.Action(nop, "Entering " + chdir_str))
+ # Go to target's directory and do our job
+ env.fs.chdir(chdir, 1) # Go into target's directory
+ try:
+ cmd = _CmdRunner('$XGETTEXTCOM', '$XGETTEXTCOMSTR')
+ action = SCons.Action.Action(cmd, strfunction=cmd.strfunction)
+ status = action([ target[0] ], source, env)
+ except:
+ # Something went wrong.
+ env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str))
+ # Revert working dirs to previous state and re-throw exception.
+ env.fs.chdir(save_cwd, 0)
+ os.chdir(save_os_cwd)
+ raise
+ # Print chdir message.
+ env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str))
+ # Revert working dirs to previous state.
+ env.fs.chdir(save_cwd, 0)
+ os.chdir(save_os_cwd)
+ # If the command was not successfull, return error code.
+ if status: return status
+
+ new_content = cmd.out
+
+ if not new_content:
+ # When xgettext finds no internationalized messages, no *.pot is created
+ # (because we don't want to bother translators with empty POT files).
+ needs_update = False
+ explain = "no internationalized messages encountered"
+ else:
+ if target[0].exists():
+ # If the file already exists, it's left unaltered unless its messages
+ # are outdated (w.r.t. to these recovered by xgettext from sources).
+ old_content = target[0].get_text_contents()
+ re_cdate = re.compile(r'^"POT-Creation-Date: .*"$[\r\n]?', re.M)
+ old_content_nocdate = re.sub(re_cdate,"",old_content)
+ new_content_nocdate = re.sub(re_cdate,"",new_content)
+ if(old_content_nocdate == new_content_nocdate):
+ # Messages are up-to-date
+ needs_update = False
+ explain = "messages in file found to be up-to-date"
+ else:
+ # Messages are outdated
+ needs_update = True
+ explain = "messages in file were outdated"
+ else:
+ # No POT file found, create new one
+ needs_update = True
+ explain = "new file"
+ if needs_update:
+ # Print message employing SCons.Action.Action for that.
+ msg = "Writting " + repr(str(target[0])) + " (" + explain + ")"
+ env.Execute(SCons.Action.Action(nop, msg))
+ f = open(str(target[0]),"w")
+ f.write(new_content)
+ f.close()
+ return 0
+ else:
+ # Print message employing SCons.Action.Action for that.
+ msg = "Not writting " + repr(str(target[0])) + " (" + explain + ")"
+ env.Execute(SCons.Action.Action(nop, msg))
+ return 0
+#############################################################################
+
+#############################################################################
+from SCons.Builder import BuilderBase
+#############################################################################
+class _POTBuilder(BuilderBase):
+ def _execute(self, env, target, source, *args):
+ if not target:
+ if env.has_key('POTDOMAIN') and env['POTDOMAIN']:
+ domain = env['POTDOMAIN']
+ else:
+ domain = 'messages'
+ target = [ domain ]
+ return BuilderBase._execute(self, env, target, source, *args)
+#############################################################################
+
+#############################################################################
+def _scan_xgettext_from_files(target, source, env, files = None, path = None):
+ """ Parses `POTFILES.in`-like file and returns list of extracted file names.
+ """
+ import re
+ import SCons.Util
+ import SCons.Node.FS
+
+ if files is None:
+ return 0
+ if not SCons.Util.is_List(files):
+ files = [ files ]
+
+ if path is None:
+ if env.has_key('XGETTEXTPATH'):
+ path = env['XGETTEXTPATH']
+ else:
+ path = []
+ if not SCons.Util.is_List(path):
+ path = [ path ]
+
+ dirs = ()
+ for p in path:
+ if not isinstance(p, SCons.Node.FS.Base):
+ if SCons.Util.is_String(p):
+ p = env.subst(p, source = source, target = target)
+ p = env.arg2nodes(p, env.fs.Dir)
+ if SCons.Util.is_List(p):
+ dirs = dirs + tuple(p)
+ else:
+ dirs += (p,)
+ if not dirs:
+ dirs = (env.fs.getcwd(),)
+
+ re_comment = re.compile(r'^#[^\n\r]*$\r?\n?', re.M)
+ re_emptyln = re.compile(r'^[ \t\r]*$\r?\n?', re.M)
+ re_trailws = re.compile(r'[ \t\r]+$')
+ for f in files:
+ # Find files in search path $XGETTEXTPATH
+ if isinstance(f, SCons.Node.FS.Base) and f.rexists():
+ contents = f.get_text_contents()
+ contents = re_comment.sub("", contents)
+ contents = re_emptyln.sub("", contents)
+ contents = re_trailws.sub("", contents)
+ depnames = contents.splitlines()
+ for depname in depnames:
+ depfile = SCons.Node.FS.find_file(depname, dirs)
+ if not depfile:
+ depfile = env.arg2nodes(depname, dirs[0].File)
+ env.Depends(target, depfile)
+ return 0
+#############################################################################
+
+#############################################################################
+def _pot_update_emitter(target, source, env):
+ """ Emitter function for `POTUpdate` builder """
+ from SCons.Tool.GettextCommon import _POTargetFactory
+ import SCons.Util
+ import SCons.Node.FS
+
+ if env.has_key('XGETTEXTFROM'):
+ xfrom = env['XGETTEXTFROM']
+ else:
+ return target, source
+ if not SCons.Util.is_List(xfrom):
+ xfrom = [ xfrom ]
+
+ files = []
+ for xf in xfrom:
+ if not isinstance(xf, SCons.Node.FS.Base):
+ if SCons.Util.is_String(xf):
+ xf = env.subst(xf, source = source, target = target)
+ xf = env.arg2nodes(xf)
+ if SCons.Util.is_List(xf):
+ files.extend(xf)
+ else:
+ files.append(xf)
+ if files:
+ env.Depends(target, files)
+ _scan_xgettext_from_files(target, source, env, files)
+ return target, source
+#############################################################################
+
+#############################################################################
+from SCons.Environment import _null
+#############################################################################
+def _POTUpdateBuilderWrapper(env, target=None, source=_null, **kw):
+ return env._POTUpdateBuilder(target, source, **kw)
+#############################################################################
+
+#############################################################################
+def _POTUpdateBuilder(env, **kw):
+ """ Creates `POTUpdate` builder object """
+ import SCons.Action
+ from SCons.Tool.GettextCommon import _POTargetFactory
+ kw['action'] = SCons.Action.Action(_update_pot_file, None)
+ kw['suffix'] = '$POTSUFFIX'
+ kw['target_factory'] = _POTargetFactory(env, alias='$POTUPDATE_ALIAS').File
+ kw['emitter'] = _pot_update_emitter
+ return _POTBuilder(**kw)
+#############################################################################
+
+#############################################################################
+def generate(env,**kw):
+ """ Generate `xgettext` tool """
+ import SCons.Util
+ from SCons.Tool.GettextCommon import RPaths, _detect_xgettext
+
+ env['XGETTEXT'] = _detect_xgettext(env)
+ # NOTE: sources="$SOURCES" would work as well. However, we use following
+ # construction to convert absolute paths provided by scons onto paths
+ # relative to current working dir. Note, that scons expands $SOURCE(S) to
+ # absolute paths for sources $SOURCE(s) outside of current subtree (e.g. in
+ # "../"). With source=$SOURCE these absolute paths would be written to the
+ # resultant *.pot file (and its derived *.po files) as references to lines in
+ # source code (e.g. referring lines in *.c files). Such references would be
+ # correct (e.g. in poedit) only on machine on which *.pot was generated and
+ # would be of no use on other hosts (having a copy of source code located
+ # in different place in filesystem).
+ sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET' \
+ + ', SOURCES)} $)'
+
+ # NOTE: the output from $XGETTEXTCOM command must go to stdout, not to a file.
+ # This is required by the POTUpdate builder's action.
+ xgettextcom = '$XGETTEXT $XGETTEXTFLAGS $_XGETTEXTPATHFLAGS' \
+ + ' $_XGETTEXTFROMFLAGS -o - ' + sources
+
+ xgettextpathflags = '$( ${_concat( XGETTEXTPATHPREFIX, XGETTEXTPATH' \
+ + ', XGETTEXTPATHSUFFIX, __env__, RDirs, TARGET, SOURCES)} $)'
+ xgettextfromflags = '$( ${_concat( XGETTEXTFROMPREFIX, XGETTEXTFROM' \
+ + ', XGETTEXTFROMSUFFIX, __env__, target=TARGET, source=SOURCES)} $)'
+
+ env.SetDefault(
+ _XGETTEXTDOMAIN = '${TARGET.filebase}',
+ XGETTEXTFLAGS = [ ],
+ XGETTEXTCOM = xgettextcom,
+ XGETTEXTCOMSTR = '',
+ XGETTEXTPATH = [ ],
+ XGETTEXTPATHPREFIX = '-D',
+ XGETTEXTPATHSUFFIX = '',
+ XGETTEXTFROM = None,
+ XGETTEXTFROMPREFIX = '-f',
+ XGETTEXTFROMSUFFIX = '',
+ _XGETTEXTPATHFLAGS = xgettextpathflags,
+ _XGETTEXTFROMFLAGS = xgettextfromflags,
+ POTSUFFIX = ['.pot'],
+ POTUPDATE_ALIAS = 'pot-update',
+ XgettextRPaths = RPaths(env)
+ )
+ env.Append( BUILDERS = {
+ '_POTUpdateBuilder' : _POTUpdateBuilder(env)
+ } )
+ env.AddMethod(_POTUpdateBuilderWrapper, 'POTUpdate')
+ env.AlwaysBuild(env.Alias('$POTUPDATE_ALIAS'))
+#############################################################################
+
+#############################################################################
+def exists(env):
+ """ Check, whether the tool exists """
+ from SCons.Tool.GettextCommon import _xgettext_exists
+ return _xgettext_exists(env)
+#############################################################################
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Tool/xgettext.xml b/src/engine/SCons/Tool/xgettext.xml
new file mode 100644
index 00000000..0a919d6f
--- /dev/null
+++ b/src/engine/SCons/Tool/xgettext.xml
@@ -0,0 +1,288 @@
+<!--
+__TOOL_COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
+<tool name="xgettext">
+<summary>
+This scons tool is a part of scons &t-link-gettext; toolset. It provides
+scons interface to <command>xgettext(1)</command>
+program, which extracts internationalized messages from source code. The tool
+provides &b-POTUpdate; builder to make <literal>PO</literal>
+<emphasis>Template</emphasis> files.
+</summary>
+<sets>
+POTSUFFIX
+POTUPDATE_ALIAS
+XGETTEXTCOM
+XGETTEXTCOMSTR
+XGETTEXTFLAGS
+XGETTEXTFROM
+XGETTEXTFROMPREFIX
+XGETTEXTFROMSUFFIX
+XGETTEXTPATH
+XGETTEXTPATHPREFIX
+XGETTEXTPATHSUFFIX
+_XGETTEXTDOMAIN
+_XGETTEXTFROMFLAGS
+_XGETTEXTPATHFLAGS
+</sets>
+<uses>
+POTDOMAIN
+</uses>
+</tool>
+
+<builder name="POTUpdate">
+<summary>
+The builder belongs to &t-link-xgettext; tool. The builder updates target
+<literal>POT</literal> file if exists or creates one if it doesn't. The node is
+not built by default (i.e. it is <literal>Ignore</literal>d from
+<literal>'.'</literal>), but only on demand (i.e. when given
+<literal>POT</literal> file is required or when special alias is invoked). This
+builder adds its targe node (<filename>messages.pot</filename>, say) to a
+special alias (<literal>pot-update</literal> by default, see
+&cv-link-POTUPDATE_ALIAS;) so you can update/create them easily with
+<command>scons pot-update</command>. The file is not written until there is no
+real change in internationalized messages (or in comments that enter
+<literal>POT</literal> file).
+
+<note> <para>You may see <command>xgettext(1)</command> being invoked by the
+&t-link-xgettext; tool even if there is no real change in internationalized
+messages (so the <literal>POT</literal> file is not being updated). This
+happens every time a source file has changed. In such case we invoke
+<command>xgettext(1)</command> and compare its output with the content of
+<literal>POT</literal> file to decide whether the file should be updated or
+not.</para></note>
+
+<emphasis>Example 1.</emphasis>
+Let's create <filename>po/</filename> directory and place following
+<filename>SConstruct</filename> script there:
+<example>
+ # SConstruct in 'po/' subdir
+ env = Environment( tools = ['default', 'xgettext'] )
+ env.POTUpdate(['foo'], ['../a.cpp', '../b.cpp'])
+ env.POTUpdate(['bar'], ['../c.cpp', '../d.cpp'])
+</example>
+Then invoke scons few times:
+<example>
+ user@host:$ scons # Does not create foo.pot nor bar.pot
+ user@host:$ scons foo.pot # Updates or creates foo.pot
+ user@host:$ scons pot-update # Updates or creates foo.pot and bar.pot
+ user@host:$ scons -c # Does not clean foo.pot nor bar.pot.
+</example>
+the results shall be as the comments above say.
+
+<emphasis>Example 2.</emphasis>
+The &b-POTUpdate; builder may be used with no target specified, in which
+case default target <filename>messages.pot</filename> will be used. The
+default target may also be overriden by setting &cv-link-POTDOMAIN; construction
+variable or providing it as an override to &b-POTUpdate; builder:
+<example>
+ # SConstruct script
+ env = Environment( tools = ['default', 'xgettext'] )
+ env['POTDOMAIN'] = "foo"
+ env.POTUpdate(source = ["a.cpp", "b.cpp"]) # Creates foo.pot ...
+ env.POTUpdate(POTDOMAIN = "bar", source = ["c.cpp", "d.cpp"]) # and bar.pot
+</example>
+
+<emphasis>Example 3.</emphasis>
+The sources may be specified within separate file, for example
+<filename>POTFILES.in</filename>:
+<example>
+ # POTFILES.in in 'po/' subdirectory
+ ../a.cpp
+ ../b.cpp
+ # end of file
+</example>
+The name of the file (<filename>POTFILES.in</filename>) containing the list of
+sources is provided via &cv-link-XGETTEXTFROM;:
+<example>
+ # SConstruct file in 'po/' subdirectory
+ env = Environment( tools = ['default', 'xgettext'] )
+ env.POTUpdate(XGETTEXTFROM = 'POTFILES.in')
+</example>
+
+<emphasis>Example 4.</emphasis>
+You may use &cv-link-XGETTEXTPATH; to define source search path. Assume, for
+example, that you have files <filename>a.cpp</filename>,
+<filename>b.cpp</filename>, <filename>po/SConstruct</filename>,
+<filename>po/POTFILES.in</filename>. Then your <literal>POT</literal>-related
+files could look as below:
+<example>
+ # POTFILES.in in 'po/' subdirectory
+ a.cpp
+ b.cpp
+ # end of file
+</example>
+
+<example>
+ # SConstruct file in 'po/' subdirectory
+ env = Environment( tools = ['default', 'xgettext'] )
+ env.POTUpdate(XGETTEXTFROM = 'POTFILES.in', XGETTEXTPATH='../')
+</example>
+
+<emphasis>Example 5.</emphasis>
+Multiple search directories may be defined within a list, i.e.
+<literal>XGETTEXTPATH = ['dir1', 'dir2', ...]</literal>. The order in the list
+determines the search order of source files. The path to the first file found
+is used.
+
+Let's create <filename>0/1/po/SConstruct</filename> script:
+<example>
+ # SConstruct file in '0/1/po/' subdirectory
+ env = Environment( tools = ['default', 'xgettext'] )
+ env.POTUpdate(XGETTEXTFROM = 'POTFILES.in', XGETTEXTPATH=['../', '../../'])
+</example>
+and <filename>0/1/po/POTFILES.in</filename>:
+<example>
+ # POTFILES.in in '0/1/po/' subdirectory
+ a.cpp
+ # end of file
+</example>
+Write two <filename>*.cpp</filename> files, the first one is
+<filename>0/a.cpp</filename>:
+<example>
+ /* 0/a.cpp */
+ gettext("Hello from ../../a.cpp")
+</example>
+and the second is <filename>0/1/a.cpp</filename>:
+<example>
+ /* 0/1/a.cpp */
+ gettext("Hello from ../a.cpp")
+</example>
+then run scons. You'll obtain <literal>0/1/po/messages.pot</literal> with the
+message <literal>"Hello from ../a.cpp"</literal>. When you reverse order in
+<varname>$XGETTEXTFOM</varname>, i.e. when you write SConscript as
+<example>
+ # SConstruct file in '0/1/po/' subdirectory
+ env = Environment( tools = ['default', 'xgettext'] )
+ env.POTUpdate(XGETTEXTFROM = 'POTFILES.in', XGETTEXTPATH=['../../', '../'])
+</example> then the <filename>messages.pot</filename> will contain
+<literal>msgid "Hello from ../../a.cpp"</literal> line and not
+<literal>msgid "Hello from ../a.cpp"</literal>.
+
+</summary>
+
+</builder>
+
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="POTSUFFIX">
+<summary>
+Suffix used for PO Template files (default: <literal>'.pot'</literal>).
+See &t-link-xgettext; tool and &b-link-POTUpdate; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="POTUPDATE_ALIAS">
+<summary>
+Name of the common phony target for all PO Templates created with
+&b-link-POUpdate; (default: <literal>'pot-update'</literal>).
+See &t-link-xgettext; tool and &b-link-POTUpdate; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="XGETTEXT">
+<summary>
+Path to <command>xgettext(1)</command> program (found via
+<function>Detect()</function>).
+See &t-link-xgettext; tool and &b-link-POTUpdate; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="XGETTEXTCOM">
+<summary>
+Complete xgettext command line.
+See &t-link-xgettext; tool and &b-link-POTUpdate; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="XGETTEXTCOMSTR">
+<summary>
+A string that is shown when <command>xgettext(1)</command> command is invoked
+(default: <literal>''</literal>, which means "print &cv-link-XGETTEXTCOM;").
+See &t-link-xgettext; tool and &b-link-POTUpdate; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="XGETTEXTFLAGS">
+<summary>
+Additional flags to <command>xgettext(1)</command>.
+See &t-link-xgettext; tool and &b-link-POTUpdate; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="XGETTEXTFROM">
+<summary>
+Name of file containing list of <command>xgettext(1)</command>'s source
+files. Autotools' users know this as <filename>POTFILES.in</filename> so they
+will in most cases set <literal>XGETTEXTFROM="POTFILES.in"</literal> here.
+The &cv-XGETTEXTFROM; files have same syntax and semantics as the well known
+GNU <filename>POTFILES.in</filename>.
+See &t-link-xgettext; tool and &b-link-POTUpdate; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="XGETTEXTPATH">
+<summary>
+List of directories, there <command>xgettext(1)</command> will look for
+source files (default: <literal>[]</literal>).
+<note><para>
+This variable works only together with &cv-link-XGETTEXTFROM;
+</para></note>
+See also &t-link-xgettext; tool and &b-link-POTUpdate; builder.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="XGETTEXTPATHPREFIX">
+<summary>
+This flag is used to add single search path to
+<command>xgettext(1)</command>'s commandline (default:
+<literal>'-D'</literal>).
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="XGETTEXTPATHSUFFIX">
+<summary>
+(default: <literal>''</literal>)
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="XGETTEXTFROMPREFIX">
+<summary>
+This flag is used to add single &cv-link-XGETTEXTFROM; file to
+<command>xgettext(1)</command>'s commandline (default:
+<literal>'-f'</literal>).
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="XGETTEXTFROMSUFFIX">
+<summary>
+(default: <literal>''</literal>)
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="_XGETTEXTDOMAIN">
+<summary>
+Internal "macro". Generates <command>xgettext</command> domain name
+form source and target (default: <literal>'${TARGET.filebase}'</literal>).
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="_XGETTEXTFROMFLAGS">
+<summary>
+Internal "macro". Genrates list of <literal>-D&lt;dir&gt;</literal> flags
+from the &cv-link-XGETTEXTPATH; list.
+</summary>
+</cvar>
+<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
+<cvar name="_XGETTEXTPATHFLAGS">
+<summary>
+Internal "macro". Generates list of <literal>-f&lt;file&gt;</literal> flags
+from &cv-link-XGETTEXTFROM;.
+</summary>
+</cvar>
+
+<!--
+
+-->
diff --git a/test/GETTEXT/Translate_doc_user_examples1.py b/test/GETTEXT/Translate_doc_user_examples1.py
new file mode 100644
index 00000000..946f18be
--- /dev/null
+++ b/test/GETTEXT/Translate_doc_user_examples1.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+# NOTE: When integrating into upstream SCons development tree, remove the next
+# line, and the "toolpath = ..." line
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.subdir('po/')
+test.write('po/SConstruct',
+"""
+env = Environment(
+ toolpath = ['""" + site_scons + """/SConsToolGettext']
+, tools = ["default", "gettext"]
+)
+env['POAUTOINIT'] = 1
+env.Translate(['en','pl'], ['../a.cpp','../b.cpp'])
+""")
+#
+test.write('a.cpp', """ gettext("Hello from a.cpp") """)
+test.write('b.cpp', """ gettext("Hello from b.cpp") """)
+
+# NOTE: msginit(1) prints all its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-update', stderr = None, chdir = 'po')
+test.must_exist('po/messages.pot')
+test.must_exist('po/en.po', 'po/pl.po')
+test.must_contain('po/en.po', "Hello from a.cpp")
+test.must_contain('po/en.po', "Hello from b.cpp")
+test.must_contain('po/pl.po', "Hello from a.cpp")
+test.must_contain('po/pl.po', "Hello from b.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/GETTEXT/Translate_doc_user_examples2.py b/test/GETTEXT/Translate_doc_user_examples2.py
new file mode 100644
index 00000000..51464d44
--- /dev/null
+++ b/test/GETTEXT/Translate_doc_user_examples2.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+# NOTE: When integrating into upstream SCons development tree, remove the next
+# line, and the "toolpath = ..." line
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.subdir('po/')
+test.write('po/SConstruct',
+"""
+env = Environment(
+ toolpath = ['""" + site_scons + """/SConsToolGettext']
+, tools = ["default", "gettext"]
+)
+env['POAUTOINIT'] = 1
+env['XGETTEXTPATH'] = ['../']
+env.Translate(LINGUAS_FILE = 1, XGETTEXTFROM = 'POTFILES.in')
+""")
+#
+test.write('po/LINGUAS', """\
+en pl
+""")
+#
+test.write('po/POTFILES.in', """\
+# POTFILES.in
+a.cpp
+b.cpp
+# end
+""")
+#
+test.write('a.cpp', """ gettext("Hello from a.cpp") """)
+test.write('b.cpp', """ gettext("Hello from b.cpp") """)
+
+# NOTE: msginit(1) prints all its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-update', stderr = None, chdir = 'po')
+test.must_exist('po/messages.pot')
+test.must_exist('po/en.po', 'po/pl.po')
+test.must_contain('po/en.po', "Hello from a.cpp")
+test.must_contain('po/en.po', "Hello from b.cpp")
+test.must_contain('po/pl.po', "Hello from a.cpp")
+test.must_contain('po/pl.po', "Hello from b.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/GETTEXT/Translate_doc_user_examples3.py b/test/GETTEXT/Translate_doc_user_examples3.py
new file mode 100644
index 00000000..6a93b5ee
--- /dev/null
+++ b/test/GETTEXT/Translate_doc_user_examples3.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+# NOTE: When integrating into upstream SCons development tree, remove the next
+# line, and the "toolpath = ..." line
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.subdir('src', ['src', 'po'], 'build')
+test.write('SConstruct',
+"""
+env = Environment(
+ toolpath = ['""" + site_scons + """/SConsToolGettext']
+, tools = ["default", "gettext"]
+)
+VariantDir('build', 'src', duplicate = 0)
+env['POAUTOINIT'] = 1
+SConscript('src/po/SConscript.i18n', exports = 'env')
+SConscript('build/po/SConscript', exports = 'env')
+""")
+#
+test.write('src/po/SConscript.i18n', """\
+# src/po/SConscript.i18n
+Import('env')
+env.Translate(LINGUAS_FILE=1, XGETTEXTFROM='POTFILES.in', XGETTEXTPATH=['../'])
+""")
+#
+test.write('src/po/SConscript',"""\
+# src/po/SConscript
+Import('env')
+env.MOFiles(LINGUAS_FILE = 1)
+""")
+test.write('src/po/LINGUAS', """\
+en pl
+""")
+#
+test.write('src/po/POTFILES.in', """\
+# POTFILES.in
+a.cpp
+b.cpp
+# end
+""")
+#
+test.write('src/a.cpp', """ gettext("Hello from a.cpp") """)
+test.write('src/b.cpp', """ gettext("Hello from b.cpp") """)
+
+# NOTE: msginit(1) prints all its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-update', stderr = None)
+test.must_exist('src/po/messages.pot')
+test.must_exist('src/po/en.po', 'src/po/pl.po')
+test.must_not_exist('build/po/en.po', 'build/po/pl.po')
+test.must_contain('src/po/en.po', "Hello from a.cpp")
+test.must_contain('src/po/en.po', "Hello from b.cpp")
+test.must_contain('src/po/pl.po', "Hello from a.cpp")
+test.must_contain('src/po/pl.po', "Hello from b.cpp")
+
+test.run(arguments = '.', stderr = None)
+test.must_exist('build/po/en.mo', 'build/po/pl.mo')
+test.must_not_exist('src/po/en.mo', 'src/po/pl.mo')
+
+test.run(arguments = '-c', stderr = None)
+test.must_exist('src/po/messages.pot')
+test.must_exist('src/po/en.po', 'src/po/pl.po')
+test.must_not_exist('build/po/en.mo', 'build/po/pl.mo')
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/GETTEXT/doc_user_examples1.py b/test/GETTEXT/doc_user_examples1.py
new file mode 100644
index 00000000..3d05a215
--- /dev/null
+++ b/test/GETTEXT/doc_user_examples1.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+# NOTE: When integrating into upstream SCons development tree, remove the next
+# line, and the "toolpath = ..." line
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment(
+ toolpath = ['""" + site_scons + """/SConsToolGettext']
+, tools = ["default", "gettext"]
+)
+""")
+test.run(arguments = '.')
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGFMT/MOFile_doc_user_examples1.py b/test/MSGFMT/MOFile_doc_user_examples1.py
new file mode 100644
index 00000000..71b5996c
--- /dev/null
+++ b/test/MSGFMT/MOFile_doc_user_examples1.py
@@ -0,0 +1,114 @@
+
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env.MOFiles(['pl', 'en'])
+""")
+#
+##test.write('LINGUAS',
+##"""
+##en
+##pl
+##""")
+#
+test.write('en.po',"""\
+# English translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Pawel Tomulik <ptomulik@meil.pw.edu.pl>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dummypkg 1.0\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:37+0200\\n"
+"Last-Translator: Pawel Tomulik <ptomulik@meil.pw.edu.pl>\\n"
+"Language-Team: English\\n"
+"Language: en\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Old message from a.cpp"
+""")
+#
+test.write('pl.po',"""\
+# Polish translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dummypkg 1.0\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: pl\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Stara wiadomosc z a.cpp"
+""")
+
+test.run(arguments = '.')
+test.must_exist('en.mo', 'pl.mo')
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGFMT/MOFile_doc_user_examples2.py b/test/MSGFMT/MOFile_doc_user_examples2.py
new file mode 100644
index 00000000..ad67b3e6
--- /dev/null
+++ b/test/MSGFMT/MOFile_doc_user_examples2.py
@@ -0,0 +1,114 @@
+
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env.MOFiles(LINGUAS_FILE = 1)
+""")
+#
+test.write('LINGUAS',
+"""
+en
+pl
+""")
+#
+test.write('en.po',"""\
+# English translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Pawel Tomulik <ptomulik@meil.pw.edu.pl>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dummypkg 1.0\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:37+0200\\n"
+"Last-Translator: Pawel Tomulik <ptomulik@meil.pw.edu.pl>\\n"
+"Language-Team: English\\n"
+"Language: en\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Old message from a.cpp"
+""")
+#
+test.write('pl.po',"""\
+# Polish translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dummypkg 1.0\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: pl\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Stara wiadomosc z a.cpp"
+""")
+
+test.run(arguments = '.')
+test.must_exist('en.mo', 'pl.mo')
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGFMT/MOFile_doc_user_examples3.py b/test/MSGFMT/MOFile_doc_user_examples3.py
new file mode 100644
index 00000000..e7cc0ff0
--- /dev/null
+++ b/test/MSGFMT/MOFile_doc_user_examples3.py
@@ -0,0 +1,163 @@
+
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env.MOFiles(['en', 'pl'], LINGUAS_FILE = 1)
+""")
+test.write('LINGUAS',
+"""
+de
+fr
+""")
+#
+test.write('en.po',"""\
+# English translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Pawel Tomulik <ptomulik@meil.pw.edu.pl>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dummypkg 1.0\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:37+0200\\n"
+"Last-Translator: Pawel Tomulik <ptomulik@meil.pw.edu.pl>\\n"
+"Language-Team: English\\n"
+"Language: en\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Old message from a.cpp"
+""")
+#
+test.write('pl.po',"""\
+# Polish translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dummypkg 1.0\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: pl\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Stara wiadomosc z a.cpp"
+""")
+#
+test.write('de.po',"""\
+# German translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dummypkg 1.0\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: de\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr ""
+""")
+#
+test.write('fr.po',"""\
+# French translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dummypkg 1.0\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: fr\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr ""
+""")
+
+test.run(arguments = '.')
+test.must_exist('en.mo', 'pl.mo', 'de.mo', 'fr.mo')
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGFMT/MOFile_doc_user_examples4.py b/test/MSGFMT/MOFile_doc_user_examples4.py
new file mode 100644
index 00000000..8737b2b0
--- /dev/null
+++ b/test/MSGFMT/MOFile_doc_user_examples4.py
@@ -0,0 +1,115 @@
+
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env['LINGUAS_FILE'] = 1
+env.MOFiles()
+""")
+#
+test.write('LINGUAS',
+"""
+en
+pl
+""")
+#
+test.write('en.po',"""\
+# English translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Pawel Tomulik <ptomulik@meil.pw.edu.pl>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dummypkg 1.0\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:37+0200\\n"
+"Last-Translator: Pawel Tomulik <ptomulik@meil.pw.edu.pl>\\n"
+"Language-Team: English\\n"
+"Language: en\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Old message from a.cpp"
+""")
+#
+test.write('pl.po',"""\
+# Polish translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dummypkg 1.0\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: pl\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Stara wiadomosc z a.cpp"
+""")
+
+test.run(arguments = '.')
+test.must_exist('en.mo', 'pl.mo')
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGINIT/POinit_doc_user_examples1.py b/test/MSGINIT/POinit_doc_user_examples1.py
new file mode 100644
index 00000000..9082a11f
--- /dev/null
+++ b/test/MSGINIT/POinit_doc_user_examples1.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env['POAUTOINIT'] = 1
+env.POInit(['en','pl']) # messages.pot --&gt; [en.po, pl.po]
+""")
+#
+test.write('messages.pot',"""\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\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"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=CHARSET\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+#
+#: a.cpp:1
+msgid "Hello from a.cpp"
+msgstr ""
+""")
+
+# NOTE: msginit(1) prints all its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-create', stderr = None)
+test.must_exist('en.po', 'pl.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGINIT/POinit_doc_user_examples2.py b/test/MSGINIT/POinit_doc_user_examples2.py
new file mode 100644
index 00000000..a96d921f
--- /dev/null
+++ b/test/MSGINIT/POinit_doc_user_examples2.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env['POAUTOINIT'] = 1
+env.POInit(['en','pl'], ['foo']) # foo.pot --&gt; [en.po, pl.po]
+""")
+#
+test.write('foo.pot',"""\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\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"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=CHARSET\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+#
+#: a.cpp:1
+msgid "Hello from a.cpp"
+msgstr ""
+""")
+
+# NOTE: msginit(1) prints all its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-create', stderr = None)
+test.must_exist('en.po', 'pl.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGINIT/POinit_doc_user_examples3.py b/test/MSGINIT/POinit_doc_user_examples3.py
new file mode 100644
index 00000000..f21f8745
--- /dev/null
+++ b/test/MSGINIT/POinit_doc_user_examples3.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env['POAUTOINIT'] = 1
+env.POInit(['en','pl'], POTDOMAIN='foo') # foo.pot --&gt; [en.po, pl.po]
+""")
+#
+test.write('foo.pot',"""\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\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"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=CHARSET\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+#
+#: a.cpp:1
+msgid "Hello from a.cpp"
+msgstr ""
+""")
+
+# NOTE: msginit(1) prints all its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-create', stderr = None)
+test.must_exist('en.po', 'pl.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGINIT/POinit_doc_user_examples4.py b/test/MSGINIT/POinit_doc_user_examples4.py
new file mode 100644
index 00000000..2bcb68ec
--- /dev/null
+++ b/test/MSGINIT/POinit_doc_user_examples4.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env['POAUTOINIT'] = 1
+env.POInit(LINGUAS_FILE = 1) # needs 'LINGUAS' file
+""")
+test.write('LINGUAS',"""
+en
+pl
+""")
+#
+test.write('messages.pot',"""\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\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"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=CHARSET\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+#
+#: a.cpp:1
+msgid "Hello from a.cpp"
+msgstr ""
+""")
+
+# NOTE: msginit(1) prints all its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-create', stderr = None)
+test.must_exist('en.po', 'pl.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGINIT/POinit_doc_user_examples5.py b/test/MSGINIT/POinit_doc_user_examples5.py
new file mode 100644
index 00000000..c3971e72
--- /dev/null
+++ b/test/MSGINIT/POinit_doc_user_examples5.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env['POAUTOINIT'] = 1
+env.POInit(['en', 'pl'], LINGUAS_FILE = 1) # needs 'LINGUAS' file
+""")
+test.write('LINGUAS',"""
+de
+fr
+""")
+#
+test.write('messages.pot',"""\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\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"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=CHARSET\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+#
+#: a.cpp:1
+msgid "Hello from a.cpp"
+msgstr ""
+""")
+
+# NOTE: msginit(1) prints all its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-create', stderr = None)
+test.must_exist('en.po', 'pl.po', 'de.po', 'fr.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+test.must_contain('de.po', "Hello from a.cpp")
+test.must_contain('fr.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGINIT/POinit_doc_user_examples6.py b/test/MSGINIT/POinit_doc_user_examples6.py
new file mode 100644
index 00000000..bf694fae
--- /dev/null
+++ b/test/MSGINIT/POinit_doc_user_examples6.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env['POAUTOINIT'] = 1
+env['LINGUAS_FILE'] = 1
+env['POTDOMAIN'] = 'foo'
+env.POInit()
+""")
+test.write('LINGUAS',"""
+en
+pl
+""")
+#
+test.write('foo.pot',"""\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\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"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=CHARSET\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+#
+#: a.cpp:1
+msgid "Hello from a.cpp"
+msgstr ""
+""")
+
+# NOTE: msginit(1) prints all its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-create', stderr = None)
+test.must_exist('en.po', 'pl.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGMERGE/POUpdate_doc_user_examples1.py b/test/MSGMERGE/POUpdate_doc_user_examples1.py
new file mode 100644
index 00000000..d925568c
--- /dev/null
+++ b/test/MSGMERGE/POUpdate_doc_user_examples1.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env.POUpdate(['en','pl']) # messages.pot --&gt; [en.po, pl.po]
+""")
+#
+test.write('messages.pot',"""\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\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"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=CHARSET\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+#
+#: a.cpp:1
+msgid "Hello from a.cpp"
+msgstr ""
+""")
+#
+test.write('en.po',"""\
+# English translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Pawel Tomulik <ptomulik@meil.pw.edu.pl>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:37+0200\\n"
+"Last-Translator: Pawel Tomulik <ptomulik@meil.pw.edu.pl>\\n"
+"Language-Team: English\\n"
+"Language: en\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Old message from a.cpp"
+""")
+#
+test.write('pl.po',"""\
+# Polish translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: pl\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Stara wiadomosc z a.cpp"
+""")
+
+# NOTE: msgmerge(1) prints its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-update', stderr = None)
+test.must_exist('en.po', 'pl.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGMERGE/POUpdate_doc_user_examples2.py b/test/MSGMERGE/POUpdate_doc_user_examples2.py
new file mode 100644
index 00000000..0126391f
--- /dev/null
+++ b/test/MSGMERGE/POUpdate_doc_user_examples2.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env.POUpdate(['en','pl'], ['foo']) # foo.pot --&gt; [en.po, pl.po]
+""")
+#
+test.write('foo.pot',"""\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\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"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=CHARSET\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+#
+#: a.cpp:1
+msgid "Hello from a.cpp"
+msgstr ""
+""")
+#
+test.write('en.po',"""\
+# English translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Pawel Tomulik <ptomulik@meil.pw.edu.pl>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:37+0200\\n"
+"Last-Translator: Pawel Tomulik <ptomulik@meil.pw.edu.pl>\\n"
+"Language-Team: English\\n"
+"Language: en\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Old message from a.cpp"
+""")
+#
+test.write('pl.po',"""\
+# Polish translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: pl\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Stara wiadomosc z a.cpp"
+""")
+
+# NOTE: msgmerge(1) prints all messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-update', stderr = None)
+test.must_exist('en.po', 'pl.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGMERGE/POUpdate_doc_user_examples3.py b/test/MSGMERGE/POUpdate_doc_user_examples3.py
new file mode 100644
index 00000000..31c09c5f
--- /dev/null
+++ b/test/MSGMERGE/POUpdate_doc_user_examples3.py
@@ -0,0 +1,138 @@
+
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env.POUpdate(['en','pl'], POTDOMAIN='foo') # foo.pot --&gt; [en.po, pl.po]
+""")
+#
+test.write('foo.pot',"""\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\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"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=CHARSET\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+#
+#: a.cpp:1
+msgid "Hello from a.cpp"
+msgstr ""
+""")
+#
+test.write('en.po',"""\
+# English translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Pawel Tomulik <ptomulik@meil.pw.edu.pl>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:37+0200\\n"
+"Last-Translator: Pawel Tomulik <ptomulik@meil.pw.edu.pl>\\n"
+"Language-Team: English\\n"
+"Language: en\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Old message from a.cpp"
+""")
+#
+test.write('pl.po',"""\
+# Polish translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: pl\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Stara wiadomosc z a.cpp"
+""")
+
+# NOTE: msgmerge(1) prints its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-update', stderr = None)
+test.must_exist('en.po', 'pl.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGMERGE/POUpdate_doc_user_examples4.py b/test/MSGMERGE/POUpdate_doc_user_examples4.py
new file mode 100644
index 00000000..51d944f9
--- /dev/null
+++ b/test/MSGMERGE/POUpdate_doc_user_examples4.py
@@ -0,0 +1,144 @@
+
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env.POUpdate(LINGUAS_FILE = 1) # needs 'LINGUAS' file
+""")
+#
+test.write('LINGUAS',
+"""
+en
+pl
+""")
+#
+test.write('messages.pot',"""\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\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"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=CHARSET\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+#
+#: a.cpp:1
+msgid "Hello from a.cpp"
+msgstr ""
+""")
+#
+test.write('en.po',"""\
+# English translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Pawel Tomulik <ptomulik@meil.pw.edu.pl>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:37+0200\\n"
+"Last-Translator: Pawel Tomulik <ptomulik@meil.pw.edu.pl>\\n"
+"Language-Team: English\\n"
+"Language: en\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Old message from a.cpp"
+""")
+#
+test.write('pl.po',"""\
+# Polish translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: pl\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Stara wiadomosc z a.cpp"
+""")
+
+# NOTE: msgmerge(1) prints all messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-update', stderr = None)
+test.must_exist('messages.pot', 'en.po', 'pl.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGMERGE/POUpdate_doc_user_examples5.py b/test/MSGMERGE/POUpdate_doc_user_examples5.py
new file mode 100644
index 00000000..07751caf
--- /dev/null
+++ b/test/MSGMERGE/POUpdate_doc_user_examples5.py
@@ -0,0 +1,143 @@
+
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env.POUpdate(LINGUAS_FILE = 1, source = ['foo'])
+""")
+test.write('LINGUAS',
+"""
+en
+pl
+""")
+#
+test.write('foo.pot',"""\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\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"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=CHARSET\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+#
+#: a.cpp:1
+msgid "Hello from a.cpp"
+msgstr ""
+""")
+#
+test.write('en.po',"""\
+# English translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Pawel Tomulik <ptomulik@meil.pw.edu.pl>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:37+0200\\n"
+"Last-Translator: Pawel Tomulik <ptomulik@meil.pw.edu.pl>\\n"
+"Language-Team: English\\n"
+"Language: en\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Old message from a.cpp"
+""")
+#
+test.write('pl.po',"""\
+# Polish translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: pl\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Stara wiadomosc z a.cpp"
+""")
+
+# NOTE: msgmerge(1) prints its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-update', stderr = None)
+test.must_exist('en.po', 'pl.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGMERGE/POUpdate_doc_user_examples6.py b/test/MSGMERGE/POUpdate_doc_user_examples6.py
new file mode 100644
index 00000000..bd71acf3
--- /dev/null
+++ b/test/MSGMERGE/POUpdate_doc_user_examples6.py
@@ -0,0 +1,194 @@
+
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+env.POUpdate(['en', 'pl'], LINGUAS_FILE = 1)
+""")
+test.write('LINGUAS',
+"""
+de
+fr
+""")
+test.write('messages.pot',"""\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\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"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=CHARSET\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+#
+#: a.cpp:1
+msgid "Hello from a.cpp"
+msgstr ""
+""")
+#
+test.write('en.po',"""\
+# English translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Pawel Tomulik <ptomulik@meil.pw.edu.pl>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:37+0200\\n"
+"Last-Translator: Pawel Tomulik <ptomulik@meil.pw.edu.pl>\\n"
+"Language-Team: English\\n"
+"Language: en\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Old message from a.cpp"
+""")
+#
+test.write('pl.po',"""\
+# Polish translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: pl\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr "Stara wiadomosc z a.cpp"
+""")
+#
+test.write('de.po',"""\
+# German translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: de\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr ""
+""")
+#
+test.write('fr.po',"""\
+# French translations for PACKAGE package.
+# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Automatically generated, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2012-05-27 00:35+0200\\n"
+"PO-Revision-Date: 2012-05-27 00:35+0200\\n"
+"Last-Translator: Automatically generated\\n"
+"Language-Team: none\\n"
+"Language: fr\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=ASCII\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+#: a.cpp:1
+msgid "Old message from a.cpp"
+msgstr ""
+""")
+
+# Note: msgmerge(1) prints its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-update', stderr = None)
+test.must_exist('en.po', 'pl.po', 'de.po', 'fr.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+test.must_contain('de.po', "Hello from a.cpp")
+test.must_contain('fr.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSGMERGE/POUpdate_doc_user_examples8.py b/test/MSGMERGE/POUpdate_doc_user_examples8.py
new file mode 100644
index 00000000..e113e2ce
--- /dev/null
+++ b/test/MSGMERGE/POUpdate_doc_user_examples8.py
@@ -0,0 +1,74 @@
+
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+# Trivial example. Just load the tool.
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ["default", "gettext"] )
+
+# script-wise settings
+env['POAUTOINIT'] = 1
+env['LINGUAS_FILE'] = 1
+env['POTDOMAIN'] = 'foo'
+env.POTUpdate(source = 'a.cpp')
+env.POUpdate()
+""")
+test.write('LINGUAS',
+"""
+en
+pl
+""")
+test.write('a.cpp', """ gettext("Hello from a.cpp") """)
+
+# Note: msgmerge(1) prints its messages to stderr, we must ignore them,
+# So, stderr=None is crucial here. It is no point to match stderr to some
+# specific valuse; the messages are internationalized :) ).
+test.run(arguments = 'po-update', stderr = None)
+test.must_exist('foo.pot', 'en.po', 'pl.po')
+test.must_contain('en.po', "Hello from a.cpp")
+test.must_contain('pl.po', "Hello from a.cpp")
+
+test.pass_test()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/XGETTEXT/POTUpdate_doc_user_examples1.py b/test/XGETTEXT/POTUpdate_doc_user_examples1.py
new file mode 100644
index 00000000..63bdfdb2
--- /dev/null
+++ b/test/XGETTEXT/POTUpdate_doc_user_examples1.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+test = TestSCons.TestSCons()
+
+test.subdir('po')
+test.write('po/SConstruct',
+"""
+env = Environment( tools = ['default', 'xgettext'] )
+env.POTUpdate(['foo'], ['../a.cpp', '../b.cpp'])
+env.POTUpdate(['bar'], ['../c.cpp', '../d.cpp'])
+""")
+test.write('a.cpp', """ gettext("Hello from a.cpp") """)
+test.write('b.cpp', """ gettext("Hello from b.cpp") """)
+test.write('c.cpp', """ gettext("Hello from c.cpp") """)
+test.write('d.cpp', """ gettext("Hello from d.cpp") """)
+
+# scons '.' does not create foo.pot nor bar.pot
+test.run(arguments = '.', chdir = 'po')
+test.must_not_exist('po/foo.pot', 'po/bar.pot')
+
+# scons 'foo.pot' creates foo.pot
+test.run(arguments = 'foo.pot', chdir = 'po')
+test.must_exist('po/foo.pot')
+test.must_not_exist('po/bar.pot')
+test.must_contain('po/foo.pot',"Hello from a.cpp")
+test.must_contain('po/foo.pot',"Hello from b.cpp")
+test.must_not_contain('po/foo.pot',"Hello from c.cpp")
+test.must_not_contain('po/foo.pot',"Hello from d.cpp")
+
+# scons 'pot-update' creates foo.pot and bar.pot
+test.run(arguments = 'pot-update', chdir = 'po')
+test.must_exist('po/foo.pot', 'po/bar.pot')
+test.must_not_contain('po/bar.pot',"Hello from a.cpp")
+test.must_not_contain('po/bar.pot',"Hello from b.cpp")
+test.must_contain('po/bar.pot',"Hello from c.cpp")
+test.must_contain('po/bar.pot',"Hello from d.cpp")
+
+# scons -c does not clean anything
+test.run(arguments = '-c', chdir = 'po')
+test.must_exist('po/foo.pot', 'po/bar.pot')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/XGETTEXT/POTUpdate_doc_user_examples2.py b/test/XGETTEXT/POTUpdate_doc_user_examples2.py
new file mode 100644
index 00000000..3698d244
--- /dev/null
+++ b/test/XGETTEXT/POTUpdate_doc_user_examples2.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct',
+"""
+env = Environment( tools = ['default', 'xgettext'] )
+env['POTDOMAIN'] = "foo"
+env.POTUpdate(source = ["a.cpp", "b.cpp"]) # Creates foo.pot ...
+env.POTUpdate(POTDOMAIN = "bar", source = ["c.cpp", "d.cpp"]) # and bar.pot
+""")
+test.write('a.cpp', """ gettext("Hello from a.cpp") """)
+test.write('b.cpp', """ gettext("Hello from b.cpp") """)
+test.write('c.cpp', """ gettext("Hello from c.cpp") """)
+test.write('d.cpp', """ gettext("Hello from d.cpp") """)
+
+test.run(arguments = 'pot-update')
+
+test.must_exist('foo.pot')
+test.must_contain('foo.pot', "Hello from a.cpp")
+test.must_contain('foo.pot', "Hello from b.cpp")
+test.must_not_contain('foo.pot', "Hello from c.cpp")
+test.must_not_contain('foo.pot', "Hello from d.cpp")
+
+test.must_exist('bar.pot')
+test.must_not_contain('bar.pot', "Hello from a.cpp")
+test.must_not_contain('bar.pot', "Hello from b.cpp")
+test.must_contain('bar.pot', "Hello from c.cpp")
+test.must_contain('bar.pot', "Hello from d.cpp")
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/XGETTEXT/POTUpdate_doc_user_examples3.py b/test/XGETTEXT/POTUpdate_doc_user_examples3.py
new file mode 100644
index 00000000..de9687e4
--- /dev/null
+++ b/test/XGETTEXT/POTUpdate_doc_user_examples3.py
@@ -0,0 +1,67 @@
+
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+test = TestSCons.TestSCons()
+
+test.subdir('po')
+test.write('po/SConstruct',
+"""
+# SConstruct file in 'po/' subdirectory
+env = Environment( tools = ['default', 'xgettext'] )
+env.POTUpdate(XGETTEXTFROM = 'POTFILES.in')
+""")
+test.write('po/POTFILES.in',
+"""
+# POTFILES.in in 'po/' subdirectory
+../a.cpp
+../b.cpp
+# end of file
+""")
+test.write('a.cpp', """ gettext("Hello from a.cpp") """)
+test.write('b.cpp', """ gettext("Hello from b.cpp") """)
+
+# scons 'pot-update' creates messages.pot
+test.run(arguments = 'pot-update', chdir = 'po')
+test.must_exist('po/messages.pot')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/XGETTEXT/POTUpdate_doc_user_examples4.py b/test/XGETTEXT/POTUpdate_doc_user_examples4.py
new file mode 100644
index 00000000..881f65e0
--- /dev/null
+++ b/test/XGETTEXT/POTUpdate_doc_user_examples4.py
@@ -0,0 +1,67 @@
+
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+test = TestSCons.TestSCons()
+
+test.subdir('po')
+test.write('po/SConstruct',
+"""
+# SConstruct file in 'po/' subdirectory
+env = Environment( tools = ['default', 'xgettext'] )
+env.POTUpdate(XGETTEXTFROM = 'POTFILES.in', XGETTEXTPATH='../')
+""")
+test.write('po/POTFILES.in',
+"""
+# POTFILES.in in 'po/' subdirectory
+a.cpp
+b.cpp
+# end of file
+""")
+test.write('a.cpp', """ gettext("Hello from a.cpp") """)
+test.write('b.cpp', """ gettext("Hello from b.cpp") """)
+
+# scons 'pot-update' creates messages.pot
+test.run(arguments = 'pot-update', chdir = 'po')
+test.must_exist('po/messages.pot')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/XGETTEXT/POTUpdate_doc_user_examples5.py b/test/XGETTEXT/POTUpdate_doc_user_examples5.py
new file mode 100644
index 00000000..4afb3cf9
--- /dev/null
+++ b/test/XGETTEXT/POTUpdate_doc_user_examples5.py
@@ -0,0 +1,81 @@
+
+#!/usr/bin/env python
+#
+# __TOOL_COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Make sure, that the examples given in user guide all work.
+"""
+
+import TestSCons
+import os
+
+site_scons = os.environ['SCONS_TOOL_LIB_DIR']
+
+###############################################################################
+test = TestSCons.TestSCons()
+
+test.subdir('0', ['0','1'], ['0', '1', 'po'])
+test.write('0/1/po/SConstruct',
+"""
+# SConstruct file in '0/1/po/' subdirectory
+env = Environment( tools = ['default', 'xgettext'] )
+env.POTUpdate(XGETTEXTFROM = 'POTFILES.in', XGETTEXTPATH=['../', '../../'])
+""")
+test.write('0/1/po/POTFILES.in',
+"""
+# POTFILES.in in '0/1/po/' subdirectory
+a.cpp
+# end of file
+""")
+test.write('0/a.cpp', """ gettext("Hello from ../../a.cpp") """)
+test.write('0/1/a.cpp', """ gettext("Hello from ../a.cpp") """)
+
+# scons 'pot-update' creates messages.pot
+test.run(arguments = 'pot-update', chdir = '0/1/po')
+test.must_exist('0/1/po/messages.pot')
+test.must_contain('0/1/po/messages.pot', 'Hello from ../a.cpp')
+test.must_not_contain('0/1/po/messages.pot', 'Hello from ../../a.cpp')
+
+test.write('0/1/po/SConstruct',
+"""
+# SConstruct file in '0/1/po/' subdirectory
+env = Environment(
+ toolpath = ['""" + site_scons + """/SConsToolGettext']
+, tools = ['default', 'xgettext']
+)
+env.POTUpdate(XGETTEXTFROM = 'POTFILES.in', XGETTEXTPATH=['../../', '../'])
+""")
+test.run(arguments = 'pot-update', chdir = '0/1/po')
+test.must_contain('0/1/po/messages.pot', 'Hello from ../../a.cpp')
+test.must_not_contain('0/1/po/messages.pot', 'Hello from ../a.cpp')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: