gettext: C#

1 
1 15.5.12 C#
1 ----------
1 
1 RPMs
1      pnet, pnetlib 0.6.2 or newer, or mono 0.29 or newer
1 
1 File extension
1      ‘cs’
1 
1 String syntax
1      ‘"abc"’, ‘@"abc"’
1 
1 gettext shorthand
1      _("abc")
1 
1 gettext/ngettext functions
1      ‘GettextResourceManager.GetString’,
1      ‘GettextResourceManager.GetPluralString’
1      ‘GettextResourceManager.GetParticularString’
1      ‘GettextResourceManager.GetParticularPluralString’
1 
1 textdomain
1      ‘new GettextResourceManager(domain)’
1 
1 bindtextdomain
1      —, compiled message catalogs are located in subdirectories of the
1      directory containing the executable
1 
1 setlocale
1      automatic
1 
1 Prerequisite
1      —
1 
1 Use or emulate GNU gettext
1      —, uses a C# specific message catalog format
1 
1 Extractor
1      ‘xgettext -k_’
1 
1 Formatting with positions
1      ‘String.Format "{1} {0}"’
1 
1 Portability
1      fully portable
1 
1 po-mode marking
1      —
1 
1    Before marking strings as internationalizable, uses of the string
1 concatenation operator need to be converted to ‘String.Format’
1 invocations.  For example, ‘"file "+filename+" not found"’ becomes
1 ‘String.Format("file {0} not found", filename)’.  Only after this is
1 done, can the strings be marked and extracted.
1 
1    GNU gettext uses the native C#/.NET internationalization mechanism,
1 namely the classes ‘ResourceManager’ and ‘ResourceSet’.  Applications
1 use the ‘ResourceManager’ methods to retrieve the native language
1 translation of strings.  An instance of ‘ResourceSet’ is the in-memory
1 representation of a message catalog file.  The ‘ResourceManager’ loads
1 and accesses ‘ResourceSet’ instances as needed to look up the
1 translations.
1 
1    There are two formats of ‘ResourceSet’s that can be directly loaded
1 by the C# runtime: ‘.resources’ files and ‘.dll’ files.
1 
1    • The ‘.resources’ format is a binary file usually generated through
1      the ‘resgen’ or ‘monoresgen’ utility, but which doesn’t support
1      plural forms.  ‘.resources’ files can also be embedded in .NET
1      ‘.exe’ files.  This only affects whether a file system access is
1      performed to load the message catalog; it doesn’t affect the
1      contents of the message catalog.
1 
1    • On the other hand, the ‘.dll’ format is a binary file that is
1      compiled from ‘.cs’ source code and can support plural forms
1      (provided it is accessed through the GNU gettext API, see below).
1 
1    Note that these .NET ‘.dll’ and ‘.exe’ files are not tied to a
1 particular platform; their file format and GNU gettext for C# can be
1 used on any platform.
1 
1    To convert a PO file to a ‘.resources’ file, the ‘msgfmt’ program can
1 be used with the option ‘--csharp-resources’.  To convert a ‘.resources’
1 file back to a PO file, the ‘msgunfmt’ program can be used with the
1 option ‘--csharp-resources’.  You can also, in some cases, use the
1 ‘resgen’ program (from the ‘pnet’ package) or the ‘monoresgen’ program
1 (from the ‘mono’/‘mcs’ package).  These programs can also convert a
1 ‘.resources’ file back to a PO file.  But beware: as of this writing
1 (January 2004), the ‘monoresgen’ converter is quite buggy and the
1 ‘resgen’ converter ignores the encoding of the PO files.
1 
1    To convert a PO file to a ‘.dll’ file, the ‘msgfmt’ program can be
1 used with the option ‘--csharp’.  The result will be a ‘.dll’ file
1 containing a subclass of ‘GettextResourceSet’, which itself is a
1 subclass of ‘ResourceSet’.  To convert a ‘.dll’ file containing a
1 ‘GettextResourceSet’ subclass back to a PO file, the ‘msgunfmt’ program
1 can be used with the option ‘--csharp’.
1 
1    The advantages of the ‘.dll’ format over the ‘.resources’ format are:
1 
1   1. Freedom to localize: Users can add their own translations to an
1      application after it has been built and distributed.  Whereas when
1      the programmer uses a ‘ResourceManager’ constructor provided by the
1      system, the set of ‘.resources’ files for an application must be
1      specified when the application is built and cannot be extended
1      afterwards.
1 
1   2. Plural handling: A message catalog in ‘.dll’ format supports the
1      plural handling function ‘GetPluralString’.  Whereas ‘.resources’
1      files can only contain data and only support lookups that depend on
1      a single string.
1 
1   3. Context handling: A message catalog in ‘.dll’ format supports the
1      query-with-context functions ‘GetParticularString’ and
1      ‘GetParticularPluralString’.  Whereas ‘.resources’ files can only
1      contain data and only support lookups that depend on a single
1      string.
1 
1   4. The ‘GettextResourceManager’ that loads the message catalogs in
1      ‘.dll’ format also provides for inheritance on a per-message basis.
1      For example, in Austrian (‘de_AT’) locale, translations from the
1      German (‘de’) message catalog will be used for messages not found
1      in the Austrian message catalog.  This has the consequence that the
1      Austrian translators need only translate those few messages for
1      which the translation into Austrian differs from the German one.
1      Whereas when working with ‘.resources’ files, each message catalog
1      must provide the translations of all messages by itself.
1 
1   5. The ‘GettextResourceManager’ that loads the message catalogs in
1      ‘.dll’ format also provides for a fallback: The English MSGID is
1      returned when no translation can be found.  Whereas when working
1      with ‘.resources’ files, a language-neutral ‘.resources’ file must
1      explicitly be provided as a fallback.
1 
1    On the side of the programmatic APIs, the programmer can use either
1 the standard ‘ResourceManager’ API and the GNU ‘GettextResourceManager’
1 API. The latter is an extension of the former, because
1 ‘GettextResourceManager’ is a subclass of ‘ResourceManager’.
1 
1   1. The ‘System.Resources.ResourceManager’ API.
1 
1      This API works with resources in ‘.resources’ format.
1 
1      The creation of the ‘ResourceManager’ is done through
1             new ResourceManager(domainname, Assembly.GetExecutingAssembly())
1 
1      The ‘GetString’ function returns a string’s translation.  Note that
1      this function returns null when a translation is missing (i.e. not
1      even found in the fallback resource file).
1 
1   2. The ‘GNU.Gettext.GettextResourceManager’ API.
1 
1      This API works with resources in ‘.dll’ format.
1 
1      Reference documentation is in the csharpdoc directory
1      (csharpdoc/index.html).
1 
1      The creation of the ‘ResourceManager’ is done through
1             new GettextResourceManager(domainname)
1 
1      The ‘GetString’ function returns a string’s translation.  Note that
1      when a translation is missing, the MSGID argument is returned
1      unchanged.
1 
1      The ‘GetPluralString’ function returns a string translation with
1      plural handling, like the ‘ngettext’ function in C.
1 
1      The ‘GetParticularString’ function returns a string’s translation,
1      specific to a particular context, like the ‘pgettext’ function in
1      C. Note that when a translation is missing, the MSGID argument is
1      returned unchanged.
1 
1      The ‘GetParticularPluralString’ function returns a string
1      translation, specific to a particular context, with plural
1      handling, like the ‘npgettext’ function in C.
1 
1      To use this API, one needs the ‘GNU.Gettext.dll’ file which is part
1      of the GNU gettext package and distributed under the LGPL.
1 
1    You can also mix both approaches: use the
1 ‘GNU.Gettext.GettextResourceManager’ constructor, but otherwise use only
1 the ‘ResourceManager’ type and only the ‘GetString’ method.  This is
1 appropriate when you want to profit from the tools for PO files, but
1 don’t want to change an existing source code that uses ‘ResourceManager’
1 and don’t (yet) need the ‘GetPluralString’ method.
1 
1    Two examples, using the second API, are available in the ‘examples’
1 directory: ‘hello-csharp’, ‘hello-csharp-forms’.
1 
1    Now, to make use of the API and define a shorthand for ‘GetString’,
1 there are two idioms that you can choose from:
1 
1    • In a unique class of your project, say ‘Util’, define a static
1      variable holding the ‘ResourceManager’ instance:
1 
1           public static GettextResourceManager MyResourceManager =
1             new GettextResourceManager("domain-name");
1 
1      All classes containing internationalized strings then contain
1 
1           private static GettextResourceManager Res = Util.MyResourceManager;
1           private static String _(String s) { return Res.GetString(s); }
1 
1      and the shorthand is used like this:
1 
1           Console.WriteLine(_("Operation completed."));
1 
1    • You add a class with a very short name, say ‘S’, containing just
1      the definition of the resource manager and of the shorthand:
1 
1           public class S {
1             public static GettextResourceManager MyResourceManager =
1               new GettextResourceManager("domain-name");
1             public static String _(String s) {
1                return MyResourceManager.GetString(s);
1             }
1           }
1 
1      and the shorthand is used like this:
1 
1           Console.WriteLine(S._("Operation completed."));
1 
1    Which of the two idioms you choose, will depend on whether copying
1 two lines of codes into every class is more acceptable in your project
1 than a class with a single-letter name.
1