Edit depends call in i18n
This commit is contained in:
parent
9f0ab4ae5a
commit
a13636ca49
8 changed files with 52 additions and 53 deletions
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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 = []
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
"""Создаёт токен"""
|
"""Создаёт токен"""
|
||||||
|
|
|
||||||
|
|
@ -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-интерфейс.
|
||||||
|
|
|
||||||
|
|
@ -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") для указанного устройства.
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
"""Очищает данные узлов подсети в указанном файле или во всех файлах.
|
"""Очищает данные узлов подсети в указанном файле или во всех файлах.
|
||||||
|
|
|
||||||
|
|
@ -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]:
|
||||||
|
|
|
||||||
|
|
@ -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 = request.query_params.get("locale")
|
locale = None
|
||||||
if not locale:
|
if hasattr(request, "query_params"):
|
||||||
# Если параметр отсутствует, проверяем куку 'locale'
|
locale = request.query_params.get("locale")
|
||||||
|
if not locale and hasattr(request, "cookies"):
|
||||||
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)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue