]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Support for GNUstep .strings format.
authorBruno Haible <bruno@clisp.org>
Wed, 22 Oct 2003 10:49:08 +0000 (10:49 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:11:05 +0000 (12:11 +0200)
55 files changed:
gettext-tools/doc/ChangeLog
gettext-tools/doc/msgattrib.texi
gettext-tools/doc/msgcat.texi
gettext-tools/doc/msgcmp.texi
gettext-tools/doc/msgcomm.texi
gettext-tools/doc/msgconv.texi
gettext-tools/doc/msgen.texi
gettext-tools/doc/msgexec.texi
gettext-tools/doc/msgfilter.texi
gettext-tools/doc/msgfmt.texi
gettext-tools/doc/msggrep.texi
gettext-tools/doc/msginit.texi
gettext-tools/doc/msgmerge.texi
gettext-tools/doc/msgunfmt.texi
gettext-tools/doc/msguniq.texi
gettext-tools/doc/xgettext.texi
gettext-tools/po/ChangeLog
gettext-tools/po/POTFILES.in
gettext-tools/src/ChangeLog
gettext-tools/src/FILES
gettext-tools/src/Makefile.am
gettext-tools/src/Makefile.msvc
gettext-tools/src/Makefile.vms
gettext-tools/src/msgattrib.c
gettext-tools/src/msgcat.c
gettext-tools/src/msgcmp.c
gettext-tools/src/msgcomm.c
gettext-tools/src/msgconv.c
gettext-tools/src/msgen.c
gettext-tools/src/msgexec.c
gettext-tools/src/msgfilter.c
gettext-tools/src/msgfmt.c
gettext-tools/src/msggrep.c
gettext-tools/src/msginit.c
gettext-tools/src/msgmerge.c
gettext-tools/src/msgunfmt.c
gettext-tools/src/msguniq.c
gettext-tools/src/po-gram-gen.y
gettext-tools/src/read-po-abstract.c
gettext-tools/src/read-po-abstract.h
gettext-tools/src/read-po.c
gettext-tools/src/read-properties.c
gettext-tools/src/read-stringtable.c [new file with mode: 0644]
gettext-tools/src/read-stringtable.h [new file with mode: 0644]
gettext-tools/src/write-po.c
gettext-tools/src/write-po.h
gettext-tools/src/write-stringtable.c [new file with mode: 0644]
gettext-tools/src/write-stringtable.h [new file with mode: 0644]
gettext-tools/src/x-po.c
gettext-tools/src/x-stringtable.h [new file with mode: 0644]
gettext-tools/src/xgettext.c
gettext-tools/tests/ChangeLog
gettext-tools/tests/Makefile.am
gettext-tools/tests/msgcat-13 [new file with mode: 0755]
gettext-tools/tests/xgettext-33 [new file with mode: 0755]

index d8271c18479b712989a5bb22dec81667440249b9..5f869c3cef1b9dc8b6ef9c93040371fca7a83f06 100644 (file)
@@ -1,3 +1,22 @@
+2003-10-12  Bruno Haible  <bruno@clisp.org>
+
+       * msgattrib.texi: Document --stringtable-input and --stringtable-output
+       options.
+       * msgcat.texi: Likewise.
+       * msgcomm.texi: Likewise.
+       * msgconv.text: Likewise.
+       * msgen.texi: Likewise.
+       * msgfilter.texi: Likewise.
+       * msgrep.texi: Likewise.
+       * msginit.texi: Likewise.
+       * msgmerge.texi: Likewise.
+       * msguniq.texi: Likewise.
+       * msgcmp.texi: Document --stringtable-input option.
+       * msgexec.texi: Likewise.
+       * msgfmt.texi: Likewise.
+       * msgunfmt.texi: Document --stringtable-output option.
+       * xgettext.texi: Likewise. Document --language=NXStringTable.
+
 2003-10-11  Bruno Haible  <bruno@clisp.org>
 
        * gettext.texi (PHP): Drop phplib from list of RPMs.
index f4c31702b0d089208b10cbaa07d74d2793d6f28e..d27912a9ee6f095e6959e999545ab6b131553e8a 100644 (file)
@@ -128,6 +128,11 @@ obsolete messages and makes them non-obsolete.
 Assume the input file is a Java ResourceBundle in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msgattrib} option}
+Assume the input file is a NeXTstep/GNUstep localized resource file in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Output details
@@ -169,6 +174,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax.  Note
 that this file format doesn't support plural forms and silently drops
 obsolete messages.
 
+@item --stringtable-output
+@opindex --stringtable-output@r{, @code{msgattrib} option}
+Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax.
+Note that this file format doesn't support plural forms.
+
 @item -w @var{number}
 @itemx --width=@var{number}
 @opindex -w@r{, @code{msgattrib} option}
index 0e61e18ba54979900579d81bb5cb2a50be589cda..c53d883cd761c71d4e54728923727f7330a7e8a8 100644 (file)
@@ -92,6 +92,11 @@ printed.
 Assume the input files are Java ResourceBundles in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msgcat} option}
+Assume the input files are NeXTstep/GNUstep localized resource files in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Output details
@@ -144,6 +149,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax.  Note
 that this file format doesn't support plural forms and silently drops
 obsolete messages.
 
+@item --stringtable-output
+@opindex --stringtable-output@r{, @code{msgcat} option}
+Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax.
+Note that this file format doesn't support plural forms.
+
 @item -w @var{number}
 @itemx --width=@var{number}
 @opindex -w@r{, @code{msgcat} option}
index 80b7eee15bb788f5be2de4af56af1f6b4f844c49..b7f5a2a8b63dfe995fd79f03a3cc4b8370cec96c 100644 (file)
@@ -52,6 +52,11 @@ Apply @var{ref}.pot to each of the domains in @var{def}.po.
 Assume the input files are Java ResourceBundles in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msgcmp} option}
+Assume the input files are NeXTstep/GNUstep localized resource files in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Informative output
index 0ad42036af2c7ef7fc8f73b59e26bf8e4b7e0a3b..86fc711f427c0bf848e5f06cd45615a3b035d38b 100644 (file)
@@ -90,6 +90,11 @@ printed.
 Assume the input files are Java ResourceBundles in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msgcomm} option}
+Assume the input files are NeXTstep/GNUstep localized resource files in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Output details
@@ -131,6 +136,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax.  Note
 that this file format doesn't support plural forms and silently drops
 obsolete messages.
 
+@item --stringtable-output
+@opindex --stringtable-output@r{, @code{msgcomm} option}
+Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax.
+Note that this file format doesn't support plural forms.
+
 @item -w @var{number}
 @itemx --width=@var{number}
 @opindex -w@r{, @code{msgcomm} option}
index 8148244135a9b7c45b29766d8f2f72ac8e57e256..c5f53f6eeef298a1cbb57252e0284c4b79d58216 100644 (file)
@@ -63,6 +63,11 @@ The default encoding is the current locale's encoding.
 Assume the input file is a Java ResourceBundle in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msgonv} option}
+Assume the input file is a NeXTstep/GNUstep localized resource file in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Output details
@@ -102,6 +107,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax.  Note
 that this file format doesn't support plural forms and silently drops
 obsolete messages.
 
+@item --stringtable-output
+@opindex --stringtable-output@r{, @code{msgconv} option}
+Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax.
+Note that this file format doesn't support plural forms.
+
 @item -w @var{number}
 @itemx --width=@var{number}
 @opindex -w@r{, @code{msgconv} option}
index b3a7e524510df0eff5e10405ef72a59b48983b3f..7923cd7ba8e21046164f8a0d66cedf4348b26507 100644 (file)
@@ -56,6 +56,11 @@ or if it is @samp{-}.
 Assume the input file is a Java ResourceBundle in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msgen} option}
+Assume the input file is a NeXTstep/GNUstep localized resource file in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Output details
@@ -95,6 +100,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax.  Note
 that this file format doesn't support plural forms and silently drops
 obsolete messages.
 
+@item --stringtable-output
+@opindex --stringtable-output@r{, @code{msgen} option}
+Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax.
+Note that this file format doesn't support plural forms.
+
 @item -w @var{number}
 @itemx --width=@var{number}
 @opindex -w@r{, @code{msgen} option}
index 7163fa40fa464c7290a9964df2b59e0097294238..46118327063e863b1b19b6b4899e6bfad2de7932 100644 (file)
@@ -66,6 +66,11 @@ If no @var{inputfile} is given or if it is @samp{-}, standard input is read.
 Assume the input file is a Java ResourceBundle in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msgexec} option}
+Assume the input file is a NeXTstep/GNUstep localized resource file in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Informative output
index 7c78dc875a875a8f400e19717a8c35e2e7499912..4e978cdb5cfd1545a8750711fa5f73f76ff2f48e 100644 (file)
@@ -104,6 +104,11 @@ Suppress automatic printing of pattern space.
 Assume the input file is a Java ResourceBundle in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msgfilter} option}
+Assume the input file is a NeXTstep/GNUstep localized resource file in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Output details
@@ -147,6 +152,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax.  Note
 that this file format doesn't support plural forms and silently drops
 obsolete messages.
 
+@item --stringtable-output
+@opindex --stringtable-output@r{, @code{msgfilter} option}
+Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax.
+Note that this file format doesn't support plural forms.
+
 @item -w @var{number}
 @itemx --width=@var{number}
 @opindex -w@r{, @code{msgfilter} option}
index 1444368565b09d07e0be939e6b10efac66dc3760..821ca8855167b1d1c6dc8d59814571f8cda01ddf 100644 (file)
@@ -126,6 +126,11 @@ written in the specified directory.
 Assume the input files are Java ResourceBundles in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msgfmt} option}
+Assume the input files are NeXTstep/GNUstep localized resource files in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Input file interpretation
index b8dfe5ff56e2dfd2c2c8ec846971c2ad2d2f4673..d3b4eb8a9cce8019ec6d0348aed8d455e6c9a7b5 100644 (file)
@@ -143,6 +143,11 @@ Ignore case distinctions.
 Assume the input file is a Java ResourceBundle in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msggrep} option}
+Assume the input file is a NeXTstep/GNUstep localized resource file in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Output details
@@ -180,6 +185,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax.  Note
 that this file format doesn't support plural forms and silently drops
 obsolete messages.
 
+@item --stringtable-output
+@opindex --stringtable-output@r{, @code{msggrep} option}
+Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax.
+Note that this file format doesn't support plural forms.
+
 @item -w @var{number}
 @itemx --width=@var{number}
 @opindex -w@r{, @code{msggrep} option}
index e2f53917475f576451b4df1079ce3f7756e20685..5b0f5253580184357a1bab37211a4ff16b2f4069 100644 (file)
@@ -48,6 +48,11 @@ standard output.
 Assume the input file is a Java ResourceBundle in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msginit} option}
+Assume the input file is a NeXTstep/GNUstep localized resource file in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Output details
@@ -74,6 +79,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax.  Note
 that this file format doesn't support plural forms and silently drops
 obsolete messages.
 
+@item --stringtable-output
+@opindex --stringtable-output@r{, @code{msginit} option}
+Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax.
+Note that this file format doesn't support plural forms.
+
 @item -w @var{number}
 @itemx --width=@var{number}
 @opindex -w@r{, @code{msginit} option}
index d2830d0730c3971e291ff7ed73d229f95bcf8a1b..90dccd5b9c05598daab11abc5e96290ce3453529 100644 (file)
@@ -138,6 +138,11 @@ up the operation considerably.
 Assume the input files are Java ResourceBundles in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msgmerge} option}
+Assume the input files are NeXTstep/GNUstep localized resource files in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Output details
@@ -177,6 +182,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax.  Note
 that this file format doesn't support plural forms and silently drops
 obsolete messages.
 
+@item --stringtable-output
+@opindex --stringtable-output@r{, @code{msgmerge} option}
+Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax.
+Note that this file format doesn't support plural forms.
+
 @item -w @var{number}
 @itemx --width=@var{number}
 @opindex -w@r{, @code{msgmerge} option}
index afd4f19bc6fa23c196406b44bd2daf99b53a6674..150bcd9f1398c771b8924564db1b65567ddcae8f 100644 (file)
@@ -118,6 +118,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax.  Note
 that this file format doesn't support plural forms and silently drops
 obsolete messages.
 
+@item --stringtable-output
+@opindex --stringtable-output@r{, @code{msgunfmt} option}
+Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax.
+Note that this file format doesn't support plural forms.
+
 @item -w @var{number}
 @itemx --width=@var{number}
 @opindex -w@r{, @code{msgunfmt} option}
index 42c897ebb164a1318121b9e755f9187feb839a4d..43bb4823635cb3b905d92eadb49fe56f74da1c9b 100644 (file)
@@ -76,6 +76,11 @@ Print only unique messages, discard duplicates.
 Assume the input file is a Java ResourceBundle in Java @code{.properties}
 syntax, not in PO file syntax.
 
+@item --stringtable-input
+@opindex --stringtable-input@r{, @code{msguniq} option}
+Assume the input file is a NeXTstep/GNUstep localized resource file in
+@code{.strings} syntax, not in PO file syntax.
+
 @end table
 
 @subsection Output details
@@ -128,6 +133,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax.  Note
 that this file format doesn't support plural forms and silently drops
 obsolete messages.
 
+@item --stringtable-output
+@opindex --stringtable-output@r{, @code{msguniq} option}
+Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax.
+Note that this file format doesn't support plural forms.
+
 @item -w @var{number}
 @itemx --width=@var{number}
 @opindex -w@r{, @code{msguniq} option}
index a29cbc76fd7a1f4bc3aa4fbc3c6bb8cb699d0fe3..2c84ee6e36cfbf2b5f975e191123c95a1c65c05b 100644 (file)
@@ -72,7 +72,7 @@ Specifies the language of the input files.  The supported languages
 are @code{C}, @code{C++}, @code{ObjectiveC}, @code{PO}, @code{Python},
 @code{Lisp}, @code{EmacsLisp}, @code{librep}, @code{Smalltalk}, @code{Java},
 @code{JavaProperties}, @code{awk}, @code{YCP}, @code{Tcl}, @code{Perl},
-@code{PHP}, @code{GCC-source}, @code{RST}, @code{Glade}.
+@code{PHP}, @code{GCC-source}, @code{NXStringTable}, @code{RST}, @code{Glade}.
 
 @item -C
 @itemx --c++
@@ -269,6 +269,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax.  Note
 that this file format doesn't support plural forms and silently drops
 obsolete messages.
 
+@item --stringtable-output
+@opindex --stringtable-output@r{, @code{xgettext} option}
+Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax.
+Note that this file format doesn't support plural forms.
+
 @item -w @var{number}
 @itemx --width=@var{number}
 @opindex -w@r{, @code{xgettext} option}
index 94b61407813c7a4779c84dc25bb7849a20124b12..8ccd553898866f6618465c2e8a4b8a77d7637073 100644 (file)
@@ -1,3 +1,7 @@
+2003-10-14  Bruno Haible  <bruno@clisp.org>
+
+       * POTFILES.in: Add src/read-stringtable.c.
+
 2003-10-09  Bruno Haible  <bruno@clisp.org>
 
        * POTFILES.in: Add src/java.c.
index 74046b099d6f292343667029f5bb2aef8a79383c..c35255253c0254c0442eb96468d717e56ed6d460 100644 (file)
@@ -68,6 +68,7 @@ src/read-java.c
 src/read-mo.c
 src/read-po.c
 src/read-properties.c
+src/read-stringtable.c
 src/read-tcl.c
 src/urlget.c
 src/write-java.c
index 7e023b41481dbf76cd47dd2e9ab510477a7aba2f..2a104ea60ad93b5ca6345046173c1163f8c40299 100644 (file)
@@ -1,3 +1,100 @@
+2003-10-18  Bruno Haible  <bruno@clisp.org>
+
+       Support for GNUstep .strings format.
+       * read-stringtable.h: New file.
+       * read-stringtable.c: New file.
+       * read-po-abstract.h (enum input_syntax_ty): New item
+       syntax_stringtable.
+       (po_callback_comment_dispatcher): Renamed from po_callback_comment.
+       (po_callback_comment, po_callback_comment_special): New declarations.
+       * read-po-abstract.c: Include read-stringtable.h.
+       (po_scan): Add support for syntax_stringtable.
+       (po_callback_comment_dispatcher): Renamed from po_callback_comment.
+       (po_callback_comment, po_callback_comment_dot): New functions.
+       (po_callback_comment_special): New function.
+       * read-po.c (read_po): Set mdlp->encoding for syntax_stringtable too.
+       * po-gram-gen.y: Update po_callback_comment_dispatcher call.
+       * read-properties.c (properties_parse): Likewise.
+       * write-stringtable.h: New file.
+       * write-stringtable.c: New file.
+       * write-po.h (make_format_description_string, significant_format_p):
+       New declarations.
+       (message_print_syntax_stringtable): New declaration.
+       * write-po.c: Include write-stringtable.h.
+       (make_format_description_string, significant_format_p): Make
+       non-static.
+       (use_syntax_stringtable): New variable.
+       (message_print_syntax_stringtable): New function.
+       (msgdomain_list_print): Add check for plural forms for
+       syntax_stringtable too. Add support for writing the .strings format.
+       * msgattrib.c (long_options): Add --stringtable-input/output.
+       (main): Handle them.
+       (usage): Document options --stringtable-input/output.
+       * msgcat.c (long_options): Add --stringtable-input/output.
+       (main): Handle them. If option --stringtable-output is used, convert to
+       UTF-8 and ignore the to_code.
+       (usage): Document options --stringtable-input/output.
+       * msgcmp.c (long_options): Add --stringtable-input.
+       (main): Handle it.
+       (usage): Document option --stringtable-input.
+       * msgcomm.c (long_options): Add --stringtable-input/output.
+       (main): Handle them.
+       (usage): Document options --stringtable-input/output.
+       * msgconv.c (long_options): Add --stringtable-input/output.
+       (main): Handle them. If option --stringtable-output is used, ignore the
+       to_code.
+       (usage): Document options --stringtable-input/output.
+       * msgen.c (long_options): Add --stringtable-input/output.
+       (main): Handle them.
+       (usage): Document options --stringtable-input/output.
+       * msgexec.c: Include limits.h.
+       (long_options): Add --stringtable-input.
+       (main): Handle it.
+       (usage): Document option --stringtable-input.
+       * msgfilter.c (long_options): Add --stringtable-input/output.
+       (main): Handle them.
+       (usage): Document options --stringtable-input/output.
+       * msgfmt.c (long_options): Add --stringtable-input.
+       (main): Handle it.
+       (usage): Document option --stringtable-input.
+       * msggrep.c (long_options): Add --stringtable-input/output.
+       (main): Handle them.
+       (usage): Document options --stringtable-input/output.
+       * msginit.c (long_options): Add --stringtable-input/output.
+       (main): Handle them.
+       (usage): Document options --stringtable-input/output.
+       * msgmerge.c (long_options): Add --stringtable-input/output.
+       (main): Handle them. In update mode, --stringtable-input implies
+       --stringtable-output.
+       (usage): Document options --stringtable-input/output.
+       * msgunfmt.c (long_options): Add --stringtable-output.
+       (main): Handle it.
+       (usage): Document option --stringtable-output.
+       * msguniq.c (long_options): Add --stringtable-input/output.
+       (main): Handle them.
+       (usage): Document options --stringtable-input/output.
+       * x-stringtable.h: New file.
+       * x-po.c: Include x-stringtable.h.
+       (extract_stringtable): New function.
+       * xgettext.c: Include x-stringtable.h.
+       (long_options): Add --stringtable-output.
+       (main): Handle it.
+       (usage): Document options -L NXStringTable and --stringtable-output.
+       (finalize_header): If --stringtable-output was given, set the charset.
+       (language_to_extractor): Add support for .strings format.
+       (extension_to_language): Likewise.
+       * Makefile.am (noinst_HEADERS): Add read-stringtable.h,
+       write-stringtable.h, x-stringtable.h.
+       (COMMON_SOURCE): Add read-stringtable.c.
+       (libgettextsrc_la_SOURCES): Add write-stringtable.c.
+       * Makefile.msvc (OBJECTS): Add read-stringtable.obj,
+       write-stringtable.obj.
+       (read-stringtable.obj, write-stringtable.obj): New rules.
+       * Makefile.vms (OBJECTS): Add read-stringtable.obj,
+       write-stringtable.obj.
+       (read-stringtable.obj, write-stringtable.obj): New rules.
+       * FILES: Update.
+
 2003-10-21  Bruno Haible  <bruno@clisp.org>
 
        * hostname.c (xgethostname): Add support for native Woe32 API.
index 9f4ad08eef089715f0a201cecea5ce800e86d02c..e67a6a746cfe3c2f67b6a5b1e4227eaa6e8a1333 100644 (file)
@@ -38,6 +38,10 @@ write-po.c
 write-properties.h
 write-properties.c
                 Output of a list-of-messages to a Java .properties file.
+write-stringtable.h
+write-stringtable.c
+                Output of a list-of-messages to a NeXTstep/GNUstep .strings
+                file.
 
 +-------------- Reading PO files
 | open-po.h
@@ -59,8 +63,11 @@ write-properties.c
 | po-gram-gen.y
 | read-properties.h
 | read-properties.c
+| read-stringtable.h
+| read-stringtable.c
 | read-po-abstract.c
-|               Parsing of PO files and Java .properties files.
+|               Parsing of PO files and Java .properties and NeXTstep/GNUstep
+|              .strings files.
 |         read-po-abstract.h
 |                       General parser structure.
 |         po-hash.h
@@ -73,6 +80,9 @@ write-properties.c
 |         read-properties.h
 |         read-properties.c
 |                       Parsing of Java .properties files.
+|         read-stringtable.h
+|         read-stringtable.c
+|                       Parsing of NeXTstep/GNUstep .strings files.
 |         read-po-abstract.c
 |                       Top-level parser functions and callbacks.
 |
@@ -217,8 +227,10 @@ format.c        Table of the language dependent format string handlers.
 |               String extractor for C.
 | x-po.h
 | x-properties.h
+| x-stringtable.h
 | x-po.c
-|               String extractor from PO files and Java .properties files.
+|               String extractor from PO files and Java .properties and
+|               NeXTstep/GNUstep .strings files.
 | x-sh.h
 | x-sh.c
 |               String extractor for Shell.
index 29c45c310cf3d25c0a8ec2f44eb8c3def13aa30f..fc8cae11cd613250b0c1faaa591027988950139f 100644 (file)
@@ -35,14 +35,15 @@ lib_LTLIBRARIES = libgettextsrc.la libgettextpo.la
 include_HEADERS = gettext-po.h
 
 noinst_HEADERS = pos.h message.h po-gram.h po-hash.h po-charset.h po-lex.h \
-open-po.h read-po-abstract.h read-po.h read-properties.h str-list.h \
-write-po.h write-properties.h dir-list.h file-list.h po-gram-gen.h \
-po-gram-gen2.h po-hash-gen.h msgl-charset.h msgl-equal.h msgl-iconv.h \
-msgl-ascii.h msgl-cat.h msgl-english.h msgfmt.h msgunfmt.h plural-count.h \
-read-mo.h write-mo.h read-java.h write-java.h read-tcl.h write-tcl.h \
-po-time.h plural-table.h format.h xgettext.h x-c.h x-po.h x-sh.h x-python.h \
-x-lisp.h x-elisp.h x-librep.h x-smalltalk.h x-java.h x-properties.h x-awk.h \
-x-ycp.h x-tcl.h x-perl.h x-php.h x-rst.h x-glade.h
+open-po.h read-po-abstract.h read-po.h read-properties.h read-stringtable.h \
+str-list.h write-po.h write-properties.h write-stringtable.h dir-list.h \
+file-list.h po-gram-gen.h po-gram-gen2.h po-hash-gen.h msgl-charset.h \
+msgl-equal.h msgl-iconv.h msgl-ascii.h msgl-cat.h msgl-english.h msgfmt.h \
+msgunfmt.h plural-count.h read-mo.h write-mo.h read-java.h write-java.h \
+read-tcl.h write-tcl.h po-time.h plural-table.h format.h xgettext.h x-c.h \
+x-po.h x-sh.h x-python.h x-lisp.h x-elisp.h x-librep.h x-smalltalk.h x-java.h \
+x-properties.h x-awk.h x-ycp.h x-tcl.h x-perl.h x-php.h x-stringtable.h \
+x-rst.h x-glade.h
 
 EXTRA_DIST += FILES project-id ChangeLog.0
 
@@ -87,7 +88,7 @@ JAVACOMP = $(SHELL) ../lib/javacomp.sh
 # (read-po-abstract.c <--> po-hash-gen.y <--> po-gram-gen.y <--> po-lex.c) -> message.c -> str-list.c.
 COMMON_SOURCE = message.c \
 read-po-abstract.c po-lex.c po-gram-gen.y po-hash-gen.y po-charset.c \
-read-properties.c open-po.c dir-list.c str-list.c
+read-properties.c read-stringtable.c open-po.c dir-list.c str-list.c
 
 # xgettext and msgfmt deal with format strings.
 FORMAT_SOURCE = format.c format-invalid.h \
@@ -98,8 +99,8 @@ format-gcc-internal.c
 
 # libgettextsrc contains all code that is needed by at least two programs.
 libgettextsrc_la_SOURCES = \
-$(COMMON_SOURCE) read-po.c write-properties.c write-po.c msgl-ascii.c \
-msgl-iconv.c msgl-equal.c msgl-cat.c msgl-english.c file-list.c \
+$(COMMON_SOURCE) read-po.c write-properties.c write-stringtable.c write-po.c \
+msgl-ascii.c msgl-iconv.c msgl-equal.c msgl-cat.c msgl-english.c file-list.c \
 msgl-charset.c po-time.c plural.c plural-table.c $(FORMAT_SOURCE)
 
 # libgettextpo contains the public API for PO files.
index 46ae9630c26d8e831f09a5c3c3e2f518bbebbe0d..d9c2f922e43133072068112b6d931469e2cb843a 100644 (file)
@@ -112,11 +112,13 @@ OBJECTS = \
   po-hash-gen.obj \
   po-charset.obj \
   read-properties.obj \
+  read-stringtable.obj \
   open-po.obj \
   dir-list.obj \
   str-list.obj \
   read-po.obj \
   write-properties.obj \
+  write-stringtable.obj \
   write-po.obj \
   msgl-ascii.obj \
   msgl-iconv.obj \
@@ -189,6 +191,9 @@ po-charset.obj : po-charset.c
 read-properties.obj : read-properties.c
        $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c read-properties.c
 
+read-stringtable.obj : read-stringtable.c
+       $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c read-stringtable.c
+
 open-po.obj : open-po.c
        $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c open-po.c
 
@@ -204,6 +209,9 @@ read-po.obj : read-po.c
 write-properties.obj : write-properties.c
        $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c write-properties.c
 
+write-stringtable.obj : write-stringtable.c
+       $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c write-stringtable.c
+
 write-po.obj : write-po.c
        $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c write-po.c
 
index 0e46986af08d1bbab0ee89ec3eb9ba93e20416d9..2282c7fbca6923a69a4777e86b221e7f302da97a 100644 (file)
@@ -58,11 +58,13 @@ OBJECTS = \
   po-hash-gen.obj, \
   po-charset.obj, \
   read-properties.obj, \
+  read-stringtable.obj, \
   open-po.obj, \
   dir-list.obj, \
   str-list.obj, \
   read-po.obj, \
   write-properties.obj, \
+  write-stringtable.obj, \
   write-po.obj, \
   msgl-ascii.obj, \
   msgl-iconv.obj, \
@@ -133,6 +135,9 @@ po-charset.obj : po-charset.c
 read-properties.obj : read-properties.c
        $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) read-properties.c
 
+read-stringtable.obj : read-stringtable.c
+       $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) read-stringtable.c
+
 open-po.obj : open-po.c
        $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) open-po.c
 
@@ -148,6 +153,9 @@ read-po.obj : read-po.c
 write-properties.obj : write-properties.c
        $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) write-properties.c
 
+write-stringtable.obj : write-stringtable.c
+       $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) write-stringtable.c
+
 write-po.obj : write-po.c
        $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) write-po.c
 
index 0e78d9fa4d7e07be785e43c3dd76fcd10b4993d9..fede0840dc850a9795a8631945b9bd39a60a1639 100644 (file)
@@ -97,6 +97,8 @@ static const struct option long_options[] =
   { "set-obsolete", no_argument, NULL, CHAR_MAX + 9 },
   { "sort-by-file", no_argument, NULL, 'F' },
   { "sort-output", no_argument, NULL, 's' },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 16 },
+  { "stringtable-output", no_argument, NULL, CHAR_MAX + 17 },
   { "strict", no_argument, NULL, 'S' },
   { "translated", no_argument, NULL, CHAR_MAX + 1 },
   { "untranslated", no_argument, NULL, CHAR_MAX + 2 },
@@ -288,6 +290,14 @@ main (int argc, char **argv)
        ignore_file = optarg;
        break;
 
+      case CHAR_MAX + 16: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
+
+      case CHAR_MAX + 17: /* --stringtable-output */
+       message_print_syntax_stringtable ();
+       break;
+
       default:
        usage (EXIT_FAILURE);
        /* NOTREACHED */
@@ -430,6 +440,8 @@ Attribute manipulation:\n"));
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input file is in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
       printf ("\n");
       printf (_("\
 Output details:\n"));
@@ -450,6 +462,8 @@ Output details:\n"));
       printf (_("\
   -p, --properties-output     write out a Java .properties file\n"));
       printf (_("\
+      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
+      printf (_("\
   -w, --width=NUMBER          set output page width\n"));
       printf (_("\
       --no-wrap               do not break long message lines, longer than\n\
index f78ee2b530990891e088f3f17790ef02932120d9..5c90f87be0b53ea84900a2ddf17985bf0316ec60 100644 (file)
@@ -71,6 +71,8 @@ static const struct option long_options[] =
   { "sort-by-file", no_argument, NULL, 'F' },
   { "sort-output", no_argument, NULL, 's' },
   { "strict", no_argument, NULL, 'S' },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 3 },
+  { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 },
   { "to-code", required_argument, NULL, 't' },
   { "unique", no_argument, NULL, 'u' },
   { "use-first", no_argument, NULL, CHAR_MAX + 1 },
@@ -240,6 +242,14 @@ main (int argc, char **argv)
        message_page_width_ignore ();
        break;
 
+      case CHAR_MAX + 3: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
+
+      case CHAR_MAX + 4: /* --stringtable-output */
+       message_print_syntax_stringtable ();
+       break;
+
       default:
        usage (EXIT_FAILURE);
        /* NOTREACHED */
@@ -290,6 +300,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
   /* Read input files, then filter, convert and merge messages.  */
   result = catenate_msgdomain_list (file_list,
                                    output_syntax != syntax_properties
+                                   && output_syntax != syntax_stringtable
                                    ? to_code
                                    : "UTF-8");
 
@@ -372,6 +383,9 @@ Message selection:\n"));
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input files are in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input files are in NeXTstep/GNUstep .strings\n\
+                              syntax\n"));
       printf ("\n");
       printf (_("\
 Output details:\n"));
@@ -397,6 +411,8 @@ Output details:\n"));
       printf (_("\
   -p, --properties-output     write out a Java .properties file\n"));
       printf (_("\
+      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
+      printf (_("\
   -w, --width=NUMBER          set output page width\n"));
       printf (_("\
       --no-wrap               do not break long message lines, longer than\n\
index 0ec8309969a6a4eb2df34a5ff4df52b8cb98ea51..00c1692ad69b01096a47a82b642f5627f2a8d5a0 100644 (file)
@@ -55,6 +55,7 @@ static const struct option long_options[] =
   { "help", no_argument, NULL, 'h' },
   { "multi-domain", no_argument, NULL, 'm' },
   { "properties-input", no_argument, NULL, 'P' },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 1 },
   { "version", no_argument, NULL, 'V' },
   { NULL, 0, NULL, 0 }
 };
@@ -122,6 +123,10 @@ main (int argc, char *argv[])
        do_version = true;
        break;
 
+      case CHAR_MAX + 1: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
+
       default:
        usage (EXIT_FAILURE);
        break;
@@ -207,6 +212,9 @@ Operation modifiers:\n"));
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input files are in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input files are in NeXTstep/GNUstep .strings\n\
+                              syntax\n"));
       printf ("\n");
       printf (_("\
 Informative output:\n"));
index 6a6c41ba1b652eb6d1e754c9ceb2627f09d94573..bff1c82a92611260b353c77714a906fdf9b6e2a1 100644 (file)
@@ -75,6 +75,8 @@ static const struct option long_options[] =
   { "sort-by-file", no_argument, NULL, 'F' },
   { "sort-output", no_argument, NULL, 's' },
   { "strict", no_argument, NULL, 'S' },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 3 },
+  { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 },
   { "to-code", required_argument, NULL, 't' },
   { "unique", no_argument, NULL, 'u' },
   { "version", no_argument, NULL, 'V' },
@@ -237,6 +239,14 @@ main (int argc, char *argv[])
        message_page_width_ignore ();
        break;
 
+      case CHAR_MAX + 3: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
+
+      case CHAR_MAX + 4: /* --stringtable-output */
+       message_print_syntax_stringtable ();
+       break;
+
       default:
        usage (EXIT_FAILURE);
        /* NOTREACHED */
@@ -378,6 +388,9 @@ Message selection:\n"));
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input files are in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input files are in NeXTstep/GNUstep .strings\n\
+                              syntax\n"));
       printf ("\n");
       printf (_("\
 Output details:\n"));
@@ -398,6 +411,8 @@ Output details:\n"));
       printf (_("\
   -p, --properties-output     write out a Java .properties file\n"));
       printf (_("\
+      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
+      printf (_("\
   -w, --width=NUMBER          set output page width\n"));
       printf (_("\
       --no-wrap               do not break long message lines, longer than\n\
index 448bbffa6706c05087619dfd8dcfa722b9153212..adea84a67c0646a19552955e22fce5a9f22cc9b1 100644 (file)
@@ -69,6 +69,8 @@ static const struct option long_options[] =
   { "sort-by-file", no_argument, NULL, 'F' },
   { "sort-output", no_argument, NULL, 's' },
   { "strict", no_argument, NULL, 'S' },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 2 },
+  { "stringtable-output", no_argument, NULL, CHAR_MAX + 3 },
   { "to-code", required_argument, NULL, 't' },
   { "version", no_argument, NULL, 'V' },
   { "width", required_argument, NULL, 'w', },
@@ -194,6 +196,14 @@ main (int argc, char **argv)
        message_page_width_ignore ();
        break;
 
+      case CHAR_MAX + 2: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
+
+      case CHAR_MAX + 3: /* --stringtable-output */
+       message_print_syntax_stringtable ();
+       break;
+
       default:
        usage (EXIT_FAILURE);
        break;
@@ -245,7 +255,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
   result = read_po_file (input_file);
 
   /* Convert if and only if the output syntax supports different encodings.  */
-  if (output_syntax != syntax_properties)
+  if (output_syntax != syntax_properties
+      && output_syntax != syntax_stringtable)
     result = iconv_msgdomain_list (result, to_code, input_file);
 
   /* Sort the results.  */
@@ -309,6 +320,8 @@ The default encoding is the current locale's encoding.\n"));
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input file is in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
       printf ("\n");
       printf (_("\
 Output details:\n"));
@@ -329,6 +342,8 @@ Output details:\n"));
       printf (_("\
   -p, --properties-output     write out a Java .properties file\n"));
       printf (_("\
+      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
+      printf (_("\
   -w, --width=NUMBER          set output page width\n"));
       printf (_("\
       --no-wrap               do not break long message lines, longer than\n\
index f90a37c47210b8e6624dd5d1e516c137e0848f6f..cabe80bcd4a2140561cc59a64ac890c4487cbe19 100644 (file)
@@ -65,6 +65,8 @@ static const struct option long_options[] =
   { "sort-by-file", no_argument, NULL, 'F' },
   { "sort-output", no_argument, NULL, 's' },
   { "strict", no_argument, NULL, 'S' },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 2 },
+  { "stringtable-output", no_argument, NULL, CHAR_MAX + 3 },
   { "version", no_argument, NULL, 'V' },
   { "width", required_argument, NULL, 'w', },
   { NULL, 0, NULL, 0 }
@@ -180,6 +182,14 @@ main (int argc, char **argv)
        message_page_width_ignore ();
        break;
 
+      case CHAR_MAX + 2: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
+
+      case CHAR_MAX + 3: /* --stringtable-output */
+       message_print_syntax_stringtable ();
+       break;
+
       default:
        usage (EXIT_FAILURE);
        break;
@@ -285,6 +295,8 @@ or if it is -.\n"));
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input file is in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
       printf ("\n");
       printf (_("\
 Output details:\n"));
@@ -305,6 +317,8 @@ Output details:\n"));
       printf (_("\
   -p, --properties-output     write out a Java .properties file\n"));
       printf (_("\
+      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
+      printf (_("\
   -w, --width=NUMBER          set output page width\n"));
       printf (_("\
       --no-wrap               do not break long message lines, longer than\n\
index 66e6331d793e71ea837470ea2c382f6219493c33..4b3f4221f5314fb4c3bbc9ac182d1196717f6275 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <errno.h>
 #include <getopt.h>
+#include <limits.h>
 #include <locale.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -79,6 +80,7 @@ static const struct option long_options[] =
   { "help", no_argument, NULL, 'h' },
   { "input", required_argument, NULL, 'i' },
   { "properties-input", no_argument, NULL, 'P' },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 1 },
   { "version", no_argument, NULL, 'V' },
   { NULL, 0, NULL, 0 }
 };
@@ -158,6 +160,10 @@ main (int argc, char **argv)
        do_version = true;
        break;
 
+      case CHAR_MAX + 1: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
+
       default:
        usage (EXIT_FAILURE);
        break;
@@ -264,6 +270,8 @@ If no input file is given or if it is -, standard input is read.\n"));
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input file is in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
       printf ("\n");
       printf (_("\
 Informative output:\n"));
index b3e4911b8e727d9bece3e5ba5db2820691bcb315..88b6ed0cd05a06a552006fb5a00496f0c77061dc 100644 (file)
@@ -116,6 +116,8 @@ static const struct option long_options[] =
   { "sort-by-file", no_argument, NULL, 'F' },
   { "sort-output", no_argument, NULL, 's' },
   { "strict", no_argument, NULL, 'S' },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 4 },
+  { "stringtable-output", no_argument, NULL, CHAR_MAX + 5 },
   { "version", no_argument, NULL, 'V' },
   { "width", required_argument, NULL, 'w', },
   { NULL, 0, NULL, 0 }
@@ -247,6 +249,14 @@ main (int argc, char **argv)
        message_page_width_ignore ();
        break;
 
+      case CHAR_MAX + 4: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
+
+      case CHAR_MAX + 5: /* --stringtable-output */
+       message_print_syntax_stringtable ();
+       break;
+
       default:
        usage (EXIT_FAILURE);
        break;
@@ -405,6 +415,8 @@ Useful FILTER-OPTIONs when the FILTER is 'sed':\n"));
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input file is in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
       printf ("\n");
       printf (_("\
 Output details:\n"));
@@ -427,6 +439,8 @@ Output details:\n"));
       printf (_("\
   -p, --properties-output     write out a Java .properties file\n"));
       printf (_("\
+      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
+      printf (_("\
   -w, --width=NUMBER          set output page width\n"));
       printf (_("\
       --no-wrap               do not break long message lines, longer than\n\
index 5d2460811fd629504f6198b94e4015af96e88f06..a30b98a05607fb33ae4c4215765dc71fc77eeef5 100644 (file)
@@ -167,6 +167,7 @@ static const struct option long_options[] =
   { "resource", required_argument, NULL, 'r' },
   { "statistics", no_argument, &do_statistics, 1 },
   { "strict", no_argument, NULL, 'S' },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 8 },
   { "tcl", no_argument, NULL, CHAR_MAX + 7 },
   { "use-fuzzy", no_argument, NULL, 'f' },
   { "verbose", no_argument, NULL, 'v' },
@@ -281,7 +282,7 @@ main (int argc, char *argv[])
       case 'V':
        do_version = true;
        break;
-      case CHAR_MAX + 1:
+      case CHAR_MAX + 1: /* --check-accelerators */
        check_accelerators = true;
        if (optarg != NULL)
          {
@@ -294,25 +295,28 @@ main (int argc, char *argv[])
                     "--check-accelerators");
          }
        break;
-      case CHAR_MAX + 2:
+      case CHAR_MAX + 2: /* --check-domain */
        check_domain = true;
        break;
-      case CHAR_MAX + 3:
+      case CHAR_MAX + 3: /* --check-format */
        check_format_strings = true;
        break;
-      case CHAR_MAX + 4:
+      case CHAR_MAX + 4: /* --check-header */
        check_header = true;
        break;
-      case CHAR_MAX + 5:
+      case CHAR_MAX + 5: /* --java2 */
        java_mode = true;
        assume_java2 = true;
        break;
-      case CHAR_MAX + 6:
+      case CHAR_MAX + 6: /* --no-hash */
        no_hash_table = true;
        break;
-      case CHAR_MAX + 7:
+      case CHAR_MAX + 7: /* --tcl */
        tcl_mode = true;
        break;
+      case CHAR_MAX + 8: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
       default:
        usage (EXIT_FAILURE);
        break;
@@ -428,8 +432,12 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
       ++optind;
     }
 
-  /* We know a priori that properties_parse() converts strings to UTF-8.  */
-  canon_encoding = (input_syntax == syntax_properties ? po_charset_utf8 : NULL);
+  /* We know a priori that properties_parse() and stringtable_parse() convert
+     strings to UTF-8.  */
+  canon_encoding =
+    (input_syntax == syntax_properties || input_syntax == syntax_stringtable
+     ? po_charset_utf8
+     : NULL);
 
   /* Remove obsolete messages.  They were only needed for duplicate
      checking.  */
@@ -571,6 +579,9 @@ specified directory.\n"));
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input files are in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input files are in NeXTstep/GNUstep .strings\n\
+                              syntax\n"));
       printf ("\n");
       printf (_("\
 Input file interpretation:\n"));
index 1fc10a961fc66a611b3561c325f0ab026cc2e040..0b5c29b942b0ccd2a4a5ebecb1b2dcd5c3874982 100644 (file)
@@ -107,6 +107,8 @@ static const struct option long_options[] =
   { "sort-by-file", no_argument, NULL, CHAR_MAX + 4 },
   { "sort-output", no_argument, NULL, CHAR_MAX + 5 },
   { "strict", no_argument, NULL, 'S' },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 7 },
+  { "stringtable-output", no_argument, NULL, CHAR_MAX + 8 },
   { "version", no_argument, NULL, 'V' },
   { "width", required_argument, NULL, 'w' },
   { NULL, 0, NULL, 0 }
@@ -290,6 +292,14 @@ main (int argc, char **argv)
        message_page_width_ignore ();
        break;
 
+      case CHAR_MAX + 7: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
+
+      case CHAR_MAX + 8: /* --stringtable-output */
+       message_print_syntax_stringtable ();
+       break;
+
       default:
        usage (EXIT_FAILURE);
        break;
@@ -488,6 +498,8 @@ expressions if -E is given, or fixed strings if -F is given.\n\
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input file is in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
       printf ("\n");
       printf (_("\
 Output details:\n"));
@@ -508,6 +520,8 @@ Output details:\n"));
       printf (_("\
   -p, --properties-output     write out a Java .properties file\n"));
       printf (_("\
+      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
+      printf (_("\
   -w, --width=NUMBER          set output page width\n"));
       printf (_("\
       --no-wrap               do not break long message lines, longer than\n\
index fb63147f28bf40891a7d3fce44563045766d92ce..459286fdd2ca1411a4b03fdcda3fd9aad7224e2a 100644 (file)
@@ -133,6 +133,8 @@ static const struct option long_options[] =
   { "output-file", required_argument, NULL, 'o' },
   { "properties-input", no_argument, NULL, 'P' },
   { "properties-output", no_argument, NULL, 'p' },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 3 },
+  { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 },
   { "version", no_argument, NULL, 'V' },
   { "width", required_argument, NULL, 'w' },
   { NULL, 0, NULL, 0 }
@@ -242,6 +244,14 @@ main (int argc, char **argv)
        message_page_width_ignore ();
        break;
 
+      case CHAR_MAX + 3: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
+
+      case CHAR_MAX + 4: /* --stringtable-output */
+       message_print_syntax_stringtable ();
+       break;
+
       default:
        usage (EXIT_FAILURE);
        break;
@@ -379,6 +389,8 @@ locale setting.  If it is -, the results are written to standard output.\n"));
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input file is in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
       printf ("\n");
       printf (_("\
 Output details:\n"));
@@ -389,6 +401,8 @@ Output details:\n"));
       printf (_("\
   -p, --properties-output     write out a Java .properties file\n"));
       printf (_("\
+      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
+      printf (_("\
   -w, --width=NUMBER          set output page width\n"));
       printf (_("\
       --no-wrap               do not break long message lines, longer than\n\
index 658cfd6f092115c47ae187a78efdd33b5d544c93..14aa79e779089bed6c20b78f7ccbf3a9cd93e62a 100644 (file)
@@ -103,6 +103,8 @@ static const struct option long_options[] =
   { "sort-output", no_argument, NULL, 's' },
   { "silent", no_argument, NULL, 'q' },
   { "strict", no_argument, NULL, CHAR_MAX + 2 },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 5 },
+  { "stringtable-output", no_argument, NULL, CHAR_MAX + 6 },
   { "suffix", required_argument, NULL, CHAR_MAX + 3 },
   { "update", no_argument, NULL, 'U' },
   { "verbose", no_argument, NULL, 'v' },
@@ -270,6 +272,14 @@ main (int argc, char **argv)
        message_page_width_ignore ();
        break;
 
+      case CHAR_MAX + 5: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
+
+      case CHAR_MAX + 6: /* --stringtable-output */
+       message_print_syntax_stringtable ();
+       break;
+
       default:
        usage (EXIT_FAILURE);
        break;
@@ -341,6 +351,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
   /* In update mode, --properties-input implies --properties-output.  */
   if (update_mode && input_syntax == syntax_properties)
     message_print_syntax_properties ();
+  /* In update mode, --stringtable-input implies --stringtable-output.  */
+  if (update_mode && input_syntax == syntax_stringtable)
+    message_print_syntax_stringtable ();
 
   /* Merge the two files.  */
   result = merge (argv[optind], argv[optind + 1], &def);
@@ -482,6 +495,9 @@ Operation modifiers:\n"));
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input files are in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input files are in NeXTstep/GNUstep .strings\n\
+                              syntax\n"));
       printf ("\n");
       printf (_("\
 Output details:\n"));
@@ -502,6 +518,8 @@ Output details:\n"));
       printf (_("\
   -p, --properties-output     write out a Java .properties file\n"));
       printf (_("\
+      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
+      printf (_("\
   -w, --width=NUMBER          set output page width\n"));
       printf (_("\
       --no-wrap               do not break long message lines, longer than\n\
index e6ce82468ff61d7b9f11529e7cd658a3a70a6a05..61ff5cbf544431feb1d95d2b0353a6f7233fea78 100644 (file)
@@ -77,6 +77,7 @@ static const struct option long_options[] =
   { "resource", required_argument, NULL, 'r' },
   { "sort-output", no_argument, NULL, 's' },
   { "strict", no_argument, NULL, 'S' },
+  { "stringtable-output", no_argument, NULL, CHAR_MAX + 3 },
   { "tcl", no_argument, NULL, CHAR_MAX + 1 },
   { "verbose", no_argument, NULL, 'v' },
   { "version", no_argument, NULL, 'V' },
@@ -203,6 +204,10 @@ main (int argc, char **argv)
        message_page_width_ignore ();
        break;
 
+      case CHAR_MAX + 3: /* --stringtable-output */
+       message_print_syntax_stringtable ();
+       break;
+
       default:
        usage (EXIT_FAILURE);
        break;
@@ -395,6 +400,8 @@ Output details:\n"));
       printf (_("\
   -p, --properties-output     write out a Java .properties file\n"));
       printf (_("\
+      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
+      printf (_("\
   -w, --width=NUMBER          set output page width\n"));
       printf (_("\
       --no-wrap               do not break long message lines, longer than\n\
index 6e7ff9ec6e8620da3dd787dd92746d8946701d60..26d82f3833b767c0ec21646f177aeebac97e1c76 100644 (file)
@@ -70,6 +70,8 @@ static const struct option long_options[] =
   { "sort-by-file", no_argument, NULL, 'F' },
   { "sort-output", no_argument, NULL, 's' },
   { "strict", no_argument, NULL, 'S' },
+  { "stringtable-input", no_argument, NULL, CHAR_MAX + 3 },
+  { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 },
   { "to-code", required_argument, NULL, 't' },
   { "unique", no_argument, NULL, 'u' },
   { "use-first", no_argument, NULL, CHAR_MAX + 1 },
@@ -216,6 +218,14 @@ main (int argc, char **argv)
        message_page_width_ignore ();
        break;
 
+      case CHAR_MAX + 3: /* --stringtable-input */
+       input_syntax = syntax_stringtable;
+       break;
+
+      case CHAR_MAX + 4: /* --stringtable-output */
+       message_print_syntax_stringtable ();
+       break;
+
       default:
        usage (EXIT_FAILURE);
        /* NOTREACHED */
@@ -338,6 +348,8 @@ Message selection:\n"));
 Input file syntax:\n"));
       printf (_("\
   -P, --properties-input      input file is in Java .properties syntax\n"));
+      printf (_("\
+      --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
       printf ("\n");
       printf (_("\
 Output details:\n"));
@@ -363,6 +375,8 @@ Output details:\n"));
       printf (_("\
   -p, --properties-output     write out a Java .properties file\n"));
       printf (_("\
+      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
+      printf (_("\
   -w, --width=NUMBER          set output page width\n"));
       printf (_("\
       --no-wrap               do not break long message lines, longer than\n\
index 29624223f0a11b7a5a810cd41144a51054fd6a05..cca925760866aee3bb1451ecd05b03d3957ca8b6 100644 (file)
@@ -288,6 +288,6 @@ string_list
 comment
        : COMMENT
                {
-                 po_callback_comment ($1.string);
+                 po_callback_comment_dispatcher ($1.string);
                }
        ;
index 1b02a1cb4b0fd0459843c831c4359fb20f2a5132..0aa1300f533718d921548fb44662442c914e370f 100644 (file)
@@ -31,6 +31,7 @@
 #include "po-gram.h"
 #include "po-hash.h"
 #include "read-properties.h"
+#include "read-stringtable.h"
 #include "xalloc.h"
 #include "gettext.h"
 
@@ -177,6 +178,11 @@ po_scan (abstract_po_reader_ty *pop, FILE *fp,
       properties_parse (pop, fp, real_filename, logical_filename);
       po_scan_end (pop);
       break;
+    case syntax_stringtable:
+      po_scan_start (pop);
+      stringtable_parse (pop, fp, real_filename, logical_filename);
+      po_scan_end (pop);
+      break;
     default:
       abort ();
     }
@@ -219,6 +225,22 @@ po_callback_message (char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
 }
 
 
+void
+po_callback_comment (const char *s)
+{
+  /* assert(callback_arg); */
+  call_comment (callback_arg, s);
+}
+
+
+void
+po_callback_comment_dot (const char *s)
+{
+  /* assert(callback_arg); */
+  call_comment_dot (callback_arg, s);
+}
+
+
 /* This function is called by po_parse_comment_filepos(), once for each
    filename.  */
 void
@@ -229,6 +251,14 @@ po_callback_comment_filepos (const char *name, size_t line)
 }
 
 
+void
+po_callback_comment_special (const char *s)
+{
+  /* assert(callback_arg); */
+  call_comment_special (callback_arg, s);
+}
+
+
 /* Parse a special comment and put the result in *fuzzyp, formatp, *wrapp.  */
 void
 po_parse_comment_special (const char *s,
@@ -332,11 +362,10 @@ po_parse_comment_special (const char *s,
    call_comment_filepos (via po_parse_comment_filepos), or
    call_comment_special.  */
 void
-po_callback_comment (const char *s)
+po_callback_comment_dispatcher (const char *s)
 {
-  /* assert(callback_arg); */
   if (*s == '.')
-    call_comment_dot (callback_arg, s + 1);
+    po_callback_comment_dot (s + 1);
   else if (*s == ':')
     {
       /* Parse the file location string.  If the parse succeeds, the
@@ -346,12 +375,12 @@ po_callback_comment (const char *s)
       if (po_parse_comment_filepos (s + 1) == 0)
        /* Do nothing, it is a GNU-style file pos line.  */ ;
       else
-       call_comment (callback_arg, s + 1);
+       po_callback_comment (s + 1);
     }
   else if (*s == ',' || *s == '!')
     {
       /* Get all entries in the special comment line.  */
-      call_comment_special (callback_arg, s + 1);
+      po_callback_comment_special (s + 1);
     }
   else
     {
@@ -365,6 +394,6 @@ po_callback_comment (const char *s)
          && po_parse_comment_filepos (s) == 0)
        /* Do nothing, it is a Sun-style file pos line.  */ ;
       else
-       call_comment (callback_arg, s);
+       po_callback_comment (s);
     }
 }
index 85b960f974a1d5e937a76c10578755a051c989ee..0c076f0262bbad8b25d38f35190f02598166dd45 100644 (file)
@@ -133,7 +133,8 @@ extern abstract_po_reader_ty *
 enum input_syntax_ty
 {
   syntax_po,
-  syntax_properties
+  syntax_properties,
+  syntax_stringtable
 };
 typedef enum input_syntax_ty input_syntax_ty;
 
@@ -161,6 +162,8 @@ extern void po_callback_message (char *msgid, lex_pos_ty *msgid_pos,
 extern void po_callback_comment (const char *s);
 extern void po_callback_comment_dot (const char *s);
 extern void po_callback_comment_filepos (const char *s, size_t line);
+extern void po_callback_comment_special (const char *s);
+extern void po_callback_comment_dispatcher (const char *s);
 
 /* Parse a special comment and put the result in *fuzzyp, formatp, *wrapp.  */
 extern void po_parse_comment_special (const char *s, bool *fuzzyp,
index e80635d6eb15fc6ac9a029316cd8fab52e2e8d67..f8735aae6d3a0854aa3f0b8ec9f403fb94d7322a 100644 (file)
@@ -450,8 +450,9 @@ read_po (FILE *fp, const char *real_filename, const char *logical_filename)
   pop->allow_duplicates_if_same_msgstr = false;
   pop->mdlp = msgdomain_list_alloc (!pop->allow_duplicates);
   pop->mlp = msgdomain_list_sublist (pop->mdlp, pop->domain, true);
-  if (input_syntax == syntax_properties)
-    /* We know a priori that properties_parse() converts strings to UTF-8.  */
+  if (input_syntax == syntax_properties || input_syntax == syntax_stringtable)
+    /* We know a priori that properties_parse() and stringtable_parse()
+       convert strings to UTF-8.  */
     pop->mdlp->encoding = po_charset_utf8;
   po_lex_pass_obsolete_entries (true);
   po_scan ((abstract_po_reader_ty *) pop, fp, real_filename, logical_filename,
index e95b787e6ead5213d420487e35f37fa70058b0a7..eac198fb2cdb0a7399ae98605b72c095db0403ad 100644 (file)
@@ -502,7 +502,7 @@ properties_parse (abstract_po_reader_ty *this, FILE *file,
            }
          buffer[buflen] = '\0';
 
-         po_callback_comment (conv_from_java (conv_from_iso_8859_1 (buffer)));
+         po_callback_comment_dispatcher (conv_from_java (conv_from_iso_8859_1 (buffer)));
        }
       else
        {
diff --git a/gettext-tools/src/read-stringtable.c b/gettext-tools/src/read-stringtable.c
new file mode 100644 (file)
index 0000000..e938a72
--- /dev/null
@@ -0,0 +1,967 @@
+/* Reading NeXTstep/GNUstep .strings files.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include "read-stringtable.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "error-progname.h"
+#include "read-po-abstract.h"
+#include "po-hash.h"
+#include "xalloc.h"
+#include "exit.h"
+#include "utf8-ucs4.h"
+#include "ucs4-utf8.h"
+#include "gettext.h"
+
+#define _(str) gettext (str)
+
+/* The format of NeXTstep/GNUstep .strings files is documented in
+     gnustep-base-1.8.0/Tools/make_strings/Using.txt
+   and in the comments of method propertyListFromStringsFileFormat in
+     gnustep-base-1.8.0/Source/NSString.m
+   In summary, it's a Objective-C like file with pseudo-assignments of the form
+          "key" = "value";
+   where the key is the msgid and the value is the msgstr.
+
+   The implementation of the parser of .strings files is in
+     gnustep-base-1.8.0/Source/NSString.m
+     function GSPropertyListFromStringsFormat
+     (indirectly called from NSBundle's method localizedStringForKey).
+
+   A test case is in
+     gnustep-base-1.8.0/Testing/English.lproj/NXStringTable.example
+ */
+
+/* Handling of comments: We copy all comments from the .strings file to
+   the PO file. This is not really needed; it's a service for translators
+   who don't like PO files and prefer to maintain the .strings file.  */
+
+
+/* Real filename, used in error messages about the input file.  */
+static const char *real_file_name;
+
+/* File name and line number.  */
+extern lex_pos_ty gram_pos;
+
+/* The input file stream.  */
+static FILE *fp;
+
+
+/* Phase 1: Read a byte.
+   Max. 4 pushback characters.  */
+
+static unsigned char phase1_pushback[4];
+static int phase1_pushback_length;
+
+static int
+phase1_getc ()
+{
+  int c;
+
+  if (phase1_pushback_length)
+    return phase1_pushback[--phase1_pushback_length];
+
+  c = getc (fp);
+
+  if (c == EOF)
+    {
+      if (ferror (fp))
+       error (EXIT_FAILURE, errno, _("error while reading \"%s\""),
+              real_file_name);
+      return EOF;
+    }
+
+  return c;
+}
+
+static void
+phase1_ungetc (int c)
+{
+  if (c != EOF)
+    phase1_pushback[phase1_pushback_length++] = c;
+}
+
+
+/* Phase 2: Read an UCS-4 character.
+   Max. 2 pushback characters.  */
+
+/* End-of-file indicator for functions returning an UCS-4 character.  */
+#define UEOF -1
+
+static int phase2_pushback[4];
+static int phase2_pushback_length;
+
+/* The input file can be in Unicode encoding (UCS-2BE, UCS-2LE, UTF-8, each
+   with a BOM!), or otherwise the locale-dependent default encoding is used.
+   Since we don't want to depend on the locale here, we use ISO-8859-1
+   instead.  */
+enum enc
+{
+  enc_undetermined,
+  enc_ucs2be,
+  enc_ucs2le,
+  enc_utf8,
+  enc_iso8859_1
+};
+static enum enc encoding;
+
+static int
+phase2_getc ()
+{
+  if (phase2_pushback_length)
+    return phase2_pushback[--phase2_pushback_length];
+
+  if (encoding == enc_undetermined)
+    {
+      /* Determine the input file's encoding.  */
+      int c0, c1;
+
+      c0 = phase1_getc ();
+      if (c0 == EOF)
+       return UEOF;
+      c1 = phase1_getc ();
+      if (c1 == EOF)
+       {
+         phase1_ungetc (c0);
+         encoding = enc_iso8859_1;
+       }
+      else if (c0 == 0xfe && c1 == 0xff)
+       encoding = enc_ucs2be;
+      else if (c0 == 0xff && c1 == 0xfe)
+       encoding = enc_ucs2le;
+      else
+       {
+         int c2;
+
+         c2 = phase1_getc ();
+         if (c2 == EOF)
+           {
+             phase1_ungetc (c1);
+             phase1_ungetc (c0);
+             encoding = enc_iso8859_1;
+           }
+         else if (c0 == 0xef && c1 == 0xbb && c2 == 0xbf)
+           encoding = enc_utf8;
+         else
+           {
+             phase1_ungetc (c2);
+             phase1_ungetc (c1);
+             phase1_ungetc (c0);
+             encoding = enc_iso8859_1;
+           }
+       }
+    }
+
+  switch (encoding)
+    {
+    case enc_ucs2be:
+      /* Read an UCS-2BE encoded character.  */
+      {
+       int c0, c1;
+
+       c0 = phase1_getc ();
+       if (c0 == EOF)
+         return UEOF;
+       c1 = phase1_getc ();
+       if (c1 == EOF)
+         return UEOF;
+       return (c0 << 8) + c1;
+      }
+
+    case enc_ucs2le:
+      /* Read an UCS-2LE encoded character.  */
+      {
+       int c0, c1;
+
+       c0 = phase1_getc ();
+       if (c0 == EOF)
+         return UEOF;
+       c1 = phase1_getc ();
+       if (c1 == EOF)
+         return UEOF;
+       return c0 + (c1 << 8);
+      }
+
+    case enc_utf8:
+      /* Read an UTF-8 encoded character.  */
+      {
+       unsigned char buf[6];
+       unsigned int count;
+       int c;
+       unsigned int uc;
+
+       c = phase1_getc ();
+       if (c == EOF)
+         return UEOF;
+       buf[0] = c;
+       count = 1;
+
+       if (buf[0] >= 0xc0)
+         {
+           c = phase1_getc ();
+           if (c == EOF)
+             return UEOF;
+           buf[1] = c;
+           count = 2;
+         }
+
+       if (buf[0] >= 0xe0
+           && ((buf[1] ^ 0x80) < 0x40))
+         {
+           c = phase1_getc ();
+           if (c == EOF)
+             return UEOF;
+           buf[2] = c;
+           count = 3;
+         }
+
+       if (buf[0] >= 0xf0
+           && ((buf[1] ^ 0x80) < 0x40)
+           && ((buf[2] ^ 0x80) < 0x40))
+         {
+           c = phase1_getc ();
+           if (c == EOF)
+             return UEOF;
+           buf[3] = c;
+           count = 4;
+         }
+
+       if (buf[0] >= 0xf8
+           && ((buf[1] ^ 0x80) < 0x40)
+           && ((buf[2] ^ 0x80) < 0x40)
+           && ((buf[3] ^ 0x80) < 0x40))
+         {
+           c = phase1_getc ();
+           if (c == EOF)
+             return UEOF;
+           buf[4] = c;
+           count = 5;
+         }
+
+       if (buf[0] >= 0xfc
+           && ((buf[1] ^ 0x80) < 0x40)
+           && ((buf[2] ^ 0x80) < 0x40)
+           && ((buf[3] ^ 0x80) < 0x40)
+           && ((buf[4] ^ 0x80) < 0x40))
+         {
+           c = phase1_getc ();
+           if (c == EOF)
+             return UEOF;
+           buf[5] = c;
+           count = 6;
+         }
+
+       u8_mbtouc (&uc, buf, count);
+       return uc;
+      }
+
+    case enc_iso8859_1:
+      /* Read an ISO-8859-1 encoded character.  */
+      {
+       int c = phase1_getc ();
+
+       if (c == EOF)
+         return UEOF;
+       return c;
+      }
+
+    default:
+      abort ();
+    }
+}
+
+static void
+phase2_ungetc (int c)
+{
+  if (c != UEOF)
+    phase2_pushback[phase2_pushback_length++] = c;
+}
+
+
+/* Phase 3: Read an UCS-4 character, with line number handling.  */
+
+static int
+phase3_getc ()
+{
+  int c = phase2_getc ();
+
+  if (c == '\n')
+    gram_pos.line_number++;
+
+  return c;
+}
+
+static void
+phase3_ungetc (int c)
+{
+  if (c == '\n')
+    --gram_pos.line_number;
+  phase2_ungetc (c);
+}
+
+
+/* Convert from UCS-4 to UTF-8.  */
+static char *
+conv_from_ucs4 (const int *buffer, size_t buflen)
+{
+  unsigned char *utf8_string;
+  size_t pos;
+  unsigned char *q;
+
+  /* Each UCS-4 word needs 6 bytes at worst.  */
+  utf8_string = (unsigned char *) xmalloc (6 * buflen + 1);
+
+  for (pos = 0, q = utf8_string; pos < buflen; )
+    {
+      unsigned int uc;
+      int n;
+
+      uc = buffer[pos++];
+      n = u8_uctomb (q, uc, 6);
+      assert (n > 0);
+      q += n;
+    }
+  *q = '\0';
+  assert (q - utf8_string <= 6 * buflen);
+
+  return (char *) utf8_string;
+}
+
+
+/* Parse a string enclosed in double-quotes.  Input is UCS-4 encoded.
+   Return the string in UTF-8 encoding, or NULL if the input doesn't represent
+   a valid string enclosed in double-quotes.  */
+static char *
+parse_escaped_string (const int *string, size_t length)
+{
+  static int *buffer;
+  static size_t bufmax;
+  static size_t buflen;
+  const int *string_limit = string + length;
+  int c;
+
+  if (string == string_limit)
+    return NULL;
+  c = *string++;
+  if (c != '"')
+    return NULL;
+  buflen = 0;
+  for (;;)
+    {
+      if (string == string_limit)
+       return NULL;
+      c = *string++;
+      if (c == '"')
+       break;
+      if (c == '\\')
+       {
+         if (string == string_limit)
+           return NULL;
+         c = *string++;
+         if (c >= '0' && c <= '7')
+           {
+             unsigned int n = 0;
+             int j = 0;
+             for (;;)
+               {
+                 n = n * 8 + (c - '0');
+                 if (++j == 3)
+                   break;
+                 if (string == string_limit)
+                   break;
+                 c = *string;
+                 if (!(c >= '0' && c <= '7'))
+                   break;
+                 string++;
+               }
+             c = n;
+           }
+         else if (c == 'u' || c == 'U')
+           {
+             unsigned int n = 0;
+             int j;
+             for (j = 0; j < 4; j++)
+               {
+                 if (string == string_limit)
+                   break;
+                 c = *string;
+                 if (c >= '0' && c <= '9')
+                   n = n * 16 + (c - '0');
+                 else if (c >= 'A' && c <= 'F')
+                   n = n * 16 + (c - 'A' + 10);
+                 else if (c >= 'a' && c <= 'f')
+                   n = n * 16 + (c - 'a' + 10);
+                 else
+                   break;
+                 string++;
+               }
+             c = n;
+           }
+         else
+           switch (c)
+             {
+             case 'a': c = '\a'; break;
+             case 'b': c = '\b'; break;
+             case 't': c = '\t'; break;
+             case 'r': c = '\r'; break;
+             case 'n': c = '\n'; break;
+             case 'v': c = '\v'; break;
+             case 'f': c = '\f'; break;
+             }
+       }
+      if (buflen >= bufmax)
+       {
+         bufmax = 2 * bufmax + 10;
+         buffer = xrealloc (buffer, bufmax * sizeof (int));
+       }
+      buffer[buflen++] = c;
+    }
+
+  return conv_from_ucs4 (buffer, buflen);
+}
+
+
+/* Accumulating flag comments.  */
+
+static char *special_comment;
+
+static inline void
+special_comment_reset ()
+{
+  if (special_comment != NULL)
+    free (special_comment);
+  special_comment = NULL;
+}
+
+static void
+special_comment_add (const char *flag)
+{
+  if (special_comment == NULL)
+    special_comment = xstrdup (flag);
+  else
+    {
+      size_t total_len = strlen (special_comment) + 2 + strlen (flag) + 1;
+      special_comment = xrealloc (special_comment, total_len);
+      strcat (special_comment, ", ");
+      strcat (special_comment, flag);
+    }
+}
+
+static inline void
+special_comment_finish ()
+{
+  if (special_comment != NULL)
+    {
+      po_callback_comment_special (special_comment);
+      free (special_comment);
+      special_comment = NULL;
+    }
+}
+
+
+/* Accumulating comments.  */
+
+static int *buffer;
+static size_t bufmax;
+static size_t buflen;
+static bool next_is_obsolete;
+static bool next_is_fuzzy;
+static char *fuzzy_msgstr;
+static bool expect_fuzzy_msgstr_as_c_comment;
+static bool expect_fuzzy_msgstr_as_cxx_comment;
+
+static inline void
+comment_start ()
+{
+  buflen = 0;
+}
+
+static inline void
+comment_add (int c)
+{
+  if (buflen >= bufmax)
+    {
+      bufmax = 2 * bufmax + 10;
+      buffer = xrealloc (buffer, bufmax * sizeof (int));
+    }
+  buffer[buflen++] = c;
+}
+
+static inline void
+comment_line_end (size_t chars_to_remove, bool test_for_fuzzy_msgstr)
+{
+  char *line;
+
+  buflen -= chars_to_remove;
+  /* Drop trailing white space, but not EOLs.  */
+  while (buflen >= 1
+        && (buffer[buflen - 1] == ' ' || buffer[buflen - 1] == '\t'))
+    --buflen;
+
+  /* At special positions we interpret a comment of the form
+       = "escaped string"
+     with an optional trailing semicolon as being the fuzzy msgstr, not a
+     regular comment.  */
+  if (test_for_fuzzy_msgstr
+      && buflen > 2 && buffer[0] == '=' && buffer[1] == ' '
+      && (fuzzy_msgstr =
+         parse_escaped_string (buffer + 2,
+                               buflen - (buffer[buflen - 1] == ';') - 2)))
+    return;
+
+  line = conv_from_ucs4 (buffer, buflen);
+
+  if (strcmp (line, "Flag: untranslated") == 0)
+    {
+      special_comment_add ("fuzzy");
+      next_is_fuzzy = true;
+    }
+  else if (strcmp (line, "Flag: unmatched") == 0)
+    next_is_obsolete = true;
+  else if (strlen (line) >= 6 && memcmp (line, "Flag: ", 6) == 0)
+    special_comment_add (line + 6);
+  else if (strlen (line) >= 9 && memcmp (line, "Comment: ", 9) == 0)
+    /* A comment extracted from the source.  */
+    po_callback_comment_dot (line + 9);
+  else
+    {
+      char *last_colon;
+      unsigned long number;
+      char *endp;
+
+      if (strlen (line) >= 6 && memcmp (line, "File: ", 6) == 0
+         && (last_colon = strrchr (line + 6, ':')) != NULL
+         && *(last_colon + 1) != '\0'
+         && (number = strtoul (last_colon + 1, &endp, 10), *endp == '\0'))
+       {
+         /* A "File: <filename>:<number>" type comment.  */
+         *last_colon = '\0';
+         po_callback_comment_filepos (line + 6, number);
+       }
+      else
+       po_callback_comment (line);
+    }
+}
+
+
+/* Phase 4: Replace each comment that is not inside a string with a space
+   character.  */
+
+static int
+phase4_getc ()
+{
+  int c;
+
+  c = phase3_getc ();
+  if (c != '/')
+    return c;
+  c = phase3_getc ();
+  switch (c)
+    {
+    default:
+      phase3_ungetc (c);
+      return '/';
+
+    case '*':
+      /* C style comment.  */
+      {
+       bool last_was_star;
+       size_t trailing_stars;
+       bool seen_newline;
+
+       comment_start ();
+       last_was_star = false;
+       trailing_stars = 0;
+       seen_newline = false;
+       /* Drop additional stars at the beginning of the comment.  */
+       for (;;)
+         {
+           c = phase3_getc ();
+           if (c != '*')
+             break;
+           last_was_star = true;
+         }
+       phase3_ungetc (c);
+       for (;;)
+         {
+           c = phase3_getc ();
+           if (c == UEOF)
+             break;
+           /* We skip all leading white space, but not EOLs.  */
+           if (!(buflen == 0 && (c == ' ' || c == '\t')))
+             comment_add (c);
+           switch (c)
+             {
+             case '\n':
+               seen_newline = true;
+               comment_line_end (1, false);
+               comment_start ();
+               last_was_star = false;
+               trailing_stars = 0;
+               continue;
+
+             case '*':
+               last_was_star = true;
+               trailing_stars++;
+               continue;
+
+             case '/':
+               if (last_was_star)
+                 {
+                   /* Drop additional stars at the end of the comment.  */
+                   comment_line_end (trailing_stars + 1,
+                                     expect_fuzzy_msgstr_as_c_comment
+                                     && !seen_newline);
+                   break;
+                 }
+               /* FALLTHROUGH */
+
+             default:
+               last_was_star = false;
+               trailing_stars = 0;
+               continue;
+             }
+           break;
+         }
+       return ' ';
+      }
+
+    case '/':
+      /* C++ style comment.  */
+      comment_start ();
+      for (;;)
+       {
+         c = phase3_getc ();
+         if (c == '\n' || c == UEOF)
+           break;
+         /* We skip all leading white space, but not EOLs.  */
+         if (!(buflen == 0 && (c == ' ' || c == '\t')))
+           comment_add (c);
+       }
+      comment_line_end (0, expect_fuzzy_msgstr_as_cxx_comment);
+      return '\n';
+    }
+}
+
+static inline void
+phase4_ungetc (int c)
+{
+  phase3_ungetc (c);
+}
+
+
+/* Return true if a character is considered as whitespace.  */
+static bool
+is_whitespace (int c)
+{
+  return (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f'
+         || c == '\b');
+}
+
+/* Return true if a character needs quoting, i.e. cannot be used in unquoted
+   tokens.  */
+static bool
+is_quotable (int c)
+{
+  if ((c >= '0' && c <= '9')
+      || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
+    return false;
+  switch (c)
+    {
+    case '!': case '#': case '$': case '%': case '&': case '*':
+    case '+': case '-': case '.': case '/': case ':': case '?':
+    case '@': case '|': case '~': case '_': case '^':
+      return false;
+    default:
+      return true;
+    }
+}
+
+
+/* Read a key or value string.
+   Return the string in UTF-8 encoding, or NULL if no string is seen.
+   Return the start position of the string in *pos.  */
+static char *
+read_string (lex_pos_ty *pos)
+{
+  static int *buffer;
+  static size_t bufmax;
+  static size_t buflen;
+  int c;
+
+  /* Skip whitespace before the string.  */
+  do
+    c = phase4_getc ();
+  while (is_whitespace (c));
+
+  if (c == UEOF)
+    /* No more string.  */
+    return NULL;
+
+  *pos = gram_pos;
+  buflen = 0;
+  if (c == '"')
+    {
+      /* Read a string enclosed in double-quotes.  */
+      for (;;)
+       {
+         c = phase3_getc ();
+         if (c == UEOF || c == '"')
+           break;
+         if (c == '\\')
+           {
+             c = phase3_getc ();
+             if (c == UEOF)
+               break;
+             if (c >= '0' && c <= '7')
+               {
+                 unsigned int n = 0;
+                 int j = 0;
+                 for (;;)
+                   {
+                     n = n * 8 + (c - '0');
+                     if (++j == 3)
+                       break;
+                     c = phase3_getc ();
+                     if (!(c >= '0' && c <= '7'))
+                       {
+                         phase3_ungetc (c);
+                         break;
+                       }
+                   }
+                 c = n;
+               }
+             else if (c == 'u' || c == 'U')
+               {
+                 unsigned int n = 0;
+                 int j;
+                 for (j = 0; j < 4; j++)
+                   {
+                     c = phase3_getc ();
+                     if (c >= '0' && c <= '9')
+                       n = n * 16 + (c - '0');
+                     else if (c >= 'A' && c <= 'F')
+                       n = n * 16 + (c - 'A' + 10);
+                     else if (c >= 'a' && c <= 'f')
+                       n = n * 16 + (c - 'a' + 10);
+                     else
+                       {
+                         phase3_ungetc (c);
+                         break;
+                       }
+                   }
+                 c = n;
+               }
+             else
+               switch (c)
+                 {
+                 case 'a': c = '\a'; break;
+                 case 'b': c = '\b'; break;
+                 case 't': c = '\t'; break;
+                 case 'r': c = '\r'; break;
+                 case 'n': c = '\n'; break;
+                 case 'v': c = '\v'; break;
+                 case 'f': c = '\f'; break;
+                 }
+           }
+         if (buflen >= bufmax)
+           {
+             bufmax = 2 * bufmax + 10;
+             buffer = xrealloc (buffer, bufmax * sizeof (int));
+           }
+         buffer[buflen++] = c;
+       }
+      if (c == UEOF)
+       {
+         error_with_progname = false;
+         error (0, 0, _("%s:%d: warning: unterminated string"),
+                real_file_name, gram_pos.line_number);
+         error_with_progname = true;
+       }
+    }
+  else
+    {
+      /* Read a token outside quotes.  */
+      if (is_quotable (c))
+       {
+         error_with_progname = false;
+         error (0, 0, _("%s:%d: warning: syntax error"),
+                real_file_name, gram_pos.line_number);
+         error_with_progname = true;
+       }
+      for (; c != UEOF && !is_quotable (c); c = phase4_getc ())
+       {
+         if (buflen >= bufmax)
+           {
+             bufmax = 2 * bufmax + 10;
+             buffer = xrealloc (buffer, bufmax * sizeof (int));
+           }
+         buffer[buflen++] = c;
+       }
+    }
+
+  return conv_from_ucs4 (buffer, buflen);
+}
+
+
+/* Read a .strings file from a stream, and dispatch to the various
+   abstract_po_reader_class_ty methods.  */
+void
+stringtable_parse (abstract_po_reader_ty *pop, FILE *file,
+                  const char *real_filename, const char *logical_filename)
+{
+  fp = file;
+  real_file_name = real_filename;
+  gram_pos.file_name = xstrdup (real_file_name);
+  gram_pos.line_number = 1;
+  encoding = enc_undetermined;
+  expect_fuzzy_msgstr_as_c_comment = false;
+  expect_fuzzy_msgstr_as_cxx_comment = false;
+
+  for (;;)
+    {
+      char *msgid;
+      lex_pos_ty msgid_pos;
+      char *msgstr;
+      lex_pos_ty msgstr_pos;
+      int c;
+
+      /* Prepare for next msgid/msgstr pair.  */
+      special_comment_reset ();
+      next_is_obsolete = false;
+      next_is_fuzzy = false;
+      fuzzy_msgstr = NULL;
+
+      /* Read the key and all the comments preceding it.  */
+      msgid = read_string (&msgid_pos);
+      if (msgid == NULL)
+       break;
+
+      special_comment_finish ();
+
+      /* Skip whitespace.  */
+      do
+       c = phase4_getc ();
+      while (is_whitespace (c));
+
+      /* Expect a '=' or ';'.  */
+      if (c == UEOF)
+       {
+         error_with_progname = false;
+         error (0, 0, _("%s:%d: warning: unterminated key/value pair"),
+                real_file_name, gram_pos.line_number);
+         error_with_progname = true;
+         break;
+       }
+      if (c == ';')
+       {
+         /* "key"; is an abbreviation for "key"=""; and does not
+            necessarily designate an untranslated entry.  */
+         msgstr = "";
+         msgstr_pos = msgid_pos;
+         po_callback_message (msgid, &msgid_pos, NULL,
+                              msgstr, strlen (msgstr) + 1, &msgstr_pos,
+                              false, next_is_obsolete);
+       }
+      else if (c == '=')
+       {
+         /* Read the value.  */
+         msgstr = read_string (&msgstr_pos);
+         if (msgstr == NULL)
+           {
+             error_with_progname = false;
+             error (0, 0, _("%s:%d: warning: unterminated key/value pair"),
+                    real_file_name, gram_pos.line_number);
+             error_with_progname = true;
+             break;
+           }
+
+         /* Skip whitespace.  But for fuzzy key/value pairs, look for the
+            tentative msgstr in the form of a C style comment.  */
+         expect_fuzzy_msgstr_as_c_comment = next_is_fuzzy;
+         do
+           {
+             c = phase4_getc ();
+             if (fuzzy_msgstr != NULL)
+               expect_fuzzy_msgstr_as_c_comment = false;
+           }
+         while (is_whitespace (c));
+         expect_fuzzy_msgstr_as_c_comment = false;
+
+         /* Expect a ';'.  */
+         if (c == ';')
+           {
+             /* But for fuzzy key/value pairs, look for the tentative msgstr
+                in the form of a C++ style comment. */
+             if (fuzzy_msgstr == NULL && next_is_fuzzy)
+               {
+                 do
+                   c = phase3_getc ();
+                 while (c == ' ');
+                 phase3_ungetc (c);
+
+                 expect_fuzzy_msgstr_as_cxx_comment = true;
+                 c = phase4_getc ();
+                 phase4_ungetc (c);
+                 expect_fuzzy_msgstr_as_cxx_comment = false;
+               }
+             if (fuzzy_msgstr != NULL && strcmp (msgstr, msgid) == 0)
+               msgstr = fuzzy_msgstr;
+
+             /* A key/value pair.  */
+             po_callback_message (msgid, &msgid_pos, NULL,
+                                  msgstr, strlen (msgstr) + 1, &msgstr_pos,
+                                  false, next_is_obsolete);
+           }
+         else
+           {
+             error_with_progname = false;
+             error (0, 0, _("\
+%s:%d: warning: syntax error, expected ';' after string"),
+                    real_file_name, gram_pos.line_number);
+             error_with_progname = true;
+             break;
+           }
+       }
+      else
+       {
+         error_with_progname = false;
+         error (0, 0, _("\
+%s:%d: warning: syntax error, expected '=' or ';' after string"),
+                real_file_name, gram_pos.line_number);
+         error_with_progname = true;
+         break;
+       }
+    }
+
+  fp = NULL;
+  real_file_name = NULL;
+  gram_pos.line_number = 0;
+}
diff --git a/gettext-tools/src/read-stringtable.h b/gettext-tools/src/read-stringtable.h
new file mode 100644 (file)
index 0000000..3f3d9ad
--- /dev/null
@@ -0,0 +1,30 @@
+/* Reading NeXTstep/GNUstep .strings files.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _READ_STRINGTABLE_H
+#define _READ_STRINGTABLE_H
+
+#include "read-po-abstract.h"
+
+/* Read a .strings file from a stream, and dispatch to the various
+   abstract_po_reader_class_ty methods.  */
+extern void stringtable_parse (abstract_po_reader_ty *pop, FILE *fp,
+                              const char *real_filename,
+                              const char *logical_filename);
+
+#endif /* _READ_STRINGTABLE_H */
index 90782683a23b6f92e039cc3de191155357605cdc..68c02cd013df6be2fe0f904c0101741332709f59 100644 (file)
@@ -40,6 +40,7 @@
 #include "linebreak.h"
 #include "msgl-ascii.h"
 #include "write-properties.h"
+#include "write-stringtable.h"
 #include "xalloc.h"
 #include "strstr.h"
 #include "fwriteerror.h"
@@ -64,7 +65,7 @@
 /* Convert IS_FORMAT in the context of programming language LANG to a flag
    string for use in #, flags.  */
 
-static const char *
+const char *
 make_format_description_string (enum is_format is_format, const char *lang,
                                bool debug)
 {
@@ -97,7 +98,7 @@ make_format_description_string (enum is_format is_format, const char *lang,
 
 /* Return true if IS_FORMAT is worth mentioning in a #, flags list.  */
 
-static bool
+bool
 significant_format_p (enum is_format is_format)
 {
   return is_format != undecided && is_format != impossible;
@@ -387,6 +388,16 @@ message_print_syntax_properties ()
 }
 
 
+/* Whether to output a file in NeXTstep/GNUstep .strings syntax.  */
+static bool use_syntax_stringtable = false;
+
+void
+message_print_syntax_stringtable ()
+{
+  use_syntax_stringtable = true;
+}
+
+
 /* ================ msgdomain_list_print() and subroutines. ================ */
 
 
@@ -1038,10 +1049,15 @@ msgdomain_list_print (msgdomain_list_ty *mdlp, const char *filename,
     }
 
   /* Check whether the output format can accomodate all messages.  */
-  if (use_syntax_properties)
+  if (use_syntax_properties || use_syntax_stringtable)
     {
       if (mdlp->nitems > 1)
-       error (EXIT_FAILURE, 0, _("Cannot output multiple translation domains into a single file with Java .properties syntax. Try using PO file syntax instead."));
+       {
+         if (use_syntax_properties)
+           error (EXIT_FAILURE, 0, _("Cannot output multiple translation domains into a single file with Java .properties syntax. Try using PO file syntax instead."));
+         if (use_syntax_stringtable)
+           error (EXIT_FAILURE, 0, _("Cannot output multiple translation domains into a single file with NeXTstep/GNUstep .strings syntax."));
+       }
       if (mdlp->nitems == 1)
        {
          message_list_ty *mlp = mdlp->item[0]->messages;
@@ -1063,9 +1079,14 @@ msgdomain_list_print (msgdomain_list_ty *mdlp, const char *filename,
          if (has_plural != NULL)
            {
              error_with_progname = false;
-             error_at_line (EXIT_FAILURE, 0,
-                            has_plural->file_name, has_plural->line_number,
-                            _("message catalog has plural form translations, but the output format does not support them. Try generating a Java class using \"msgfmt --java\", instead of a properties file."));
+             if (use_syntax_properties)
+               error_at_line (EXIT_FAILURE, 0,
+                              has_plural->file_name, has_plural->line_number,
+                              _("message catalog has plural form translations, but the output format does not support them. Try generating a Java class using \"msgfmt --java\", instead of a properties file."));
+             if (use_syntax_stringtable)
+               error_at_line (EXIT_FAILURE, 0,
+                              has_plural->file_name, has_plural->line_number,
+                              _("message catalog has plural form translations, but the output format does not support them."));
              error_with_progname = true;
            }
        }           
@@ -1089,6 +1110,8 @@ msgdomain_list_print (msgdomain_list_ty *mdlp, const char *filename,
 
   if (use_syntax_properties)
     msgdomain_list_print_properties (mdlp, fp, page_width, debug);
+  else if (use_syntax_stringtable)
+    msgdomain_list_print_stringtable (mdlp, fp, page_width, debug);
   else
     msgdomain_list_print_po (mdlp, fp, debug);
 
index 5cbe3199a04b2c662b13e0b19b1f8ff82971a0d3..3d7ac905214f63e1b60f591d32adadcf680e433b 100644 (file)
@@ -31,6 +31,14 @@ extern "C" {
 #endif
 
 
+/* These functions are used to output a #, flags line.  */
+extern const char *
+       make_format_description_string (enum is_format is_format,
+                                      const char *lang, bool debug);
+extern bool
+       significant_format_p (enum is_format is_format);
+
+
 /* These functions output parts of a message, as comments.  */
 extern void
        message_print_comment (const message_ty *mp, FILE *fp);
@@ -56,6 +64,8 @@ extern void
        message_print_style_escape (bool flag);
 extern void
        message_print_syntax_properties (void);
+extern void
+       message_print_syntax_stringtable (void);
 
 /* Output MDLP into a PO file with the given FILENAME, according to the
    parameters set by the functions above.  */
diff --git a/gettext-tools/src/write-stringtable.c b/gettext-tools/src/write-stringtable.c
new file mode 100644 (file)
index 0000000..f99d2d1
--- /dev/null
@@ -0,0 +1,311 @@
+/* Writing NeXTstep/GNUstep .strings files.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include "write-stringtable.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "message.h"
+#include "msgl-ascii.h"
+#include "msgl-iconv.h"
+#include "po-charset.h"
+#include "strstr.h"
+#include "write-po.h"
+
+/* The format of NeXTstep/GNUstep .strings files is documented in
+     gnustep-base-1.8.0/Tools/make_strings/Using.txt
+   and in the comments of method propertyListFromStringsFileFormat in
+     gnustep-base-1.8.0/Source/NSString.m
+   In summary, it's a Objective-C like file with pseudo-assignments of the form
+          "key" = "value";
+   where the key is the msgid and the value is the msgstr.
+ */
+
+/* Handling of comments: We copy all comments from the PO file to the
+   .strings file. This is not really needed; it's a service for translators
+   who don't like PO files and prefer to maintain the .strings file.  */
+
+/* Since the interpretation of text files in GNUstep depends on the locale's
+   encoding if they don't have a BOM, we choose one of three encodings with
+   a BOM: UCS-2BE, UCS-2LE, UTF-8.  Since the first two of these don't cope
+   with all of Unicode and we don't know whether GNUstep will switch to
+   UTF-16 instead of UCS-2, we use UTF-8 with BOM.  BOMs are bad because they
+   get in the way when concatenating files, but here we have no choice.  */
+
+/* Writes a key or value to the file, without newline.  */
+static void
+write_escaped_string (FILE *fp, const char *str)
+{
+  const char *str_limit = str + strlen (str);
+
+  putc ('"', fp);
+  while (str < str_limit)
+    {
+      unsigned char c = (unsigned char) *str++;
+
+      if (c == '\t')
+       {
+         putc ('\\', fp);
+         putc ('t', fp);
+       }
+      else if (c == '\n')
+       {
+         putc ('\\', fp);
+         putc ('n', fp);
+       }
+      else if (c == '\r')
+       {
+         putc ('\\', fp);
+         putc ('r', fp);
+       }
+      else if (c == '\f')
+       {
+         putc ('\\', fp);
+         putc ('f', fp);
+       }
+      else if (c == '\\' || c == '"')
+       {
+         putc ('\\', fp);
+         putc (c, fp);
+       }
+      else
+       putc (c, fp);
+    }
+  putc ('"', fp);
+}
+
+/* Writes a message to the file.  */
+static void
+write_message (FILE *fp, const message_ty *mp, size_t page_width, bool debug)
+{
+  /* Print translator comment if available.  */
+  if (mp->comment != NULL)
+    {
+      size_t j;
+
+      for (j = 0; j < mp->comment->nitems; ++j)
+       {
+         const char *s = mp->comment->item[j];
+
+         /* Test whether it is safe to output the comment in C style, or
+            whether we need C++ style for it.  */
+         if (strstr (s, "*/") == NULL)
+           {
+             fputs ("/*", fp);
+             if (*s != '\0' && *s != '\n' && *s != ' ')
+               putc (' ', fp);
+             fputs (s, fp);
+             fputs (" */\n", fp);
+           }
+         else
+           do
+             {
+               const char *e;
+               fputs ("//", fp);
+               if (*s != '\0' && *s != '\n' && *s != ' ')
+                 putc (' ', fp);
+               e = strchr (s, '\n');
+               if (e == NULL)
+                 {
+                   fputs (s, fp);
+                   s = NULL;
+                 }
+               else
+                 {
+                   fwrite (s, 1, e - s, fp);
+                   s = e + 1;
+                 }
+               putc ('\n', fp);
+             }
+           while (s != NULL);
+       }
+    }
+
+  /* Print xgettext extracted comments.  */
+  if (mp->comment_dot != NULL)
+    {
+      size_t j;
+
+      for (j = 0; j < mp->comment_dot->nitems; ++j)
+       {
+         const char *s = mp->comment_dot->item[j];
+
+         /* Test whether it is safe to output the comment in C style, or
+            whether we need C++ style for it.  */
+         if (strstr (s, "*/") == NULL)
+           {
+             fputs ("/* Comment: ", fp);
+             fputs (s, fp);
+             fputs (" */\n", fp);
+           }
+         else
+           {
+             bool first = true;
+             do
+               {
+                 const char *e;
+                 fputs ("//", fp);
+                 if (first || (*s != '\0' && *s != '\n' && *s != ' '))
+                   putc (' ', fp);
+                 if (first)
+                   fputs ("Comment: ", fp);
+                 e = strchr (s, '\n');
+                 if (e == NULL)
+                   {
+                     fputs (s, fp);
+                     s = NULL;
+                   }
+                 else
+                   {
+                     fwrite (s, 1, e - s, fp);
+                     s = e + 1;
+                   }
+                 putc ('\n', fp);
+                 first = false;
+               }
+             while (s != NULL);
+           }
+       }
+    }
+
+  /* Print the file position comments.  */
+  if (mp->filepos_count != 0)
+    {
+      size_t j;
+
+      for (j = 0; j < mp->filepos_count; ++j)
+       {
+         lex_pos_ty *pp = &mp->filepos[j];
+         char *cp = pp->file_name;
+         while (cp[0] == '.' && cp[1] == '/')
+           cp += 2;
+         fprintf (fp, "/* File: %s:%ld */\n", cp, (long) pp->line_number);
+       }
+    }
+
+  /* Print flag information in special comment.  */
+  if (mp->is_fuzzy || mp->msgstr[0] == '\0')
+    fputs ("/* Flag: untranslated */\n", fp);
+  if (mp->obsolete)
+    fputs ("/* Flag: unmatched */\n", fp);
+  {
+    size_t i;
+    for (i = 0; i < NFORMATS; i++)
+      if (significant_format_p (mp->is_format[i]))
+       {
+         fputs ("/* Flag:", fp);
+         fputs (make_format_description_string (mp->is_format[i],
+                                                format_language[i], debug),
+                fp);
+         fputs (" */\n", fp);
+       }
+  }
+
+  /* Now write the untranslated string and the translated string.  */
+  write_escaped_string (fp, mp->msgid);
+  fputs (" = ", fp);
+  if (mp->msgstr[0] != '\0')
+    {
+      if (mp->is_fuzzy)
+       {
+         /* Output the msgid as value, so that at runtime the untranslated
+            string is returned.  */
+         write_escaped_string (fp, mp->msgid);
+
+         /* Output the msgstr as a comment, so that at runtime
+            propertyListFromStringsFileFormat ignores it.  */
+         if (strstr (mp->msgstr, "*/") == NULL)
+           {
+             fputs (" /* = ", fp);
+             write_escaped_string (fp, mp->msgstr);
+             fputs (" */", fp);
+           }
+         else
+           {
+             fputs ("; // = ", fp);
+             write_escaped_string (fp, mp->msgstr);
+           }
+       }
+      else
+       write_escaped_string (fp, mp->msgstr);
+    }
+  else
+    {
+      /* Output the msgid as value, so that at runtime the untranslated
+        string is returned.  */
+      write_escaped_string (fp, mp->msgid);
+    }
+  putc (';', fp);
+
+  putc ('\n', fp);
+}
+
+/* Writes an entire message list to the file.  */
+static void
+write_stringtable (FILE *fp, message_list_ty *mlp, const char *canon_encoding,
+                  size_t page_width, bool debug)
+{
+  bool blank_line;
+  size_t j;
+
+  /* Convert the messages to Unicode.  */
+  iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL);
+
+  /* Output the BOM.  */
+  if (!is_ascii_message_list (mlp))
+    fputs ("\xef\xbb\xbf", fp);
+
+  /* Loop through the messages.  */
+  blank_line = false;
+  for (j = 0; j < mlp->nitems; ++j)
+    {
+      const message_ty *mp = mlp->item[j];
+
+      if (mp->msgid_plural == NULL)
+       {
+         if (blank_line)
+           putc ('\n', fp);
+
+         write_message (fp, mp, page_width, debug);
+
+         blank_line = true;
+       }
+    }
+}
+
+/* Output the contents of a PO file in .strings syntax.  */
+void
+msgdomain_list_print_stringtable (msgdomain_list_ty *mdlp, FILE *fp,
+                                 size_t page_width, bool debug)
+{
+  message_list_ty *mlp;
+
+  if (mdlp->nitems == 1)
+    mlp = mdlp->item[0]->messages;
+  else
+    mlp = message_list_alloc (false);
+  write_stringtable (fp, mlp, mdlp->encoding, page_width, debug);
+}
diff --git a/gettext-tools/src/write-stringtable.h b/gettext-tools/src/write-stringtable.h
new file mode 100644 (file)
index 0000000..6b2787c
--- /dev/null
@@ -0,0 +1,33 @@
+/* Writing NeXTstep/GNUstep .strings files.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _WRITE_STRINGTABLE_H
+#define _WRITE_STRINGTABLE_H
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "message.h"
+
+/* Output the contents of a PO file in .strings syntax.  */
+extern void
+       msgdomain_list_print_stringtable (msgdomain_list_ty *mdlp, FILE *fp,
+                                        size_t page_width, bool debug);
+
+#endif /* _WRITE_STRINGTABLE_H */
index 594531550c2fb6b8336f9d5fca6d551576128232..89580b798428b55529fa4feb090dfec0060a1054 100644 (file)
@@ -30,6 +30,7 @@
 #include "xgettext.h"
 #include "x-po.h"
 #include "x-properties.h"
+#include "x-stringtable.h"
 #include "xalloc.h"
 #include "read-po.h"
 #include "po-lex.h"
@@ -139,3 +140,13 @@ extract_properties (FILE *fp,
 {
   extract (fp, real_filename,  logical_filename, syntax_properties, mdlp);
 }
+
+
+void
+extract_stringtable (FILE *fp,
+                    const char *real_filename, const char *logical_filename,
+                    flag_context_list_table_ty *flag_table,
+                    msgdomain_list_ty *mdlp)
+{
+  extract (fp, real_filename,  logical_filename, syntax_stringtable, mdlp);
+}
diff --git a/gettext-tools/src/x-stringtable.h b/gettext-tools/src/x-stringtable.h
new file mode 100644 (file)
index 0000000..8e9b81f
--- /dev/null
@@ -0,0 +1,30 @@
+/* xgettext NXStringTable backend.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+
+#define EXTENSIONS_STRINGTABLE \
+  { "strings", "NXStringTable" },                                      \
+
+#define SCANNERS_STRINGTABLE \
+  { "NXStringTable",   extract_stringtable, NULL, NULL, NULL },        \
+
+/* Scan a JavaProperties file and add its translatable strings to mdlp.  */
+extern void extract_stringtable (FILE *fp, const char *real_filename,
+                                const char *logical_filename,
+                                flag_context_list_table_ty *flag_table,
+                                msgdomain_list_ty *mdlp);
index 0ab44b95998cf294a0b97e562a443ab380de5a79..c10b3ead41b9e76dfbecd6a6b22dd7930b4d2745 100644 (file)
@@ -84,6 +84,7 @@ extern "C" {
 #include "x-tcl.h"
 #include "x-perl.h"
 #include "x-php.h"
+#include "x-stringtable.h"
 #include "x-rst.h"
 #include "x-glade.h"
 
@@ -126,7 +127,7 @@ static const char *msgstr_suffix;
 /* Directory in which output files are created.  */
 static char *output_dir;
 
-/* The output syntax: .pot or .properties.  */
+/* The output syntax: .pot or .properties or .strings.  */
 static input_syntax_ty output_syntax = syntax_po;
 
 /* If nonzero omit header with information about this run.  */
@@ -179,7 +180,7 @@ static const struct option long_options[] =
   { "exclude-file", required_argument, NULL, 'x' },
   { "extract-all", no_argument, NULL, 'a' },
   { "files-from", required_argument, NULL, 'f' },
-  { "flag", required_argument, NULL, CHAR_MAX + 7 },
+  { "flag", required_argument, NULL, CHAR_MAX + 8 },
   { "force-po", no_argument, &force_po, 1 },
   { "foreign-user", no_argument, NULL, CHAR_MAX + 2 },
   { "from-code", required_argument, NULL, CHAR_MAX + 3 },
@@ -202,6 +203,7 @@ static const struct option long_options[] =
   { "sort-output", no_argument, NULL, 's' },
   { "strict", no_argument, NULL, 'S' },
   { "string-limit", required_argument, NULL, 'l' },
+  { "stringtable-output", no_argument, NULL, CHAR_MAX + 7 },
   { "trigraphs", no_argument, NULL, 'T' },
   { "version", no_argument, NULL, 'V' },
   { "width", required_argument, NULL, 'w', },
@@ -453,7 +455,11 @@ main (int argc, char *argv[])
        message_print_syntax_properties ();
        output_syntax = syntax_properties;
        break;
-      case CHAR_MAX + 7:       /* --flag */
+      case CHAR_MAX + 7:       /* --stringtable-output */
+       message_print_syntax_stringtable ();
+       output_syntax = syntax_stringtable;
+       break;
+      case CHAR_MAX + 8:       /* --flag */
        xgettext_record_flag (optarg);
        break;
       default:
@@ -721,7 +727,7 @@ Choice of input file language:\n"));
                                 (C, C++, ObjectiveC, PO, Shell, Python, Lisp,\n\
                                 EmacsLisp, librep, Smalltalk, Java,\n\
                                 JavaProperties, awk, YCP, Tcl, Perl, PHP,\n\
-                                GCC-source, RST, Glade)\n"));
+                                GCC-source, NXStringTable, RST, Glade)\n"));
       printf (_("\
   -C, --c++                   shorthand for --language=C++\n"));
       printf (_("\
@@ -793,6 +799,8 @@ Output details:\n"));
       printf (_("\
       --properties-output     write out a Java .properties file\n"));
       printf (_("\
+      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
+      printf (_("\
   -w, --width=NUMBER          set output page width\n"));
       printf (_("\
       --no-wrap               do not break long message lines, longer than\n\
@@ -1994,7 +2002,9 @@ finalize_header (msgdomain_list_ty *mdlp)
          has_nonascii = true;
       }
 
-    if (has_nonascii || output_syntax == syntax_properties)
+    if (has_nonascii
+       || output_syntax == syntax_properties
+       || output_syntax == syntax_stringtable)
       {
        message_list_ty *mlp = mdlp->item[0]->messages;
 
@@ -2038,6 +2048,7 @@ language_to_extractor (const char *name)
     SCANNERS_TCL
     SCANNERS_PERL
     SCANNERS_PHP
+    SCANNERS_STRINGTABLE
     SCANNERS_RST
     SCANNERS_GLADE
     /* Here will follow more languages and their scanners: pike, C#, etc...
@@ -2095,6 +2106,7 @@ extension_to_language (const char *extension)
     EXTENSIONS_TCL
     EXTENSIONS_PERL
     EXTENSIONS_PHP
+    EXTENSIONS_STRINGTABLE
     EXTENSIONS_RST
     EXTENSIONS_GLADE
     /* Here will follow more file extensions: cs ... */
index 2d66349e20adc6698eb20b0cae96cecfd3754edb..a093c2762307ffb7c14286203acb34515aac68c2 100644 (file)
@@ -1,3 +1,9 @@
+2003-10-12  Bruno Haible  <bruno@clisp.org>
+
+       * msgcat-13: New file.
+       * xgettext-33: New file.
+       * Makefile.am (TESTS): Add them.
+
 2003-10-12  Bruno Haible  <bruno@clisp.org>
 
        * xgettext-32: New file.
index f960b9a80ec32c2a488e17bc1a339f0433e03085..0fdb2897c79a59de8d04fe7d577ed7a1905465dc 100644 (file)
@@ -25,7 +25,7 @@ TESTS = gettext-1 gettext-2 \
        msgattrib-6 msgattrib-7 msgattrib-8 msgattrib-9 msgattrib-10 \
        msgattrib-11 msgattrib-12 msgattrib-13 msgattrib-14 msgattrib-15 \
        msgcat-1 msgcat-2 msgcat-3 msgcat-4 msgcat-5 msgcat-6 msgcat-7 \
-       msgcat-8 msgcat-9 msgcat-10 msgcat-11 msgcat-12 \
+       msgcat-8 msgcat-9 msgcat-10 msgcat-11 msgcat-12 msgcat-13 \
        msgcmp-1 msgcmp-2 msgcmp-3 \
        msgcomm-1 msgcomm-2 msgcomm-3 msgcomm-4 msgcomm-5 msgcomm-6 msgcomm-7 \
        msgcomm-8 msgcomm-9 msgcomm-10 msgcomm-11 msgcomm-12 msgcomm-13 \
@@ -51,6 +51,7 @@ TESTS = gettext-1 gettext-2 \
        xgettext-18 xgettext-19 xgettext-20 xgettext-21 xgettext-22 \
        xgettext-23 xgettext-24 xgettext-25 xgettext-26 xgettext-27 \
        xgettext-28 xgettext-29 xgettext-30 xgettext-31 xgettext-32 \
+       xgettext-33 \
        format-awk-1 format-awk-2 \
        format-c-1 format-c-2 format-c-3 format-c-4 \
        format-elisp-1 format-elisp-2 \
diff --git a/gettext-tools/tests/msgcat-13 b/gettext-tools/tests/msgcat-13
new file mode 100755 (executable)
index 0000000..9938540
--- /dev/null
@@ -0,0 +1,69 @@
+#! /bin/sh
+
+# Test reading in NeXTstep/GNUstep .strings syntax.
+
+tmpfiles=""
+trap 'rm -fr $tmpfiles' 1 2 3 15
+
+tmpfiles="$tmpfiles mcat-test13.in"
+cat <<\EOF > mcat-test13.in
+/* This is an example of a string table file. Everything inside a comment
+is completely ignored, even if in "quotes", or \escape characters, etc.
+*/
+
+"title"        = "pattern II target 1";
+
+/* This is an example of excape codes in the string table, codes */
+/* that are not one of abfnrtv are stripped of the \ character */
+"escapes"    = "This is a tab \t and a return \n or a \a but not a \p";
+"escapes2"    = "Well how about a \0? Guess not.";
+
+/* more parameters, white space between tokens is ignored */
+"actualSize"   
+       = 
+               "0.000250 0.000250";
+
+/* a key with no value assumes the value is the same as the key */
+"hoe322070.element";
+EOF
+
+tmpfiles="$tmpfiles mcat-test13.out"
+rm -f mcat-test13.out
+: ${MSGCAT=msgcat}
+${MSGCAT} --stringtable-input mcat-test13.in -o mcat-test13.out
+test $? = 0 || { rm -fr $tmpfiles; exit 1; }
+
+tmpfiles="$tmpfiles mcat-test13.ok"
+cat << \EOF > mcat-test13.ok
+# This is an example of a string table file. Everything inside a comment
+# is completely ignored, even if in "quotes", or \escape characters, etc.
+#
+msgid "title"
+msgstr "pattern II target 1"
+
+# This is an example of excape codes in the string table, codes
+# that are not one of abfnrtv are stripped of the \ character
+msgid "escapes"
+msgstr ""
+"This is a tab \t and a return \n"
+" or a \a but not a p"
+
+msgid "escapes2"
+msgstr "Well how about a "
+
+# more parameters, white space between tokens is ignored
+msgid "actualSize"
+msgstr "0.000250 0.000250"
+
+# a key with no value assumes the value is the same as the key
+msgid "hoe322070.element"
+msgstr "hoe322070.element"
+EOF
+
+: ${DIFF=diff}
+${DIFF} mcat-test13.ok mcat-test13.out
+result=$?
+
+rm -fr $tmpfiles
+
+exit $result
diff --git a/gettext-tools/tests/xgettext-33 b/gettext-tools/tests/xgettext-33
new file mode 100755 (executable)
index 0000000..a4f17f9
--- /dev/null
@@ -0,0 +1,72 @@
+#! /bin/sh
+
+# Test extractor of NeXTstep/GNUstep .strings files.
+
+tmpfiles=""
+trap 'rm -fr $tmpfiles' 1 2 3 15
+
+tmpfiles="$tmpfiles xg-test33.strings"
+cat <<\EOF > xg-test33.strings
+/***
+German.lproj/Localizable.strings
+updated by make_strings 2003-10-12 15:31:50 +0200
+add comments above this one
+***/
+
+
+/*** Strings from Hello.m ***/
+/* File: Hello.m:57 */
+/* File: Hello.m:56 */
+"Hello, world!" = "Hallo Welt!";
+/* File: Hello.m:67 */
+"This program is running as process number %d."
+= "Dieses Programm läuft mit der Prozess-Nummer %d.";
+EOF
+
+tmpfiles="$tmpfiles xg-test33.tmp xg-test33.po"
+: ${XGETTEXT=xgettext}
+${XGETTEXT} xg-test33.strings -o xg-test33.tmp
+test $? = 0 || { rm -fr $tmpfiles; exit 1; }
+grep -v 'POT-Creation-Date' < xg-test33.tmp > xg-test33.po
+
+tmpfiles="$tmpfiles xg-test33.ok"
+cat <<\EOF > xg-test33.ok
+# 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"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#
+# German.lproj/Localizable.strings
+# updated by make_strings 2003-10-12 15:31:50 +0200
+# add comments above this one
+#
+# Strings from Hello.m
+#: Hello.m:57 Hello.m:56
+msgid "Hello, world!"
+msgstr "Hallo Welt!"
+
+#: Hello.m:67
+msgid "This program is running as process number %d."
+msgstr "Dieses Programm läuft mit der Prozess-Nummer %d."
+EOF
+
+: ${DIFF=diff}
+${DIFF} xg-test33.ok xg-test33.po
+result=$?
+
+rm -fr $tmpfiles
+
+exit $result