This repository provides User Manual for setting up a Docker environment tailored for testing DGTD code.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

238 lines
7.3 KiB

"""Locale utilities."""
from __future__ import annotations
import locale
import sys
from gettext import NullTranslations, translation
from os import path
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Iterable
from typing import Any, Callable
class _TranslationProxy:
"""
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__ = '_catalogue', '_namespace', '_message'
def __init__(self, catalogue: str, namespace: str, message: str) -> None:
self._catalogue = catalogue
self._namespace = namespace
self._message = message
def __str__(self) -> str:
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[str, str, str]:
return self._catalogue, self._namespace, self._message
def __setstate__(self, tup: tuple[str, str, str]) -> None:
self._catalogue, self._namespace, self._message = tup
def __copy__(self) -> _TranslationProxy:
return _TranslationProxy(self._catalogue, self._namespace, self._message)
def __repr__(self) -> str:
try:
return f'i{self.__str__()!r}'
except Exception:
return (
self.__class__.__name__
+ f'({self._catalogue}, {self._namespace}, {self._message})'
)
def __add__(self, other: str) -> str:
return self.__str__() + other
def __radd__(self, other: str) -> str:
return other + self.__str__()
def __mod__(self, other: str) -> str:
return self.__str__() % other
def __rmod__(self, other: str) -> str:
return other % self.__str__()
def __mul__(self, other: Any) -> str:
return self.__str__() * other
def __rmul__(self, other: Any) -> str:
return other * self.__str__()
def __hash__(self) -> int:
return hash(self.__str__())
def __eq__(self, other: object) -> bool:
return self.__str__() == other
def __lt__(self, string: str) -> bool:
return self.__str__() < string
def __contains__(self, char: str) -> bool:
return char in self.__str__()
def __len__(self) -> int:
return len(self.__str__())
def __getitem__(self, index: int | slice) -> str:
return self.__str__()[index]
translators: dict[tuple[str, str], NullTranslations] = {}
def init(
locale_dirs: Iterable[str | None],
language: str | None,
catalog: str = 'sphinx',
namespace: str = 'general',
) -> tuple[NullTranslations, bool]:
"""Look for message catalogs in `locale_dirs` and *ensure* that there is at
least a NullTranslations catalog set in `translators`. If called multiple
times or if several ``.mo`` files are found, their contents are merged
together (thus making ``init`` reentrant).
"""
translator = translators.get((namespace, catalog))
# ignore previously failed attempts to find message catalogs
if translator.__class__ is NullTranslations:
translator = None
if language:
if '_' in language:
# for language having country code (like "de_AT")
languages: list[str] | None = [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)
if translator is None:
translator = trans
else:
translator.add_fallback(trans)
except Exception:
# Language couldn't be found in the specified path
pass
if translator is not None:
has_translation = True
else:
translator = NullTranslations()
has_translation = False
# guarantee translators[(namespace, catalog)] exists
translators[namespace, catalog] = translator
return translator, has_translation
_LOCALE_DIR = path.abspath(path.dirname(__file__))
def init_console(
locale_dir: str | None = None,
catalog: str = 'sphinx',
) -> tuple[NullTranslations, bool]:
"""Initialize locale for console.
.. versionadded:: 1.8
"""
if locale_dir is None:
locale_dir = _LOCALE_DIR
if sys.platform == 'win32':
language = None
else:
try:
# encoding is ignored
language, _ = locale.getlocale(locale.LC_MESSAGES)
except AttributeError:
# Fallback to the default language in case LC_MESSAGES is not defined.
language = None
return init([locale_dir], language, catalog, 'console')
def get_translator(catalog: str = 'sphinx', namespace: str = 'general') -> NullTranslations:
return translators.get((namespace, catalog), NullTranslations())
def is_translator_registered(catalog: str = 'sphinx', namespace: str = 'general') -> bool:
return (namespace, catalog) in translators
def get_translation(catalog: str, namespace: str = 'general') -> Callable[[str], str]:
"""Get a translation function based on the *catalog* and *namespace*.
The extension can use this API to translate the messages on the
extension::
import os
from sphinx.locale import get_translation
MESSAGE_CATALOG_NAME = 'myextension' # name of *.pot, *.po and *.mo files
_ = get_translation(MESSAGE_CATALOG_NAME)
text = _('Hello Sphinx!')
def setup(app):
package_dir = os.path.abspath(os.path.dirname(__file__))
locale_dir = os.path.join(package_dir, 'locales')
app.add_message_catalog(MESSAGE_CATALOG_NAME, locale_dir)
With this code, sphinx searches a message catalog from
``${package_dir}/locales/${language}/LC_MESSAGES/myextension.mo``.
The :confval:`language` is used for the searching.
.. versionadded:: 1.8
"""
def gettext(message: str) -> str:
if not is_translator_registered(catalog, namespace):
# not initialized yet
return _TranslationProxy(catalog, namespace, message) # type: ignore[return-value] # NoQA: E501
else:
translator = get_translator(catalog, namespace)
return translator.gettext(message)
return gettext
# A shortcut for sphinx-core
#: Translation function for messages on documentation (menu, labels, themes and so on).
#: This function follows :confval:`language` setting.
_ = get_translation('sphinx')
#: Translation function for console messages
#: This function follows locale setting (`LC_ALL`, `LC_MESSAGES` and so on).
__ = get_translation('sphinx', 'console')
# labels
admonitionlabels = {
'attention': _('Attention'),
'caution': _('Caution'),
'danger': _('Danger'),
'error': _('Error'),
'hint': _('Hint'),
'important': _('Important'),
'note': _('Note'),
'seealso': _('See also'),
'tip': _('Tip'),
'warning': _('Warning'),
}