Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Update gettext.py and related test to 3.12 version #5287

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 83 additions & 95 deletions Lib/gettext.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,16 @@
# find this format documented anywhere.


import locale
import os
import re
import sys


__all__ = ['NullTranslations', 'GNUTranslations', 'Catalog',
'find', 'translation', 'install', 'textdomain', 'bindtextdomain',
'bind_textdomain_codeset',
'dgettext', 'dngettext', 'gettext', 'lgettext', 'ldgettext',
'ldngettext', 'lngettext', 'ngettext',
'bindtextdomain', 'find', 'translation', 'install',
'textdomain', 'dgettext', 'dngettext', 'gettext',
'ngettext', 'pgettext', 'dpgettext', 'npgettext',
'dnpgettext'
]

_default_localedir = os.path.join(sys.base_prefix, 'share', 'locale')
Expand All @@ -83,6 +82,7 @@
(?P<INVALID>\w+|.) # invalid token
""", re.VERBOSE|re.DOTALL)


def _tokenize(plural):
for mo in re.finditer(_token_pattern, plural):
kind = mo.lastgroup
Expand All @@ -94,12 +94,14 @@ def _tokenize(plural):
yield value
yield ''


def _error(value):
if value:
return ValueError('unexpected token in plural form: %s' % value)
else:
return ValueError('unexpected end of plural form')


_binary_ops = (
('||',),
('&&',),
Expand All @@ -111,6 +113,7 @@ def _error(value):
_binary_ops = {op: i for i, ops in enumerate(_binary_ops, 1) for op in ops}
_c2py_ops = {'||': 'or', '&&': 'and', '/': '//'}


def _parse(tokens, priority=-1):
result = ''
nexttok = next(tokens)
Expand Down Expand Up @@ -160,6 +163,7 @@ def _parse(tokens, priority=-1):

return result, nexttok


def _as_int(n):
try:
i = round(n)
Expand All @@ -172,6 +176,7 @@ def _as_int(n):
DeprecationWarning, 4)
return n


def c2py(plural):
"""Gets a C expression as used in PO files for plural forms and returns a
Python function that implements an equivalent expression.
Expand Down Expand Up @@ -209,6 +214,7 @@ def func(n):


def _expand_lang(loc):
import locale
loc = locale.normalize(loc)
COMPONENT_CODESET = 1 << 0
COMPONENT_TERRITORY = 1 << 1
Expand Down Expand Up @@ -249,12 +255,10 @@ def _expand_lang(loc):
return ret



class NullTranslations:
def __init__(self, fp=None):
self._info = {}
self._charset = None
self._output_charset = None
self._fallback = None
if fp is not None:
self._parse(fp)
Expand All @@ -273,13 +277,6 @@ def gettext(self, message):
return self._fallback.gettext(message)
return message

def lgettext(self, message):
if self._fallback:
return self._fallback.lgettext(message)
if self._output_charset:
return message.encode(self._output_charset)
return message.encode(locale.getpreferredencoding())

def ngettext(self, msgid1, msgid2, n):
if self._fallback:
return self._fallback.ngettext(msgid1, msgid2, n)
Expand All @@ -288,48 +285,43 @@ def ngettext(self, msgid1, msgid2, n):
else:
return msgid2

def lngettext(self, msgid1, msgid2, n):
def pgettext(self, context, message):
if self._fallback:
return self._fallback.lngettext(msgid1, msgid2, n)
return self._fallback.pgettext(context, message)
return message

def npgettext(self, context, msgid1, msgid2, n):
if self._fallback:
return self._fallback.npgettext(context, msgid1, msgid2, n)
if n == 1:
tmsg = msgid1
return msgid1
else:
tmsg = msgid2
if self._output_charset:
return tmsg.encode(self._output_charset)
return tmsg.encode(locale.getpreferredencoding())
return msgid2

def info(self):
return self._info

def charset(self):
return self._charset

def output_charset(self):
return self._output_charset

def set_output_charset(self, charset):
self._output_charset = charset

def install(self, names=None):
import builtins
builtins.__dict__['_'] = self.gettext
if hasattr(names, "__contains__"):
if "gettext" in names:
builtins.__dict__['gettext'] = builtins.__dict__['_']
if "ngettext" in names:
builtins.__dict__['ngettext'] = self.ngettext
if "lgettext" in names:
builtins.__dict__['lgettext'] = self.lgettext
if "lngettext" in names:
builtins.__dict__['lngettext'] = self.lngettext
if names is not None:
allowed = {'gettext', 'ngettext', 'npgettext', 'pgettext'}
for name in allowed & set(names):
builtins.__dict__[name] = getattr(self, name)


class GNUTranslations(NullTranslations):
# Magic number of .mo files
LE_MAGIC = 0x950412de
BE_MAGIC = 0xde120495

# The encoding of a msgctxt and a msgid in a .mo file is
# msgctxt + "\x04" + msgid (gettext version >= 0.15)
CONTEXT = "%s\x04%s"

# Acceptable .mo versions
VERSIONS = (0, 1)

Expand Down Expand Up @@ -385,6 +377,9 @@ def _parse(self, fp):
item = b_item.decode().strip()
if not item:
continue
# Skip over comment lines:
if item.startswith('#-#-#-#-#') and item.endswith('#-#-#-#-#'):
continue
k = v = None
if ':' in item:
k, v = item.split(':', 1)
Expand Down Expand Up @@ -423,46 +418,48 @@ def _parse(self, fp):
masteridx += 8
transidx += 8

def lgettext(self, message):
def gettext(self, message):
missing = object()
tmsg = self._catalog.get(message, missing)
if tmsg is missing:
if self._fallback:
return self._fallback.lgettext(message)
tmsg = message
if self._output_charset:
return tmsg.encode(self._output_charset)
return tmsg.encode(locale.getpreferredencoding())
tmsg = self._catalog.get((message, self.plural(1)), missing)
if tmsg is not missing:
return tmsg
if self._fallback:
return self._fallback.gettext(message)
return message

def lngettext(self, msgid1, msgid2, n):
def ngettext(self, msgid1, msgid2, n):
try:
tmsg = self._catalog[(msgid1, self.plural(n))]
except KeyError:
if self._fallback:
return self._fallback.lngettext(msgid1, msgid2, n)
return self._fallback.ngettext(msgid1, msgid2, n)
if n == 1:
tmsg = msgid1
else:
tmsg = msgid2
if self._output_charset:
return tmsg.encode(self._output_charset)
return tmsg.encode(locale.getpreferredencoding())
return tmsg

def gettext(self, message):
def pgettext(self, context, message):
ctxt_msg_id = self.CONTEXT % (context, message)
missing = object()
tmsg = self._catalog.get(message, missing)
tmsg = self._catalog.get(ctxt_msg_id, missing)
if tmsg is missing:
if self._fallback:
return self._fallback.gettext(message)
return message
return tmsg
tmsg = self._catalog.get((ctxt_msg_id, self.plural(1)), missing)
if tmsg is not missing:
return tmsg
if self._fallback:
return self._fallback.pgettext(context, message)
return message

def ngettext(self, msgid1, msgid2, n):
def npgettext(self, context, msgid1, msgid2, n):
ctxt_msg_id = self.CONTEXT % (context, msgid1)
try:
tmsg = self._catalog[(msgid1, self.plural(n))]
tmsg = self._catalog[ctxt_msg_id, self.plural(n)]
except KeyError:
if self._fallback:
return self._fallback.ngettext(msgid1, msgid2, n)
return self._fallback.npgettext(context, msgid1, msgid2, n)
if n == 1:
tmsg = msgid1
else:
Expand Down Expand Up @@ -507,12 +504,12 @@ def find(domain, localedir=None, languages=None, all=False):
return result



# a mapping between absolute .mo file path and Translation object
_translations = {}


def translation(domain, localedir=None, languages=None,
class_=None, fallback=False, codeset=None):
class_=None, fallback=False):
if class_ is None:
class_ = GNUTranslations
mofiles = find(domain, localedir, languages, all=True)
Expand All @@ -538,25 +535,20 @@ def translation(domain, localedir=None, languages=None,
# are not used.
import copy
t = copy.copy(t)
if codeset:
t.set_output_charset(codeset)
if result is None:
result = t
else:
result.add_fallback(t)
return result


def install(domain, localedir=None, codeset=None, names=None):
t = translation(domain, localedir, fallback=True, codeset=codeset)
def install(domain, localedir=None, *, names=None):
t = translation(domain, localedir, fallback=True)
t.install(names)



# a mapping b/w domains and locale directories
_localedirs = {}
# a mapping b/w domains and codesets
_localecodesets = {}
# current global domain, `messages' used for compatibility w/ GNU gettext
_current_domain = 'messages'

Expand All @@ -575,63 +567,59 @@ def bindtextdomain(domain, localedir=None):
return _localedirs.get(domain, _default_localedir)


def bind_textdomain_codeset(domain, codeset=None):
global _localecodesets
if codeset is not None:
_localecodesets[domain] = codeset
return _localecodesets.get(domain)


def dgettext(domain, message):
try:
t = translation(domain, _localedirs.get(domain, None),
codeset=_localecodesets.get(domain))
t = translation(domain, _localedirs.get(domain, None))
except OSError:
return message
return t.gettext(message)

def ldgettext(domain, message):
codeset = _localecodesets.get(domain)
try:
t = translation(domain, _localedirs.get(domain, None), codeset=codeset)
except OSError:
return message.encode(codeset or locale.getpreferredencoding())
return t.lgettext(message)

def dngettext(domain, msgid1, msgid2, n):
try:
t = translation(domain, _localedirs.get(domain, None),
codeset=_localecodesets.get(domain))
t = translation(domain, _localedirs.get(domain, None))
except OSError:
if n == 1:
return msgid1
else:
return msgid2
return t.ngettext(msgid1, msgid2, n)

def ldngettext(domain, msgid1, msgid2, n):
codeset = _localecodesets.get(domain)

def dpgettext(domain, context, message):
try:
t = translation(domain, _localedirs.get(domain, None), codeset=codeset)
t = translation(domain, _localedirs.get(domain, None))
except OSError:
return message
return t.pgettext(context, message)


def dnpgettext(domain, context, msgid1, msgid2, n):
try:
t = translation(domain, _localedirs.get(domain, None))
except OSError:
if n == 1:
tmsg = msgid1
return msgid1
else:
tmsg = msgid2
return tmsg.encode(codeset or locale.getpreferredencoding())
return t.lngettext(msgid1, msgid2, n)
return msgid2
return t.npgettext(context, msgid1, msgid2, n)


def gettext(message):
return dgettext(_current_domain, message)

def lgettext(message):
return ldgettext(_current_domain, message)

def ngettext(msgid1, msgid2, n):
return dngettext(_current_domain, msgid1, msgid2, n)

def lngettext(msgid1, msgid2, n):
return ldngettext(_current_domain, msgid1, msgid2, n)

def pgettext(context, message):
return dpgettext(_current_domain, context, message)


def npgettext(context, msgid1, msgid2, n):
return dnpgettext(_current_domain, context, msgid1, msgid2, n)


# dcgettext() has been deemed unnecessary and is not implemented.

Expand Down
Loading