3 # Helper script for translating desktop integration data
4 # Copyright (C) 2009 Peter Brett <peter@peter-b.co.uk>
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 # Print a simple help message, then exit with EXITSTATUS
25 Carry out translation tasks on desktop integration data.
28 desktop-i18n --extract <options> -- <xgettext_options>
29 desktop-i18n --create <options> INFILE OUTFILE
33 --extract Extract strings by calling xgettext
34 --create Substitute translated strings
35 --setup Setup a source tree to use desktop-i18n
36 --help Print this message
38 Options for --extract mode:
40 Specify xgettext executable to use
42 Options for --create mode:
44 Specify gettext executable to use
46 Retrieve translated bmessages from TEXTDOMAIN
47 --localedir=TEXTDOMAINDIR
48 Retrieve message catalog from TEXTDOMAINDIR
49 --lang=LANG Add a language to translate messages into
51 In order for this to work, all strings to be matched must be on a
52 single line. In a .desktop file, a translatable name-value pair must
53 have the desired name prefixed by an underscore. For example:
55 _Comment=gEDA Schematic Editor
57 In a MIME info file, XML tag pairs where the tagname begins with an
58 underscore are recognized. Both tags must be on the same line, and
59 the tag must be the only XML content on the line. Whitespace at the
60 start of the line before the opening tag is preserved. For example:
62 <_comment>gEDA circuit schematic</_comment>
64 Do not include double-quotes (") or slashes (\) in translatable
70 # extract_desktop INFILE
71 # ----------------------
72 # Parse desktop file data from standard input and generate C on
73 # standard output. If an error occurs, a message is printed blaming
76 # First argument is name of file being processed
77 echo "/* Generated from $1 by desktop-i18n */"
79 # Loop over each line of standard input
83 regexp
='^_\([^=]*\)=\(.*\)$'
84 if ! (echo $REPLY |
grep $regexp > /dev
/null
); then
87 name
=`echo $REPLY | sed -e "s:$regexp:\1:"`
88 msgid
=`echo $REPLY | sed -e "s:$regexp:\2:"`
90 # Test for bad characters
91 if (echo $msgid |
grep '["\\]' > /dev
/null
); then
92 echo "$1:$n: msgid contains invalid character" >&2
96 # Generate output line
97 if test "x$name" != x
-a "x$msgid" != x
; then
100 echo "$1:$n: name or msgid is empty" >&2
109 # Parse XML mimeinfo data from standard input and generate C on
110 # standard output. If an error occurs, a message is printed blaming
113 echo "/* Generated from $1 by desktop-i18n */"
115 # Loop over each line of standard input
119 regexp
='<_\([a-zA-Z][a-zA-Z]*\)>\(.*\)</_\1>'
120 if ! (echo $REPLY |
grep $regexp > /dev
/null
); then
123 name
=`echo $REPLY | sed -e "s:$regexp:\1:"`
124 msgid
=`echo $REPLY | sed -e "s:$regexp:\2:"`
126 # Test for bad characters
127 if (echo $msgid |
grep '["\\]' > /dev
/null
); then
128 echo "$1:$n: msgid contains invalid character" >&2
132 # Generate output line
133 if test "x$name" != x
-a "x$msgid" != x
; then
134 echo "_(\"$msgid\");"
136 echo "$1:$n: name or msgid is empty" >&2
142 # do_extract [OPTION]... -- [XGETTEXT_OPTION]...
143 # ----------------------------------------------
144 # A wrapper around xgettext. It identifies the file lists and search
145 # directories being used by xgettext, and from them any desktop or
146 # mimeinfo files to be processed.
148 # It then creates a new private directory, and adds it to the xgettext
149 # search path. It creates a new file list and set of preprocessed
150 # files in that directory, and then calls xgettext (preserving all
151 # other original arguments).
155 # First we have to process the command-line arguments
157 # Split into name=value
158 name
=`echo $arg | sed -e's:=.*::'`
159 value
=`echo $arg | sed -e's:^[^=]*=*::'`
161 if test "X$in_xg_args" = X
; then
162 # This is an argument only for this script
164 --xgettext) XGETTEXT
="$value";;
171 # This is an argument to xgettext. Luckily the Makefile only
172 # uses full-length arguments, and we only really care about the
175 --directory) search_dirs
="$search_dirs $value";;
176 --files-from) file_lists
="$file_lists $value";;
178 # We just want to pass this arg straight to xgettext, so
179 # stick it back on the end of the positional parameters
180 set x
"$@" "$arg"; shift;;
184 # Discard processed arg from positional parameters
188 # If our private data directory exists, die. Otherwise, create it.
190 if test -d $priv_dir; then
191 echo "desktop-i18n: $PWD/$priv_dir already exists"
196 # Process file lists if necessary
197 if test "X$file_lists" != X
; then
198 # Extract names of files we need to preprocess
199 desktop_in
=`cat $file_lists | grep ".desktop.in$"`
200 xml_in
=`cat $file_lists | grep ".xml.in$"`
202 # Create a new POTFILES file which uses the postprocessed
203 # filenames instead of the original ones.
205 sed -e "s:.desktop.in$:.desktop.in.h:" -e "s:.xml.in$:.xml.in.h:" \
209 # Preprocess .desktop files
210 for f
in $desktop_in; do
211 src
=`_search_file $f $search_dirs` ||
{ rm -rf $priv_dir; exit 3; }
212 mkdir
-p $priv_dir/`dirname $f`
213 extract_desktop
$f < $src > $priv_dir/$f.h
216 # Preprocess .xml files
218 src
=`_search_file $f $search_dirs` ||
{ rm -rf $priv_dir; exit 3; }
219 mkdir
-p $priv_dir/`dirname $f`
220 extract_xml
$f < $src > $priv_dir/$f.h
223 # Call xgettext (recall we saved some args in $@)
224 gen_args
="--files-from=$priv_dir/POTFILES --directory=$priv_dir"
225 for d
in $search_dirs; do
226 gen_args
="$gen_args --directory=$d"
228 $XGETTEXT $gen_args "$@"
230 # Clean up private directory
238 if test -f "$d/$f"; then echo "$d/$f"; exit; fi
240 echo "desktop-i18n: Cannot find $f in xgettext search directories"
243 # create_desktop INFILE
244 # ---------------------
245 # Parse desktop file data from standard input and generate a
246 # translated desktop file on standard output. If an error occurs, a
247 # message is printed blaming INFILE.
249 # Loop over each line of standard input
253 regexp
='^_\([^=]*\)=\(.*\)$'
254 if ! (echo $REPLY |
grep $regexp > /dev
/null
); then
258 name
=`echo $REPLY | sed -e "s:$regexp:\1:"`
259 msgid
=`echo $REPLY | sed -e "s:$regexp:\2:"`
261 # Test for bad characters
262 if (echo $msgid |
grep '["\\]' > /dev
/null
); then
263 echo "$1:$n: msgid contains invalid character" >&2
267 # Generate first output line
270 # Generate language-specific output lines
271 for lang
in $LINGUAS; do
272 msg
=`LANGUAGE=$lang $GETTEXT "$msgid"`
273 # If translated message is unmodified, don't write an output
275 if test "x$msg" = x
-o "$msg" = "$msgid"; then
279 echo "$name[$lang]=$msg"
286 # Parse XML mimeinfo data from standard input and generate a
287 # translated mimeinfo file on standard output. If an error occurs, a
288 # message is printed blaming INFILE.
290 # Loop over each line of standard input
294 # We have to do an ugly hack to avoid stripping whitespace.
297 read REPLY ||
{ IFS
="$saveIFS" ; break; }
301 regexp
='<_\([a-zA-Z][a-zA-Z]*\)>\(.*\)</_\1>'
302 if ! (echo $REPLY |
grep $regexp > /dev
/null
); then
306 name
=`echo $REPLY | sed -e "s:$regexp:\1:"`
307 msgid
=`echo $REPLY | sed -e "s:$regexp:\2:"`
308 prefix
=`echo $REPLY | sed -e "s:^\(.*\)<_$name>.*:\1:"`
309 suffix
=`echo $REPLY | sed -e "s:.*</_$name>\(.*\):\1:"`
311 # Test for bad characters
312 if (echo $msgid |
grep '["\\]' > /dev
/null
); then
313 echo "$1:$n: msgid contains invalid character" >&2
317 # Test for non-empty prefix/suffix
318 if test "x$prefix" != x
-o "x$suffix" != x
; then
319 echo "$1:$n: translatable tag must be alone on line" >&2
323 # Generate first output line
324 echo "$REPLY" |
sed -e "s:<_\($name\)>\(.*\)</_\1>:<\1>\2</\1>:"
326 # Generate language-specific output lines
327 for lang
in $LINGUAS; do
328 msg
=`LANGUAGE=$lang $GETTEXT "$msgid"`
329 # If translated message is unmodified, don't write an output
331 if test "x$msg" = x
-o "$msg" = "$msgid"; then
334 echo "$REPLY" |
sed -e "s,<_\($name\)>\(.*\)</_\1>,<\1 xml:lang=\"$lang\">$msg</\1>,"
339 # do_create [OPTION]... INFILE OUTFILE
340 # ------------------------------------
341 # Substitutes translations into .desktop or mimeinfo files.
345 # First process command-line arguments
347 # Split into name=value
348 name
=`echo $arg | sed -e's:=.*::'`
349 value
=`echo $arg | sed -e's:^[^=]*=*::'`
352 --gettext) GETTEXT
=$value;;
353 --domain) TEXTDOMAIN
=$value;;
354 --localedir) TEXTDOMAINDIR
=$value;;
355 --lang) LINGUAS
="$LINGUAS $value";;
357 # Arg might be a filename, so save it at the end of the
358 # positional parameters
359 set x
"$@" "$arg"; shift
362 # Discard processed arg from positional parameters
366 if test $# != 2; then usage
1; fi # Should only have 2 args left
367 INFILE
=$1; OUTFILE
=$2
368 if ! test -r $INFILE; then
369 echo "desktop-i18n: Cannot open $INFILE for reading."
378 if (echo "$INFILE" |
grep ".desktop.in$" > /dev
/null
); then
379 create_desktop
$INFILE < $INFILE > $OUTFILE
383 if (echo "$INFILE" |
grep ".xml.in$" > /dev
/null
); then
384 create_xml
$INFILE < $INFILE > $OUTFILE
388 echo "desktop-i18n: $INFILE: Unrecognized extension"
394 # Try to set up a source tree to use desktop-i18n.
396 # This is a nasty bit of hackery. We need to insert some rules into
397 # the Makefile.in.in installed by gettextize/autopoint so that make
398 # knows how to generate input for xgettext.
400 # Unfortunately, there's no nice way to do this, so we do it by
401 # appending some rules onto each Makefile.in.in, using the following
404 # 1. Look for configure.ac in DIR, or in cwd if DIR wasn't
405 # specified. If we can't find it, whinge.
406 # 2. If configure.ac doesn't have AX_DESKTOP_I18N, quit successfully.
407 # 3. Find anywhere where AC_CONFIG_FILES is called. For each
408 # Makefile.in found in the list of files to create:
409 # (a) Check for Makefile.in.in. If it doesn't exist, skip with a warning.
410 # (b) If Makefile.in.in contains the string DESKTOP_I18N_RULES,
412 # (c) Append a chunk of rules onto Makefile.in.in
414 # Note that we can't use a po/Rules-* file because substitution is not
415 # carried out on these files.
418 if test "x$1" = x
; then srcdir
=.
; else srcdir
=$1; fi
420 # Can we find configure.ac or configure.in?
421 for f
in configure.ac configure.
in; do
422 if test -r $srcdir/$f; then
427 if test "x$ac_file" = x
; then
428 echo "Cannot find configure.ac or configure.in!"
432 # Check that configure.ac is readable
433 if ! test -r $ac_file; then
434 echo "Cannot open $ac_file for reading."
438 # Is the AX_DESKTOP_I18N macro present?
439 if ! grep AX_DESKTOP_I18N
$ac_file > /dev
/null
; then
443 # Now we use a piece of m4 code to try and discover all of the
444 # configuration files. This is UGLY AND BAD, because it only detects
445 # when AC_CONFIG_FILES is called in the main configure script (if
446 # AC_CONFIG_FILES is called by another macro somewhere, it won't be
448 cat - $ac_file > conftest
<<EOF
451 define([AC_CONFIG_FILES], [divert([0])[\$1]divert([-1])])
453 conf_files
=`m4 conftest`
456 # Look for any files called Makefile.in.
457 for f
in $conf_files; do
458 # Discard any composition rules and prepend srcdir.
459 f
=`echo "$f" | sed -e 's,:.*,,'`
462 # Skip files not called Makefile.in
463 if test `echo "$f" | sed -e 's:.*/::'` != Makefile.
in; then
467 # Check that a corresponding Makefile.in.in exists and we can
469 if ! test -r $f.
in -a -w $f.
in; then
470 echo "desktop-i18n: Cannot process $f.in"
474 # Check that we haven't already hacked it
475 if grep DESKTOP_I18N_RULES
$f.
in > /dev
/null
; then
480 echo "desktop-i18n: modifying $f.in"
483 # DESKTOP_I18N_RULES (Do not edit or remove this line)
484 #####################################################################
485 # Makefile rules needed by the desktop-i18n tool.
486 # Copyright (C) 2009 Peter Brett <peter@peter-b.co.uk>
488 # This program is free software; you can redistribute it and/or modify
489 # it under the terms of the GNU General Public License as published by
490 # the Free Software Foundation; either version 2 of the License, or
491 # (at your option) any later version.
493 # This program is distributed in the hope that it will be useful,
494 # but WITHOUT ANY WARRANTY; without even the implied warranty of
495 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
496 # GNU General Public License for more details.
498 # You should have received a copy of the GNU General Public License
499 # along with this program; if not, write to the Free Software
500 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
502 top_builddir = @top_builddir@
505 DESKTOP_I18N_LOCALE_DIR = @DESKTOP_I18N_LOCALE_DIR@
507 # We need to temporarily install the localisation files somewhere so
508 # that desktop-i18n --create can look up messages in them. We recreate
509 # the timestamp before *and* after running 'make install' so that the
510 # make doesn't go into an infinite loop!
512 stamp-i18n: \$(DESKTOP_I18N_LOCALE_DIR) stamp-po Makefile
513 @echo timestamp > stamp-i18nT && mv stamp-i18nT stamp-i18n
514 \$(MAKE) prefix=\$(DESKTOP_I18N_LOCALE_DIR) install && \
515 cp \$(srcdir)/LINGUAS \$(DESKTOP_I18N_LOCALE_DIR)/\$(DOMAIN).LINGUAS \
517 @echo timestamp > stamp-i18nT && mv stamp-i18nT stamp-i18n
518 \$(DESKTOP_I18N_LOCALE_DIR):
519 \$(MKDIR_P) \$(DESKTOP_I18N_LOCALE_DIR)
523 -rm -rf \$(DESKTOP_I18N_LOCALE_DIR) stamp-i18n
525 # End of desktop-i18n rules
526 #####################################################################
534 # First argument has to be the mode of operation. Then call the
535 # appropriate function to process the rest of the arguments and do the
537 if test -z $1; then usage
1; fi
540 --extract) do_extract
"$@";;
541 --create) do_create
"$@";;
542 --setup) do_setup
"$@";;