diff --git a/bot/middlewares/i18n.py b/bot/middlewares/i18n.py
index 80bb2b8..7140bb5 100644
--- a/bot/middlewares/i18n.py
+++ b/bot/middlewares/i18n.py
@@ -45,10 +45,27 @@ class JsonI18n:
exc_info=True)
def gettext(self, lang_code: Optional[str], key: str, **kwargs) -> str:
- effective_lang_code = lang_code if lang_code and lang_code in self.locales_data else self.default_lang
+ # Determine effective language with robust fallback
+ if lang_code and lang_code in self.locales_data:
+ effective_lang_code = lang_code
+ elif self.default_lang in self.locales_data:
+ effective_lang_code = self.default_lang
+ elif 'en' in self.locales_data:
+ effective_lang_code = 'en'
+ else:
+ effective_lang_code = lang_code or self.default_lang
lang_data = self.locales_data.get(effective_lang_code)
if lang_data is None:
+ # Try explicit fallback to English if available
+ fallback_data = self.locales_data.get('en')
+ if fallback_data is not None:
+ text = fallback_data.get(key)
+ if text is not None:
+ try:
+ return text.format(**kwargs) if kwargs else text
+ except Exception:
+ return text
logging.warning(
f"No language data for '{effective_lang_code}' (default '{self.default_lang}' also missing). Key '{key}' will be returned as is."
)
diff --git a/locales/ru.json b/locales/ru.json
index 651b26d..53a60b8 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -140,7 +140,7 @@
"subscription_expired_notification": "π ΠΡΠΈΠ²Π΅Ρ, {user_name}!\n\nβ Π‘ΡΠΎΠΊ Π²Π°ΡΠ΅ΠΉ ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠΈ Π½Π° VPN ΠΈΡΡΠ΅ΠΊ ({end_date}).\n\nΠΡΠΎΠ΄Π»ΠΈΡΠ΅ Π΅Ρ ΠΏΠΎ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π½ΠΈΠΆΠ΅.",
"subscription_expired_yesterday_notification": "π ΠΡΠΈΠ²Π΅Ρ, {user_name}!\n\nβ³ ΠΠ°ΡΠ° ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠ° Π½Π° VPN ΠΈΡΡΠ΅ΠΊΠ»Π° ΡΡΡΠΊΠΈ Π½Π°Π·Π°Π΄ ({end_date}).\n\nΠΡΠΎΠ΄Π»ΠΈΡΠ΅ Π΅Ρ ΠΏΠΎ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π½ΠΈΠΆΠ΅.",
"tribute_subscription_cancelled": "π¨ ΠΠΎΠ΄ΠΏΠΈΡΠΊΠ° ΠΎΡΠΌΠ΅Π½Π΅Π½Π°\n\nΠΠ°ΡΠ° ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠ° Tribute Π±ΡΠ»Π° ΠΎΡΠΌΠ΅Π½Π΅Π½Π°. Π£ Π²Π°Ρ Π΅ΡΡΡ 24 ΡΠ°ΡΠ° Π΄Π»Ρ Π²ΠΎΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΈΡ Π΄ΠΎΡΡΡΠΏΠ°, ΠΏΠΎΡΠ»Π΅ ΡΠ΅Π³ΠΎ ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠ° Π±ΡΠ΄Π΅Ρ Π·Π°Π±Π»ΠΎΠΊΠΈΡΠΎΠ²Π°Π½Π°.\n\nΠΠ»Ρ ΠΏΡΠΎΠ΄Π»Π΅Π½ΠΈΡ ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠΈ Π½Π°ΠΆΠΌΠΈΡΠ΅ ΠΊΠ½ΠΎΠΏΠΊΡ Π½ΠΈΠΆΠ΅.",
- "yookassa_auto_renewal": "π ΠΠΎΠ΄ΠΏΠΈΡΠΊΠ° Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΠΏΡΠΎΠ΄Π»Π΅Π½Π°\n\nΠΠ°ΡΠ° ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠ° Π±ΡΠ»Π° Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΠΏΡΠΎΠ΄Π»Π΅Π½Π° Π½Π° {months} ΠΌΠ΅Ρ.\nΠΠΎΠ²Π°Ρ Π΄Π°ΡΠ° ΠΎΠΊΠΎΠ½ΡΠ°Π½ΠΈΡ: {end_date}",
+ "yookassa_auto_renewal": "π ΠΠΎΠ΄ΠΏΠΈΡΠΊΠ° Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΠΏΡΠΎΠ΄Π»Π΅Π½Π°\n\nΠΠ°ΡΠ° ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠ° Π±ΡΠ»Π° Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΠΏΡΠΎΠ΄Π»Π΅Π½Π° Π½Π° {months} ΠΌΠ΅Ρ.\nΠΠΎΠ²Π°Ρ Π΄Π°ΡΠ° ΠΎΠΊΠΎΠ½ΡΠ°Π½ΠΈΡ: {end_date}",
"admin_promo_set_validity_days": "β° Π£ΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ ΡΡΠΎΠΊ (Π΄Π½ΠΈ)",
"admin_back_to_panel": "β¬
οΈ Π ΠΏΠ°Π½Π΅Π»Ρ",
"admin_promo_unlimited": "βΎοΈ ΠΠ΅ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½Π½ΠΎ",