from googletrans import Translator, LANGUAGES import asyncio from typing import List, Dict, Optional, Tuple import logging logger = logging.getLogger(__name__) class TranslationService: def __init__(self): self.translator = Translator() self.languages = LANGUAGES # Кэш для обратного поиска языков self._name_to_code_cache = None def _build_name_cache(self): """Построить кэш для поиска кода языка по названию""" if self._name_to_code_cache is None: self._name_to_code_cache = {} for code, name in self.languages.items(): self._name_to_code_cache[name.lower()] = code # Добавляем русские названия russian_names = { 'russian': 'ru', 'английский': 'en', 'немецкий': 'de', 'французский': 'fr', 'испанский': 'es', 'итальянский': 'it', 'португальский': 'pt', 'китайский': 'zh-cn', 'японский': 'ja', 'корейский': 'ko', 'арабский': 'ar', 'турецкий': 'tr' } self._name_to_code_cache.update(russian_names) return self._name_to_code_cache def get_language_code(self, lang: str) -> str: """Получить код языка из названия или кода""" if not lang or lang == 'auto': return 'auto' # Если это уже код языка if lang in self.languages: return lang # Ищем по названию name_cache = self._build_name_cache() return name_cache.get(lang.lower(), 'auto') def get_language_name(self, code: str) -> str: """Получить название языка по коду""" return self.languages.get(code, code) async def translate(self, text: str, dest: str = 'ru', src: str = 'auto') -> Dict: """Асинхронный перевод текста""" try: # Получаем коды языков dest_code = self.get_language_code(dest) src_code = self.get_language_code(src) if src != 'auto' else 'auto' # Выполняем перевод в отдельном потоке, так как googletrans не асинхронный loop = asyncio.get_event_loop() result = await loop.run_in_executor( None, lambda: self.translator.translate(text, src=src_code, dest=dest_code) ) # Получаем альтернативные переводы (если есть) alternatives = [] if hasattr(result, 'extra_data') and result.extra_data: possible_translations = result.extra_data.get('possible-translations', []) if possible_translations and len(possible_translations) > 0: for translation_group in possible_translations[:3]: if translation_group and len(translation_group) > 0: for translation_item in translation_group[:2]: if isinstance(translation_item, list) and len(translation_item) > 1: alternatives.append(translation_item[1]) return { 'original_text': result.origin, 'translated_text': result.text, 'source_lang': result.src, 'target_lang': dest_code, 'source_lang_name': self.get_language_name(result.src), 'target_lang_name': self.get_language_name(dest_code), 'pronunciation': result.pronunciation, 'alternatives': alternatives[:5] if alternatives else None } except Exception as e: logger.error(f"Translation error: {str(e)}") raise Exception(f"Ошибка перевода: {str(e)}") async def translate_batch(self, texts: List[str], dest: str = 'ru', src: str = 'auto') -> List[Dict]: """Пакетный перевод текстов""" tasks = [self.translate(text, dest, src) for text in texts] results = await asyncio.gather(*tasks, return_exceptions=True) translations = [] for result in results: if isinstance(result, Exception): translations.append({ 'error': str(result), 'original_text': '', 'translated_text': '' }) else: translations.append(result) return translations async def detect_language(self, text: str) -> Dict: """Определение языка текста""" try: loop = asyncio.get_event_loop() result = await loop.run_in_executor( None, lambda: self.translator.detect(text) ) return { 'lang': result.lang, 'lang_name': self.get_language_name(result.lang), 'confidence': result.confidence } except Exception as e: logger.error(f"Language detection error: {str(e)}") raise Exception(f"Ошибка определения языка: {str(e)}") def get_supported_languages(self) -> List[Dict]: """Получить список поддерживаемых языков""" languages = [] for code, name in sorted(self.languages.items()): languages.append({ 'code': code, 'name': name, 'native_name': name # Можно добавить маппинг на родные названия }) return languages