Spaces:
Sleeping
Sleeping
| """ | |
| translator.py β Traduction multi-moteurs avec fallback automatique | |
| Utilise deep-translator uniquement (pas de conflit avec gradio/httpx) | |
| Ordre de fallback : | |
| 1. deep-translator GoogleTranslator (Google Translate, gratuit) | |
| 2. deep-translator MyMemoryTranslator (5000 mots/jour gratuit) | |
| 3. deep-translator LibreTranslator (open source) | |
| 4. Texte franΓ§ais original conservΓ© (jamais de crash) | |
| Codes de langue supportΓ©s : fr, en, sw, rn (Rundi/Kirundi) | |
| """ | |
| import time | |
| # ββ Mapping codes internes β codes deep-translator βββββββββββββββββββββββββββ | |
| # deep-translator GoogleTranslator accepte les noms complets ou codes ISO | |
| DEEP_GOOGLE_CODES = { | |
| "fr": "fr", | |
| "en": "en", | |
| "sw": "sw", | |
| "rn": "rn", # Rundi β supportΓ© par Google Translate | |
| } | |
| # MyMemoryTranslator utilise le format "lang-REGION" | |
| MYMEMORY_CODES = { | |
| "fr": "fr-FR", | |
| "en": "en-US", | |
| "sw": "sw-KE", | |
| "rn": "rn-BI", # Rundi β Burundi | |
| } | |
| # LibreTranslator codes ISO 639-1 | |
| LIBRE_CODES = { | |
| "fr": "fr", | |
| "en": "en", | |
| "sw": "sw", | |
| "rn": "rn", | |
| } | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # MOTEUR 1 β deep-translator GoogleTranslator | |
| # Utilise Google Translate en arrière-plan, gratuit et sans API key | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _translate_deep_google(text: str, lang_code: str) -> str | None: | |
| dest = DEEP_GOOGLE_CODES.get(lang_code) | |
| if not dest: | |
| return None | |
| try: | |
| from deep_translator import GoogleTranslator | |
| result = GoogleTranslator(source="fr", target=dest).translate(text) | |
| if result and result.strip() and len(result.strip()) > 3: | |
| return result.strip() | |
| except Exception as e: | |
| print(f" deep-google ECHEC ({lang_code}) : {str(e)[:70]}") | |
| return None | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # MOTEUR 2 β deep-translator MyMemoryTranslator | |
| # 5000 mots/jour gratuit sans compte | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _translate_mymemory(text: str, lang_code: str) -> str | None: | |
| dest = MYMEMORY_CODES.get(lang_code) | |
| if not dest: | |
| return None | |
| try: | |
| from deep_translator import MyMemoryTranslator | |
| result = MyMemoryTranslator(source="fr-FR", target=dest).translate(text) | |
| if result and result.strip() and len(result.strip()) > 3: | |
| # MyMemory retourne un avertissement si la limite est atteinte | |
| if any(w in result for w in ["MYMEMORY WARNING", "QUOTA FINISHED", "YOU USED"]): | |
| print(f" MyMemory : limite atteinte") | |
| return None | |
| return result.strip() | |
| except Exception as e: | |
| print(f" MyMemory ECHEC ({lang_code}) : {str(e)[:70]}") | |
| return None | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # MOTEUR 3 β deep-translator LibreTranslator | |
| # Open source, serveur public disponible | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _translate_libre(text: str, lang_code: str) -> str | None: | |
| dest = LIBRE_CODES.get(lang_code) | |
| if not dest: | |
| return None | |
| try: | |
| from deep_translator import LibreTranslator | |
| result = LibreTranslator( | |
| source="fr", | |
| target=dest, | |
| url="https://libretranslate.com", | |
| api_key="" | |
| ).translate(text) | |
| if result and result.strip() and len(result.strip()) > 3: | |
| return result.strip() | |
| except Exception as e: | |
| print(f" LibreTranslate ECHEC ({lang_code}) : {str(e)[:70]}") | |
| return None | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # FONCTION PRINCIPALE β fallback automatique | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Ordre des moteurs : du plus fiable au moins fiable | |
| _ENGINES = [ | |
| ("deep-google", _translate_deep_google), | |
| ("mymemory", _translate_mymemory), | |
| ("libretranslate",_translate_libre), | |
| ] | |
| def translate(text: str, lang_code: str, pause: float = 0.1) -> str: | |
| """ | |
| Traduit un texte franΓ§ais vers lang_code avec fallback automatique. | |
| Essaie chaque moteur dans l'ordre jusqu'au premier succès. | |
| Si tous Γ©chouent β retourne le texte original. | |
| lang_code : "fr" | "en" | "sw" | "rn" | |
| pause : dΓ©lai entre tentatives (secondes) | |
| """ | |
| if lang_code == "fr" or not text or not text.strip(): | |
| return text | |
| for engine_name, engine_fn in _ENGINES: | |
| try: | |
| result = engine_fn(text, lang_code) | |
| if result: | |
| print(f"Traduction OK via {engine_name} ({lang_code})") | |
| time.sleep(pause) | |
| return result | |
| else: | |
| print(f" {engine_name} : rΓ©sultat vide β moteur suivant") | |
| except Exception as e: | |
| print(f" {engine_name} erreur inattendue : {str(e)[:60]}") | |
| time.sleep(pause) | |
| # Tous les moteurs ont Γ©chouΓ© | |
| print(f"TOUS les moteurs ont Γ©chouΓ© ({lang_code}) β texte original conservΓ©") | |
| return text | |
| def translate_fields(fields: dict, lang_code: str) -> dict: | |
| """ | |
| Traduit un dictionnaire de champs texte du franΓ§ais vers lang_code. | |
| Chaque champ est traduit indΓ©pendamment avec fallback. | |
| fields : {"disease_name": "...", "cause": "...", ...} | |
| Retourne les champs traduits (ou originaux si Γ©chec). | |
| """ | |
| if lang_code == "fr": | |
| return fields | |
| translated = {} | |
| for key, value in fields.items(): | |
| if not value or value in ("β", ""): | |
| translated[key] = value | |
| continue | |
| translated[key] = translate(value, lang_code) | |
| return translated | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # TEST β lance ce fichier directement pour vΓ©rifier les moteurs | |
| # python translator.py | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| if __name__ == "__main__": | |
| tests = { | |
| "disease_name": "Mildiou de la tomate", | |
| "cause": "Champignon Phytophthora infestans. FavorisΓ© par l'humiditΓ© Γ©levΓ©e.", | |
| "treatment": "Appliquer un fongicide cuivrique. Retirer les feuilles infectΓ©es.", | |
| } | |
| for code, label in [("en", "English"), ("sw", "Swahili"), ("rn", "Rundi/Kirundi")]: | |
| print(f"\n{'='*50}") | |
| print(f"LANGUE : {label} ({code})") | |
| print(f"{'='*50}") | |
| results = translate_fields(tests, code) | |
| for key, val in results.items(): | |
| print(f" {key}: {val}") | |