Edit depends call in i18n

This commit is contained in:
parent 9f0ab4ae5a
commit a13636ca49
8 changed files with 52 additions and 53 deletions

View file

@ -44,7 +44,7 @@ class ContainerPositionManager:
}, },
} }
def get_position_and_state(self, container_name: str, translations: Translations = Depends(get_translations())) -> Tuple[int, int, bool]: def get_position_and_state(self, container_name: str, translations: Translations = None) -> Tuple[int, int, bool]:
"""Получает текущие координаты и состояние указанного контейнера. """Получает текущие координаты и состояние указанного контейнера.
Args: Args:
@ -57,6 +57,7 @@ class ContainerPositionManager:
Raises: Raises:
ValueError: Если указан неверный идентификатор контейнера. ValueError: Если указан неверный идентификатор контейнера.
""" """
translations = translations or get_translations()()
container = self.positions.get(container_name) container = self.positions.get(container_name)
if not container: if not container:
raise ValueError(translations.gettext("Неверное имя контейнера: {container_name}").format(container_name=container_name)) raise ValueError(translations.gettext("Неверное имя контейнера: {container_name}").format(container_name=container_name))

View file

@ -18,7 +18,6 @@
""" """
import os import os
import logging import logging
from fastapi import Depends
import netifaces import netifaces
from netaddr import IPNetwork from netaddr import IPNetwork
from utils.i18n import get_translations, _ from utils.i18n import get_translations, _
@ -45,7 +44,7 @@ class NetworkScanner:
вывода информации о клиентах. вывода информации о клиентах.
""" """
def __init__(self, interface=None, translations: Translations = Depends(get_translations())): def __init__(self, interface=None, translations: Translations = None):
"""Инициализация параметров сетевого сканера. """Инициализация параметров сетевого сканера.
Args: Args:
@ -55,7 +54,7 @@ class NetworkScanner:
Инициализирует интерфейс, информацию об IP-адресах и локальный MAC-адрес. Инициализирует интерфейс, информацию об IP-адресах и локальный MAC-адрес.
""" """
self.translations = translations self.translations = translations or get_translations()()
self.interface = None self.interface = None
self.ip_info = [] self.ip_info = []
self.networks = [] self.networks = []

View file

@ -1,6 +1,6 @@
from jose import JWTError, jwt from jose import JWTError, jwt
from datetime import datetime, timedelta from datetime import datetime, timedelta
from fastapi import HTTPException, Depends, Request from fastapi import HTTPException, Depends
from fastapi.security import OAuth2PasswordBearer from fastapi.security import OAuth2PasswordBearer
from models.auth import UserCreate, UserLogin, UserResponse, Token from models.auth import UserCreate, UserLogin, UserResponse, Token
from storage.json_storage import JsonStorage from storage.json_storage import JsonStorage
@ -35,10 +35,10 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login")
class AuthService: class AuthService:
"""Сервис для регистрации, авторизации и управления сессиями""" """Сервис для регистрации, авторизации и управления сессиями"""
def __init__(self, translations: Translations = Depends(get_translations())): def __init__(self, translations: Optional[Translations] = None):
self.storage = JsonStorage() self.storage = JsonStorage()
self.session_storage = SessionStorage() self.session_storage = SessionStorage()
self.translations = translations self.translations = translations or get_translations()()
def create_access_token(self, data: dict) -> str: def create_access_token(self, data: dict) -> str:
"""Создаёт токен""" """Создаёт токен"""

View file

@ -20,7 +20,6 @@ import logging
from typing import Tuple, Optional from typing import Tuple, Optional
from utils.i18n import get_translations, _ from utils.i18n import get_translations, _
from babel.support import Translations from babel.support import Translations
from fastapi import Depends
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -37,13 +36,7 @@ class WifiConnectionService:
Автоматически определяет доступный Wi-Fi-интерфейс и сохраняет его имя. Автоматически определяет доступный Wi-Fi-интерфейс и сохраняет его имя.
""" """
self.interface = self._get_wifi_interface() self.interface = self._get_wifi_interface()
if translations is None: self.translations = translations or get_translations()()
try:
self.translations = Translations.load("locales", ["ru"], "messages")
except Exception:
self.translations = Translations()
else:
self.translations = translations
def _get_wifi_interface(self) -> str: def _get_wifi_interface(self) -> str:
"""Автоматически определяет Wi-Fi-интерфейс. """Автоматически определяет Wi-Fi-интерфейс.

View file

@ -34,7 +34,6 @@ from models.network import (
import subprocess import subprocess
from utils.i18n import get_translations, _ from utils.i18n import get_translations, _
from babel.support import Translations from babel.support import Translations
from fastapi import Depends
class NetworkService: class NetworkService:
"""Сервис для взаимодействия с NetworkManager через D-Bus. """Сервис для взаимодействия с NetworkManager через D-Bus.
@ -43,7 +42,7 @@ class NetworkService:
их конфигурациях IP, Wi-Fi и состояниях. их конфигурациях IP, Wi-Fi и состояниях.
""" """
def __init__(self, translations: Translations = Depends(get_translations())): def __init__(self, translations: Translations = None):
"""Инициализирует сервис NetworkManager. """Инициализирует сервис NetworkManager.
Устанавливает системный D-Bus и создаёт объекты для взаимодействия с Устанавливает системный D-Bus и создаёт объекты для взаимодействия с
@ -52,7 +51,7 @@ class NetworkService:
self.system_bus = sd_bus_open_system() self.system_bus = sd_bus_open_system()
self.nm = NetworkManager(self.system_bus) self.nm = NetworkManager(self.system_bus)
self.nm_settings = NetworkManagerSettings(self.system_bus) self.nm_settings = NetworkManagerSettings(self.system_bus)
self.translations = translations self.translations = translations or get_translations()()
async def get_ip_method(self, device: NetworkDeviceGeneric, ip_type: str) -> str: async def get_ip_method(self, device: NetworkDeviceGeneric, ip_type: str) -> str:
"""Получает метод IP (например, "auto", "manual") для указанного устройства. """Получает метод IP (например, "auto", "manual") для указанного устройства.

View file

@ -4,7 +4,6 @@ from typing import Optional
from utils.i18n import get_translations from utils.i18n import get_translations
from babel.support import Translations from babel.support import Translations
from fastapi import Depends
from pathlib import Path from pathlib import Path
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
@ -13,10 +12,10 @@ logger = logging.getLogger(__name__)
class SettingsService: class SettingsService:
"""Сервис для управления настройками и очистки данных сети.""" """Сервис для управления настройками и очистки данных сети."""
def __init__(self, translations: Translations = Depends(get_translations())): def __init__(self, translations: Translations = None):
self.subnet_base_path = "storage/subnets" self.subnet_base_path = "storage/subnets"
self.wifi_file = "storage/wifi/wifi.json" self.wifi_file = "storage/wifi/wifi.json"
self.translations = translations self.translations = translations or get_translations()()
def clear_subnet(self, subnet: Optional[str] = None) -> bool: def clear_subnet(self, subnet: Optional[str] = None) -> bool:
"""Очищает данные узлов подсети в указанном файле или во всех файлах. """Очищает данные узлов подсети в указанном файле или во всех файлах.

View file

@ -11,7 +11,6 @@ from pathlib import Path
import json import json
from utils.i18n import get_translations from utils.i18n import get_translations
from babel.support import Translations from babel.support import Translations
from fastapi import Depends
# Настройка логирования # Настройка логирования
logging.basicConfig( logging.basicConfig(
@ -34,10 +33,10 @@ class WifiStorage:
- Создаёт директорию хранения при инициализации, ведёт логирование путей. - Создаёт директорию хранения при инициализации, ведёт логирование путей.
- Валидирует структуру при чтении и безопасно записывает JSON с Unicode и отступами. - Валидирует структуру при чтении и безопасно записывает JSON с Unicode и отступами.
""" """
def __init__(self, storage_path: str = "storage/wifi/wifi.json", translations: Translations = Depends(get_translations())): def __init__(self, storage_path: str = "storage/wifi/wifi.json", translations: Translations = None):
self.storage_file = Path(storage_path) self.storage_file = Path(storage_path)
self.storage_file.parent.mkdir(parents=True, exist_ok=True) self.storage_file.parent.mkdir(parents=True, exist_ok=True)
self.translations = translations self.translations = translations or get_translations()()
logger.info(f"Wi-Fi storage initialized at: {self.storage_file.absolute()}") logger.info(f"Wi-Fi storage initialized at: {self.storage_file.absolute()}")
def load_notes(self) -> Dict[str, Optional[str]]: def load_notes(self) -> Dict[str, Optional[str]]:
@ -85,15 +84,15 @@ class WifiService:
- Кэширование определения вендора. - Кэширование определения вендора.
- Сохранение SSID даже без заметок для будущих операций. - Сохранение SSID даже без заметок для будущих операций.
""" """
def __init__(self, translations: Translations = Depends(get_translations())): def __init__(self, translations: Translations = None):
self.mac_lookup = MacLookup() self.mac_lookup = MacLookup()
self.wifi = pywifi.PyWiFi() self.wifi = pywifi.PyWiFi()
self.interface = self._get_wifi_interface() self.interface = self._get_wifi_interface()
if not hasattr(translations, 'gettext'): validated_translations = translations or get_translations()()
if not hasattr(validated_translations, "gettext"):
logger.warning("Translations object does not support gettext, using fallback") logger.warning("Translations object does not support gettext, using fallback")
self.translations = Translations.load("utils/locales/en/LC_MESSAGES/services.mo") validated_translations = get_translations()()
else: self.translations = validated_translations
self.translations = translations
self.storage = WifiStorage() self.storage = WifiStorage()
def _get_wifi_interface(self) -> Optional[object]: def _get_wifi_interface(self) -> Optional[object]:

View file

@ -16,40 +16,49 @@
региональных суффиксов) для упрощения. региональных суффиксов) для упрощения.
- Модуль ведёт отладочное логирование выбора и загрузки локали. - Модуль ведёт отладочное логирование выбора и загрузки локали.
""" """
from fastapi import Request, Depends from fastapi import Request, WebSocket
from babel.support import Translations from babel.support import Translations
import logging import logging
from typing import Optional, Union
from pathlib import Path
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
LOCALES_DIR = Path(__file__).resolve().parent.parent / "locales"
def _load_translations(locale: str) -> Translations:
"""Подгружает словарь переводов с fallback на ru."""
try:
translations = Translations.load(str(LOCALES_DIR), [locale], "messages")
if not translations._catalog:
logger.warning(f"Translations for locale {locale} not found, falling back to ru")
translations = Translations.load(str(LOCALES_DIR), ["ru"], "messages")
return translations
except Exception as e: # pragma: no cover - логируем и возвращаем ru
logger.error(f"Failed to load translations for locale {locale}: {str(e)}")
return Translations.load(str(LOCALES_DIR), ["ru"], "messages")
def get_translations() -> callable: def get_translations() -> callable:
""" """
Создаёт зависимость для загрузки переводов на основе заголовка Accept-Language Создаёт зависимость для загрузки переводов на основе заголовка Accept-Language
или параметра запроса 'locale'. По умолчанию используется русский язык. или параметра запроса 'locale'. По умолчанию используется русский язык.
""" """
def translations_dependency(request: Request) -> Translations: def translations_dependency(request: Optional[Union[Request, WebSocket]] = None) -> Translations:
if request is None:
logger.warning("Translations dependency called without request/websocket; fallback to ru")
return _load_translations("ru")
# Проверяем параметр запроса 'locale', если он есть # Проверяем параметр запроса 'locale', если он есть
locale = None
if hasattr(request, "query_params"):
locale = request.query_params.get("locale") locale = request.query_params.get("locale")
if not locale: if not locale and hasattr(request, "cookies"):
# Если параметр отсутствует, проверяем куку 'locale'
locale = request.cookies.get("locale") locale = request.cookies.get("locale")
if not locale: if not locale and hasattr(request, "headers"):
# Если куки нет, используем заголовок Accept-Language
locale = request.headers.get("Accept-Language", "ru").split(",")[0].split("-")[0] locale = request.headers.get("Accept-Language", "ru").split(",")[0].split("-")[0]
locale = locale or "ru"
logger.debug(f"Determined locale: {locale}") logger.debug(f"Determined locale: {locale}")
try: return _load_translations(locale)
translations = Translations.load("locales", [locale], "messages")
if not translations._catalog:
logger.warning(f"Translations for locale {locale} not found, falling back to ru")
translations = Translations.load("locales", ["ru"], "messages")
logger.debug(f"Loaded translations for locale {locale}, catalog size: {len(translations._catalog)}")
return translations
except Exception as e:
logger.error(f"Failed to load translations for locale {locale}: {str(e)}")
# Fallback на русский
logger.debug("Falling back to ru translations")
return Translations.load("locales", ["ru"], "messages")
return translations_dependency return translations_dependency
@ -66,7 +75,7 @@ def _(msgid: str, request: Request = None) -> str:
""" """
if request is None: if request is None:
# Язык, который будет отображаться по умолчанию # Язык, который будет отображаться по умолчанию
translations = Translations.load("locales", ["ru"], "messages") translations = _load_translations("ru")
logger.debug(f"Using default ru translations for msgid: {msgid}") logger.debug(f"Using default ru translations for msgid: {msgid}")
else: else:
translations = get_translations()(request) translations = get_translations()(request)