translations.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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 requests
  12. from . import utils
  13. logger = logging.getLogger(__name__)
  14. class Translator:
  15. def __init__(self, client, db):
  16. self._client = client
  17. self.db = db
  18. async def init(self) -> bool:
  19. self._data = {}
  20. if not (lang := self.db.get(__name__, "lang", False)):
  21. return False
  22. for language in lang.split(" "):
  23. if utils.check_url(language):
  24. try:
  25. ndata = (await utils.run_sync(requests.get, lang)).json()
  26. except Exception:
  27. logger.exception(f"Unable to decode {lang}")
  28. continue
  29. data = ndata.get("data", ndata)
  30. if any(not isinstance(i, str) for i in data.values()):
  31. logger.exception(
  32. "Translation pack format is not valid (typecheck failed)"
  33. )
  34. continue
  35. self._data.update(data)
  36. continue
  37. possible_pack_path = os.path.join(
  38. utils.get_base_dir(),
  39. f"langpacks/{language}.json",
  40. )
  41. if os.path.isfile(possible_pack_path):
  42. with open(possible_pack_path, "r") as f:
  43. self._data.update(json.load(f))
  44. return True
  45. return True
  46. def getkey(self, key):
  47. return self._data.get(key, False)
  48. def gettext(self, text):
  49. return self.getkey(text) or text
  50. class Strings:
  51. def __init__(self, mod, translator):
  52. self._mod = mod
  53. self._translator = translator
  54. if not translator:
  55. logger.debug(f"Module {mod=} got empty translator {translator=}")
  56. self._base_strings = mod.strings # Back 'em up, bc they will get replaced
  57. def __getitem__(self, key: str) -> str:
  58. return (
  59. self._translator.getkey(f"{self._mod.__module__}.{key}")
  60. if self._translator is not None
  61. else False
  62. ) or (
  63. getattr(
  64. self._mod,
  65. next(
  66. (
  67. f"strings_{lang}"
  68. for lang in self._translator.db.get(
  69. __name__,
  70. "lang",
  71. "en",
  72. ).split(" ")
  73. if hasattr(self._mod, f"strings_{lang}")
  74. and isinstance(getattr(self._mod, f"strings_{lang}"), dict)
  75. and key in getattr(self._mod, f"strings_{lang}")
  76. ),
  77. utils.rand(32),
  78. ),
  79. self._base_strings,
  80. )
  81. if self._translator is not None
  82. else self._base_strings
  83. ).get(
  84. key,
  85. self._base_strings.get(key, "Unknown strings"),
  86. )
  87. def __call__(
  88. self,
  89. key: str,
  90. _=None, # Compatibility tweak for FTG\GeekTG
  91. ) -> str:
  92. return self.__getitem__(key)
  93. def __iter__(self):
  94. return self._base_strings.__iter__()