gettext.py
branch3.5
changeset 3278 293068aeee41
parent 3274 7d53d8491932
child 3279 6a2cde3f886e
equal deleted inserted replaced
3277:4fdb165ae3de 3278:293068aeee41
     6 
     6 
     7 I18N refers to the operation by which a program is made aware of multiple
     7 I18N refers to the operation by which a program is made aware of multiple
     8 languages.  L10N refers to the adaptation of your program, once
     8 languages.  L10N refers to the adaptation of your program, once
     9 internationalized, to the local language and cultural habits.
     9 internationalized, to the local language and cultural habits.
    10 
    10 
    11 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
       
    12 """
    11 """
    13 
    12 
    14 # This module represents the integration of work, contributions, feedback, and
    13 # This module represents the integration of work, contributions, feedback, and
    15 # suggestions from the following people:
    14 # suggestions from the following people:
    16 #
    15 #
    45 #
    44 #
    46 # - Support Solaris .mo file formats.  Unfortunately, we've been unable to
    45 # - Support Solaris .mo file formats.  Unfortunately, we've been unable to
    47 #   find this format documented anywhere.
    46 #   find this format documented anywhere.
    48 
    47 
    49 
    48 
    50 import copy, os, re, struct, sys
    49 import locale, copy, os, re, struct, sys
    51 from errno import ENOENT
    50 from errno import ENOENT
    52 
    51 
    53 
    52 
    54 __all__ = ['NullTranslations', 'GNUTranslations', 'Catalog',
    53 __all__ = ['NullTranslations', 'GNUTranslations', 'Catalog',
    55            'find', 'translation', 'install', 'textdomain', 'bindtextdomain',
    54            'find', 'translation', 'install', 'textdomain', 'bindtextdomain',
    76 def c2py(plural):
    75 def c2py(plural):
    77     """Gets a C expression as used in PO files for plural forms and returns a
    76     """Gets a C expression as used in PO files for plural forms and returns a
    78     Python lambda function that implements an equivalent expression.
    77     Python lambda function that implements an equivalent expression.
    79     """
    78     """
    80     # Security check, allow only the "n" identifier
    79     # Security check, allow only the "n" identifier
    81     from StringIO import StringIO
    80     try:
       
    81         from cStringIO import StringIO
       
    82     except ImportError:
       
    83         from StringIO import StringIO
    82     import token, tokenize
    84     import token, tokenize
    83     tokens = tokenize.generate_tokens(StringIO(plural).readline)
    85     tokens = tokenize.generate_tokens(StringIO(plural).readline)
    84     try:
    86     try:
    85         danger = [x for x in tokens if x[0] == token.NAME and x[1] != 'n']
    87         danger = [x for x in tokens if x[0] == token.NAME and x[1] != 'n']
    86     except tokenize.TokenError:
    88     except tokenize.TokenError:
   170 
   172 
   171 class NullTranslations:
   173 class NullTranslations:
   172     def __init__(self, fp=None):
   174     def __init__(self, fp=None):
   173         self._info = {}
   175         self._info = {}
   174         self._charset = None
   176         self._charset = None
       
   177         self._output_charset = None
   175         self._fallback = None
   178         self._fallback = None
   176         if fp is not None:
   179         if fp is not None:
   177             self._parse(fp)
   180             self._parse(fp)
   178 
   181 
   179     def _parse(self, fp):
   182     def _parse(self, fp):
   188     def gettext(self, message):
   191     def gettext(self, message):
   189         if self._fallback:
   192         if self._fallback:
   190             return self._fallback.gettext(message)
   193             return self._fallback.gettext(message)
   191         return message
   194         return message
   192 
   195 
       
   196     def pgettext(self, context, message):
       
   197         if self._fallback:
       
   198             return self._fallback.pgettext(context, message)
       
   199         return message
       
   200 
       
   201     def lgettext(self, message):
       
   202         if self._fallback:
       
   203             return self._fallback.lgettext(message)
       
   204         return message
       
   205 
       
   206     def lpgettext(self, context, message):
       
   207         if self._fallback:
       
   208             return self._fallback.lpgettext(context, message)
       
   209         return message
       
   210 
   193     def ngettext(self, msgid1, msgid2, n):
   211     def ngettext(self, msgid1, msgid2, n):
   194         if self._fallback:
   212         if self._fallback:
   195             return self._fallback.ngettext(msgid1, msgid2, n)
   213             return self._fallback.ngettext(msgid1, msgid2, n)
       
   214         if n == 1:
       
   215             return msgid1
       
   216         else:
       
   217             return msgid2
       
   218 
       
   219     def npgettext(self, context, msgid1, msgid2, n):
       
   220         if self._fallback:
       
   221             return self._fallback.npgettext(context, msgid1, msgid2, n)
       
   222         if n == 1:
       
   223             return msgid1
       
   224         else:
       
   225             return msgid2
       
   226 
       
   227     def lngettext(self, msgid1, msgid2, n):
       
   228         if self._fallback:
       
   229             return self._fallback.lngettext(msgid1, msgid2, n)
       
   230         if n == 1:
       
   231             return msgid1
       
   232         else:
       
   233             return msgid2
       
   234 
       
   235     def lnpgettext(self, context, msgid1, msgid2, n):
       
   236         if self._fallback:
       
   237             return self._fallback.lnpgettext(context, msgid1, msgid2, n)
   196         if n == 1:
   238         if n == 1:
   197             return msgid1
   239             return msgid1
   198         else:
   240         else:
   199             return msgid2
   241             return msgid2
   200 
   242 
   201     def ugettext(self, message):
   243     def ugettext(self, message):
   202         if self._fallback:
   244         if self._fallback:
   203             return self._fallback.ugettext(message)
   245             return self._fallback.ugettext(message)
   204         return unicode(message)
   246         return unicode(message)
   205 
   247 
       
   248     def upgettext(self, context, message):
       
   249         if self._fallback:
       
   250             return self._fallback.upgettext(context, message)
       
   251         return unicode(message)
       
   252 
   206     def ungettext(self, msgid1, msgid2, n):
   253     def ungettext(self, msgid1, msgid2, n):
   207         if self._fallback:
   254         if self._fallback:
   208             return self._fallback.ungettext(msgid1, msgid2, n)
   255             return self._fallback.ungettext(msgid1, msgid2, n)
       
   256         if n == 1:
       
   257             return unicode(msgid1)
       
   258         else:
       
   259             return unicode(msgid2)
       
   260 
       
   261     def unpgettext(self, context, msgid1, msgid2, n):
       
   262         if self._fallback:
       
   263             return self._fallback.unpgettext(context, msgid1, msgid2, n)
   209         if n == 1:
   264         if n == 1:
   210             return unicode(msgid1)
   265             return unicode(msgid1)
   211         else:
   266         else:
   212             return unicode(msgid2)
   267             return unicode(msgid2)
   213 
   268 
   215         return self._info
   270         return self._info
   216 
   271 
   217     def charset(self):
   272     def charset(self):
   218         return self._charset
   273         return self._charset
   219 
   274 
   220     def install(self, unicode=False):
   275     def output_charset(self):
       
   276         return self._output_charset
       
   277 
       
   278     def set_output_charset(self, charset):
       
   279         self._output_charset = charset
       
   280 
       
   281     def install(self, unicode=False, names=None):
   221         import __builtin__
   282         import __builtin__
   222         __builtin__.__dict__['_'] = unicode and self.ugettext or self.gettext
   283         __builtin__.__dict__['_'] = unicode and self.ugettext or self.gettext
       
   284         if hasattr(names, "__contains__"):
       
   285             if "gettext" in names:
       
   286                 __builtin__.__dict__['gettext'] = __builtin__.__dict__['_']
       
   287             if "pgettext" in names:
       
   288                 __builtin__.__dict__['pgettext'] = (unicode and self.upgettext
       
   289                                                     or self.pgettext)
       
   290             if "ngettext" in names:
       
   291                 __builtin__.__dict__['ngettext'] = (unicode and self.ungettext
       
   292                                                              or self.ngettext)
       
   293             if "npgettext" in names:
       
   294                 __builtin__.__dict__['npgettext'] = \
       
   295                     (unicode and self.unpgettext or self.npgettext)
       
   296             if "lgettext" in names:
       
   297                 __builtin__.__dict__['lgettext'] = self.lgettext
       
   298             if "lpgettext" in names:
       
   299                 __builtin__.__dict__['lpgettext'] = self.lpgettext
       
   300             if "lngettext" in names:
       
   301                 __builtin__.__dict__['lngettext'] = self.lngettext
       
   302             if "lnpgettext" in names:
       
   303                 __builtin__.__dict__['lnpgettext'] = self.lnpgettext
   223 
   304 
   224 
   305 
   225 class GNUTranslations(NullTranslations):
   306 class GNUTranslations(NullTranslations):
   226     # Magic number of .mo files
   307     # Magic number of .mo files
   227     LE_MAGIC = 0x950412deL
   308     LE_MAGIC = 0x950412deL
   228     BE_MAGIC = 0xde120495L
   309     BE_MAGIC = 0xde120495L
       
   310 
       
   311     # The encoding of a msgctxt and a msgid in a .mo file is
       
   312     # msgctxt + "\x04" + msgid (gettext version >= 0.15)
       
   313     CONTEXT_ENCODING = "%s\x04%s"
   229 
   314 
   230     def _parse(self, fp):
   315     def _parse(self, fp):
   231         """Override this method to support alternative .mo formats."""
   316         """Override this method to support alternative .mo formats."""
   232         unpack = struct.unpack
   317         unpack = struct.unpack
   233         filename = getattr(fp, 'name', '')
   318         filename = getattr(fp, 'name', '')
   260             else:
   345             else:
   261                 raise IOError(0, 'File is corrupt', filename)
   346                 raise IOError(0, 'File is corrupt', filename)
   262             # See if we're looking at GNU .mo conventions for metadata
   347             # See if we're looking at GNU .mo conventions for metadata
   263             if mlen == 0:
   348             if mlen == 0:
   264                 # Catalog description
   349                 # Catalog description
   265                 # don't handle multi-lines fields here, and skip
       
   266                 # lines which don't look like a header description
       
   267                 # (e.g. "header: value")
       
   268                 lastk = k = None
   350                 lastk = k = None
   269                 for item in tmsg.splitlines():
   351                 for item in tmsg.splitlines():
   270                     item = item.strip()
   352                     item = item.strip()
   271                     if not item or not ':' in item:
   353                     if not item:
   272                         continue
   354                         continue
   273                     k, v = item.split(':', 1)
   355                     if ':' in item:
   274                     k = k.strip().lower()
   356                         k, v = item.split(':', 1)
   275                     v = v.strip()
   357                         k = k.strip().lower()
   276                     self._info[k] = v
   358                         v = v.strip()
       
   359                         self._info[k] = v
       
   360                         lastk = k
       
   361                     elif lastk:
       
   362                         self._info[lastk] += '\n' + item
   277                     if k == 'content-type':
   363                     if k == 'content-type':
   278                         self._charset = v.split('charset=')[1]
   364                         self._charset = v.split('charset=')[1]
   279                     elif k == 'plural-forms':
   365                     elif k == 'plural-forms':
   280                         v = v.split(';')
   366                         v = v.split(';')
   281                         plural = v[1].split('plural=')[1]
   367                         plural = v[1].split('plural=')[1]
   287             # require alternative encodings (e.g. Zope's ZCML and ZPT).  For
   373             # require alternative encodings (e.g. Zope's ZCML and ZPT).  For
   288             # traditional gettext applications, the msgid conversion will
   374             # traditional gettext applications, the msgid conversion will
   289             # cause no problems since us-ascii should always be a subset of
   375             # cause no problems since us-ascii should always be a subset of
   290             # the charset encoding.  We may want to fall back to 8-bit msgids
   376             # the charset encoding.  We may want to fall back to 8-bit msgids
   291             # if the Unicode conversion fails.
   377             # if the Unicode conversion fails.
   292             if msg.find('\x00') >= 0:
   378             if '\x00' in msg:
   293                 # Plural forms
   379                 # Plural forms
   294                 msgid1, msgid2 = msg.split('\x00')
   380                 msgid1, msgid2 = msg.split('\x00')
   295                 tmsg = tmsg.split('\x00')
   381                 tmsg = tmsg.split('\x00')
   296                 if self._charset:
   382                 if self._charset:
   297                     msgid1 = unicode(msgid1, self._charset)
   383                     msgid1 = unicode(msgid1, self._charset)
   313         if tmsg is missing:
   399         if tmsg is missing:
   314             if self._fallback:
   400             if self._fallback:
   315                 return self._fallback.gettext(message)
   401                 return self._fallback.gettext(message)
   316             return message
   402             return message
   317         # Encode the Unicode tmsg back to an 8-bit string, if possible
   403         # Encode the Unicode tmsg back to an 8-bit string, if possible
   318         if self._charset:
   404         if self._output_charset:
       
   405             return tmsg.encode(self._output_charset)
       
   406         elif self._charset:
   319             return tmsg.encode(self._charset)
   407             return tmsg.encode(self._charset)
   320         return tmsg
   408         return tmsg
       
   409 
       
   410     def pgettext(self, context, message):
       
   411         ctxt_msg_id = self.CONTEXT_ENCODING % (context, message)
       
   412         missing = object()
       
   413         tmsg = self._catalog.get(ctxt_msg_id, missing)
       
   414         if tmsg is missing:
       
   415             if self._fallback:
       
   416                 return self._fallback.pgettext(context, message)
       
   417             return message
       
   418         # Encode the Unicode tmsg back to an 8-bit string, if possible
       
   419         if self._output_charset:
       
   420             return tmsg.encode(self._output_charset)
       
   421         elif self._charset:
       
   422             return tmsg.encode(self._charset)
       
   423         return tmsg
       
   424         
       
   425     def lgettext(self, message):
       
   426         missing = object()
       
   427         tmsg = self._catalog.get(message, missing)
       
   428         if tmsg is missing:
       
   429             if self._fallback:
       
   430                 return self._fallback.lgettext(message)
       
   431             return message
       
   432         if self._output_charset:
       
   433             return tmsg.encode(self._output_charset)
       
   434         return tmsg.encode(locale.getpreferredencoding())
       
   435 
       
   436     def lpgettext(self, context, message):
       
   437         ctxt_msg_id = self.CONTEXT_ENCODING % (context, message)
       
   438         missing = object()
       
   439         tmsg = self._catalog.get(ctxt_msg_id, missing)
       
   440         if tmsg is missing:
       
   441             if self._fallback:
       
   442                 return self._fallback.lpgettext(context, message)
       
   443             return message
       
   444         if self._output_charset:
       
   445             return tmsg.encode(self._output_charset)
       
   446         return tmsg.encode(locale.getpreferredencoding())
   321 
   447 
   322     def ngettext(self, msgid1, msgid2, n):
   448     def ngettext(self, msgid1, msgid2, n):
   323         try:
   449         try:
   324             tmsg = self._catalog[(msgid1, self.plural(n))]
   450             tmsg = self._catalog[(msgid1, self.plural(n))]
   325             if self._charset:
   451             if self._output_charset:
       
   452                 return tmsg.encode(self._output_charset)
       
   453             elif self._charset:
   326                 return tmsg.encode(self._charset)
   454                 return tmsg.encode(self._charset)
   327             return tmsg
   455             return tmsg
   328         except KeyError:
   456         except KeyError:
   329             if self._fallback:
   457             if self._fallback:
   330                 return self._fallback.ngettext(msgid1, msgid2, n)
   458                 return self._fallback.ngettext(msgid1, msgid2, n)
       
   459             if n == 1:
       
   460                 return msgid1
       
   461             else:
       
   462                 return msgid2
       
   463 
       
   464     def npgettext(self, context, msgid1, msgid2, n):
       
   465         ctxt_msg_id = self.CONTEXT_ENCODING % (context, msgid1)
       
   466         try:
       
   467             tmsg = self._catalog[(ctxt_msg_id, self.plural(n))]
       
   468             if self._output_charset:
       
   469                 return tmsg.encode(self._output_charset)
       
   470             elif self._charset:
       
   471                 return tmsg.encode(self._charset)
       
   472             return tmsg
       
   473         except KeyError:
       
   474             if self._fallback:
       
   475                 return self._fallback.npgettext(context, msgid1, msgid2, n)
       
   476             if n == 1:
       
   477                 return msgid1
       
   478             else:
       
   479                 return msgid2        
       
   480 
       
   481     def lngettext(self, msgid1, msgid2, n):
       
   482         try:
       
   483             tmsg = self._catalog[(msgid1, self.plural(n))]
       
   484             if self._output_charset:
       
   485                 return tmsg.encode(self._output_charset)
       
   486             return tmsg.encode(locale.getpreferredencoding())
       
   487         except KeyError:
       
   488             if self._fallback:
       
   489                 return self._fallback.lngettext(msgid1, msgid2, n)
       
   490             if n == 1:
       
   491                 return msgid1
       
   492             else:
       
   493                 return msgid2
       
   494 
       
   495     def lnpgettext(self, context, msgid1, msgid2, n):
       
   496         ctxt_msg_id = self.CONTEXT_ENCODING % (context, msgid1)
       
   497         try:
       
   498             tmsg = self._catalog[(ctxt_msg_id, self.plural(n))]
       
   499             if self._output_charset:
       
   500                 return tmsg.encode(self._output_charset)
       
   501             return tmsg.encode(locale.getpreferredencoding())
       
   502         except KeyError:
       
   503             if self._fallback:
       
   504                 return self._fallback.lnpgettext(context, msgid1, msgid2, n)
   331             if n == 1:
   505             if n == 1:
   332                 return msgid1
   506                 return msgid1
   333             else:
   507             else:
   334                 return msgid2
   508                 return msgid2
   335 
   509 
   340             if self._fallback:
   514             if self._fallback:
   341                 return self._fallback.ugettext(message)
   515                 return self._fallback.ugettext(message)
   342             return unicode(message)
   516             return unicode(message)
   343         return tmsg
   517         return tmsg
   344 
   518 
       
   519     def upgettext(self, context, message):
       
   520         ctxt_message_id = self.CONTEXT_ENCODING % (context, message)
       
   521         missing = object()
       
   522         tmsg = self._catalog.get(ctxt_message_id, missing)
       
   523         if tmsg is missing:
       
   524             if self._fallback:
       
   525                 return self._fallback.upgettext(context, message)
       
   526             return unicode(message)
       
   527         return tmsg
       
   528 
   345     def ungettext(self, msgid1, msgid2, n):
   529     def ungettext(self, msgid1, msgid2, n):
   346         try:
   530         try:
   347             tmsg = self._catalog[(msgid1, self.plural(n))]
   531             tmsg = self._catalog[(msgid1, self.plural(n))]
   348         except KeyError:
   532         except KeyError:
   349             if self._fallback:
   533             if self._fallback:
   350                 return self._fallback.ungettext(msgid1, msgid2, n)
   534                 return self._fallback.ungettext(msgid1, msgid2, n)
       
   535             if n == 1:
       
   536                 tmsg = unicode(msgid1)
       
   537             else:
       
   538                 tmsg = unicode(msgid2)
       
   539         return tmsg
       
   540 
       
   541     def unpgettext(self, context, msgid1, msgid2, n):
       
   542         ctxt_message_id = self.CONTEXT_ENCODING % (context, msgid1)
       
   543         try:
       
   544             tmsg = self._catalog[(ctxt_message_id, self.plural(n))]
       
   545         except KeyError:
       
   546             if self._fallback:
       
   547                 return self._fallback.unpgettext(context, msgid1, msgid2, n)
   351             if n == 1:
   548             if n == 1:
   352                 tmsg = unicode(msgid1)
   549                 tmsg = unicode(msgid1)
   353             else:
   550             else:
   354                 tmsg = unicode(msgid2)
   551                 tmsg = unicode(msgid2)
   355         return tmsg
   552         return tmsg
   395 
   592 
   396 # a mapping between absolute .mo file path and Translation object
   593 # a mapping between absolute .mo file path and Translation object
   397 _translations = {}
   594 _translations = {}
   398 
   595 
   399 def translation(domain, localedir=None, languages=None,
   596 def translation(domain, localedir=None, languages=None,
   400                 class_=None, fallback=False):
   597                 class_=None, fallback=False, codeset=None):
   401     if class_ is None:
   598     if class_ is None:
   402         class_ = GNUTranslations
   599         class_ = GNUTranslations
   403     mofiles = find(domain, localedir, languages, all=1)
   600     mofiles = find(domain, localedir, languages, all=1)
   404     if not mofiles:
   601     if not mofiles:
   405         if fallback:
   602         if fallback:
   412     for mofile in mofiles:
   609     for mofile in mofiles:
   413         key = os.path.abspath(mofile)
   610         key = os.path.abspath(mofile)
   414         t = _translations.get(key)
   611         t = _translations.get(key)
   415         if t is None:
   612         if t is None:
   416             t = _translations.setdefault(key, class_(open(mofile, 'rb')))
   613             t = _translations.setdefault(key, class_(open(mofile, 'rb')))
   417         # Copy the translation object to allow setting fallbacks.
   614         # Copy the translation object to allow setting fallbacks and
   418         # All other instance data is shared with the cached object.
   615         # output charset. All other instance data is shared with the
       
   616         # cached object.
   419         t = copy.copy(t)
   617         t = copy.copy(t)
       
   618         if codeset:
       
   619             t.set_output_charset(codeset)
   420         if result is None:
   620         if result is None:
   421             result = t
   621             result = t
   422         else:
   622         else:
   423             result.add_fallback(t)
   623             result.add_fallback(t)
   424     return result
   624     return result
   425 
   625 
   426 
   626 
   427 def install(domain, localedir=None, unicode=False):
   627 def install(domain, localedir=None, unicode=False, codeset=None, names=None):
   428     translation(domain, localedir, fallback=True).install(unicode)
   628     t = translation(domain, localedir, fallback=True, codeset=codeset)
       
   629     t.install(unicode, names)
   429 
   630 
   430 
   631 
   431 
   632 
   432 # a mapping b/w domains and locale directories
   633 # a mapping b/w domains and locale directories
   433 _localedirs = {}
   634 _localedirs = {}
       
   635 # a mapping b/w domains and codesets
       
   636 _localecodesets = {}
   434 # current global domain, `messages' used for compatibility w/ GNU gettext
   637 # current global domain, `messages' used for compatibility w/ GNU gettext
   435 _current_domain = 'messages'
   638 _current_domain = 'messages'
   436 
   639 
   437 
   640 
   438 def textdomain(domain=None):
   641 def textdomain(domain=None):
   441         _current_domain = domain
   644         _current_domain = domain
   442     return _current_domain
   645     return _current_domain
   443 
   646 
   444 
   647 
   445 def bindtextdomain(domain, localedir=None):
   648 def bindtextdomain(domain, localedir=None):
       
   649     global _localedirs
   446     if localedir is not None:
   650     if localedir is not None:
   447         _localedirs[domain] = localedir
   651         _localedirs[domain] = localedir
   448     return _localedirs.get(domain, _default_localedir)
   652     return _localedirs.get(domain, _default_localedir)
   449 
   653 
   450 
   654 
       
   655 def bind_textdomain_codeset(domain, codeset=None):
       
   656     global _localecodesets
       
   657     if codeset is not None:
       
   658         _localecodesets[domain] = codeset
       
   659     return _localecodesets.get(domain)
       
   660 
       
   661 
   451 def dgettext(domain, message):
   662 def dgettext(domain, message):
   452     try:
   663     try:
   453         t = translation(domain, _localedirs.get(domain, None))
   664         t = translation(domain, _localedirs.get(domain, None),
       
   665                         codeset=_localecodesets.get(domain))
   454     except IOError:
   666     except IOError:
   455         return message
   667         return message
   456     return t.gettext(message)
   668     return t.gettext(message)
   457 
   669 
       
   670 def dpgettext(domain, context, message):
       
   671     try:
       
   672         t = translation(domain, _localedirs.get(domain, None),
       
   673                         codeset=_localecodesets.get(domain))
       
   674     except IOError:
       
   675         return message
       
   676     return t.pgettext(context, message)
       
   677 
       
   678 def ldgettext(domain, message):
       
   679     try:
       
   680         t = translation(domain, _localedirs.get(domain, None),
       
   681                         codeset=_localecodesets.get(domain))
       
   682     except IOError:
       
   683         return message
       
   684     return t.lgettext(message)
       
   685 
       
   686 def ldpgettext(domain, context, message):
       
   687     try:
       
   688         t = translation(domain, _localedirs.get(domain, None),
       
   689                         codeset=_localecodesets.get(domain))
       
   690     except IOError:
       
   691         return message
       
   692     return t.lpgettext(context, message)
   458 
   693 
   459 def dngettext(domain, msgid1, msgid2, n):
   694 def dngettext(domain, msgid1, msgid2, n):
   460     try:
   695     try:
   461         t = translation(domain, _localedirs.get(domain, None))
   696         t = translation(domain, _localedirs.get(domain, None),
       
   697                         codeset=_localecodesets.get(domain))
   462     except IOError:
   698     except IOError:
   463         if n == 1:
   699         if n == 1:
   464             return msgid1
   700             return msgid1
   465         else:
   701         else:
   466             return msgid2
   702             return msgid2
   467     return t.ngettext(msgid1, msgid2, n)
   703     return t.ngettext(msgid1, msgid2, n)
   468 
   704 
       
   705 def dnpgettext(domain, context, msgid1, msgid2, n):
       
   706     try:
       
   707         t = translation(domain, _localedirs.get(domain, None),
       
   708                         codeset=_localecodesets.get(domain))
       
   709     except IOError:
       
   710         if n == 1:
       
   711             return msgid1
       
   712         else:
       
   713             return msgid2
       
   714     return t.npgettext(context, msgid1, msgid2, n)
       
   715 
       
   716 def ldngettext(domain, msgid1, msgid2, n):
       
   717     try:
       
   718         t = translation(domain, _localedirs.get(domain, None),
       
   719                         codeset=_localecodesets.get(domain))
       
   720     except IOError:
       
   721         if n == 1:
       
   722             return msgid1
       
   723         else:
       
   724             return msgid2
       
   725     return t.lngettext(msgid1, msgid2, n)
       
   726 
       
   727 def ldnpgettext(domain, context, msgid1, msgid2, n):
       
   728     try:
       
   729         t = translation(domain, _localedirs.get(domain, None),
       
   730                         codeset=_localecodesets.get(domain))
       
   731     except IOError:
       
   732         if n == 1:
       
   733             return msgid1
       
   734         else:
       
   735             return msgid2
       
   736     return t.lnpgettext(context, msgid1, msgid2, n)
   469 
   737 
   470 def gettext(message):
   738 def gettext(message):
   471     return dgettext(_current_domain, message)
   739     return dgettext(_current_domain, message)
   472 
   740 
       
   741 def pgettext(context, message):
       
   742     return dpgettext(_current_domain, context, message)
       
   743 
       
   744 def lgettext(message):
       
   745     return ldgettext(_current_domain, message)
       
   746 
       
   747 def lpgettext(context, message):
       
   748     return ldpgettext(_current_domain, context, message)
   473 
   749 
   474 def ngettext(msgid1, msgid2, n):
   750 def ngettext(msgid1, msgid2, n):
   475     return dngettext(_current_domain, msgid1, msgid2, n)
   751     return dngettext(_current_domain, msgid1, msgid2, n)
   476 
   752 
       
   753 def npgettext(context, msgid1, msgid2, n):
       
   754     return dnpgettext(_current_domain, context, msgid1, msgid2, n)
       
   755 
       
   756 def lngettext(msgid1, msgid2, n):
       
   757     return ldngettext(_current_domain, msgid1, msgid2, n)
       
   758 
       
   759 def lnpgettext(context, msgid1, msgid2, n):
       
   760     return ldnpgettext(_current_domain, context, msgid1, msgid2, n)
   477 
   761 
   478 # dcgettext() has been deemed unnecessary and is not implemented.
   762 # dcgettext() has been deemed unnecessary and is not implemented.
   479 
   763 
   480 # James Henstridge's Catalog constructor from GNOME gettext.  Documented usage
   764 # James Henstridge's Catalog constructor from GNOME gettext.  Documented usage
   481 # was:
   765 # was: