i18n.py
127 lines
| 4.0 KiB
| text/x-python
|
PythonLexer
/ mercurial / i18n.py
Martin Geisler
|
r8226 | # i18n.py - internationalization support for mercurial | ||
# | ||||
Raphaël Gomès
|
r47575 | # Copyright 2005, 2006 Olivia Mackall <olivia@selenic.com> | ||
Martin Geisler
|
r8226 | # | ||
# This software may be used and distributed according to the terms of the | ||||
Matt Mackall
|
r10263 | # GNU General Public License version 2 or any later version. | ||
Benoit Boissinot
|
r1400 | |||
Matt Harbison
|
r52756 | from __future__ import annotations | ||
Gregory Szorc
|
r25955 | |||
import gettext as gettextmod | ||||
import locale | ||||
import os | ||||
import sys | ||||
r52178 | from typing import ( | |||
Matt Harbison
|
r52610 | Dict, | ||
r52178 | List, | |||
) | ||||
Martin von Zweigbergk
|
r44069 | from .utils import resourceutil | ||
Pulkit Goyal
|
r30050 | from . import ( | ||
encoding, | ||||
pycompat, | ||||
) | ||||
Martin Geisler
|
r7650 | |||
# modelled after templater.templatepath: | ||||
Augie Fackler
|
r14975 | if getattr(sys, 'frozen', None) is not None: | ||
Pulkit Goyal
|
r30669 | module = pycompat.sysexecutable | ||
Martin Geisler
|
r7650 | else: | ||
Pulkit Goyal
|
r31074 | module = pycompat.fsencode(__file__) | ||
Martin Geisler
|
r7650 | |||
Yuya Nishihara
|
r21987 | _languages = None | ||
Augie Fackler
|
r43346 | if ( | ||
pycompat.iswindows | ||||
Augie Fackler
|
r43347 | and b'LANGUAGE' not in encoding.environ | ||
and b'LC_ALL' not in encoding.environ | ||||
and b'LC_MESSAGES' not in encoding.environ | ||||
and b'LANG' not in encoding.environ | ||||
Augie Fackler
|
r43346 | ): | ||
Yuya Nishihara
|
r21987 | # Try to detect UI language by "User Interface Language Management" API | ||
# if no locale variables are set. Note that locale.getdefaultlocale() | ||||
# uses GetLocaleInfo(), which may be different from UI language. | ||||
# (See http://msdn.microsoft.com/en-us/library/dd374098(v=VS.85).aspx ) | ||||
try: | ||||
import ctypes | ||||
Augie Fackler
|
r43346 | |||
Matt Harbison
|
r47388 | # pytype: disable=module-attr | ||
Yuya Nishihara
|
r21987 | langid = ctypes.windll.kernel32.GetUserDefaultUILanguage() | ||
Matt Harbison
|
r47388 | # pytype: enable=module-attr | ||
Yuya Nishihara
|
r21987 | _languages = [locale.windows_locale[langid]] | ||
except (ImportError, AttributeError, KeyError): | ||||
# ctypes not found or unknown langid | ||||
pass | ||||
Mads Kiilerich
|
r22638 | |||
Martin von Zweigbergk
|
r44069 | datapath = pycompat.fsdecode(resourceutil.datapath) | ||
localedir = os.path.join(datapath, 'locale') | ||||
t = gettextmod.translation('hg', localedir, _languages, fallback=True) | ||||
try: | ||||
Matt Harbison
|
r47388 | _ugettext = t.ugettext # pytype: disable=attribute-error | ||
Martin von Zweigbergk
|
r44069 | except AttributeError: | ||
_ugettext = t.gettext | ||||
Martin Geisler
|
r7651 | |||
Augie Fackler
|
r43346 | |||
Matt Harbison
|
r52610 | _msgcache: Dict[ | ||
bytes, Dict[bytes, bytes] | ||||
] = {} # encoding: {message: translation} | ||||
Augie Fackler
|
r23031 | |||
Augie Fackler
|
r43346 | |||
r52180 | def gettext(message: bytes) -> bytes: | |||
Martin Geisler
|
r7651 | """Translate message. | ||
The message is looked up in the catalog to get a Unicode string, | ||||
which is encoded in the local encoding before being returned. | ||||
Important: message is restricted to characters in the encoding | ||||
given by sys.getdefaultencoding() which is most likely 'ascii'. | ||||
""" | ||||
# If message is None, t.ugettext will return u'None' as the | ||||
# translation whereas our callers expect us to return None. | ||||
Mads Kiilerich
|
r22638 | if message is None or not _ugettext: | ||
Martin Geisler
|
r7651 | return message | ||
Yuya Nishihara
|
r34661 | cache = _msgcache.setdefault(encoding.encoding, {}) | ||
if message not in cache: | ||||
Gregory Szorc
|
r49789 | if type(message) is str: | ||
Augie Fackler
|
r23031 | # goofy unicode docstrings in test | ||
r52181 | paragraphs: List[str] = message.split(u'\n\n') | |||
Augie Fackler
|
r23031 | else: | ||
Yuya Nishihara
|
r40290 | # should be ascii, but we have unicode docstrings in test, which | ||
# are converted to utf-8 bytes on Python 3. | ||||
Augie Fackler
|
r43347 | paragraphs = [p.decode("utf-8") for p in message.split(b'\n\n')] | ||
Augie Fackler
|
r23031 | # Be careful not to translate the empty string -- it holds the | ||
# meta data of the .po file. | ||||
Gregory Szorc
|
r29415 | u = u'\n\n'.join([p and _ugettext(p) or u'' for p in paragraphs]) | ||
Augie Fackler
|
r23031 | try: | ||
# encoding.tolocal cannot be used since it will first try to | ||||
# decode the Unicode string. Calling u.decode(enc) really | ||||
# means u.encode(sys.getdefaultencoding()).decode(enc). Since | ||||
# the Python encoding defaults to 'ascii', this fails if the | ||||
# translated string use non-ASCII characters. | ||||
Pulkit Goyal
|
r30050 | encodingstr = pycompat.sysstr(encoding.encoding) | ||
Yuya Nishihara
|
r34661 | cache[message] = u.encode(encodingstr, "replace") | ||
Augie Fackler
|
r23031 | except LookupError: | ||
# An unknown encoding results in a LookupError. | ||||
Yuya Nishihara
|
r34661 | cache[message] = message | ||
return cache[message] | ||||
Martin Geisler
|
r7651 | |||
Augie Fackler
|
r43346 | |||
Brodie Rao
|
r13849 | def _plain(): | ||
Augie Fackler
|
r43346 | if ( | ||
Augie Fackler
|
r43347 | b'HGPLAIN' not in encoding.environ | ||
and b'HGPLAINEXCEPT' not in encoding.environ | ||||
Augie Fackler
|
r43346 | ): | ||
Brodie Rao
|
r13849 | return False | ||
Augie Fackler
|
r43347 | exceptions = encoding.environ.get(b'HGPLAINEXCEPT', b'').strip().split(b',') | ||
return b'i18n' not in exceptions | ||||
Brodie Rao
|
r13849 | |||
Augie Fackler
|
r43346 | |||
Brodie Rao
|
r13849 | if _plain(): | ||
r52180 | ||||
def _(message: bytes) -> bytes: | ||||
return message | ||||
Brodie Rao
|
r10455 | else: | ||
_ = gettext | ||||