from typing import Optional from yaml import safe_load from .config import I18NConfig class I18N: def __init__(self, config: I18NConfig): self._path = config.path self._fallback_lang = config.fallback_lang self._lang = config.lang or self.fallback_lang self._dict = dict() self.load() @property def path(self): return self._path @property def fallback_lang(self): return self._fallback_lang def set_lang(self, lang: Optional[str] = None): if lang in self._dict: self._lang = lang else: self._lang = self.fallback_lang @property def lang(self): return self._lang def load(self): self._dict.clear() with open(self._path) as f: self._dict = safe_load(f) if self.fallback_lang not in self._dict: raise RuntimeError("I18N file doesn't contain fallback language section") def get(self, phrase: str, lang: Optional[str] = None): lang = lang or self.lang if lang not in self._dict: # self.logger.warning(f"Language '{lang}' not found in i18n, using fallback") lang = self.fallback_lang lang_dict = self._dict.get(lang) result = lang_dict.get(phrase) if result is None: # self.logger.error(f"Phrase '{phrase}' not found in language '{lang}'") result = f"" return result def __call__(self, phrase: str, lang: Optional[str] = None, *args, **kwargs): return self.get(phrase, lang).format(*args, **kwargs) def customized_call(self, preset_lang: Optional[str] = None, **preset_kwargs): def wrapper(phrase: str, lang: Optional[str] = None, *args, **kwargs): return self(phrase, lang or preset_lang, *args, **preset_kwargs, **kwargs) return wrapper