translations.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. # █ █ ▀ █▄▀ ▄▀█ █▀█ ▀
  2. # █▀█ █ █ █ █▀█ █▀▄ █
  3. # © Copyright 2022
  4. # https://t.me/hikariatama
  5. #
  6. # 🔒 Licensed under the GNU AGPLv3
  7. # 🌐 https://www.gnu.org/licenses/agpl-3.0.html
  8. import json
  9. import logging
  10. import os
  11. import typing
  12. import requests
  13. from . import utils
  14. from .types import Module
  15. from .tl_cache import CustomTelegramClient
  16. from .database import Database
  17. logger = logging.getLogger(__name__)
  18. class Translator:
  19. def __init__(self, client: CustomTelegramClient, db: Database):
  20. self._client = client
  21. self.db = db
  22. async def init(self) -> bool:
  23. self._data = {}
  24. if not (lang := self.db.get(__name__, "lang", False)):
  25. return False
  26. for language in lang.split(" "):
  27. if utils.check_url(language):
  28. try:
  29. ndata = (await utils.run_sync(requests.get, lang)).json()
  30. except Exception:
  31. logger.exception("Unable to decode %s", lang)
  32. continue
  33. data = ndata.get("data", ndata)
  34. if any(not isinstance(i, str) for i in data.values()):
  35. logger.exception(
  36. "Translation pack format is not valid (typecheck failed)"
  37. )
  38. continue
  39. self._data.update(data)
  40. continue
  41. possible_pack_path = os.path.join(
  42. utils.get_base_dir(),
  43. f"langpacks/{language}.json",
  44. )
  45. if os.path.isfile(possible_pack_path):
  46. with open(possible_pack_path, "r") as f:
  47. self._data.update(json.load(f))
  48. return True
  49. return True
  50. def getkey(self, key: str) -> typing.Any:
  51. return self._data.get(key, False)
  52. def gettext(self, text: str) -> typing.Any:
  53. return self.getkey(text) or text
  54. class Strings:
  55. def __init__(self, mod: Module, translator: Translator):
  56. self._mod = mod
  57. self._translator = translator
  58. if not translator:
  59. logger.debug("Module %s got empty translator %s", mod, translator)
  60. self._base_strings = mod.strings # Back 'em up, bc they will get replaced
  61. def __getitem__(self, key: str) -> str:
  62. return (
  63. self._translator.getkey(f"{self._mod.__module__}.{key}")
  64. if self._translator is not None
  65. else False
  66. ) or (
  67. getattr(
  68. self._mod,
  69. next(
  70. (
  71. f"strings_{lang}"
  72. for lang in self._translator.db.get(
  73. __name__,
  74. "lang",
  75. "en",
  76. ).split(" ")
  77. if hasattr(self._mod, f"strings_{lang}")
  78. and isinstance(getattr(self._mod, f"strings_{lang}"), dict)
  79. and key in getattr(self._mod, f"strings_{lang}")
  80. ),
  81. utils.rand(32),
  82. ),
  83. self._base_strings,
  84. )
  85. if self._translator is not None
  86. else self._base_strings
  87. ).get(
  88. key,
  89. self._base_strings.get(key, "Unknown strings"),
  90. )
  91. def __call__(
  92. self,
  93. key: str,
  94. _: typing.Optional[typing.Any] = None, # Compatibility tweak for FTG\GeekTG
  95. ) -> str:
  96. return self.__getitem__(key)
  97. def __iter__(self):
  98. return self._base_strings.__iter__()