[GRASS-dev] Plural form support in GRASS 7 translated messages

Hello all devs,
starting from r59156 (and r59189) GRASS 7 is capable of using gettext
provided plural form support for translatable messages. Thus finally
users with different plural form handling than in English language
will be able to see grammatically correct translated messages. For
English speaking GRASS users it also would mean departure from such
strange forms as "map(s)", "file(s)" etc.

I kindly ask from now on to use the new function (a macro wrapper of
dngettext) _n() to wrap any translatable text messages where its
content depends on a number. Syntax of function is following:
_n("English singular", "English plural", number)
For some usage examples, please, see locale/README

Gettext documentation on ngettext function and its use (with examples):
http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms

Relevant commits:
_n() macro: r59156 and r59189
update to documentation: r59174
extraction of _n() content to POT files: r59157
a fix for some of library messages: r59158

Currently _n() works only in C code. I hope some of Python gurus will
clarify/implement same thing for Python parts of GRASS.

Thanks to Paulo, Martin, Vaclav for a fast feedback.

When the code will settle down (read - C gurus will fix all mistakes I
made), a separate notice to translators with a request to report
"strange" strings should be made.

Thank you all,
Maris.

Maris Nartiss wrote:

Currently _n() works only in C code. I hope some of Python gurus will
clarify/implement same thing for Python parts of GRASS.

Python code uses gettext.install(), which adds several functions to
the built-in namespace:

    def install(self, unicode=False, names=None):
        import __builtin__
        __builtin__.__dict__['_'] = unicode and self.ugettext or self.gettext
        if hasattr(names, "__contains__"):
            if "gettext" in names:
                __builtin__.__dict__['gettext'] = __builtin__.__dict__['_']
            if "ngettext" in names:
                __builtin__.__dict__['ngettext'] = (unicode and self.ungettext
                                                             or self.ngettext)
            if "lgettext" in names:
                __builtin__.__dict__['lgettext'] = self.lgettext
            if "lngettext" in names:
                __builtin__.__dict__['lngettext'] = self.lngettext

If we want _n(...) to work in Python, it will need to be added
explicitly with e.g.

  import __builtin__
  __builtin__.__dict__['_n'] = __builtin__.__dict__['ngettext']

This should immediately follow the gettext.install() call, which
exists in the following files:

  scripts/v.krige/v.krige.py
  lib/python/temporal/core.py
  lib/python/script/core.py
  lib/init/prompt.py
  lib/init/grass.py
  lib/init/grass.py

Some of these use unicode=True and some don't. Setting unicode=True
binds "_" to "ugettext", which returns a unicode string. The default
setting of unicode=False binds "_" to "gettext", which returns a byte
string.

Note that passing a unicode string to a function which expects a byte
string (e.g. subprocess.Popen(), or the .write() method of streams not
explicitly opened via codecs.open()) will result in it being encoded
using the default encoding (which is usually ASCII), not the locale's
encoding.

So don't use unicode=True unless you're either prepared to explicitly
handle the encoding issues when interfacing with system functions
(command execution, I/O, etc), or you're only interacting with the
system via a library which deals with this for you (e.g. wxPython).

--
Glynn Clements <glynn@gclements.plus.com>