Source code for localizer.language_pack

from typing import Optional
import translators as ts
from localizer.FileHandler import FileHandler
from localizer.supported_file_types import FILE_TYPES
import asyncio

[docs]def count_spaces(text:str) -> int: for i, v in enumerate(text, 1): if v != ' ': return i-1 return 0
[docs]class LanguagePack: def __init__(self): self.o_t:dict[str, str] = dict() # original: translated self.new_texts:set[str] = set() self.supported_file_types:dict[str, type[FileHandler]] = dict() # extension: FileHandler self.translate_from_language = "auto" self.translate_to_language = "en" self.translators = ["deepl", "google", "bing"] self.translator_tries = 5 self.auto_translate = False for ext, fhandler in FILE_TYPES.items(): self.set_file_extension(ext, fhandler)
[docs] def translate_all(self): """Asynchronously translate all `new_texts` and store them in the pack. NOTE: The options are the LanguagePack's attributes `self.translat*` """ loop = asyncio.new_event_loop() results:dict[str, asyncio.Future[str]] = {} for original in self.new_texts: # query_text, to_language, from_language, translators, tries, auto_add results[original] = loop.run_in_executor(None, self.translate, original, None, None, None, None, False) gather = asyncio.gather(*results.values(), return_exceptions=True) loop.run_until_complete(gather) for original in results.keys(): translated = results[original].result() self.add_translation(original, translated)
[docs] def translate(self, query_text:str, to_language:Optional[str] = None, from_language:Optional[str] = None, translators:Optional[list[str]] = None, tries:Optional[int] = None, auto_add:bool = True) -> Optional[str]: """Translate `query_text` from `from_language` to `to_language` using one of the `translators` (starting from the first and using the others as fallbacks). You also have the option to automatically add the translation to the pack (if the translation succeeds) using `auto_add=True` Args: query_text (str): The original text to translate. to_language (Optional[str], optional): The code of the language for the translated text. Defaults to None. from_language (Optional[str], optional): The code of the language for the original text (or `auto`). Defaults to None. translators (Optional[list[str]], optional): A list of translators to use (first is primary and the others are fallbacks). Defaults to None. tries (Optional[int], optional): How many tries before going to the next translator. Defaults to None. auto_add (bool, optional): Wether to add the translation to the pack or return it to the program. Defaults to True. Returns: Optional[str]: If `auto_add` is True the return value is None, if `auto_add` is False the return value is the translated text. """ if not to_language: to_language = self.translate_to_language if not from_language: from_language = self.translate_from_language if not translators: translators = self.translators if not tries: tries = self.translator_tries start_spaces = count_spaces(query_text) end_spaces = count_spaces(query_text[::-1]) query_text = query_text[start_spaces:] if end_spaces != 0: query_text = query_text[:-end_spaces] for translator in translators: for i in range(tries): try: translated = (' ' * start_spaces) + ts.translate_text(query_text=query_text, translator=translator, from_language = from_language, to_language = to_language) + (' ' * end_spaces) # type: ignore if auto_add: self.add_translation(query_text, translated) else: return translated except Exception: pass
[docs] def get_file_extension(self, filename:str) -> Optional[str]: """Finds and returns the extension of the file ONLY if that extension is supported. Args: filename (str): The name of the file. Returns: Optional[str]: The extension of the file (if the extension is supported), or None (if the extension is NOT supported). """ for k in self.supported_file_types.keys(): if filename.endswith(k): return k return None
[docs] def set_file_extension(self, extension:str, fhandler:type[FileHandler]): """Creates a connection between the specified `extension` and the specified `FileHandler` which allows to later process files of that extension with the correct `FileHandler`. Args: extension (str): The extension of the file that the Handler can process (Example, .json, .csv). fhandler (type[FileHandler]): A reference to the class holding the static methods for parsing and exporting the files. """ if not extension.startswith('.'): extension = '.' + extension self.supported_file_types[extension] = fhandler
[docs] def export_file(self, file:str) -> None: """Exports the data of the language pack to the specified `file`. The data is processed and stored using the `FileHandler` for the specific file format. Args: file (str): A string with the filepath/filename of the file. (The file will be created if it doesn't exist). """ extension = self.get_file_extension(file) if not extension: raise TypeError("File must end with one of the following extensions: " + ', '.join(self.supported_file_types.keys())) fhandler = self.supported_file_types[extension] new_texts_file = file[:-len(extension)]+'.new_text'+extension fhandler.export(file, self.o_t) if self.new_texts: fhandler.export(new_texts_file, self.new_texts)
[docs] def parse_file(self, file:str) -> None: """Parses the data of `file` and stores them in the language pack. The data is processed and stored using the `FileHandler` for the specific file format. Args: file (str): A string with the filepath/filename of the file. Raises: TypeError: If there is no handler available to process this file. """ extension = self.get_file_extension(file) if not extension: raise TypeError("File must end with one of the following extensions: " + ', '.join(self.supported_file_types.keys())) fhandler = self.supported_file_types[extension] o_t = fhandler.parse(file) if isinstance(o_t, set): o_t = map(lambda x: (x,''), o_t) elif isinstance(o_t, dict): o_t = o_t.items() for o, t in o_t: self.add_translation(o, t)
[docs] def add_translation(self, original:str, translated:Optional[str] = None) -> None: """Add a translation for a sentence in the language pack. If the translated text is empty, original is added to new_texts. If `self.auto_translate` is True, an attempt to automatically translate the original using a translator API is made. Args: original (str): The original sentence. translated (Optional[str], optional): The translated sentence. Defaults to None """ if translated: self.o_t[original] = translated try: self.new_texts.remove(original) except KeyError: pass # original doesn't exist anyway. else: self.new_texts.add(original) if self.auto_translate: self.translate(original)
[docs] def gettext(self, text:str) -> str: """Get the translation of `text` if it exists, otherwise fallback to the original translation. Args: text (str): The text to be translated. Returns: str: The translated text, or the original text (If no translation was found). """ if text == '' or text in self.new_texts: return text elif text in self.o_t.keys(): return self.o_t[text] else: self.new_texts.add(text) return text