# locale_manager.py """ Locale Manager - Manages locale files for the system """ import json from pathlib import Path from typing import Dict, List, Optional from datetime import datetime import sys from utils.logger import log_info, log_error, log_debug, log_warning class LocaleManager: """Manages locale files for TTS preprocessing and system-wide language support""" _cache: Dict[str, Dict] = {} _available_locales: Optional[List[Dict[str, str]]] = None @classmethod def get_locale(cls, language: str) -> Dict: """Get locale data with caching""" if language not in cls._cache: cls._cache[language] = cls._load_locale(language) return cls._cache[language] @classmethod def _load_locale(cls, language: str) -> Dict: """Load locale from file - accepts both 'tr' and 'tr-TR' formats""" base_path = Path(__file__).parent.parent / "locales" # First try exact match locale_file = base_path / f"{language}.json" # If not found and has region code, try without region (tr-TR -> tr) if not locale_file.exists() and '-' in language: language_code = language.split('-')[0] locale_file = base_path / f"{language_code}.json" if locale_file.exists(): try: with open(locale_file, 'r', encoding='utf-8') as f: data = json.load(f) log_debug(f"✅ Loaded locale file: {locale_file.name}") return data except Exception as e: log_error(f"Failed to load locale file {locale_file}", e) # Try English fallback fallback_file = base_path / "en.json" if fallback_file.exists(): try: with open(fallback_file, 'r', encoding='utf-8') as f: data = json.load(f) log_warning(f"⚠️ Using English fallback for locale: {language}") return data except: pass # Minimal fallback if no locale files exist log_warning(f"⚠️ No locale files found, using minimal fallback") return { "code": "tr", "locale_tag": "tr-TR", "name": "Türkçe", "english_name": "Turkish" } @classmethod def list_available_locales(cls) -> List[str]: """List all available locale files""" base_path = Path(__file__).parent.parent / "locales" if not base_path.exists(): return ["en", "tr"] # Default locales return [f.stem for f in base_path.glob("*.json")] @classmethod def get_available_locales_with_names(cls) -> List[Dict[str, str]]: """Get list of all available locales with their display names""" if cls._available_locales is not None: return cls._available_locales cls._available_locales = [] base_path = Path(__file__).parent.parent / "locales" if not base_path.exists(): # Return default locales if directory doesn't exist cls._available_locales = [ { "code": "tr-TR", "name": "Türkçe", "english_name": "Turkish" }, { "code": "en-US", "name": "English", "english_name": "English (US)" } ] return cls._available_locales # Load all locale files for locale_file in base_path.glob("*.json"): try: locale_code = locale_file.stem locale_data = cls.get_locale(locale_code) cls._available_locales.append({ "code": locale_code, "name": locale_data.get("name", locale_code), "english_name": locale_data.get("english_name", locale_code) }) log_info(f"✅ Loaded locale: {locale_code} - {locale_data.get('name', 'Unknown')}") except Exception as e: log_error(f"❌ Failed to load locale {locale_file}", e) # Sort by name for consistent ordering cls._available_locales.sort(key=lambda x: x['name']) return cls._available_locales @classmethod def get_locale_details(cls, locale_code: str) -> Optional[Dict]: """Get detailed info for a specific locale""" try: locale_data = cls.get_locale(locale_code) # Ensure code is in the data locale_data['code'] = locale_code return locale_data except: return None @classmethod def is_locale_supported(cls, locale_code: str) -> bool: """Check if a locale is supported system-wide""" available_codes = [locale['code'] for locale in cls.get_available_locales_with_names()] return locale_code in available_codes @classmethod def validate_project_languages(cls, languages: List[str]) -> List[str]: """Validate that all languages are system-supported, return invalid ones""" available_codes = [locale['code'] for locale in cls.get_available_locales_with_names()] invalid_languages = [ lang for lang in languages if lang not in available_codes ] return invalid_languages @classmethod def get_default_locale(cls) -> str: """Get system default locale""" available_locales = cls.get_available_locales_with_names() # Priority: tr-TR, en-US, first available for preferred in ["tr-TR", "en-US"]: if any(locale['code'] == preferred for locale in available_locales): return preferred # Return first available or fallback if available_locales: return available_locales[0]['code'] return "en-US"