Coverage for /pythoncovmergedfiles/medio/medio/usr/lib/python3.9/gettext.py: 25%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Internationalization and localization support.
3This module provides internationalization (I18N) and localization (L10N)
4support for your Python programs by providing an interface to the GNU gettext
5message catalog library.
7I18N refers to the operation by which a program is made aware of multiple
8languages. L10N refers to the adaptation of your program, once
9internationalized, to the local language and cultural habits.
11"""
13# This module represents the integration of work, contributions, feedback, and
14# suggestions from the following people:
15#
16# Martin von Loewis, who wrote the initial implementation of the underlying
17# C-based libintlmodule (later renamed _gettext), along with a skeletal
18# gettext.py implementation.
19#
20# Peter Funk, who wrote fintl.py, a fairly complete wrapper around intlmodule,
21# which also included a pure-Python implementation to read .mo files if
22# intlmodule wasn't available.
23#
24# James Henstridge, who also wrote a gettext.py module, which has some
25# interesting, but currently unsupported experimental features: the notion of
26# a Catalog class and instances, and the ability to add to a catalog file via
27# a Python API.
28#
29# Barry Warsaw integrated these modules, wrote the .install() API and code,
30# and conformed all C and Python code to Python's coding standards.
31#
32# Francois Pinard and Marc-Andre Lemburg also contributed valuably to this
33# module.
34#
35# J. David Ibanez implemented plural forms. Bruno Haible fixed some bugs.
36#
37# TODO:
38# - Lazy loading of .mo files. Currently the entire catalog is loaded into
39# memory, but that's probably bad for large translated programs. Instead,
40# the lexical sort of original strings in GNU .mo files should be exploited
41# to do binary searches and lazy initializations. Or you might want to use
42# the undocumented double-hash algorithm for .mo files with hash tables, but
43# you'll need to study the GNU gettext code to do this.
44#
45# - Support Solaris .mo file formats. Unfortunately, we've been unable to
46# find this format documented anywhere.
49import os
50import re
51import sys
54__all__ = ['NullTranslations', 'GNUTranslations', 'Catalog',
55 'find', 'translation', 'install', 'textdomain', 'bindtextdomain',
56 'bind_textdomain_codeset',
57 'dgettext', 'dngettext', 'gettext', 'lgettext', 'ldgettext',
58 'ldngettext', 'lngettext', 'ngettext',
59 'pgettext', 'dpgettext', 'npgettext', 'dnpgettext',
60 ]
62_default_localedir = os.path.join(sys.base_prefix, 'share', 'locale')
64# Expression parsing for plural form selection.
65#
66# The gettext library supports a small subset of C syntax. The only
67# incompatible difference is that integer literals starting with zero are
68# decimal.
69#
70# https://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms
71# http://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-runtime/intl/plural.y
73_token_pattern = re.compile(r"""
74 (?P<WHITESPACES>[ \t]+) | # spaces and horizontal tabs
75 (?P<NUMBER>[0-9]+\b) | # decimal integer
76 (?P<NAME>n\b) | # only n is allowed
77 (?P<PARENTHESIS>[()]) |
78 (?P<OPERATOR>[-*/%+?:]|[><!]=?|==|&&|\|\|) | # !, *, /, %, +, -, <, >,
79 # <=, >=, ==, !=, &&, ||,
80 # ? :
81 # unary and bitwise ops
82 # not allowed
83 (?P<INVALID>\w+|.) # invalid token
84 """, re.VERBOSE|re.DOTALL)
86def _tokenize(plural):
87 for mo in re.finditer(_token_pattern, plural):
88 kind = mo.lastgroup
89 if kind == 'WHITESPACES':
90 continue
91 value = mo.group(kind)
92 if kind == 'INVALID':
93 raise ValueError('invalid token in plural form: %s' % value)
94 yield value
95 yield ''
97def _error(value):
98 if value:
99 return ValueError('unexpected token in plural form: %s' % value)
100 else:
101 return ValueError('unexpected end of plural form')
103_binary_ops = (
104 ('||',),
105 ('&&',),
106 ('==', '!='),
107 ('<', '>', '<=', '>='),
108 ('+', '-'),
109 ('*', '/', '%'),
110)
111_binary_ops = {op: i for i, ops in enumerate(_binary_ops, 1) for op in ops}
112_c2py_ops = {'||': 'or', '&&': 'and', '/': '//'}
114def _parse(tokens, priority=-1):
115 result = ''
116 nexttok = next(tokens)
117 while nexttok == '!':
118 result += 'not '
119 nexttok = next(tokens)
121 if nexttok == '(':
122 sub, nexttok = _parse(tokens)
123 result = '%s(%s)' % (result, sub)
124 if nexttok != ')':
125 raise ValueError('unbalanced parenthesis in plural form')
126 elif nexttok == 'n':
127 result = '%s%s' % (result, nexttok)
128 else:
129 try:
130 value = int(nexttok, 10)
131 except ValueError:
132 raise _error(nexttok) from None
133 result = '%s%d' % (result, value)
134 nexttok = next(tokens)
136 j = 100
137 while nexttok in _binary_ops:
138 i = _binary_ops[nexttok]
139 if i < priority:
140 break
141 # Break chained comparisons
142 if i in (3, 4) and j in (3, 4): # '==', '!=', '<', '>', '<=', '>='
143 result = '(%s)' % result
144 # Replace some C operators by their Python equivalents
145 op = _c2py_ops.get(nexttok, nexttok)
146 right, nexttok = _parse(tokens, i + 1)
147 result = '%s %s %s' % (result, op, right)
148 j = i
149 if j == priority == 4: # '<', '>', '<=', '>='
150 result = '(%s)' % result
152 if nexttok == '?' and priority <= 0:
153 if_true, nexttok = _parse(tokens, 0)
154 if nexttok != ':':
155 raise _error(nexttok)
156 if_false, nexttok = _parse(tokens)
157 result = '%s if %s else %s' % (if_true, result, if_false)
158 if priority == 0:
159 result = '(%s)' % result
161 return result, nexttok
163def _as_int(n):
164 try:
165 i = round(n)
166 except TypeError:
167 raise TypeError('Plural value must be an integer, got %s' %
168 (n.__class__.__name__,)) from None
169 import warnings
170 warnings.warn('Plural value must be an integer, got %s' %
171 (n.__class__.__name__,),
172 DeprecationWarning, 4)
173 return n
175def c2py(plural):
176 """Gets a C expression as used in PO files for plural forms and returns a
177 Python function that implements an equivalent expression.
178 """
180 if len(plural) > 1000:
181 raise ValueError('plural form expression is too long')
182 try:
183 result, nexttok = _parse(_tokenize(plural))
184 if nexttok:
185 raise _error(nexttok)
187 depth = 0
188 for c in result:
189 if c == '(':
190 depth += 1
191 if depth > 20:
192 # Python compiler limit is about 90.
193 # The most complex example has 2.
194 raise ValueError('plural form expression is too complex')
195 elif c == ')':
196 depth -= 1
198 ns = {'_as_int': _as_int}
199 exec('''if True:
200 def func(n):
201 if not isinstance(n, int):
202 n = _as_int(n)
203 return int(%s)
204 ''' % result, ns)
205 return ns['func']
206 except RecursionError:
207 # Recursion error can be raised in _parse() or exec().
208 raise ValueError('plural form expression is too complex')
211def _expand_lang(loc):
212 import locale
213 loc = locale.normalize(loc)
214 COMPONENT_CODESET = 1 << 0
215 COMPONENT_TERRITORY = 1 << 1
216 COMPONENT_MODIFIER = 1 << 2
217 # split up the locale into its base components
218 mask = 0
219 pos = loc.find('@')
220 if pos >= 0:
221 modifier = loc[pos:]
222 loc = loc[:pos]
223 mask |= COMPONENT_MODIFIER
224 else:
225 modifier = ''
226 pos = loc.find('.')
227 if pos >= 0:
228 codeset = loc[pos:]
229 loc = loc[:pos]
230 mask |= COMPONENT_CODESET
231 else:
232 codeset = ''
233 pos = loc.find('_')
234 if pos >= 0:
235 territory = loc[pos:]
236 loc = loc[:pos]
237 mask |= COMPONENT_TERRITORY
238 else:
239 territory = ''
240 language = loc
241 ret = []
242 for i in range(mask+1):
243 if not (i & ~mask): # if all components for this combo exist ...
244 val = language
245 if i & COMPONENT_TERRITORY: val += territory
246 if i & COMPONENT_CODESET: val += codeset
247 if i & COMPONENT_MODIFIER: val += modifier
248 ret.append(val)
249 ret.reverse()
250 return ret
254class NullTranslations:
255 def __init__(self, fp=None):
256 self._info = {}
257 self._charset = None
258 self._output_charset = None
259 self._fallback = None
260 if fp is not None:
261 self._parse(fp)
263 def _parse(self, fp):
264 pass
266 def add_fallback(self, fallback):
267 if self._fallback:
268 self._fallback.add_fallback(fallback)
269 else:
270 self._fallback = fallback
272 def gettext(self, message):
273 if self._fallback:
274 return self._fallback.gettext(message)
275 return message
277 def lgettext(self, message):
278 import warnings
279 warnings.warn('lgettext() is deprecated, use gettext() instead',
280 DeprecationWarning, 2)
281 import locale
282 if self._fallback:
283 with warnings.catch_warnings():
284 warnings.filterwarnings('ignore', r'.*\blgettext\b.*',
285 DeprecationWarning)
286 return self._fallback.lgettext(message)
287 if self._output_charset:
288 return message.encode(self._output_charset)
289 return message.encode(locale.getpreferredencoding())
291 def ngettext(self, msgid1, msgid2, n):
292 if self._fallback:
293 return self._fallback.ngettext(msgid1, msgid2, n)
294 if n == 1:
295 return msgid1
296 else:
297 return msgid2
299 def lngettext(self, msgid1, msgid2, n):
300 import warnings
301 warnings.warn('lngettext() is deprecated, use ngettext() instead',
302 DeprecationWarning, 2)
303 import locale
304 if self._fallback:
305 with warnings.catch_warnings():
306 warnings.filterwarnings('ignore', r'.*\blngettext\b.*',
307 DeprecationWarning)
308 return self._fallback.lngettext(msgid1, msgid2, n)
309 if n == 1:
310 tmsg = msgid1
311 else:
312 tmsg = msgid2
313 if self._output_charset:
314 return tmsg.encode(self._output_charset)
315 return tmsg.encode(locale.getpreferredencoding())
317 def pgettext(self, context, message):
318 if self._fallback:
319 return self._fallback.pgettext(context, message)
320 return message
322 def npgettext(self, context, msgid1, msgid2, n):
323 if self._fallback:
324 return self._fallback.npgettext(context, msgid1, msgid2, n)
325 if n == 1:
326 return msgid1
327 else:
328 return msgid2
330 def info(self):
331 return self._info
333 def charset(self):
334 return self._charset
336 def output_charset(self):
337 import warnings
338 warnings.warn('output_charset() is deprecated',
339 DeprecationWarning, 2)
340 return self._output_charset
342 def set_output_charset(self, charset):
343 import warnings
344 warnings.warn('set_output_charset() is deprecated',
345 DeprecationWarning, 2)
346 self._output_charset = charset
348 def install(self, names=None):
349 import builtins
350 builtins.__dict__['_'] = self.gettext
351 if names is not None:
352 allowed = {'gettext', 'lgettext', 'lngettext',
353 'ngettext', 'npgettext', 'pgettext'}
354 for name in allowed & set(names):
355 builtins.__dict__[name] = getattr(self, name)
358class GNUTranslations(NullTranslations):
359 # Magic number of .mo files
360 LE_MAGIC = 0x950412de
361 BE_MAGIC = 0xde120495
363 # The encoding of a msgctxt and a msgid in a .mo file is
364 # msgctxt + "\x04" + msgid (gettext version >= 0.15)
365 CONTEXT = "%s\x04%s"
367 # Acceptable .mo versions
368 VERSIONS = (0, 1)
370 def _get_versions(self, version):
371 """Returns a tuple of major version, minor version"""
372 return (version >> 16, version & 0xffff)
374 def _parse(self, fp):
375 """Override this method to support alternative .mo formats."""
376 # Delay struct import for speeding up gettext import when .mo files
377 # are not used.
378 from struct import unpack
379 filename = getattr(fp, 'name', '')
380 # Parse the .mo file header, which consists of 5 little endian 32
381 # bit words.
382 self._catalog = catalog = {}
383 self.plural = lambda n: int(n != 1) # germanic plural by default
384 buf = fp.read()
385 buflen = len(buf)
386 # Are we big endian or little endian?
387 magic = unpack('<I', buf[:4])[0]
388 if magic == self.LE_MAGIC:
389 version, msgcount, masteridx, transidx = unpack('<4I', buf[4:20])
390 ii = '<II'
391 elif magic == self.BE_MAGIC:
392 version, msgcount, masteridx, transidx = unpack('>4I', buf[4:20])
393 ii = '>II'
394 else:
395 raise OSError(0, 'Bad magic number', filename)
397 major_version, minor_version = self._get_versions(version)
399 if major_version not in self.VERSIONS:
400 raise OSError(0, 'Bad version number ' + str(major_version), filename)
402 # Now put all messages from the .mo file buffer into the catalog
403 # dictionary.
404 for i in range(0, msgcount):
405 mlen, moff = unpack(ii, buf[masteridx:masteridx+8])
406 mend = moff + mlen
407 tlen, toff = unpack(ii, buf[transidx:transidx+8])
408 tend = toff + tlen
409 if mend < buflen and tend < buflen:
410 msg = buf[moff:mend]
411 tmsg = buf[toff:tend]
412 else:
413 raise OSError(0, 'File is corrupt', filename)
414 # See if we're looking at GNU .mo conventions for metadata
415 if mlen == 0:
416 # Catalog description
417 lastk = None
418 for b_item in tmsg.split(b'\n'):
419 item = b_item.decode().strip()
420 if not item:
421 continue
422 # Skip over comment lines:
423 if item.startswith('#-#-#-#-#') and item.endswith('#-#-#-#-#'):
424 continue
425 k = v = None
426 if ':' in item:
427 k, v = item.split(':', 1)
428 k = k.strip().lower()
429 v = v.strip()
430 self._info[k] = v
431 lastk = k
432 elif lastk:
433 self._info[lastk] += '\n' + item
434 if k == 'content-type':
435 self._charset = v.split('charset=')[1]
436 elif k == 'plural-forms':
437 v = v.split(';')
438 plural = v[1].split('plural=')[1]
439 self.plural = c2py(plural)
440 # Note: we unconditionally convert both msgids and msgstrs to
441 # Unicode using the character encoding specified in the charset
442 # parameter of the Content-Type header. The gettext documentation
443 # strongly encourages msgids to be us-ascii, but some applications
444 # require alternative encodings (e.g. Zope's ZCML and ZPT). For
445 # traditional gettext applications, the msgid conversion will
446 # cause no problems since us-ascii should always be a subset of
447 # the charset encoding. We may want to fall back to 8-bit msgids
448 # if the Unicode conversion fails.
449 charset = self._charset or 'ascii'
450 if b'\x00' in msg:
451 # Plural forms
452 msgid1, msgid2 = msg.split(b'\x00')
453 tmsg = tmsg.split(b'\x00')
454 msgid1 = str(msgid1, charset)
455 for i, x in enumerate(tmsg):
456 catalog[(msgid1, i)] = str(x, charset)
457 else:
458 catalog[str(msg, charset)] = str(tmsg, charset)
459 # advance to next entry in the seek tables
460 masteridx += 8
461 transidx += 8
463 def lgettext(self, message):
464 import warnings
465 warnings.warn('lgettext() is deprecated, use gettext() instead',
466 DeprecationWarning, 2)
467 import locale
468 missing = object()
469 tmsg = self._catalog.get(message, missing)
470 if tmsg is missing:
471 if self._fallback:
472 return self._fallback.lgettext(message)
473 tmsg = message
474 if self._output_charset:
475 return tmsg.encode(self._output_charset)
476 return tmsg.encode(locale.getpreferredencoding())
478 def lngettext(self, msgid1, msgid2, n):
479 import warnings
480 warnings.warn('lngettext() is deprecated, use ngettext() instead',
481 DeprecationWarning, 2)
482 import locale
483 try:
484 tmsg = self._catalog[(msgid1, self.plural(n))]
485 except KeyError:
486 if self._fallback:
487 return self._fallback.lngettext(msgid1, msgid2, n)
488 if n == 1:
489 tmsg = msgid1
490 else:
491 tmsg = msgid2
492 if self._output_charset:
493 return tmsg.encode(self._output_charset)
494 return tmsg.encode(locale.getpreferredencoding())
496 def gettext(self, message):
497 missing = object()
498 tmsg = self._catalog.get(message, missing)
499 if tmsg is missing:
500 if self._fallback:
501 return self._fallback.gettext(message)
502 return message
503 return tmsg
505 def ngettext(self, msgid1, msgid2, n):
506 try:
507 tmsg = self._catalog[(msgid1, self.plural(n))]
508 except KeyError:
509 if self._fallback:
510 return self._fallback.ngettext(msgid1, msgid2, n)
511 if n == 1:
512 tmsg = msgid1
513 else:
514 tmsg = msgid2
515 return tmsg
517 def pgettext(self, context, message):
518 ctxt_msg_id = self.CONTEXT % (context, message)
519 missing = object()
520 tmsg = self._catalog.get(ctxt_msg_id, missing)
521 if tmsg is missing:
522 if self._fallback:
523 return self._fallback.pgettext(context, message)
524 return message
525 return tmsg
527 def npgettext(self, context, msgid1, msgid2, n):
528 ctxt_msg_id = self.CONTEXT % (context, msgid1)
529 try:
530 tmsg = self._catalog[ctxt_msg_id, self.plural(n)]
531 except KeyError:
532 if self._fallback:
533 return self._fallback.npgettext(context, msgid1, msgid2, n)
534 if n == 1:
535 tmsg = msgid1
536 else:
537 tmsg = msgid2
538 return tmsg
541# Locate a .mo file using the gettext strategy
542def find(domain, localedir=None, languages=None, all=False):
543 # Get some reasonable defaults for arguments that were not supplied
544 if localedir is None:
545 localedir = _default_localedir
546 if languages is None:
547 languages = []
548 for envar in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'):
549 val = os.environ.get(envar)
550 if val:
551 languages = val.split(':')
552 break
553 if 'C' not in languages:
554 languages.append('C')
555 # now normalize and expand the languages
556 nelangs = []
557 for lang in languages:
558 for nelang in _expand_lang(lang):
559 if nelang not in nelangs:
560 nelangs.append(nelang)
561 # select a language
562 if all:
563 result = []
564 else:
565 result = None
566 for lang in nelangs:
567 if lang == 'C':
568 break
569 mofile = os.path.join(localedir, lang, 'LC_MESSAGES', '%s.mo' % domain)
570 mofile_lp = os.path.join("/usr/share/locale-langpack", lang,
571 'LC_MESSAGES', '%s.mo' % domain)
573 # first look into the standard locale dir, then into the
574 # langpack locale dir
576 # standard mo file
577 if os.path.exists(mofile):
578 if all:
579 result.append(mofile)
580 else:
581 return mofile
583 # langpack mofile -> use it
584 if os.path.exists(mofile_lp):
585 if all:
586 result.append(mofile_lp)
587 else:
588 return mofile_lp
590 return result
594# a mapping between absolute .mo file path and Translation object
595_translations = {}
596_unspecified = ['unspecified']
598def translation(domain, localedir=None, languages=None,
599 class_=None, fallback=False, codeset=_unspecified):
600 if class_ is None:
601 class_ = GNUTranslations
602 mofiles = find(domain, localedir, languages, all=True)
603 if not mofiles:
604 if fallback:
605 return NullTranslations()
606 from errno import ENOENT
607 raise FileNotFoundError(ENOENT,
608 'No translation file found for domain', domain)
609 # Avoid opening, reading, and parsing the .mo file after it's been done
610 # once.
611 result = None
612 for mofile in mofiles:
613 key = (class_, os.path.abspath(mofile))
614 t = _translations.get(key)
615 if t is None:
616 with open(mofile, 'rb') as fp:
617 t = _translations.setdefault(key, class_(fp))
618 # Copy the translation object to allow setting fallbacks and
619 # output charset. All other instance data is shared with the
620 # cached object.
621 # Delay copy import for speeding up gettext import when .mo files
622 # are not used.
623 import copy
624 t = copy.copy(t)
625 if codeset is not _unspecified:
626 import warnings
627 warnings.warn('parameter codeset is deprecated',
628 DeprecationWarning, 2)
629 if codeset:
630 with warnings.catch_warnings():
631 warnings.filterwarnings('ignore', r'.*\bset_output_charset\b.*',
632 DeprecationWarning)
633 t.set_output_charset(codeset)
634 if result is None:
635 result = t
636 else:
637 result.add_fallback(t)
638 return result
641def install(domain, localedir=None, codeset=_unspecified, names=None):
642 t = translation(domain, localedir, fallback=True, codeset=codeset)
643 t.install(names)
647# a mapping b/w domains and locale directories
648_localedirs = {}
649# a mapping b/w domains and codesets
650_localecodesets = {}
651# current global domain, `messages' used for compatibility w/ GNU gettext
652_current_domain = 'messages'
655def textdomain(domain=None):
656 global _current_domain
657 if domain is not None:
658 _current_domain = domain
659 return _current_domain
662def bindtextdomain(domain, localedir=None):
663 global _localedirs
664 if localedir is not None:
665 _localedirs[domain] = localedir
666 return _localedirs.get(domain, _default_localedir)
669def bind_textdomain_codeset(domain, codeset=None):
670 import warnings
671 warnings.warn('bind_textdomain_codeset() is deprecated',
672 DeprecationWarning, 2)
673 global _localecodesets
674 if codeset is not None:
675 _localecodesets[domain] = codeset
676 return _localecodesets.get(domain)
679def dgettext(domain, message):
680 try:
681 t = translation(domain, _localedirs.get(domain, None))
682 except OSError:
683 return message
684 return t.gettext(message)
686def ldgettext(domain, message):
687 import warnings
688 warnings.warn('ldgettext() is deprecated, use dgettext() instead',
689 DeprecationWarning, 2)
690 import locale
691 codeset = _localecodesets.get(domain)
692 try:
693 with warnings.catch_warnings():
694 warnings.filterwarnings('ignore', r'.*\bparameter codeset\b.*',
695 DeprecationWarning)
696 t = translation(domain, _localedirs.get(domain, None), codeset=codeset)
697 except OSError:
698 return message.encode(codeset or locale.getpreferredencoding())
699 with warnings.catch_warnings():
700 warnings.filterwarnings('ignore', r'.*\blgettext\b.*',
701 DeprecationWarning)
702 return t.lgettext(message)
704def dngettext(domain, msgid1, msgid2, n):
705 try:
706 t = translation(domain, _localedirs.get(domain, None))
707 except OSError:
708 if n == 1:
709 return msgid1
710 else:
711 return msgid2
712 return t.ngettext(msgid1, msgid2, n)
714def ldngettext(domain, msgid1, msgid2, n):
715 import warnings
716 warnings.warn('ldngettext() is deprecated, use dngettext() instead',
717 DeprecationWarning, 2)
718 import locale
719 codeset = _localecodesets.get(domain)
720 try:
721 with warnings.catch_warnings():
722 warnings.filterwarnings('ignore', r'.*\bparameter codeset\b.*',
723 DeprecationWarning)
724 t = translation(domain, _localedirs.get(domain, None), codeset=codeset)
725 except OSError:
726 if n == 1:
727 tmsg = msgid1
728 else:
729 tmsg = msgid2
730 return tmsg.encode(codeset or locale.getpreferredencoding())
731 with warnings.catch_warnings():
732 warnings.filterwarnings('ignore', r'.*\blngettext\b.*',
733 DeprecationWarning)
734 return t.lngettext(msgid1, msgid2, n)
737def dpgettext(domain, context, message):
738 try:
739 t = translation(domain, _localedirs.get(domain, None))
740 except OSError:
741 return message
742 return t.pgettext(context, message)
745def dnpgettext(domain, context, msgid1, msgid2, n):
746 try:
747 t = translation(domain, _localedirs.get(domain, None))
748 except OSError:
749 if n == 1:
750 return msgid1
751 else:
752 return msgid2
753 return t.npgettext(context, msgid1, msgid2, n)
756def gettext(message):
757 return dgettext(_current_domain, message)
759def lgettext(message):
760 import warnings
761 warnings.warn('lgettext() is deprecated, use gettext() instead',
762 DeprecationWarning, 2)
763 with warnings.catch_warnings():
764 warnings.filterwarnings('ignore', r'.*\bldgettext\b.*',
765 DeprecationWarning)
766 return ldgettext(_current_domain, message)
768def ngettext(msgid1, msgid2, n):
769 return dngettext(_current_domain, msgid1, msgid2, n)
771def lngettext(msgid1, msgid2, n):
772 import warnings
773 warnings.warn('lngettext() is deprecated, use ngettext() instead',
774 DeprecationWarning, 2)
775 with warnings.catch_warnings():
776 warnings.filterwarnings('ignore', r'.*\bldngettext\b.*',
777 DeprecationWarning)
778 return ldngettext(_current_domain, msgid1, msgid2, n)
781def pgettext(context, message):
782 return dpgettext(_current_domain, context, message)
785def npgettext(context, msgid1, msgid2, n):
786 return dnpgettext(_current_domain, context, msgid1, msgid2, n)
789# dcgettext() has been deemed unnecessary and is not implemented.
791# James Henstridge's Catalog constructor from GNOME gettext. Documented usage
792# was:
793#
794# import gettext
795# cat = gettext.Catalog(PACKAGE, localedir=LOCALEDIR)
796# _ = cat.gettext
797# print _('Hello World')
799# The resulting catalog object currently don't support access through a
800# dictionary API, which was supported (but apparently unused) in GNOME
801# gettext.
803Catalog = translation