Skip to content

Commit

Permalink
Refactor _TranslationProxy
Browse files Browse the repository at this point in the history
  • Loading branch information
AA-Turner committed Apr 8, 2023
1 parent 31ca962 commit 2c83af0
Showing 1 changed file with 31 additions and 43 deletions.
74 changes: 31 additions & 43 deletions sphinx/locale/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,44 @@

class _TranslationProxy:
"""
Class for proxy strings from gettext translations. This is a helper for the
lazy_* functions from this module.
The proxy implementation attempts to be as complete as possible, so that
the lazy objects should mostly work as expected, for example for sorting.
"""
__slots__ = ('_func', '_args')

def __new__(cls, func: Callable[..., str], *args: str) -> _TranslationProxy:
if not args:
# not called with "function" and "arguments", but a plain string
return str(func) # type: ignore[return-value]
return object.__new__(cls)

def __getnewargs__(self) -> tuple[str]:
return (self._func,) + self._args # type: ignore
__slots__ = '_catalogue', '_namespace', '_message'

def __init__(self, func: Callable[..., str], *args: str) -> None:
self._func = func
self._args = args
def __init__(self, catalogue: str, namespace: str, message: str) -> None:
self._catalogue = catalogue
self._namespace = namespace
self._message = message

def __str__(self) -> str:
return str(self._func(*self._args))
try:
return translators[self._namespace, self._catalogue].gettext(self._message)
except KeyError:
# NullTranslations().gettext(self._message) == self._message
return self._message

def __dir__(self) -> list[str]:
return dir(str)

def __getattr__(self, name: str) -> Any:
return getattr(self.__str__(), name)

def __getstate__(self) -> tuple[Callable[..., str], tuple[str, ...]]:
return self._func, self._args
def __getstate__(self) -> tuple[str, str, str]:
return self._catalogue, self._namespace, self._message

def __setstate__(self, tup: tuple[Callable[..., str], tuple[str]]) -> None:
self._func, self._args = tup
def __setstate__(self, tup: tuple[str, str, str]) -> None:
self._catalogue, self._namespace, self._message = tup

def __copy__(self) -> _TranslationProxy:
return _TranslationProxy(self._func, *self._args)
return _TranslationProxy(self._catalogue, self._namespace, self._message)

def __repr__(self) -> str:
try:
return 'i' + repr(str(self.__str__()))
return f'i{self.__str__()!r}'
except Exception:
return f'<{self.__class__.__name__} broken>'
return (self.__class__.__name__
+ f'({self._catalogue}, {self._namespace}, {self._message})')

def __add__(self, other: str) -> str:
return self.__str__() + other
Expand Down Expand Up @@ -110,8 +104,6 @@ def init(
# ignore previously failed attempts to find message catalogs
if translator.__class__ is NullTranslations:
translator = None
# the None entry is the system's default locale path
has_translation = True

if getenv('SOURCE_DATE_EPOCH') is not None:
# Disable localization during reproducible source builds
Expand All @@ -125,15 +117,17 @@ def init(
# To achieve that, specify the ISO-639-3 'undetermined' language code,
# which should not match any translation catalogs.
languages: list[str] | None = ['und']
elif language and '_' in language:
# for language having country code (like "de_AT")
languages = [language, language.split('_')[0]]
elif language:
languages = [language]
if '_' in language:
# for language having country code (like "de_AT")
languages = [language, language.split('_')[0]]
else:
languages = [language]
else:
languages = None

# loading
# the None entry is the system's default locale path
for dir_ in locale_dirs:
try:
trans = translation(catalog, localedir=dir_, languages=languages)
Expand All @@ -144,11 +138,13 @@ def init(
except Exception:
# Language couldn't be found in the specified path
pass
# guarantee translators[(namespace, catalog)] exists
if translator is None:
if translator is not None:
has_translation = True
else:
translator = NullTranslations()
has_translation = False
translators[(namespace, catalog)] = translator
# guarantee translators[(namespace, catalog)] exists
translators[namespace, catalog] = translator
return translator, has_translation


Expand Down Expand Up @@ -181,14 +177,6 @@ def is_translator_registered(catalog: str = 'sphinx', namespace: str = 'general'
return (namespace, catalog) in translators


def _lazy_translate(catalog: str, namespace: str, message: str, *args: Any) -> str:
"""Used instead of _ when creating TranslationProxy, because _ is
not bound yet at that time.
"""
translator = get_translator(catalog, namespace)
return translator.gettext(message)


def get_translation(catalog: str, namespace: str = 'general') -> Callable[[str], str]:
"""Get a translation function based on the *catalog* and *namespace*.
Expand All @@ -214,8 +202,8 @@ def setup(app):
.. versionadded:: 1.8
"""
def gettext(message: str, *args: Any) -> str:
return _TranslationProxy(_lazy_translate, catalog, namespace, message, *args) # type: ignore[return-value] # NOQA
def gettext(message: str) -> str:
return _TranslationProxy(catalog, namespace, message) # type: ignore[return-value]

return gettext

Expand Down

0 comments on commit 2c83af0

Please sign in to comment.