+2003-12-28 Bruno Haible <bruno@clisp.org>
+
+ * gettext.texi (C#): Mention the --csharp-resources option.
+ * msgfmt.texi: Document the --csharp-resources option.
+ * msgunfmt.texi: Likewise.
+
2003-12-26 Bruno Haible <bruno@clisp.org>
Support for C#.
particular platform; their file format and GNU gettext for C# can be used
on any platform.
-To convert a PO file to a @code{.resources} file, the @code{resgen}
-program (from the @code{pnet} package) or the @code{monoresgen} program
-(from the @code{mono}/@code{mcs} package) can be used. These programs
-can also convert a @code{.resources} file back to a PO file. But beware:
-as of this writing (January 2004), the @code{monoresgen} converter is quite
-buggy and the @code{resgen} converter ignores the encoding of the PO files.
+To convert a PO file to a @code{.resources} file, the @code{msgfmt} program
+can be used with the option @samp{--csharp-resources}. To convert a
+@code{.resources} file back to a PO file, the @code{msgunfmt} program can be
+used with the option @samp{--csharp-resources}. You can also, in some cases,
+use the @code{resgen} program (from the @code{pnet} package) or the
+@code{monoresgen} program (from the @code{mono}/@code{mcs} package). These
+programs can also convert a @code{.resources} file back to a PO file. But
+beware: as of this writing (January 2004), the @code{monoresgen} converter is
+quite buggy and the @code{resgen} converter ignores the encoding of the PO
+files.
To convert a PO file to a @code{.dll} file, the @code{msgfmt} program can be
used with the option @code{--csharp}. The result will be a @code{.dll} file
C# mode: generate a .NET .dll file containing a subclass of
@code{GettextResourceSet}.
+@item --csharp-resources
+@opindex --csharp-resources@r{, @code{msgfmt} option}
+@cindex C# resources mode, and @code{msgfmt} program
+C# resources mode: generate a .NET @file{.resources} file.
+
@item --tcl
@opindex --tcl@r{, @code{msgfmt} option}
@cindex Tcl mode, and @code{msgfmt} program
C# mode: input is a .NET .dll file containing a subclass of
@code{GettextResourceSet}.
+@item --csharp-resources
+@opindex --csharp-resources@r{, @code{msgunfmt} option}
+@cindex C# resources mode, and @code{msgunfmt} program
+C# resources mode: input is a .NET @file{.resources} file.
+
@item --tcl
@opindex --tcl@r{, @code{msgunfmt} option}
@cindex Tcl mode, and @code{msgunfmt} program
+2003-12-28 Bruno Haible <bruno@clisp.org>
+
+ * write-resources.h: New file.
+ * write-resources.c: New file.
+ * msgfmt.cs: New file.
+ * msgfmt.c: Include write-resources.h.
+ (csharp_resources_mode): New variable.
+ (long_options): Add --csharp-resources.
+ (main): Handle --csharp-resources. More generic code for detection of
+ contradicting modes. Invoke msgdomain_write_csharp_resources.
+ (usage): Document --csharp-resources option.
+ (msgfmt_set_domain): Update.
+ * read-resources.h: New file.
+ * read-resources.c: New file.
+ * msgunfmt.cs (DumpResource): Add a constructor that dumps a .resources
+ file.
+ (Main): Invoke it when only one argument is given.
+ * msgunfmt.c: Include read-resources.h.
+ (csharp_resources_mode): New variable.
+ (long_options): Add --csharp-resources.
+ (main): Handle --csharp-resources. More generic code for detection of
+ contradicting modes. Invoke read_one_file instead of read_mo_file.
+ (usage): Document --csharp-resources option.
+ (read_one_file): New function.
+ * Makefile.am (noinst_HEADERS): Add read-resources.h and
+ write-resources.h.
+ (msgfmt_SOURCES): Add write-resources.c.
+ (msgunfmt_SOURCES): Add read-resources.c.
+ (EXTRA_DIST): Add msgfmt.cs.
+ (CLEANFILES): Add msgfmt.net.exe.
+ (msgfmt.net.exe): New rule.
+ (all-csharp-yes): Depend on it.
+ (install-exec-csharp-yes): Also install msgfmt.net.exe.
+ (uninstall-csharp-yes): Also uninstall msgfmt.net.exe.
+ * Makefile.msvc (msgfmt_OBJECTS): Add write-resources.obj.
+ (msgunfmt_OBJECTS): Add read-resources.obj.
+ (write-resources.obj, read-resources.obj): New rules.
+ * Makefile.vms (msgfmt_OBJECTS): Add write-resources.obj.
+ (msgunfmt_OBJECTS): Add read-resources.obj.
+ (write-resources.obj, read-resources.obj): New rules.
+ * FILES: Update.
+
2003-12-26 Bruno Haible <bruno@clisp.org>
Support for C#.
* user-email.in: Use 'gettext' instead of @PACKAGE@.
-See ChangeLog.0 for earlier changes.
\ No newline at end of file
+See ChangeLog.0 for earlier changes.
| read-csharp.c
| msgunfmt.cs
| Reading C# satellite assemblies.
+| read-resources.h
+| read-resources.c
+| msgunfmt.cs
+| Reading C# .resources files.
| read-tcl.h
| read-tcl.c
| msgunfmt.tcl
| write-csharp.h
| write-csharp.c
| Generating C# satellite assemblies.
+| write-resources.h
+| write-resources.c
+| msgfmt.cs
+| Generating C# .resources files.
| write-tcl.h
| write-tcl.c
| Generating Tcl .msg files.
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-csharp.h write-csharp.h read-tcl.h write-tcl.h write-qt.h po-time.h \
-plural-table.h format.h \
+read-csharp.h write-csharp.h read-resources.h write-resources.h read-tcl.h \
+write-tcl.h write-qt.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-csharp.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
# All programs deal with message lists.
-# All programs must read PO files. (msgunfmt also, for read-java.c and
-# read-csharp.c.)
+# All programs must read PO files. (msgunfmt also, for read-java.c,
+# read-csharp.c and read-resources.c.)
# message.c -> str-list.c.
# (read-po-abstract.c <--> po-hash-gen.y <--> po-gram-gen.y <--> po-lex.c) -> str-list.c.
# (read-po-abstract.c <--> po-hash-gen.y <--> po-gram-gen.y <--> po-lex.c) -> open-po.c -> dir-list.c -> str-list.c.
# Source dependencies.
msgcmp_SOURCES = msgcmp.c
-msgfmt_SOURCES = msgfmt.c write-mo.c write-java.c write-csharp.c write-tcl.c \
+msgfmt_SOURCES = msgfmt.c \
+ write-mo.c write-java.c write-csharp.c write-resources.c write-tcl.c \
write-qt.c plural-eval.c
msgmerge_SOURCES = msgmerge.c plural-count.c
-msgunfmt_SOURCES = msgunfmt.c read-mo.c read-java.c read-csharp.c read-tcl.c
+msgunfmt_SOURCES = msgunfmt.c \
+ read-mo.c read-java.c read-csharp.c read-resources.c read-tcl.c
xgettext_SOURCES = xgettext.c \
x-c.c x-po.c x-sh.c x-python.c x-lisp.c x-elisp.c x-librep.c x-smalltalk.c \
x-java.c x-csharp.c x-awk.c x-ycp.c x-tcl.c x-perl.c x-php.c x-rst.c \
uninstall-java-no-no:
-# Special rules for C# auxiliary program.
+# Special rules for C# auxiliary programs.
-EXTRA_DIST += msgunfmt.cs
+EXTRA_DIST += msgfmt.cs msgunfmt.cs
-CLEANFILES += msgunfmt.net.exe
+CLEANFILES += msgfmt.net.exe msgunfmt.net.exe
all-local: all-csharp-@BUILDCSHARP@
-all-csharp-yes: msgunfmt.net.exe
+all-csharp-yes: msgfmt.net.exe msgunfmt.net.exe
all-csharp-no:
+msgfmt.net.exe: msgfmt.cs
+ $(CSHARPCOMP) $(CSHARPCOMPFLAGS) -o $@ $(srcdir)/msgfmt.cs
+
msgunfmt.net.exe: msgunfmt.cs
$(CSHARPCOMP) $(CSHARPCOMPFLAGS) -o $@ -L ../../gettext-runtime/intl-csharp -l GNU.Gettext $(srcdir)/msgunfmt.cs
install-exec-local: install-exec-csharp-@BUILDCSHARP@
install-exec-csharp-yes: all-csharp-yes
$(mkinstalldirs) $(DESTDIR)$(pkglibdir)
+ $(INSTALL_DATA) msgfmt.net.exe $(DESTDIR)$(pkglibdir)/msgfmt.net.exe
$(INSTALL_DATA) msgunfmt.net.exe $(DESTDIR)$(pkglibdir)/msgunfmt.net.exe
install-exec-csharp-no:
$(mkinstalldirs) $(DESTDIR)$(pkglibdir)
uninstall-local: uninstall-csharp-@BUILDCSHARP@
uninstall-csharp-yes: all-csharp-yes
+ $(RM) $(DESTDIR)$(pkglibdir)/msgfmt.net.exe
$(RM) $(DESTDIR)$(pkglibdir)/msgunfmt.net.exe
uninstall-csharp-no:
format-qt.obj
msgcmp_OBJECTS = msgcmp.obj
-msgfmt_OBJECTS = msgfmt.obj write-mo.obj write-java.obj write-csharp.obj write-tcl.obj write-qt.obj plural-eval.obj
+msgfmt_OBJECTS = msgfmt.obj write-mo.obj write-java.obj write-csharp.obj write-resources.obj write-tcl.obj write-qt.obj plural-eval.obj
msgmerge_OBJECTS = msgmerge.obj plural-count.obj
-msgunfmt_OBJECTS = msgunfmt.obj read-mo.obj read-java.obj read-csharp.obj read-tcl.obj
+msgunfmt_OBJECTS = msgunfmt.obj read-mo.obj read-java.obj read-csharp.obj read-resources.obj read-tcl.obj
xgettext_OBJECTS = xgettext.obj x-c.obj x-po.obj x-sh.obj x-python.obj x-lisp.obj x-elisp.obj x-librep.obj x-smalltalk.obj x-java.obj x-csharp.obj x-awk.obj x-ycp.obj x-tcl.obj x-perl.obj x-php.obj x-rst.obj x-glade.obj
msgattrib_OBJECTS = msgattrib.obj
msgcat_OBJECTS = msgcat.obj
write-csharp.obj : write-csharp.c
$(CC) $(INCLUDES) $(CFLAGS) -c write-csharp.c
+write-resources.obj : write-resources.c
+ $(CC) $(INCLUDES) $(CFLAGS) -c write-resources.c
+
write-tcl.obj : write-tcl.c
$(CC) $(INCLUDES) $(CFLAGS) -c write-tcl.c
read-csharp.obj : read-csharp.c
$(CC) $(INCLUDES) $(CFLAGS) -c read-csharp.c
+read-resources.obj : read-resources.c
+ $(CC) $(INCLUDES) $(CFLAGS) -c read-resources.c
+
read-tcl.obj : read-tcl.c
$(CC) $(INCLUDES) $(CFLAGS) -c read-tcl.c
format-qt.obj
msgcmp_OBJECTS = msgcmp.obj
-msgfmt_OBJECTS = msgfmt.obj, write-mo.obj, write-java.obj, write-csharp.obj, write-tcl.obj, write-qt.obj, plural-eval.obj
+msgfmt_OBJECTS = msgfmt.obj, write-mo.obj, write-java.obj, write-csharp.obj, write-resources.obj, write-tcl.obj, write-qt.obj, plural-eval.obj
msgmerge_OBJECTS = msgmerge.obj, plural-count.obj
-msgunfmt_OBJECTS = msgunfmt.obj, read-mo.obj, read-java.obj, read-csharp.obj, read-tcl.obj
+msgunfmt_OBJECTS = msgunfmt.obj, read-mo.obj, read-java.obj, read-csharp.obj, read-resources.obj, read-tcl.obj
xgettext_OBJECTS = xgettext.obj, x-c.obj, x-po.obj, x-sh.obj, x-python.obj, x-lisp.obj, x-elisp.obj, x-librep.obj, x-smalltalk.obj, x-java.obj, x-csharp.obj, x-awk.obj, x-ycp.obj, x-tcl.obj, x-perl.obj, x-php.obj, x-rst.obj, x-glade.obj
msgattrib_OBJECTS = msgattrib.obj
msgcat_OBJECTS = msgcat.obj
write-csharp.obj : write-csharp.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) write-csharp.c
+write-resources.obj : write-resources.c
+ $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) write-resources.c
+
write-tcl.obj : write-tcl.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) write-tcl.c
read-csharp.obj : read-csharp.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) read-csharp.c
+read-resources.obj : read-resources.c
+ $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) read-resources.c
+
read-tcl.obj : read-tcl.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) read-tcl.c
#include "write-mo.h"
#include "write-java.h"
#include "write-csharp.h"
+#include "write-resources.h"
#include "write-tcl.h"
#include "write-qt.h"
static const char *csharp_locale_name;
static const char *csharp_base_directory;
+/* C# resources mode output file specification. */
+static bool csharp_resources_mode;
+
/* Tcl mode output file specification. */
static bool tcl_mode;
static const char *tcl_locale_name;
{ "check-format", no_argument, NULL, CHAR_MAX + 3 },
{ "check-header", no_argument, NULL, CHAR_MAX + 4 },
{ "csharp", no_argument, NULL, CHAR_MAX + 10 },
+ { "csharp-resources", no_argument, NULL, CHAR_MAX + 11 },
{ "directory", required_argument, NULL, 'D' },
{ "help", no_argument, NULL, 'h' },
{ "java", no_argument, NULL, 'j' },
case CHAR_MAX + 10: /* --csharp */
csharp_mode = true;
break;
+ case CHAR_MAX + 11: /* --csharp-resources */
+ csharp_resources_mode = true;
+ break;
default:
usage (EXIT_FAILURE);
break;
}
/* Check for contradicting options. */
- if (java_mode && csharp_mode)
- error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
- "--java", "--csharp");
- if (java_mode && tcl_mode)
- error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
- "--java", "--tcl");
- if (java_mode && qt_mode)
- error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
- "--java", "--qt");
- if (csharp_mode && tcl_mode)
- error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
- "--csharp", "--tcl");
- if (csharp_mode && qt_mode)
- error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
- "--csharp", "--qt");
- if (tcl_mode && qt_mode)
- error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
- "--tcl", "--qt");
+ {
+ unsigned int modes =
+ (java_mode ? 1 : 0)
+ | (csharp_mode ? 2 : 0)
+ | (csharp_resources_mode ? 4 : 0)
+ | (tcl_mode ? 8 : 0)
+ | (qt_mode ? 16 : 0);
+ static const char *mode_options[] =
+ { "--java", "--csharp", "--csharp-resources", "--tcl", "--qt" };
+ /* More than one bit set? */
+ if (modes & (modes - 1))
+ {
+ const char *first_option;
+ const char *second_option;
+ unsigned int i;
+ for (i = 0; ; i++)
+ if (modes & (1 << i))
+ break;
+ first_option = mode_options[i];
+ for (i = i + 1; ; i++)
+ if (modes & (1 << i))
+ break;
+ second_option = mode_options[i];
+ error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
+ first_option, second_option);
+ }
+ }
if (java_mode)
{
if (output_file_name != NULL)
if (output_file_name != NULL)
current_domain =
new_domain (output_file_name,
- !qt_mode && strict_uniforum ? add_mo_suffix (output_file_name)
- : output_file_name);
+ strict_uniforum && !csharp_resources_mode && !qt_mode
+ ? add_mo_suffix (output_file_name)
+ : output_file_name);
/* Process all given .po files. */
while (argc > optind)
csharp_base_directory))
exit_status = EXIT_FAILURE;
}
+ else if (csharp_resources_mode)
+ {
+ if (msgdomain_write_csharp_resources (domain->mlp, canon_encoding,
+ domain->domain_name,
+ domain->file_name))
+ exit_status = EXIT_FAILURE;
+ }
else if (tcl_mode)
{
if (msgdomain_write_tcl (domain->mlp, canon_encoding,
printf (_("\
--csharp C# mode: generate a .NET .dll file\n"));
printf (_("\
+ --csharp-resources C# resources mode: generate a .NET .resources file\n"));
+ printf (_("\
--tcl Tcl mode: generate a tcl/msgcat .msg file\n"));
printf (_("\
--qt Qt mode: generate a Qt .qm file\n"));
{
/* If no output file was given, we change it with each `domain'
directive. */
- if (!java_mode && !csharp_mode && !tcl_mode && !qt_mode
- && output_file_name == NULL)
+ if (!java_mode && !csharp_mode && !csharp_resources_mode && !tcl_mode
+ && !qt_mode && output_file_name == NULL)
{
size_t correct;
#include "read-mo.h"
#include "read-java.h"
#include "read-csharp.h"
+#include "read-resources.h"
#include "read-tcl.h"
#include "write-po.h"
#include "gettext.h"
static const char *csharp_locale_name;
static const char *csharp_base_directory;
+/* C# resources mode input file specification. */
+static bool csharp_resources_mode;
+
/* Tcl mode input file specification. */
static bool tcl_mode;
static const char *tcl_locale_name;
static const struct option long_options[] =
{
{ "csharp", no_argument, NULL, CHAR_MAX + 4 },
+ { "csharp-resources", no_argument, NULL, CHAR_MAX + 5 },
{ "escape", no_argument, NULL, 'E' },
{ "force-po", no_argument, &force_po, 1 },
{ "help", no_argument, NULL, 'h' },
__attribute__ ((noreturn))
#endif
;
+static void read_one_file (message_list_ty *mlp, const char *filename);
int
csharp_mode = true;
break;
+ case CHAR_MAX + 5: /* --csharp-resources */
+ csharp_resources_mode = true;
+ break;
+
default:
usage (EXIT_FAILURE);
break;
usage (EXIT_SUCCESS);
/* Check for contradicting options. */
- if (java_mode && csharp_mode)
- error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
- "--java", "--csharp");
- if (java_mode && tcl_mode)
- error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
- "--java", "--tcl");
- if (csharp_mode && tcl_mode)
- error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
- "--csharp", "--tcl");
+ {
+ unsigned int modes =
+ (java_mode ? 1 : 0)
+ | (csharp_mode ? 2 : 0)
+ | (csharp_resources_mode ? 4 : 0)
+ | (tcl_mode ? 8 : 0);
+ static const char *mode_options[] =
+ { "--java", "--csharp", "--csharp-resources", "--tcl" };
+ /* More than one bit set? */
+ if (modes & (modes - 1))
+ {
+ const char *first_option;
+ const char *second_option;
+ unsigned int i;
+ for (i = 0; ; i++)
+ if (modes & (1 << i))
+ break;
+ first_option = mode_options[i];
+ for (i = i + 1; ; i++)
+ if (modes & (1 << i))
+ break;
+ second_option = mode_options[i];
+ error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
+ first_option, second_option);
+ }
+ }
if (java_mode)
{
if (optind < argc)
if (optind < argc)
{
do
- read_mo_file (mlp, argv[optind]);
+ read_one_file (mlp, argv[optind]);
while (++optind < argc);
}
else
- read_mo_file (mlp, "-");
+ read_one_file (mlp, "-");
result = msgdomain_list_alloc (false);
result->item[0]->messages = mlp;
printf (_("\
--csharp C# mode: input is a .NET .dll file\n"));
printf (_("\
+ --csharp-resources C# resources mode: input is a .NET .resources file\n"));
+ printf (_("\
--tcl Tcl mode: input is a tcl/msgcat .msg file\n"));
printf ("\n");
printf (_("\
exit (status);
}
+
+
+static void
+read_one_file (message_list_ty *mlp, const char *filename)
+{
+ if (csharp_resources_mode)
+ read_resources_file (mlp, filename);
+ else
+ read_mo_file (mlp, filename);
+}
/*
* This program dumps a GettextResourceSet subclass (in a satellite assembly)
- * as a PO file.
+ * or a .resources file as a PO file.
*/
using System; /* Object, String, Type, Console, Exception */
using System.Reflection; /* Assembly, MethodInfo, ConstructorInfo */
-using System.Collections; /* Hashtable */
+using System.Collections; /* Hashtable, DictionaryEntry */
using System.IO; /* BufferedStream, StreamWriter, TextWriter, FileNotFoundException, Path */
using System.Text; /* StringBuilder, UTF8Encoding */
+using System.Resources; /* ResourceReader */
using GNU.Gettext; /* GettextResourceSet */
namespace GNU.Gettext {
}
Out.Write('\n');
}
+
+ // ---------------- Dumping a GettextResourceSet ----------------
+
private void Dump (GettextResourceSet catalog) {
MethodInfo pluralMethod =
catalog.GetType().GetMethod("GetMsgidPluralTable", Type.EmptyTypes);
Out.Close();
stream.Close();
}
+
+ // ----------------- Dumping a .resources file ------------------
+
+ public DumpResource (String filename) {
+ BufferedStream stream = new BufferedStream(Console.OpenStandardOutput());
+ Out = new StreamWriter(stream, new UTF8Encoding());
+ ResourceReader rr;
+ if (filename.Equals("-")) {
+ BufferedStream input = new BufferedStream(Console.OpenStandardInput());
+ // A temporary output stream is needed because ResourceReader expects
+ // to be able to seek in the Stream.
+ byte[] contents;
+ {
+ MemoryStream tmpstream = new MemoryStream();
+ byte[] buf = new byte[1024];
+ for (;;) {
+ int n = input.Read(buf, 0, 1024);
+ if (n == 0)
+ break;
+ tmpstream.Write(buf, 0, n);
+ }
+ contents = tmpstream.ToArray();
+ tmpstream.Close();
+ }
+ MemoryStream tmpinput = new MemoryStream(contents);
+ rr = new ResourceReader(tmpinput);
+ } else {
+ rr = new ResourceReader(filename);
+ }
+ foreach (DictionaryEntry entry in rr) // uses rr.GetEnumerator()
+ DumpMessage(entry.Key as String, null, entry.Value as String);
+ rr.Close();
+ Out.Close();
+ stream.Close();
+ }
+
+ // --------------------------------------------------------------
+
public static int Main (String[] args) {
try {
- new DumpResource(args[0], args[1], args[2]);
+ if (args.Length > 1)
+ new DumpResource(args[0], args[1], args[2]);
+ else
+ new DumpResource(args[0]);
} catch (Exception e) {
Console.Error.WriteLine(e);
Console.Error.WriteLine(e.StackTrace);