import threading
from contextlib import contextmanager
from typing import Union, Iterable, Optional, List, Callable
from typing_extensions import Self
from mcdreforged.minecraft.rtext.style import RColor, RStyle, RAction
from mcdreforged.minecraft.rtext.text import RTextBase, RText
from mcdreforged.utils import translation_util, class_util
from mcdreforged.utils.types import TranslationKeyDictRich
[文档]
class RTextMCDRTranslation(RTextBase):
"""
The translation text component used in MCDR
When MCDR is running, it will use the :meth:`~mcdreforged.plugin.server_interface.ServerInterface.tr` method
in :class:`~mcdreforged.plugin.server_interface.ServerInterface` class as the translating method,
and the language of MCDR as the fallback translation language
.. versionadded:: v2.1.0
"""
__TLS = threading.local()
__TLS.language = None
[文档]
def __init__(self, translation_key: str, *args, **kwargs):
"""
Create a :class:`RTextMCDRTranslation` component with necessary parameters for translation
:param translation_key: The translation key
:param args: The translation arguments
:param kwargs: The translation keyword arguments
"""
self.translation_key: str = translation_key
self.args = args
self.kwargs = kwargs
self.__translator = lambda *args_, **kwargs_: RText(self.translation_key)
self.__post_process: List[Callable[[RTextBase], RTextBase]] = []
from mcdreforged.plugin.server_interface import ServerInterface
server: Optional[ServerInterface] = ServerInterface.get_instance()
if server is not None:
self.set_translator(server.tr)
def set_translator(self, translate_function: Callable) -> 'RTextMCDRTranslation':
self.__translator = translate_function
return self
@classmethod
def from_translation_dict(cls, translation_dict: TranslationKeyDictRich) -> 'RTextMCDRTranslation':
def fake_tr(_key: str, _mcdr_tr_language: str):
return translation_util.translate_from_dict(translation_dict, _mcdr_tr_language)
return RTextMCDRTranslation('').set_translator(fake_tr)
def __get_translated_text(self) -> RTextBase:
language = getattr(self.__TLS, 'language', None)
if language is None:
language = translation_util.get_mcdr_language()
processed_text = self.__translator(self.translation_key, *self.args, **self.kwargs, _mcdr_tr_language=language)
processed_text = RTextBase.from_any(processed_text)
for process in self.__post_process:
processed_text = process(processed_text)
return processed_text
[文档]
@classmethod
@contextmanager
def language_context(cls, language: str):
"""
Create a context where all :class:`RTextMCDRTranslation` will use the given language to translate within
It's mostly used when you want a translated str or Minecraft json text object corresponding to this component under a specific language
MCDR will automatically apply this context with :ref:`user's preferred language <preference-language>`
right before sending messages to a player or the console
Example::
def log_message_line_by_line(server: ServerInterface):
with RTextMCDRTranslation.language_context('en_us'):
text: RTextMCDRTranslation = server.rtr('my_plugin.some_message')
text_as_str: str = text.to_plain_text() # The translation operation happens here
server.logger.info('Lines of my translation')
for line in text_as_str.splitlines():
server.logger.info('- {}'.format(line))
:param language: The language to be used during translation inside the context
"""
prev = getattr(cls.__TLS, 'language', None)
cls.__TLS.language = language
try:
yield
finally:
cls.__TLS.language = prev
def to_json_object(self) -> Union[dict, list]:
return self.__get_translated_text().to_json_object()
def to_plain_text(self) -> str:
return self.__get_translated_text().to_plain_text()
def to_colored_text(self) -> str:
return self.__get_translated_text().to_colored_text()
def to_legacy_text(self) -> str:
return self.__get_translated_text().to_legacy_text()
def copy(self) -> 'RTextBase':
copied = RTextMCDRTranslation(self.translation_key, *self.args, **self.kwargs)
copied.__translator = self.__translator
copied.__post_process = self.__post_process.copy()
return copied
def set_color(self, color: RColor) -> Self:
self.__post_process.append(lambda rt: rt.set_color(color))
return self
def set_styles(self, styles: Union[RStyle, Iterable[RStyle]]) -> Self:
self.__post_process.append(lambda rt: rt.set_styles(styles))
return self
def set_click_event(self, action: RAction, value: str) -> Self:
self.__post_process.append(lambda rt: rt.set_click_event(action, value))
return self
def set_hover_text(self, *args) -> Self:
self.__post_process.append(lambda rt: rt.set_hover_text(*args))
return self
def __repr__(self) -> str:
return class_util.represent(self)