mistral_translator 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +189 -121
- data/README_TESTING.md +33 -0
- data/SECURITY.md +157 -0
- data/docs/.nojekyll +2 -0
- data/docs/404.html +30 -0
- data/docs/README.md +153 -0
- data/docs/advanced-usage/batch-processing.md +158 -0
- data/docs/advanced-usage/error-handling.md +106 -0
- data/docs/advanced-usage/monitoring.md +133 -0
- data/docs/advanced-usage/summarization.md +86 -0
- data/docs/advanced-usage/translations.md +141 -0
- data/docs/api-reference/callbacks.md +231 -0
- data/docs/api-reference/configuration.md +74 -0
- data/docs/api-reference/errors.md +673 -0
- data/docs/api-reference/methods.md +539 -0
- data/docs/getting-started.md +179 -0
- data/docs/index.html +27 -0
- data/docs/installation.md +142 -0
- data/docs/migration-0.1.0-to-0.2.0.md +61 -0
- data/docs/rails-integration/adapters.md +84 -0
- data/docs/rails-integration/controllers.md +107 -0
- data/docs/rails-integration/jobs.md +97 -0
- data/docs/rails-integration/setup.md +339 -0
- data/examples/basic_usage.rb +129 -102
- data/examples/batch-job.rb +511 -0
- data/examples/monitoring-setup.rb +499 -0
- data/examples/rails-model.rb +399 -0
- data/lib/mistral_translator/adapters.rb +261 -0
- data/lib/mistral_translator/client.rb +103 -100
- data/lib/mistral_translator/client_helpers.rb +161 -0
- data/lib/mistral_translator/configuration.rb +171 -1
- data/lib/mistral_translator/errors.rb +16 -0
- data/lib/mistral_translator/helpers.rb +292 -0
- data/lib/mistral_translator/helpers_extensions.rb +150 -0
- data/lib/mistral_translator/levenshtein_helpers.rb +40 -0
- data/lib/mistral_translator/logger.rb +28 -4
- data/lib/mistral_translator/prompt_builder.rb +93 -41
- data/lib/mistral_translator/prompt_helpers.rb +83 -0
- data/lib/mistral_translator/prompt_metadata_helpers.rb +42 -0
- data/lib/mistral_translator/response_parser.rb +194 -23
- data/lib/mistral_translator/security.rb +72 -0
- data/lib/mistral_translator/summarizer.rb +41 -2
- data/lib/mistral_translator/translator.rb +174 -98
- data/lib/mistral_translator/translator_helpers.rb +268 -0
- data/lib/mistral_translator/version.rb +1 -1
- data/lib/mistral_translator.rb +51 -25
- metadata +39 -3
@@ -0,0 +1,673 @@
|
|
1
|
+
> **Navigation :** [🏠 Home](README.md) • [📖 API Reference](api-reference/methods.md) • [⚡ Advanced Usage](advanced-usage/translations.md) • [🛤️ Rails Integration](rails-integration/setup.md)
|
2
|
+
|
3
|
+
---
|
4
|
+
|
5
|
+
# Référence des Erreurs API
|
6
|
+
|
7
|
+
## Table des Matières
|
8
|
+
|
9
|
+
- [Hiérarchie des Erreurs](#hiérarchie-des-erreurs)
|
10
|
+
- [Erreurs de Configuration](#erreurs-de-configuration)
|
11
|
+
- [Erreurs API](#erreurs-api)
|
12
|
+
- [Erreurs de Traduction](#erreurs-de-traduction)
|
13
|
+
- [Erreurs de Sécurité](#erreurs-de-sécurité)
|
14
|
+
- [Gestion des Erreurs](#gestion-des-erreurs)
|
15
|
+
- [Bonnes Pratiques](#bonnes-pratiques)
|
16
|
+
|
17
|
+
---
|
18
|
+
|
19
|
+
## Hiérarchie des Erreurs
|
20
|
+
|
21
|
+
```
|
22
|
+
StandardError
|
23
|
+
└── MistralTranslator::Error
|
24
|
+
├── MistralTranslator::ConfigurationError
|
25
|
+
├── MistralTranslator::ApiError
|
26
|
+
│ ├── MistralTranslator::RateLimitError
|
27
|
+
│ └── MistralTranslator::AuthenticationError
|
28
|
+
├── MistralTranslator::InvalidResponseError
|
29
|
+
├── MistralTranslator::EmptyTranslationError
|
30
|
+
├── MistralTranslator::UnsupportedLanguageError
|
31
|
+
├── MistralTranslator::SecurityError
|
32
|
+
└── MistralTranslator::RateLimitExceededError
|
33
|
+
```
|
34
|
+
|
35
|
+
---
|
36
|
+
|
37
|
+
## Erreurs de Configuration
|
38
|
+
|
39
|
+
### `MistralTranslator::ConfigurationError`
|
40
|
+
|
41
|
+
**Description:** Erreur de configuration de la gem.
|
42
|
+
|
43
|
+
**Causes courantes:**
|
44
|
+
|
45
|
+
- Clé API manquante ou invalide
|
46
|
+
- URL d'API incorrecte
|
47
|
+
- Paramètres de configuration invalides
|
48
|
+
|
49
|
+
**Attributs:**
|
50
|
+
|
51
|
+
- `message` (String) - Message d'erreur descriptif
|
52
|
+
|
53
|
+
**Exemples:**
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
# Clé API manquante
|
57
|
+
MistralTranslator.configure do |config|
|
58
|
+
# config.api_key non définie
|
59
|
+
end
|
60
|
+
|
61
|
+
begin
|
62
|
+
MistralTranslator.translate("Hello", from: "en", to: "fr")
|
63
|
+
rescue MistralTranslator::ConfigurationError => e
|
64
|
+
puts "Configuration error: #{e.message}"
|
65
|
+
# => "API key is required. Set it with MistralTranslator.configure { |c| c.api_key = 'your_key' }"
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
# URL d'API incorrecte
|
71
|
+
MistralTranslator.configure do |config|
|
72
|
+
config.api_key = "valid_key"
|
73
|
+
config.api_url = "http://invalid-url" # Doit être HTTPS
|
74
|
+
end
|
75
|
+
# => MistralTranslator::ConfigurationError: API URL must use HTTPS protocol
|
76
|
+
```
|
77
|
+
|
78
|
+
**Solutions:**
|
79
|
+
|
80
|
+
- Vérifier que la clé API est définie : `ENV['MISTRAL_API_KEY']`
|
81
|
+
- Utiliser une URL HTTPS valide
|
82
|
+
- Valider les paramètres de configuration
|
83
|
+
|
84
|
+
---
|
85
|
+
|
86
|
+
## Erreurs API
|
87
|
+
|
88
|
+
### `MistralTranslator::ApiError`
|
89
|
+
|
90
|
+
**Description:** Classe de base pour toutes les erreurs API.
|
91
|
+
|
92
|
+
**Attributs:**
|
93
|
+
|
94
|
+
- `message` (String) - Message d'erreur
|
95
|
+
- `response` (Net::HTTPResponse, optionnel) - Réponse HTTP brute
|
96
|
+
- `status_code` (Integer, optionnel) - Code de statut HTTP
|
97
|
+
|
98
|
+
**Exemple:**
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
begin
|
102
|
+
MistralTranslator.translate("Hello", from: "en", to: "fr")
|
103
|
+
rescue MistralTranslator::ApiError => e
|
104
|
+
puts "API Error: #{e.message}"
|
105
|
+
puts "Status: #{e.status_code}" if e.status_code
|
106
|
+
puts "Response: #{e.response.body}" if e.response
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
---
|
111
|
+
|
112
|
+
### `MistralTranslator::AuthenticationError`
|
113
|
+
|
114
|
+
**Description:** Erreur d'authentification avec l'API Mistral.
|
115
|
+
|
116
|
+
**Hérite de:** `ApiError`
|
117
|
+
|
118
|
+
**Code HTTP:** 401
|
119
|
+
|
120
|
+
**Causes courantes:**
|
121
|
+
|
122
|
+
- Clé API invalide ou expirée
|
123
|
+
- Clé API non autorisée pour le modèle demandé
|
124
|
+
- Problème de format de la clé API
|
125
|
+
|
126
|
+
**Exemple:**
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
MistralTranslator.configure do |config|
|
130
|
+
config.api_key = "invalid_key_12345"
|
131
|
+
end
|
132
|
+
|
133
|
+
begin
|
134
|
+
MistralTranslator.translate("Hello", from: "en", to: "fr")
|
135
|
+
rescue MistralTranslator::AuthenticationError => e
|
136
|
+
puts "Authentication failed: #{e.message}"
|
137
|
+
# => "Invalid API key"
|
138
|
+
|
139
|
+
# Vérifier votre clé API
|
140
|
+
# 1. Connectez-vous à https://console.mistral.ai/
|
141
|
+
# 2. Générez une nouvelle clé API
|
142
|
+
# 3. Mettez à jour votre configuration
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
146
|
+
**Solutions:**
|
147
|
+
|
148
|
+
- Vérifier la validité de la clé API sur la console Mistral
|
149
|
+
- Régénérer une nouvelle clé si nécessaire
|
150
|
+
- S'assurer que la clé a les permissions nécessaires
|
151
|
+
|
152
|
+
---
|
153
|
+
|
154
|
+
### `MistralTranslator::RateLimitError`
|
155
|
+
|
156
|
+
**Description:** Limite de taux API dépassée.
|
157
|
+
|
158
|
+
**Hérite de:** `ApiError`
|
159
|
+
|
160
|
+
**Code HTTP:** 429
|
161
|
+
|
162
|
+
**Causes courantes:**
|
163
|
+
|
164
|
+
- Trop de requêtes envoyées en peu de temps
|
165
|
+
- Quota API mensuel dépassé
|
166
|
+
- Limites par minute/heure atteintes
|
167
|
+
|
168
|
+
**Exemple:**
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
begin
|
172
|
+
# Beaucoup de traductions rapides
|
173
|
+
100.times do |i|
|
174
|
+
MistralTranslator.translate("Text #{i}", from: "en", to: "fr")
|
175
|
+
end
|
176
|
+
rescue MistralTranslator::RateLimitError => e
|
177
|
+
puts "Rate limit exceeded: #{e.message}"
|
178
|
+
|
179
|
+
# La gem fait automatiquement des retry avec backoff exponentiel
|
180
|
+
# Mais vous pouvez aussi gérer manuellement :
|
181
|
+
puts "Waiting before retry..."
|
182
|
+
sleep(60) # Attendre 1 minute
|
183
|
+
retry
|
184
|
+
end
|
185
|
+
```
|
186
|
+
|
187
|
+
**Gestion automatique:**
|
188
|
+
La gem inclut un système de retry automatique avec backoff exponentiel :
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
MistralTranslator.configure do |config|
|
192
|
+
config.retry_delays = [2, 4, 8, 16, 32] # Délais en secondes
|
193
|
+
end
|
194
|
+
```
|
195
|
+
|
196
|
+
**Solutions:**
|
197
|
+
|
198
|
+
- Réduire la fréquence des requêtes
|
199
|
+
- Utiliser `translate_batch` pour les lots
|
200
|
+
- Ajouter des délais entre les requêtes
|
201
|
+
- Upgrader votre plan API si nécessaire
|
202
|
+
|
203
|
+
---
|
204
|
+
|
205
|
+
## Erreurs de Traduction
|
206
|
+
|
207
|
+
### `MistralTranslator::InvalidResponseError`
|
208
|
+
|
209
|
+
**Description:** Réponse invalide ou malformée de l'API.
|
210
|
+
|
211
|
+
**Attributs:**
|
212
|
+
|
213
|
+
- `message` (String) - Description de l'erreur
|
214
|
+
- `raw_response` (String, optionnel) - Réponse brute reçue
|
215
|
+
|
216
|
+
**Causes courantes:**
|
217
|
+
|
218
|
+
- JSON invalide dans la réponse API
|
219
|
+
- Structure de réponse inattendue
|
220
|
+
- Réponse tronquée ou corrompue
|
221
|
+
|
222
|
+
**Exemple:**
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
begin
|
226
|
+
MistralTranslator.translate("Hello", from: "en", to: "fr")
|
227
|
+
rescue MistralTranslator::InvalidResponseError => e
|
228
|
+
puts "Invalid response: #{e.message}"
|
229
|
+
puts "Raw response: #{e.raw_response}" if e.raw_response
|
230
|
+
|
231
|
+
# Cela peut indiquer:
|
232
|
+
# - Un problème temporaire avec l'API
|
233
|
+
# - Une réponse inattendue du serveur
|
234
|
+
# - Un problème de parsing JSON
|
235
|
+
end
|
236
|
+
```
|
237
|
+
|
238
|
+
**Solutions:**
|
239
|
+
|
240
|
+
- Réessayer la requête (souvent temporaire)
|
241
|
+
- Vérifier la status de l'API Mistral
|
242
|
+
- Signaler le problème si persistant
|
243
|
+
|
244
|
+
---
|
245
|
+
|
246
|
+
### `MistralTranslator::EmptyTranslationError`
|
247
|
+
|
248
|
+
**Description:** Traduction vide reçue de l'API.
|
249
|
+
|
250
|
+
**Causes courantes:**
|
251
|
+
|
252
|
+
- Texte source vide ou invalide
|
253
|
+
- Problème avec le prompt envoyé à l'API
|
254
|
+
- Réponse API incomplète
|
255
|
+
|
256
|
+
**Exemple:**
|
257
|
+
|
258
|
+
```ruby
|
259
|
+
begin
|
260
|
+
MistralTranslator.translate("", from: "en", to: "fr") # Texte vide
|
261
|
+
rescue MistralTranslator::EmptyTranslationError => e
|
262
|
+
puts "Empty translation: #{e.message}"
|
263
|
+
# => "Empty translation received from API"
|
264
|
+
end
|
265
|
+
|
266
|
+
# La gem gère automatiquement les textes vides :
|
267
|
+
result = MistralTranslator.translate("", from: "en", to: "fr")
|
268
|
+
puts result # => "" (sans erreur)
|
269
|
+
```
|
270
|
+
|
271
|
+
**Solutions:**
|
272
|
+
|
273
|
+
- Vérifier que le texte source n'est pas vide
|
274
|
+
- S'assurer que le texte contient du contenu traduisible
|
275
|
+
- Réessayer avec un texte différent
|
276
|
+
|
277
|
+
---
|
278
|
+
|
279
|
+
### `MistralTranslator::UnsupportedLanguageError`
|
280
|
+
|
281
|
+
**Description:** Langue non supportée par la gem.
|
282
|
+
|
283
|
+
**Attributs:**
|
284
|
+
|
285
|
+
- `language` (String) - Code de langue non supporté
|
286
|
+
|
287
|
+
**Langues supportées actuellement:**
|
288
|
+
|
289
|
+
```ruby
|
290
|
+
MistralTranslator.supported_locales
|
291
|
+
# => ["fr", "en", "es", "pt", "de", "it", "nl", "ru", "mg", "ja", "ko", "zh", "ar"]
|
292
|
+
```
|
293
|
+
|
294
|
+
**Exemple:**
|
295
|
+
|
296
|
+
```ruby
|
297
|
+
begin
|
298
|
+
MistralTranslator.translate("Hello", from: "en", to: "klingon")
|
299
|
+
rescue MistralTranslator::UnsupportedLanguageError => e
|
300
|
+
puts "Unsupported language: #{e.message}"
|
301
|
+
puts "Language requested: #{e.language}"
|
302
|
+
# => "klingon"
|
303
|
+
|
304
|
+
# Obtenir des suggestions :
|
305
|
+
suggestions = MistralTranslator::Helpers.validate_locale_with_suggestions("klingon")
|
306
|
+
if suggestions[:suggestions].any?
|
307
|
+
puts "Did you mean: #{suggestions[:suggestions].join(', ')}?"
|
308
|
+
end
|
309
|
+
end
|
310
|
+
```
|
311
|
+
|
312
|
+
**Solutions:**
|
313
|
+
|
314
|
+
- Utiliser `MistralTranslator.supported_locales` pour voir les langues disponibles
|
315
|
+
- Utiliser le helper de validation avec suggestions
|
316
|
+
- Normaliser les codes de langue (ex: "français" → "fr")
|
317
|
+
|
318
|
+
---
|
319
|
+
|
320
|
+
## Erreurs de Sécurité
|
321
|
+
|
322
|
+
### `MistralTranslator::SecurityError`
|
323
|
+
|
324
|
+
**Description:** Violation de sécurité détectée.
|
325
|
+
|
326
|
+
**Causes courantes:**
|
327
|
+
|
328
|
+
- Texte dépassant la taille limite (50,000 caractères)
|
329
|
+
- Contenu potentiellement malveillant détecté
|
330
|
+
- Tentative d'injection de prompt
|
331
|
+
|
332
|
+
**Exemple:**
|
333
|
+
|
334
|
+
```ruby
|
335
|
+
begin
|
336
|
+
huge_text = "A" * 100_000 # Texte trop grand
|
337
|
+
MistralTranslator.translate(huge_text, from: "en", to: "fr")
|
338
|
+
rescue ArgumentError => e
|
339
|
+
puts "Security limit: #{e.message}"
|
340
|
+
# => "Text too long (max 50000 chars)"
|
341
|
+
end
|
342
|
+
```
|
343
|
+
|
344
|
+
**Solutions:**
|
345
|
+
|
346
|
+
- Diviser les textes longs en plusieurs parties
|
347
|
+
- Valider le contenu avant traduction
|
348
|
+
- Utiliser `translate_batch` pour les lots importants
|
349
|
+
|
350
|
+
---
|
351
|
+
|
352
|
+
### `MistralTranslator::RateLimitExceededError`
|
353
|
+
|
354
|
+
**Description:** Limite de taux personnalisée dépassée.
|
355
|
+
|
356
|
+
**Attributs:**
|
357
|
+
|
358
|
+
- `wait_time` (Integer, optionnel) - Temps d'attente suggéré
|
359
|
+
- `retry_after` (Integer, optionnel) - Timestamp de retry
|
360
|
+
|
361
|
+
**Différence avec `RateLimitError`:**
|
362
|
+
|
363
|
+
- `RateLimitError` : Limite API Mistral (HTTP 429)
|
364
|
+
- `RateLimitExceededError` : Limite locale de la gem
|
365
|
+
|
366
|
+
**Exemple:**
|
367
|
+
|
368
|
+
```ruby
|
369
|
+
# Configuration du rate limiter local
|
370
|
+
rate_limiter = MistralTranslator::Security::BasicRateLimiter.new(
|
371
|
+
max_requests: 10,
|
372
|
+
window_seconds: 60
|
373
|
+
)
|
374
|
+
|
375
|
+
client = MistralTranslator::Client.new(rate_limiter: rate_limiter)
|
376
|
+
|
377
|
+
begin
|
378
|
+
# Trop de requêtes locales
|
379
|
+
15.times { client.complete("Hello") }
|
380
|
+
rescue MistralTranslator::RateLimitExceededError => e
|
381
|
+
puts "Local rate limit exceeded"
|
382
|
+
sleep(e.wait_time) if e.wait_time
|
383
|
+
retry
|
384
|
+
end
|
385
|
+
```
|
386
|
+
|
387
|
+
---
|
388
|
+
|
389
|
+
## Gestion des Erreurs
|
390
|
+
|
391
|
+
### Stratégies de Récupération
|
392
|
+
|
393
|
+
#### 1. Retry avec Backoff Exponentiel
|
394
|
+
|
395
|
+
```ruby
|
396
|
+
def safe_translate(text, from:, to:, max_retries: 3)
|
397
|
+
retries = 0
|
398
|
+
|
399
|
+
begin
|
400
|
+
MistralTranslator.translate(text, from: from, to: to)
|
401
|
+
rescue MistralTranslator::RateLimitError, MistralTranslator::ApiError => e
|
402
|
+
retries += 1
|
403
|
+
if retries <= max_retries
|
404
|
+
wait_time = 2 ** retries # 2, 4, 8 secondes
|
405
|
+
puts "Retry #{retries}/#{max_retries} in #{wait_time}s: #{e.message}"
|
406
|
+
sleep(wait_time)
|
407
|
+
retry
|
408
|
+
else
|
409
|
+
raise e
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
```
|
414
|
+
|
415
|
+
#### 2. Fallback avec Traduction par Défaut
|
416
|
+
|
417
|
+
```ruby
|
418
|
+
def translate_with_fallback(text, from:, to:, fallback: nil)
|
419
|
+
MistralTranslator.translate(text, from: from, to: to)
|
420
|
+
rescue MistralTranslator::Error => e
|
421
|
+
puts "Translation failed: #{e.message}"
|
422
|
+
fallback || text # Retourner le fallback ou le texte original
|
423
|
+
end
|
424
|
+
```
|
425
|
+
|
426
|
+
#### 3. Batch avec Récupération Individuelle
|
427
|
+
|
428
|
+
```ruby
|
429
|
+
def robust_batch_translate(texts, from:, to:)
|
430
|
+
begin
|
431
|
+
# Essayer le batch d'abord
|
432
|
+
MistralTranslator.translate_batch(texts, from: from, to: to)
|
433
|
+
rescue MistralTranslator::Error => e
|
434
|
+
puts "Batch failed: #{e.message}, falling back to individual translations"
|
435
|
+
|
436
|
+
# Fallback : traduction individuelle
|
437
|
+
results = {}
|
438
|
+
texts.each_with_index do |text, index|
|
439
|
+
begin
|
440
|
+
results[index] = MistralTranslator.translate(text, from: from, to: to)
|
441
|
+
rescue MistralTranslator::Error => e
|
442
|
+
puts "Failed to translate item #{index}: #{e.message}"
|
443
|
+
results[index] = text # Garder l'original en cas d'échec
|
444
|
+
end
|
445
|
+
end
|
446
|
+
results
|
447
|
+
end
|
448
|
+
end
|
449
|
+
```
|
450
|
+
|
451
|
+
#### 4. Circuit Breaker Pattern
|
452
|
+
|
453
|
+
```ruby
|
454
|
+
class TranslationCircuitBreaker
|
455
|
+
def initialize(failure_threshold: 5, reset_timeout: 60)
|
456
|
+
@failure_threshold = failure_threshold
|
457
|
+
@reset_timeout = reset_timeout
|
458
|
+
@failure_count = 0
|
459
|
+
@last_failure_time = nil
|
460
|
+
@state = :closed # :closed, :open, :half_open
|
461
|
+
end
|
462
|
+
|
463
|
+
def translate(text, from:, to:)
|
464
|
+
case @state
|
465
|
+
when :open
|
466
|
+
if Time.now - @last_failure_time > @reset_timeout
|
467
|
+
@state = :half_open
|
468
|
+
else
|
469
|
+
raise MistralTranslator::Error, "Circuit breaker is open"
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
begin
|
474
|
+
result = MistralTranslator.translate(text, from: from, to: to)
|
475
|
+
on_success
|
476
|
+
result
|
477
|
+
rescue MistralTranslator::Error => e
|
478
|
+
on_failure
|
479
|
+
raise e
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
private
|
484
|
+
|
485
|
+
def on_success
|
486
|
+
@failure_count = 0
|
487
|
+
@state = :closed
|
488
|
+
end
|
489
|
+
|
490
|
+
def on_failure
|
491
|
+
@failure_count += 1
|
492
|
+
@last_failure_time = Time.now
|
493
|
+
@state = :open if @failure_count >= @failure_threshold
|
494
|
+
end
|
495
|
+
end
|
496
|
+
```
|
497
|
+
|
498
|
+
### Logging et Monitoring
|
499
|
+
|
500
|
+
#### Configuration des Callbacks d'Erreur
|
501
|
+
|
502
|
+
```ruby
|
503
|
+
MistralTranslator.configure do |config|
|
504
|
+
config.on_translation_error = lambda do |from, to, error, attempt, timestamp|
|
505
|
+
# Log structuré
|
506
|
+
Rails.logger.error({
|
507
|
+
event: "translation_error",
|
508
|
+
from_language: from,
|
509
|
+
to_language: to,
|
510
|
+
error_class: error.class.name,
|
511
|
+
error_message: error.message,
|
512
|
+
attempt_number: attempt,
|
513
|
+
timestamp: timestamp
|
514
|
+
}.to_json)
|
515
|
+
|
516
|
+
# Notification externe (Sentry, Honeybadger, etc.)
|
517
|
+
if defined?(Sentry)
|
518
|
+
Sentry.capture_exception(error, extra: {
|
519
|
+
from_language: from,
|
520
|
+
to_language: to,
|
521
|
+
attempt_number: attempt
|
522
|
+
})
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
config.on_rate_limit = lambda do |from, to, wait_time, attempt, timestamp|
|
527
|
+
Rails.logger.warn({
|
528
|
+
event: "rate_limit",
|
529
|
+
from_language: from,
|
530
|
+
to_language: to,
|
531
|
+
wait_time: wait_time,
|
532
|
+
attempt_number: attempt,
|
533
|
+
timestamp: timestamp
|
534
|
+
}.to_json)
|
535
|
+
end
|
536
|
+
end
|
537
|
+
```
|
538
|
+
|
539
|
+
#### Métriques d'Erreurs
|
540
|
+
|
541
|
+
```ruby
|
542
|
+
# Analyser le taux d'erreur
|
543
|
+
metrics = MistralTranslator.metrics
|
544
|
+
puts "Error rate: #{metrics[:error_rate]}%"
|
545
|
+
puts "Total errors: #{metrics[:errors_count]}"
|
546
|
+
|
547
|
+
# Alertes basées sur les métriques
|
548
|
+
if metrics[:error_rate] > 10.0 # Plus de 10% d'erreurs
|
549
|
+
# Envoyer une alerte
|
550
|
+
AlertService.notify("High translation error rate: #{metrics[:error_rate]}%")
|
551
|
+
end
|
552
|
+
```
|
553
|
+
|
554
|
+
---
|
555
|
+
|
556
|
+
## Bonnes Pratiques
|
557
|
+
|
558
|
+
### 1. Gestion Proactive des Erreurs
|
559
|
+
|
560
|
+
```ruby
|
561
|
+
# ✅ Bon : Gestion spécifique des erreurs
|
562
|
+
begin
|
563
|
+
translation = MistralTranslator.translate(text, from: "fr", to: "en")
|
564
|
+
rescue MistralTranslator::UnsupportedLanguageError => e
|
565
|
+
# Gérer les langues non supportées
|
566
|
+
translation = handle_unsupported_language(text, e.language)
|
567
|
+
rescue MistralTranslator::RateLimitError => e
|
568
|
+
# Gérer les rate limits
|
569
|
+
translation = handle_rate_limit(text, e)
|
570
|
+
rescue MistralTranslator::AuthenticationError => e
|
571
|
+
# Gérer les problèmes d'auth
|
572
|
+
translation = handle_auth_error(text, e)
|
573
|
+
rescue MistralTranslator::Error => e
|
574
|
+
# Fallback général pour toutes les autres erreurs
|
575
|
+
translation = handle_general_error(text, e)
|
576
|
+
end
|
577
|
+
|
578
|
+
# ❌ Mauvais : Catch-all trop large
|
579
|
+
begin
|
580
|
+
translation = MistralTranslator.translate(text, from: "fr", to: "en")
|
581
|
+
rescue StandardError => e
|
582
|
+
# Trop générique, peut cacher d'autres problèmes
|
583
|
+
translation = text
|
584
|
+
end
|
585
|
+
```
|
586
|
+
|
587
|
+
### 2. Validation des Entrées
|
588
|
+
|
589
|
+
```ruby
|
590
|
+
def safe_translate(text, from:, to:, **options)
|
591
|
+
# Validation préalable
|
592
|
+
raise ArgumentError, "Text cannot be nil" if text.nil?
|
593
|
+
raise ArgumentError, "Text too long" if text.length > 50_000
|
594
|
+
|
595
|
+
# Validation des langues avec suggestions
|
596
|
+
from_validation = MistralTranslator::Helpers.validate_locale_with_suggestions(from)
|
597
|
+
unless from_validation[:valid]
|
598
|
+
raise MistralTranslator::UnsupportedLanguageError,
|
599
|
+
"Source language '#{from}' not supported. Suggestions: #{from_validation[:suggestions].join(', ')}"
|
600
|
+
end
|
601
|
+
|
602
|
+
# Traduction sécurisée
|
603
|
+
MistralTranslator.translate(text, from: from, to: to, **options)
|
604
|
+
end
|
605
|
+
```
|
606
|
+
|
607
|
+
### 3. Monitoring et Alertes
|
608
|
+
|
609
|
+
```ruby
|
610
|
+
class TranslationMonitor
|
611
|
+
def self.monitor_translation(&block)
|
612
|
+
start_time = Time.now
|
613
|
+
result = yield
|
614
|
+
duration = Time.now - start_time
|
615
|
+
|
616
|
+
# Log de performance
|
617
|
+
if duration > 30.0 # Plus de 30 secondes
|
618
|
+
Rails.logger.warn("Slow translation detected: #{duration}s")
|
619
|
+
end
|
620
|
+
|
621
|
+
result
|
622
|
+
rescue MistralTranslator::Error => e
|
623
|
+
# Log d'erreur avec contexte
|
624
|
+
Rails.logger.error({
|
625
|
+
event: "translation_failure",
|
626
|
+
error: e.class.name,
|
627
|
+
message: e.message,
|
628
|
+
duration: Time.now - start_time
|
629
|
+
}.to_json)
|
630
|
+
|
631
|
+
raise e
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
# Usage
|
636
|
+
translation = TranslationMonitor.monitor_translation do
|
637
|
+
MistralTranslator.translate("Hello", from: "en", to: "fr")
|
638
|
+
end
|
639
|
+
```
|
640
|
+
|
641
|
+
### 4. Tests des Scenarios d'Erreur
|
642
|
+
|
643
|
+
```ruby
|
644
|
+
# Dans vos specs RSpec
|
645
|
+
describe "error handling" do
|
646
|
+
it "handles rate limit gracefully" do
|
647
|
+
allow(MistralTranslator::Client).to receive(:new).and_raise(
|
648
|
+
MistralTranslator::RateLimitError.new("Rate limit exceeded")
|
649
|
+
)
|
650
|
+
|
651
|
+
expect {
|
652
|
+
MistralTranslator.translate("Hello", from: "en", to: "fr")
|
653
|
+
}.to raise_error(MistralTranslator::RateLimitError)
|
654
|
+
end
|
655
|
+
|
656
|
+
it "provides fallback for unsupported languages" do
|
657
|
+
result = translate_with_fallback(
|
658
|
+
"Hello",
|
659
|
+
from: "klingon",
|
660
|
+
to: "fr",
|
661
|
+
fallback: "Hello"
|
662
|
+
)
|
663
|
+
expect(result).to eq("Hello")
|
664
|
+
end
|
665
|
+
end
|
666
|
+
```
|
667
|
+
|
668
|
+
Cette approche robuste de gestion des erreurs garantit que votre application reste stable même en cas de problèmes avec l'API de traduction.
|
669
|
+
|
670
|
+
---
|
671
|
+
|
672
|
+
**API-Reference Navigation:**
|
673
|
+
[← Methods](api-reference/methods.md) | [Errors](api-reference/errors.md) | [Callbacks](api-reference/callbacks.md) | [Configuration](api-reference/configuration.md) →
|