Spaces:
Building
Building
# 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 | |
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] | |
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" | |
} | |
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")] | |
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 | |
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 | |
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 | |
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 | |
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" |