From: Bruno Haible Date: Thu, 8 Jan 2004 11:48:40 +0000 (+0000) Subject: Support for C# in msgunfmt. X-Git-Tag: v0.14~83 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ee792c755d35e75bd72fda0455951f41ca8d3678;p=thirdparty%2Fgettext.git Support for C# in msgunfmt. --- diff --git a/gettext-tools/src/msgunfmt.cs b/gettext-tools/src/msgunfmt.cs new file mode 100644 index 000000000..348ce222f --- /dev/null +++ b/gettext-tools/src/msgunfmt.cs @@ -0,0 +1,191 @@ +/* GNU gettext for C# + * Copyright (C) 2003-2004 Free Software Foundation, Inc. + * Written by Bruno Haible , 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. + */ + +/* + * This program dumps a GettextResourceSet subclass (in a satellite assembly) + * as a PO file. + */ + +using System; /* Object, String, Type, Console, Exception */ +using System.Reflection; /* Assembly, MethodInfo, ConstructorInfo */ +using System.Collections; /* Hashtable */ +using System.IO; /* BufferedStream, StreamWriter, TextWriter, FileNotFoundException, Path */ +using System.Text; /* StringBuilder, UTF8Encoding */ +using GNU.Gettext; /* GettextResourceSet */ + +namespace GNU.Gettext { + public class DumpResource { + private TextWriter Out; + private void DumpString (String str) { + int n = str.Length; + Out.Write('"'); + for (int i = 0; i < n; i++) { + char c = str[i]; + if (c == 0x0008) { + Out.Write('\\'); Out.Write('b'); + } else if (c == 0x000c) { + Out.Write('\\'); Out.Write('f'); + } else if (c == 0x000a) { + Out.Write('\\'); Out.Write('n'); + } else if (c == 0x000d) { + Out.Write('\\'); Out.Write('r'); + } else if (c == 0x0009) { + Out.Write('\\'); Out.Write('t'); + } else if (c == '\\' || c == '"') { + Out.Write('\\'); Out.Write(c); + } else + Out.Write(c); + } + Out.Write('"'); + } + private void DumpMessage (String msgid, String msgid_plural, Object msgstr) { + Out.Write("msgid "); DumpString(msgid); Out.Write('\n'); + if (msgid_plural != null) { + Out.Write("msgid_plural "); DumpString(msgid_plural); Out.Write('\n'); + for (int i = 0; i < (msgstr as String[]).Length; i++) { + Out.Write("msgstr[" + i + "] "); + DumpString((msgstr as String[])[i]); + Out.Write('\n'); + } + } else { + Out.Write("msgstr "); DumpString(msgstr as String); Out.Write('\n'); + } + Out.Write('\n'); + } + private void Dump (GettextResourceSet catalog) { + MethodInfo pluralMethod = + catalog.GetType().GetMethod("GetMsgidPluralTable", Type.EmptyTypes); + // Search for the header entry. + { + Object header_entry = catalog.GetObject(""); + // If there is no header entry, fake one. + // FIXME: This is not needed; right after po_lex_charset_init set + // the PO charset to UTF-8. + if (header_entry == null) + header_entry = "Content-Type: text/plain; charset=UTF-8\n"; + DumpMessage("", null, header_entry); + } + // Now the other messages. + { + Hashtable plural = null; + if (pluralMethod != null) + plural = pluralMethod.Invoke(catalog, new Object[0]) as Hashtable; + foreach (String key in catalog.Keys) + if (!"".Equals(key)) { + Object value = catalog.GetObject(key); + String key_plural = + (plural != null && value is String[] ? plural[key] as String : null); + DumpMessage(key, key_plural, value); + } + } + } + // Essentially taken from class GettextResourceManager. + private static Assembly GetSatelliteAssembly (String baseDirectory, String resourceName, String cultureName) { + String satelliteExpectedLocation = + baseDirectory + + Path.DirectorySeparatorChar + cultureName + + Path.DirectorySeparatorChar + resourceName + ".resources.dll"; + return Assembly.LoadFrom(satelliteExpectedLocation); + } + // Taken from class GettextResourceManager. + private static String ConstructClassName (String resourceName) { + // We could just return an arbitrary fixed class name, like "Messages", + // assuming that every assembly will only ever contain one + // GettextResourceSet subclass, but this assumption would break the day + // we want to support multi-domain PO files in the same format... + bool valid = (resourceName.Length > 0); + for (int i = 0; valid && i < resourceName.Length; i++) { + char c = resourceName[i]; + if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_') + || (i > 0 && c >= '0' && c <= '9'))) + valid = false; + } + if (valid) + return resourceName; + else { + // Use hexadecimal escapes, using the underscore as escape character. + String hexdigit = "0123456789abcdef"; + StringBuilder b = new StringBuilder(); + b.Append("__UESCAPED__"); + for (int i = 0; i < resourceName.Length; i++) { + char c = resourceName[i]; + if (c >= 0xd800 && c < 0xdc00 + && i+1 < resourceName.Length + && resourceName[i+1] >= 0xdc00 && resourceName[i+1] < 0xe000) { + // Combine two UTF-16 words to a character. + char c2 = resourceName[i+1]; + int uc = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + b.Append('_'); + b.Append('U'); + b.Append(hexdigit[(uc >> 28) & 0x0f]); + b.Append(hexdigit[(uc >> 24) & 0x0f]); + b.Append(hexdigit[(uc >> 20) & 0x0f]); + b.Append(hexdigit[(uc >> 16) & 0x0f]); + b.Append(hexdigit[(uc >> 12) & 0x0f]); + b.Append(hexdigit[(uc >> 8) & 0x0f]); + b.Append(hexdigit[(uc >> 4) & 0x0f]); + b.Append(hexdigit[uc & 0x0f]); + i++; + } else if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') + || (c >= '0' && c <= '9'))) { + int uc = c; + b.Append('_'); + b.Append('u'); + b.Append(hexdigit[(uc >> 12) & 0x0f]); + b.Append(hexdigit[(uc >> 8) & 0x0f]); + b.Append(hexdigit[(uc >> 4) & 0x0f]); + b.Append(hexdigit[uc & 0x0f]); + } else + b.Append(c); + } + return b.ToString(); + } + } + // Essentially taken from class GettextResourceManager. + private static GettextResourceSet InstantiateResourceSet (Assembly satelliteAssembly, String resourceName, String cultureName) { + Type clazz = satelliteAssembly.GetType(ConstructClassName(resourceName)+"_"+cultureName.Replace('-','_')); + ConstructorInfo constructor = clazz.GetConstructor(Type.EmptyTypes); + return constructor.Invoke(null) as GettextResourceSet; + } + public DumpResource (String baseDirectory, String resourceName, String cultureName) { + // We are only interested in the messages belonging to the locale + // itself, not in the inherited messages. Therefore we instantiate just + // the GettextResourceSet, not a GettextResourceManager. + Assembly satelliteAssembly = + GetSatelliteAssembly(baseDirectory, resourceName, cultureName); + GettextResourceSet catalog = + InstantiateResourceSet(satelliteAssembly, resourceName, cultureName); + BufferedStream stream = new BufferedStream(Console.OpenStandardOutput()); + Out = new StreamWriter(stream, new UTF8Encoding()); + Dump(catalog); + Out.Close(); + stream.Close(); + } + public static int Main (String[] args) { + try { + new DumpResource(args[0], args[1], args[2]); + } catch (Exception e) { + Console.Error.WriteLine(e); + Console.Error.WriteLine(e.StackTrace); + return 1; + } + return 0; + } + } +}