truthound-dashboard 1.3.1__py3-none-any.whl → 1.4.0__py3-none-any.whl
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.
- truthound_dashboard/api/alerts.py +258 -0
- truthound_dashboard/api/anomaly.py +1302 -0
- truthound_dashboard/api/cross_alerts.py +352 -0
- truthound_dashboard/api/deps.py +143 -0
- truthound_dashboard/api/drift_monitor.py +540 -0
- truthound_dashboard/api/lineage.py +1151 -0
- truthound_dashboard/api/maintenance.py +363 -0
- truthound_dashboard/api/middleware.py +373 -1
- truthound_dashboard/api/model_monitoring.py +805 -0
- truthound_dashboard/api/notifications_advanced.py +2452 -0
- truthound_dashboard/api/plugins.py +2096 -0
- truthound_dashboard/api/profile.py +211 -14
- truthound_dashboard/api/reports.py +853 -0
- truthound_dashboard/api/router.py +147 -0
- truthound_dashboard/api/rule_suggestions.py +310 -0
- truthound_dashboard/api/schema_evolution.py +231 -0
- truthound_dashboard/api/sources.py +47 -3
- truthound_dashboard/api/triggers.py +190 -0
- truthound_dashboard/api/validations.py +13 -0
- truthound_dashboard/api/validators.py +333 -4
- truthound_dashboard/api/versioning.py +309 -0
- truthound_dashboard/api/websocket.py +301 -0
- truthound_dashboard/core/__init__.py +27 -0
- truthound_dashboard/core/anomaly.py +1395 -0
- truthound_dashboard/core/anomaly_explainer.py +633 -0
- truthound_dashboard/core/cache.py +206 -0
- truthound_dashboard/core/cached_services.py +422 -0
- truthound_dashboard/core/charts.py +352 -0
- truthound_dashboard/core/connections.py +1069 -42
- truthound_dashboard/core/cross_alerts.py +837 -0
- truthound_dashboard/core/drift_monitor.py +1477 -0
- truthound_dashboard/core/drift_sampling.py +669 -0
- truthound_dashboard/core/i18n/__init__.py +42 -0
- truthound_dashboard/core/i18n/detector.py +173 -0
- truthound_dashboard/core/i18n/messages.py +564 -0
- truthound_dashboard/core/lineage.py +971 -0
- truthound_dashboard/core/maintenance.py +443 -5
- truthound_dashboard/core/model_monitoring.py +1043 -0
- truthound_dashboard/core/notifications/channels.py +1020 -1
- truthound_dashboard/core/notifications/deduplication/__init__.py +143 -0
- truthound_dashboard/core/notifications/deduplication/policies.py +274 -0
- truthound_dashboard/core/notifications/deduplication/service.py +400 -0
- truthound_dashboard/core/notifications/deduplication/stores.py +2365 -0
- truthound_dashboard/core/notifications/deduplication/strategies.py +422 -0
- truthound_dashboard/core/notifications/dispatcher.py +43 -0
- truthound_dashboard/core/notifications/escalation/__init__.py +149 -0
- truthound_dashboard/core/notifications/escalation/backends.py +1384 -0
- truthound_dashboard/core/notifications/escalation/engine.py +429 -0
- truthound_dashboard/core/notifications/escalation/models.py +336 -0
- truthound_dashboard/core/notifications/escalation/scheduler.py +1187 -0
- truthound_dashboard/core/notifications/escalation/state_machine.py +330 -0
- truthound_dashboard/core/notifications/escalation/stores.py +2896 -0
- truthound_dashboard/core/notifications/events.py +49 -0
- truthound_dashboard/core/notifications/metrics/__init__.py +115 -0
- truthound_dashboard/core/notifications/metrics/base.py +528 -0
- truthound_dashboard/core/notifications/metrics/collectors.py +583 -0
- truthound_dashboard/core/notifications/routing/__init__.py +169 -0
- truthound_dashboard/core/notifications/routing/combinators.py +184 -0
- truthound_dashboard/core/notifications/routing/config.py +375 -0
- truthound_dashboard/core/notifications/routing/config_parser.py +867 -0
- truthound_dashboard/core/notifications/routing/engine.py +382 -0
- truthound_dashboard/core/notifications/routing/expression_engine.py +1269 -0
- truthound_dashboard/core/notifications/routing/jinja2_engine.py +774 -0
- truthound_dashboard/core/notifications/routing/rules.py +625 -0
- truthound_dashboard/core/notifications/routing/validator.py +678 -0
- truthound_dashboard/core/notifications/service.py +2 -0
- truthound_dashboard/core/notifications/stats_aggregator.py +850 -0
- truthound_dashboard/core/notifications/throttling/__init__.py +83 -0
- truthound_dashboard/core/notifications/throttling/builder.py +311 -0
- truthound_dashboard/core/notifications/throttling/stores.py +1859 -0
- truthound_dashboard/core/notifications/throttling/throttlers.py +633 -0
- truthound_dashboard/core/openlineage.py +1028 -0
- truthound_dashboard/core/plugins/__init__.py +39 -0
- truthound_dashboard/core/plugins/docs/__init__.py +39 -0
- truthound_dashboard/core/plugins/docs/extractor.py +703 -0
- truthound_dashboard/core/plugins/docs/renderers.py +804 -0
- truthound_dashboard/core/plugins/hooks/__init__.py +63 -0
- truthound_dashboard/core/plugins/hooks/decorators.py +367 -0
- truthound_dashboard/core/plugins/hooks/manager.py +403 -0
- truthound_dashboard/core/plugins/hooks/protocols.py +265 -0
- truthound_dashboard/core/plugins/lifecycle/__init__.py +41 -0
- truthound_dashboard/core/plugins/lifecycle/hot_reload.py +584 -0
- truthound_dashboard/core/plugins/lifecycle/machine.py +419 -0
- truthound_dashboard/core/plugins/lifecycle/states.py +266 -0
- truthound_dashboard/core/plugins/loader.py +504 -0
- truthound_dashboard/core/plugins/registry.py +810 -0
- truthound_dashboard/core/plugins/reporter_executor.py +588 -0
- truthound_dashboard/core/plugins/sandbox/__init__.py +59 -0
- truthound_dashboard/core/plugins/sandbox/code_validator.py +243 -0
- truthound_dashboard/core/plugins/sandbox/engines.py +770 -0
- truthound_dashboard/core/plugins/sandbox/protocols.py +194 -0
- truthound_dashboard/core/plugins/sandbox.py +617 -0
- truthound_dashboard/core/plugins/security/__init__.py +68 -0
- truthound_dashboard/core/plugins/security/analyzer.py +535 -0
- truthound_dashboard/core/plugins/security/policies.py +311 -0
- truthound_dashboard/core/plugins/security/protocols.py +296 -0
- truthound_dashboard/core/plugins/security/signing.py +842 -0
- truthound_dashboard/core/plugins/security.py +446 -0
- truthound_dashboard/core/plugins/validator_executor.py +401 -0
- truthound_dashboard/core/plugins/versioning/__init__.py +51 -0
- truthound_dashboard/core/plugins/versioning/constraints.py +377 -0
- truthound_dashboard/core/plugins/versioning/dependencies.py +541 -0
- truthound_dashboard/core/plugins/versioning/semver.py +266 -0
- truthound_dashboard/core/profile_comparison.py +601 -0
- truthound_dashboard/core/report_history.py +570 -0
- truthound_dashboard/core/reporters/__init__.py +57 -0
- truthound_dashboard/core/reporters/base.py +296 -0
- truthound_dashboard/core/reporters/csv_reporter.py +155 -0
- truthound_dashboard/core/reporters/html_reporter.py +598 -0
- truthound_dashboard/core/reporters/i18n/__init__.py +65 -0
- truthound_dashboard/core/reporters/i18n/base.py +494 -0
- truthound_dashboard/core/reporters/i18n/catalogs.py +930 -0
- truthound_dashboard/core/reporters/json_reporter.py +160 -0
- truthound_dashboard/core/reporters/junit_reporter.py +233 -0
- truthound_dashboard/core/reporters/markdown_reporter.py +207 -0
- truthound_dashboard/core/reporters/pdf_reporter.py +209 -0
- truthound_dashboard/core/reporters/registry.py +272 -0
- truthound_dashboard/core/rule_generator.py +2088 -0
- truthound_dashboard/core/scheduler.py +822 -12
- truthound_dashboard/core/schema_evolution.py +858 -0
- truthound_dashboard/core/services.py +152 -9
- truthound_dashboard/core/statistics.py +718 -0
- truthound_dashboard/core/streaming_anomaly.py +883 -0
- truthound_dashboard/core/triggers/__init__.py +45 -0
- truthound_dashboard/core/triggers/base.py +226 -0
- truthound_dashboard/core/triggers/evaluators.py +609 -0
- truthound_dashboard/core/triggers/factory.py +363 -0
- truthound_dashboard/core/unified_alerts.py +870 -0
- truthound_dashboard/core/validation_limits.py +509 -0
- truthound_dashboard/core/versioning.py +709 -0
- truthound_dashboard/core/websocket/__init__.py +59 -0
- truthound_dashboard/core/websocket/manager.py +512 -0
- truthound_dashboard/core/websocket/messages.py +130 -0
- truthound_dashboard/db/__init__.py +30 -0
- truthound_dashboard/db/models.py +3375 -3
- truthound_dashboard/main.py +22 -0
- truthound_dashboard/schemas/__init__.py +396 -1
- truthound_dashboard/schemas/anomaly.py +1258 -0
- truthound_dashboard/schemas/base.py +4 -0
- truthound_dashboard/schemas/cross_alerts.py +334 -0
- truthound_dashboard/schemas/drift_monitor.py +890 -0
- truthound_dashboard/schemas/lineage.py +428 -0
- truthound_dashboard/schemas/maintenance.py +154 -0
- truthound_dashboard/schemas/model_monitoring.py +374 -0
- truthound_dashboard/schemas/notifications_advanced.py +1363 -0
- truthound_dashboard/schemas/openlineage.py +704 -0
- truthound_dashboard/schemas/plugins.py +1293 -0
- truthound_dashboard/schemas/profile.py +420 -34
- truthound_dashboard/schemas/profile_comparison.py +242 -0
- truthound_dashboard/schemas/reports.py +285 -0
- truthound_dashboard/schemas/rule_suggestion.py +434 -0
- truthound_dashboard/schemas/schema_evolution.py +164 -0
- truthound_dashboard/schemas/source.py +117 -2
- truthound_dashboard/schemas/triggers.py +511 -0
- truthound_dashboard/schemas/unified_alerts.py +223 -0
- truthound_dashboard/schemas/validation.py +25 -1
- truthound_dashboard/schemas/validators/__init__.py +11 -0
- truthound_dashboard/schemas/validators/base.py +151 -0
- truthound_dashboard/schemas/versioning.py +152 -0
- truthound_dashboard/static/index.html +2 -2
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/METADATA +142 -22
- truthound_dashboard-1.4.0.dist-info/RECORD +239 -0
- truthound_dashboard/static/assets/index-BZG20KuF.js +0 -586
- truthound_dashboard/static/assets/index-D_HyZ3pb.css +0 -1
- truthound_dashboard/static/assets/unmerged_dictionaries-CtpqQBm0.js +0 -1
- truthound_dashboard-1.3.1.dist-info/RECORD +0 -110
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/WHEEL +0 -0
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/entry_points.txt +0 -0
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
"""Internationalized error messages for 15 languages.
|
|
2
|
+
|
|
3
|
+
This module provides a centralized error message catalog supporting
|
|
4
|
+
15 languages to match the report i18n system.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from truthound_dashboard.core.i18n import get_message, SupportedLocale
|
|
8
|
+
|
|
9
|
+
message = get_message("source_not_found", SupportedLocale.KOREAN)
|
|
10
|
+
# Returns: "데이터 소스를 찾을 수 없습니다"
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from truthound_dashboard.core.reporters.i18n.base import SupportedLocale
|
|
19
|
+
|
|
20
|
+
# Error message catalog for 15 languages
|
|
21
|
+
# Keys are error codes, values are dicts mapping locale codes to messages
|
|
22
|
+
ERROR_MESSAGES: dict[str, dict[str, str]] = {
|
|
23
|
+
# Source errors
|
|
24
|
+
"source_not_found": {
|
|
25
|
+
"en": "Data source not found",
|
|
26
|
+
"ko": "데이터 소스를 찾을 수 없습니다",
|
|
27
|
+
"ja": "データソースが見つかりません",
|
|
28
|
+
"zh": "找不到数据源",
|
|
29
|
+
"de": "Datenquelle nicht gefunden",
|
|
30
|
+
"fr": "Source de données introuvable",
|
|
31
|
+
"es": "Fuente de datos no encontrada",
|
|
32
|
+
"pt": "Fonte de dados não encontrada",
|
|
33
|
+
"it": "Origine dati non trovata",
|
|
34
|
+
"ru": "Источник данных не найден",
|
|
35
|
+
"ar": "مصدر البيانات غير موجود",
|
|
36
|
+
"th": "ไม่พบแหล่งข้อมูล",
|
|
37
|
+
"vi": "Không tìm thấy nguồn dữ liệu",
|
|
38
|
+
"id": "Sumber data tidak ditemukan",
|
|
39
|
+
"tr": "Veri kaynağı bulunamadı",
|
|
40
|
+
},
|
|
41
|
+
"source_already_exists": {
|
|
42
|
+
"en": "Data source already exists",
|
|
43
|
+
"ko": "데이터 소스가 이미 존재합니다",
|
|
44
|
+
"ja": "データソースは既に存在します",
|
|
45
|
+
"zh": "数据源已存在",
|
|
46
|
+
"de": "Datenquelle existiert bereits",
|
|
47
|
+
"fr": "La source de données existe déjà",
|
|
48
|
+
"es": "La fuente de datos ya existe",
|
|
49
|
+
"pt": "A fonte de dados já existe",
|
|
50
|
+
"it": "L'origine dati esiste già",
|
|
51
|
+
"ru": "Источник данных уже существует",
|
|
52
|
+
"ar": "مصدر البيانات موجود بالفعل",
|
|
53
|
+
"th": "แหล่งข้อมูลมีอยู่แล้ว",
|
|
54
|
+
"vi": "Nguồn dữ liệu đã tồn tại",
|
|
55
|
+
"id": "Sumber data sudah ada",
|
|
56
|
+
"tr": "Veri kaynağı zaten mevcut",
|
|
57
|
+
},
|
|
58
|
+
"source_connection_failed": {
|
|
59
|
+
"en": "Failed to connect to data source",
|
|
60
|
+
"ko": "데이터 소스에 연결할 수 없습니다",
|
|
61
|
+
"ja": "データソースへの接続に失敗しました",
|
|
62
|
+
"zh": "无法连接到数据源",
|
|
63
|
+
"de": "Verbindung zur Datenquelle fehlgeschlagen",
|
|
64
|
+
"fr": "Échec de connexion à la source de données",
|
|
65
|
+
"es": "Error al conectar con la fuente de datos",
|
|
66
|
+
"pt": "Falha ao conectar à fonte de dados",
|
|
67
|
+
"it": "Connessione all'origine dati fallita",
|
|
68
|
+
"ru": "Не удалось подключиться к источнику данных",
|
|
69
|
+
"ar": "فشل الاتصال بمصدر البيانات",
|
|
70
|
+
"th": "ไม่สามารถเชื่อมต่อกับแหล่งข้อมูลได้",
|
|
71
|
+
"vi": "Không thể kết nối với nguồn dữ liệu",
|
|
72
|
+
"id": "Gagal terhubung ke sumber data",
|
|
73
|
+
"tr": "Veri kaynağına bağlanılamadı",
|
|
74
|
+
},
|
|
75
|
+
# Validation errors
|
|
76
|
+
"validation_failed": {
|
|
77
|
+
"en": "Validation failed",
|
|
78
|
+
"ko": "검증에 실패했습니다",
|
|
79
|
+
"ja": "検証に失敗しました",
|
|
80
|
+
"zh": "验证失败",
|
|
81
|
+
"de": "Validierung fehlgeschlagen",
|
|
82
|
+
"fr": "Échec de la validation",
|
|
83
|
+
"es": "La validación falló",
|
|
84
|
+
"pt": "A validação falhou",
|
|
85
|
+
"it": "Validazione fallita",
|
|
86
|
+
"ru": "Проверка не пройдена",
|
|
87
|
+
"ar": "فشل التحقق",
|
|
88
|
+
"th": "การตรวจสอบล้มเหลว",
|
|
89
|
+
"vi": "Xác thực thất bại",
|
|
90
|
+
"id": "Validasi gagal",
|
|
91
|
+
"tr": "Doğrulama başarısız",
|
|
92
|
+
},
|
|
93
|
+
"validation_in_progress": {
|
|
94
|
+
"en": "Validation is already in progress",
|
|
95
|
+
"ko": "검증이 이미 진행 중입니다",
|
|
96
|
+
"ja": "検証は既に進行中です",
|
|
97
|
+
"zh": "验证已在进行中",
|
|
98
|
+
"de": "Validierung läuft bereits",
|
|
99
|
+
"fr": "La validation est déjà en cours",
|
|
100
|
+
"es": "La validación ya está en progreso",
|
|
101
|
+
"pt": "A validação já está em andamento",
|
|
102
|
+
"it": "La validazione è già in corso",
|
|
103
|
+
"ru": "Проверка уже выполняется",
|
|
104
|
+
"ar": "التحقق قيد التنفيذ بالفعل",
|
|
105
|
+
"th": "การตรวจสอบกำลังดำเนินการอยู่แล้ว",
|
|
106
|
+
"vi": "Quá trình xác thực đang được thực hiện",
|
|
107
|
+
"id": "Validasi sudah berjalan",
|
|
108
|
+
"tr": "Doğrulama zaten devam ediyor",
|
|
109
|
+
},
|
|
110
|
+
"validator_not_found": {
|
|
111
|
+
"en": "Validator not found",
|
|
112
|
+
"ko": "검증기를 찾을 수 없습니다",
|
|
113
|
+
"ja": "バリデーターが見つかりません",
|
|
114
|
+
"zh": "找不到验证器",
|
|
115
|
+
"de": "Validator nicht gefunden",
|
|
116
|
+
"fr": "Validateur introuvable",
|
|
117
|
+
"es": "Validador no encontrado",
|
|
118
|
+
"pt": "Validador não encontrado",
|
|
119
|
+
"it": "Validatore non trovato",
|
|
120
|
+
"ru": "Валидатор не найден",
|
|
121
|
+
"ar": "أداة التحقق غير موجودة",
|
|
122
|
+
"th": "ไม่พบตัวตรวจสอบ",
|
|
123
|
+
"vi": "Không tìm thấy trình xác thực",
|
|
124
|
+
"id": "Validator tidak ditemukan",
|
|
125
|
+
"tr": "Doğrulayıcı bulunamadı",
|
|
126
|
+
},
|
|
127
|
+
# Schema errors
|
|
128
|
+
"schema_not_found": {
|
|
129
|
+
"en": "Schema not found",
|
|
130
|
+
"ko": "스키마를 찾을 수 없습니다",
|
|
131
|
+
"ja": "スキーマが見つかりません",
|
|
132
|
+
"zh": "找不到模式",
|
|
133
|
+
"de": "Schema nicht gefunden",
|
|
134
|
+
"fr": "Schéma introuvable",
|
|
135
|
+
"es": "Esquema no encontrado",
|
|
136
|
+
"pt": "Schema não encontrado",
|
|
137
|
+
"it": "Schema non trovato",
|
|
138
|
+
"ru": "Схема не найдена",
|
|
139
|
+
"ar": "المخطط غير موجود",
|
|
140
|
+
"th": "ไม่พบ Schema",
|
|
141
|
+
"vi": "Không tìm thấy lược đồ",
|
|
142
|
+
"id": "Schema tidak ditemukan",
|
|
143
|
+
"tr": "Şema bulunamadı",
|
|
144
|
+
},
|
|
145
|
+
"schema_invalid": {
|
|
146
|
+
"en": "Invalid schema format",
|
|
147
|
+
"ko": "잘못된 스키마 형식입니다",
|
|
148
|
+
"ja": "無効なスキーマ形式です",
|
|
149
|
+
"zh": "无效的模式格式",
|
|
150
|
+
"de": "Ungültiges Schema-Format",
|
|
151
|
+
"fr": "Format de schéma invalide",
|
|
152
|
+
"es": "Formato de esquema inválido",
|
|
153
|
+
"pt": "Formato de schema inválido",
|
|
154
|
+
"it": "Formato schema non valido",
|
|
155
|
+
"ru": "Недопустимый формат схемы",
|
|
156
|
+
"ar": "تنسيق المخطط غير صالح",
|
|
157
|
+
"th": "รูปแบบ Schema ไม่ถูกต้อง",
|
|
158
|
+
"vi": "Định dạng lược đồ không hợp lệ",
|
|
159
|
+
"id": "Format schema tidak valid",
|
|
160
|
+
"tr": "Geçersiz şema formatı",
|
|
161
|
+
},
|
|
162
|
+
# Schedule errors
|
|
163
|
+
"schedule_not_found": {
|
|
164
|
+
"en": "Schedule not found",
|
|
165
|
+
"ko": "스케줄을 찾을 수 없습니다",
|
|
166
|
+
"ja": "スケジュールが見つかりません",
|
|
167
|
+
"zh": "找不到计划",
|
|
168
|
+
"de": "Zeitplan nicht gefunden",
|
|
169
|
+
"fr": "Planification introuvable",
|
|
170
|
+
"es": "Programación no encontrada",
|
|
171
|
+
"pt": "Agendamento não encontrado",
|
|
172
|
+
"it": "Pianificazione non trovata",
|
|
173
|
+
"ru": "Расписание не найдено",
|
|
174
|
+
"ar": "الجدول غير موجود",
|
|
175
|
+
"th": "ไม่พบตารางเวลา",
|
|
176
|
+
"vi": "Không tìm thấy lịch trình",
|
|
177
|
+
"id": "Jadwal tidak ditemukan",
|
|
178
|
+
"tr": "Zamanlama bulunamadı",
|
|
179
|
+
},
|
|
180
|
+
"schedule_invalid_cron": {
|
|
181
|
+
"en": "Invalid cron expression",
|
|
182
|
+
"ko": "잘못된 cron 표현식입니다",
|
|
183
|
+
"ja": "無効なcron式です",
|
|
184
|
+
"zh": "无效的cron表达式",
|
|
185
|
+
"de": "Ungültiger Cron-Ausdruck",
|
|
186
|
+
"fr": "Expression cron invalide",
|
|
187
|
+
"es": "Expresión cron inválida",
|
|
188
|
+
"pt": "Expressão cron inválida",
|
|
189
|
+
"it": "Espressione cron non valida",
|
|
190
|
+
"ru": "Недопустимое cron-выражение",
|
|
191
|
+
"ar": "تعبير cron غير صالح",
|
|
192
|
+
"th": "นิพจน์ cron ไม่ถูกต้อง",
|
|
193
|
+
"vi": "Biểu thức cron không hợp lệ",
|
|
194
|
+
"id": "Ekspresi cron tidak valid",
|
|
195
|
+
"tr": "Geçersiz cron ifadesi",
|
|
196
|
+
},
|
|
197
|
+
# Notification errors
|
|
198
|
+
"notification_channel_not_found": {
|
|
199
|
+
"en": "Notification channel not found",
|
|
200
|
+
"ko": "알림 채널을 찾을 수 없습니다",
|
|
201
|
+
"ja": "通知チャンネルが見つかりません",
|
|
202
|
+
"zh": "找不到通知渠道",
|
|
203
|
+
"de": "Benachrichtigungskanal nicht gefunden",
|
|
204
|
+
"fr": "Canal de notification introuvable",
|
|
205
|
+
"es": "Canal de notificación no encontrado",
|
|
206
|
+
"pt": "Canal de notificação não encontrado",
|
|
207
|
+
"it": "Canale di notifica non trovato",
|
|
208
|
+
"ru": "Канал уведомлений не найден",
|
|
209
|
+
"ar": "قناة الإشعارات غير موجودة",
|
|
210
|
+
"th": "ไม่พบช่องทางการแจ้งเตือน",
|
|
211
|
+
"vi": "Không tìm thấy kênh thông báo",
|
|
212
|
+
"id": "Saluran notifikasi tidak ditemukan",
|
|
213
|
+
"tr": "Bildirim kanalı bulunamadı",
|
|
214
|
+
},
|
|
215
|
+
"notification_send_failed": {
|
|
216
|
+
"en": "Failed to send notification",
|
|
217
|
+
"ko": "알림 전송에 실패했습니다",
|
|
218
|
+
"ja": "通知の送信に失敗しました",
|
|
219
|
+
"zh": "发送通知失败",
|
|
220
|
+
"de": "Benachrichtigung konnte nicht gesendet werden",
|
|
221
|
+
"fr": "Échec de l'envoi de la notification",
|
|
222
|
+
"es": "Error al enviar la notificación",
|
|
223
|
+
"pt": "Falha ao enviar notificação",
|
|
224
|
+
"it": "Invio notifica fallito",
|
|
225
|
+
"ru": "Не удалось отправить уведомление",
|
|
226
|
+
"ar": "فشل إرسال الإشعار",
|
|
227
|
+
"th": "ไม่สามารถส่งการแจ้งเตือนได้",
|
|
228
|
+
"vi": "Gửi thông báo thất bại",
|
|
229
|
+
"id": "Gagal mengirim notifikasi",
|
|
230
|
+
"tr": "Bildirim gönderilemedi",
|
|
231
|
+
},
|
|
232
|
+
# Report errors
|
|
233
|
+
"report_generation_failed": {
|
|
234
|
+
"en": "Report generation failed",
|
|
235
|
+
"ko": "리포트 생성에 실패했습니다",
|
|
236
|
+
"ja": "レポート生成に失敗しました",
|
|
237
|
+
"zh": "报告生成失败",
|
|
238
|
+
"de": "Berichterstellung fehlgeschlagen",
|
|
239
|
+
"fr": "Échec de la génération du rapport",
|
|
240
|
+
"es": "Error al generar el informe",
|
|
241
|
+
"pt": "Falha na geração do relatório",
|
|
242
|
+
"it": "Generazione report fallita",
|
|
243
|
+
"ru": "Не удалось создать отчет",
|
|
244
|
+
"ar": "فشل إنشاء التقرير",
|
|
245
|
+
"th": "การสร้างรายงานล้มเหลว",
|
|
246
|
+
"vi": "Tạo báo cáo thất bại",
|
|
247
|
+
"id": "Pembuatan laporan gagal",
|
|
248
|
+
"tr": "Rapor oluşturma başarısız",
|
|
249
|
+
},
|
|
250
|
+
"report_format_unsupported": {
|
|
251
|
+
"en": "Unsupported report format",
|
|
252
|
+
"ko": "지원하지 않는 리포트 형식입니다",
|
|
253
|
+
"ja": "サポートされていないレポート形式です",
|
|
254
|
+
"zh": "不支持的报告格式",
|
|
255
|
+
"de": "Nicht unterstütztes Berichtsformat",
|
|
256
|
+
"fr": "Format de rapport non pris en charge",
|
|
257
|
+
"es": "Formato de informe no compatible",
|
|
258
|
+
"pt": "Formato de relatório não suportado",
|
|
259
|
+
"it": "Formato report non supportato",
|
|
260
|
+
"ru": "Неподдерживаемый формат отчета",
|
|
261
|
+
"ar": "تنسيق التقرير غير مدعوم",
|
|
262
|
+
"th": "รูปแบบรายงานไม่รองรับ",
|
|
263
|
+
"vi": "Định dạng báo cáo không được hỗ trợ",
|
|
264
|
+
"id": "Format laporan tidak didukung",
|
|
265
|
+
"tr": "Desteklenmeyen rapor formatı",
|
|
266
|
+
},
|
|
267
|
+
# General errors
|
|
268
|
+
"internal_error": {
|
|
269
|
+
"en": "An internal error occurred",
|
|
270
|
+
"ko": "내부 오류가 발생했습니다",
|
|
271
|
+
"ja": "内部エラーが発生しました",
|
|
272
|
+
"zh": "发生内部错误",
|
|
273
|
+
"de": "Ein interner Fehler ist aufgetreten",
|
|
274
|
+
"fr": "Une erreur interne s'est produite",
|
|
275
|
+
"es": "Se produjo un error interno",
|
|
276
|
+
"pt": "Ocorreu um erro interno",
|
|
277
|
+
"it": "Si è verificato un errore interno",
|
|
278
|
+
"ru": "Произошла внутренняя ошибка",
|
|
279
|
+
"ar": "حدث خطأ داخلي",
|
|
280
|
+
"th": "เกิดข้อผิดพลาดภายใน",
|
|
281
|
+
"vi": "Đã xảy ra lỗi nội bộ",
|
|
282
|
+
"id": "Terjadi kesalahan internal",
|
|
283
|
+
"tr": "Dahili bir hata oluştu",
|
|
284
|
+
},
|
|
285
|
+
"invalid_request": {
|
|
286
|
+
"en": "Invalid request",
|
|
287
|
+
"ko": "잘못된 요청입니다",
|
|
288
|
+
"ja": "無効なリクエストです",
|
|
289
|
+
"zh": "无效请求",
|
|
290
|
+
"de": "Ungültige Anfrage",
|
|
291
|
+
"fr": "Requête invalide",
|
|
292
|
+
"es": "Solicitud inválida",
|
|
293
|
+
"pt": "Requisição inválida",
|
|
294
|
+
"it": "Richiesta non valida",
|
|
295
|
+
"ru": "Недопустимый запрос",
|
|
296
|
+
"ar": "طلب غير صالح",
|
|
297
|
+
"th": "คำขอไม่ถูกต้อง",
|
|
298
|
+
"vi": "Yêu cầu không hợp lệ",
|
|
299
|
+
"id": "Permintaan tidak valid",
|
|
300
|
+
"tr": "Geçersiz istek",
|
|
301
|
+
},
|
|
302
|
+
"unauthorized": {
|
|
303
|
+
"en": "Unauthorized access",
|
|
304
|
+
"ko": "권한이 없습니다",
|
|
305
|
+
"ja": "アクセス権限がありません",
|
|
306
|
+
"zh": "未授权访问",
|
|
307
|
+
"de": "Unbefugter Zugriff",
|
|
308
|
+
"fr": "Accès non autorisé",
|
|
309
|
+
"es": "Acceso no autorizado",
|
|
310
|
+
"pt": "Acesso não autorizado",
|
|
311
|
+
"it": "Accesso non autorizzato",
|
|
312
|
+
"ru": "Несанкционированный доступ",
|
|
313
|
+
"ar": "وصول غير مصرح به",
|
|
314
|
+
"th": "ไม่ได้รับอนุญาต",
|
|
315
|
+
"vi": "Truy cập trái phép",
|
|
316
|
+
"id": "Akses tidak sah",
|
|
317
|
+
"tr": "Yetkisiz erişim",
|
|
318
|
+
},
|
|
319
|
+
"not_found": {
|
|
320
|
+
"en": "Resource not found",
|
|
321
|
+
"ko": "리소스를 찾을 수 없습니다",
|
|
322
|
+
"ja": "リソースが見つかりません",
|
|
323
|
+
"zh": "找不到资源",
|
|
324
|
+
"de": "Ressource nicht gefunden",
|
|
325
|
+
"fr": "Ressource introuvable",
|
|
326
|
+
"es": "Recurso no encontrado",
|
|
327
|
+
"pt": "Recurso não encontrado",
|
|
328
|
+
"it": "Risorsa non trovata",
|
|
329
|
+
"ru": "Ресурс не найден",
|
|
330
|
+
"ar": "المورد غير موجود",
|
|
331
|
+
"th": "ไม่พบทรัพยากร",
|
|
332
|
+
"vi": "Không tìm thấy tài nguyên",
|
|
333
|
+
"id": "Sumber daya tidak ditemukan",
|
|
334
|
+
"tr": "Kaynak bulunamadı",
|
|
335
|
+
},
|
|
336
|
+
"rate_limited": {
|
|
337
|
+
"en": "Rate limit exceeded",
|
|
338
|
+
"ko": "요청 한도를 초과했습니다",
|
|
339
|
+
"ja": "レート制限を超過しました",
|
|
340
|
+
"zh": "超出速率限制",
|
|
341
|
+
"de": "Ratenlimit überschritten",
|
|
342
|
+
"fr": "Limite de requêtes dépassée",
|
|
343
|
+
"es": "Límite de solicitudes excedido",
|
|
344
|
+
"pt": "Limite de requisições excedido",
|
|
345
|
+
"it": "Limite di richieste superato",
|
|
346
|
+
"ru": "Превышен лимит запросов",
|
|
347
|
+
"ar": "تم تجاوز حد المعدل",
|
|
348
|
+
"th": "เกินขีดจำกัดการร้องขอ",
|
|
349
|
+
"vi": "Vượt quá giới hạn yêu cầu",
|
|
350
|
+
"id": "Batas permintaan terlampaui",
|
|
351
|
+
"tr": "İstek limiti aşıldı",
|
|
352
|
+
},
|
|
353
|
+
# Drift detection errors
|
|
354
|
+
"drift_comparison_failed": {
|
|
355
|
+
"en": "Drift comparison failed",
|
|
356
|
+
"ko": "드리프트 비교에 실패했습니다",
|
|
357
|
+
"ja": "ドリフト比較に失敗しました",
|
|
358
|
+
"zh": "漂移比较失败",
|
|
359
|
+
"de": "Drift-Vergleich fehlgeschlagen",
|
|
360
|
+
"fr": "Échec de la comparaison de dérive",
|
|
361
|
+
"es": "Error en la comparación de deriva",
|
|
362
|
+
"pt": "Falha na comparação de drift",
|
|
363
|
+
"it": "Confronto drift fallito",
|
|
364
|
+
"ru": "Сравнение дрейфа не удалось",
|
|
365
|
+
"ar": "فشل مقارنة الانحراف",
|
|
366
|
+
"th": "การเปรียบเทียบ Drift ล้มเหลว",
|
|
367
|
+
"vi": "So sánh drift thất bại",
|
|
368
|
+
"id": "Perbandingan drift gagal",
|
|
369
|
+
"tr": "Drift karşılaştırması başarısız",
|
|
370
|
+
},
|
|
371
|
+
# Anomaly detection errors
|
|
372
|
+
"anomaly_detection_failed": {
|
|
373
|
+
"en": "Anomaly detection failed",
|
|
374
|
+
"ko": "이상 탐지에 실패했습니다",
|
|
375
|
+
"ja": "異常検出に失敗しました",
|
|
376
|
+
"zh": "异常检测失败",
|
|
377
|
+
"de": "Anomalieerkennung fehlgeschlagen",
|
|
378
|
+
"fr": "Échec de la détection d'anomalies",
|
|
379
|
+
"es": "Error en la detección de anomalías",
|
|
380
|
+
"pt": "Falha na detecção de anomalias",
|
|
381
|
+
"it": "Rilevamento anomalie fallito",
|
|
382
|
+
"ru": "Обнаружение аномалий не удалось",
|
|
383
|
+
"ar": "فشل اكتشاف الشذوذ",
|
|
384
|
+
"th": "การตรวจจับความผิดปกติล้มเหลว",
|
|
385
|
+
"vi": "Phát hiện bất thường thất bại",
|
|
386
|
+
"id": "Deteksi anomali gagal",
|
|
387
|
+
"tr": "Anomali tespiti başarısız",
|
|
388
|
+
},
|
|
389
|
+
# Profile errors
|
|
390
|
+
"profile_not_found": {
|
|
391
|
+
"en": "Profile not found",
|
|
392
|
+
"ko": "프로파일을 찾을 수 없습니다",
|
|
393
|
+
"ja": "プロファイルが見つかりません",
|
|
394
|
+
"zh": "找不到配置文件",
|
|
395
|
+
"de": "Profil nicht gefunden",
|
|
396
|
+
"fr": "Profil introuvable",
|
|
397
|
+
"es": "Perfil no encontrado",
|
|
398
|
+
"pt": "Perfil não encontrado",
|
|
399
|
+
"it": "Profilo non trovato",
|
|
400
|
+
"ru": "Профиль не найден",
|
|
401
|
+
"ar": "الملف الشخصي غير موجود",
|
|
402
|
+
"th": "ไม่พบโปรไฟล์",
|
|
403
|
+
"vi": "Không tìm thấy hồ sơ",
|
|
404
|
+
"id": "Profil tidak ditemukan",
|
|
405
|
+
"tr": "Profil bulunamadı",
|
|
406
|
+
},
|
|
407
|
+
# Plugin errors
|
|
408
|
+
"plugin_not_found": {
|
|
409
|
+
"en": "Plugin not found",
|
|
410
|
+
"ko": "플러그인을 찾을 수 없습니다",
|
|
411
|
+
"ja": "プラグインが見つかりません",
|
|
412
|
+
"zh": "找不到插件",
|
|
413
|
+
"de": "Plugin nicht gefunden",
|
|
414
|
+
"fr": "Plugin introuvable",
|
|
415
|
+
"es": "Plugin no encontrado",
|
|
416
|
+
"pt": "Plugin não encontrado",
|
|
417
|
+
"it": "Plugin non trovato",
|
|
418
|
+
"ru": "Плагин не найден",
|
|
419
|
+
"ar": "البرنامج المساعد غير موجود",
|
|
420
|
+
"th": "ไม่พบปลั๊กอิน",
|
|
421
|
+
"vi": "Không tìm thấy plugin",
|
|
422
|
+
"id": "Plugin tidak ditemukan",
|
|
423
|
+
"tr": "Eklenti bulunamadı",
|
|
424
|
+
},
|
|
425
|
+
"plugin_install_failed": {
|
|
426
|
+
"en": "Plugin installation failed",
|
|
427
|
+
"ko": "플러그인 설치에 실패했습니다",
|
|
428
|
+
"ja": "プラグインのインストールに失敗しました",
|
|
429
|
+
"zh": "插件安装失败",
|
|
430
|
+
"de": "Plugin-Installation fehlgeschlagen",
|
|
431
|
+
"fr": "Échec de l'installation du plugin",
|
|
432
|
+
"es": "Error al instalar el plugin",
|
|
433
|
+
"pt": "Falha na instalação do plugin",
|
|
434
|
+
"it": "Installazione plugin fallita",
|
|
435
|
+
"ru": "Установка плагина не удалась",
|
|
436
|
+
"ar": "فشل تثبيت البرنامج المساعد",
|
|
437
|
+
"th": "การติดตั้งปลั๊กอินล้มเหลว",
|
|
438
|
+
"vi": "Cài đặt plugin thất bại",
|
|
439
|
+
"id": "Instalasi plugin gagal",
|
|
440
|
+
"tr": "Eklenti kurulumu başarısız",
|
|
441
|
+
},
|
|
442
|
+
# Lineage errors
|
|
443
|
+
"lineage_not_found": {
|
|
444
|
+
"en": "Lineage information not found",
|
|
445
|
+
"ko": "리니지 정보를 찾을 수 없습니다",
|
|
446
|
+
"ja": "リネージ情報が見つかりません",
|
|
447
|
+
"zh": "找不到血统信息",
|
|
448
|
+
"de": "Abstammungsinformationen nicht gefunden",
|
|
449
|
+
"fr": "Informations de lignage introuvables",
|
|
450
|
+
"es": "Información de linaje no encontrada",
|
|
451
|
+
"pt": "Informações de linhagem não encontradas",
|
|
452
|
+
"it": "Informazioni di lineage non trovate",
|
|
453
|
+
"ru": "Информация о происхождении не найдена",
|
|
454
|
+
"ar": "معلومات النسب غير موجودة",
|
|
455
|
+
"th": "ไม่พบข้อมูล Lineage",
|
|
456
|
+
"vi": "Không tìm thấy thông tin lineage",
|
|
457
|
+
"id": "Informasi lineage tidak ditemukan",
|
|
458
|
+
"tr": "Köken bilgisi bulunamadı",
|
|
459
|
+
},
|
|
460
|
+
# Trigger errors
|
|
461
|
+
"trigger_not_found": {
|
|
462
|
+
"en": "Trigger not found",
|
|
463
|
+
"ko": "트리거를 찾을 수 없습니다",
|
|
464
|
+
"ja": "トリガーが見つかりません",
|
|
465
|
+
"zh": "找不到触发器",
|
|
466
|
+
"de": "Trigger nicht gefunden",
|
|
467
|
+
"fr": "Déclencheur introuvable",
|
|
468
|
+
"es": "Disparador no encontrado",
|
|
469
|
+
"pt": "Gatilho não encontrado",
|
|
470
|
+
"it": "Trigger non trovato",
|
|
471
|
+
"ru": "Триггер не найден",
|
|
472
|
+
"ar": "المشغل غير موجود",
|
|
473
|
+
"th": "ไม่พบทริกเกอร์",
|
|
474
|
+
"vi": "Không tìm thấy trigger",
|
|
475
|
+
"id": "Trigger tidak ditemukan",
|
|
476
|
+
"tr": "Tetikleyici bulunamadı",
|
|
477
|
+
},
|
|
478
|
+
"trigger_execution_failed": {
|
|
479
|
+
"en": "Trigger execution failed",
|
|
480
|
+
"ko": "트리거 실행에 실패했습니다",
|
|
481
|
+
"ja": "トリガーの実行に失敗しました",
|
|
482
|
+
"zh": "触发器执行失败",
|
|
483
|
+
"de": "Trigger-Ausführung fehlgeschlagen",
|
|
484
|
+
"fr": "Échec de l'exécution du déclencheur",
|
|
485
|
+
"es": "Error en la ejecución del disparador",
|
|
486
|
+
"pt": "Falha na execução do gatilho",
|
|
487
|
+
"it": "Esecuzione trigger fallita",
|
|
488
|
+
"ru": "Выполнение триггера не удалось",
|
|
489
|
+
"ar": "فشل تنفيذ المشغل",
|
|
490
|
+
"th": "การดำเนินการทริกเกอร์ล้มเหลว",
|
|
491
|
+
"vi": "Thực thi trigger thất bại",
|
|
492
|
+
"id": "Eksekusi trigger gagal",
|
|
493
|
+
"tr": "Tetikleyici yürütme başarısız",
|
|
494
|
+
},
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
def get_message(
|
|
499
|
+
key: str,
|
|
500
|
+
locale: SupportedLocale | str,
|
|
501
|
+
default: str | None = None,
|
|
502
|
+
) -> str:
|
|
503
|
+
"""Get localized error message.
|
|
504
|
+
|
|
505
|
+
Args:
|
|
506
|
+
key: Error message key (e.g., "source_not_found")
|
|
507
|
+
locale: Target locale (SupportedLocale enum or string code)
|
|
508
|
+
default: Default message if key not found
|
|
509
|
+
|
|
510
|
+
Returns:
|
|
511
|
+
Localized error message string.
|
|
512
|
+
|
|
513
|
+
Example:
|
|
514
|
+
>>> from truthound_dashboard.core.i18n import get_message, SupportedLocale
|
|
515
|
+
>>> get_message("source_not_found", SupportedLocale.KOREAN)
|
|
516
|
+
'데이터 소스를 찾을 수 없습니다'
|
|
517
|
+
>>> get_message("source_not_found", "ja")
|
|
518
|
+
'データソースが見つかりません'
|
|
519
|
+
"""
|
|
520
|
+
# Convert enum to string if needed
|
|
521
|
+
locale_code = locale.value if hasattr(locale, "value") else str(locale)
|
|
522
|
+
|
|
523
|
+
messages = ERROR_MESSAGES.get(key)
|
|
524
|
+
if not messages:
|
|
525
|
+
return default or key
|
|
526
|
+
|
|
527
|
+
# Try exact locale match
|
|
528
|
+
if locale_code in messages:
|
|
529
|
+
return messages[locale_code]
|
|
530
|
+
|
|
531
|
+
# Fallback to English
|
|
532
|
+
if "en" in messages:
|
|
533
|
+
return messages["en"]
|
|
534
|
+
|
|
535
|
+
return default or key
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def get_all_messages(locale: SupportedLocale | str) -> dict[str, str]:
|
|
539
|
+
"""Get all error messages for a locale.
|
|
540
|
+
|
|
541
|
+
Args:
|
|
542
|
+
locale: Target locale (SupportedLocale enum or string code)
|
|
543
|
+
|
|
544
|
+
Returns:
|
|
545
|
+
Dictionary mapping error keys to localized messages.
|
|
546
|
+
|
|
547
|
+
Example:
|
|
548
|
+
>>> from truthound_dashboard.core.i18n import get_all_messages
|
|
549
|
+
>>> messages = get_all_messages("ko")
|
|
550
|
+
>>> messages["source_not_found"]
|
|
551
|
+
'데이터 소스를 찾을 수 없습니다'
|
|
552
|
+
"""
|
|
553
|
+
locale_code = locale.value if hasattr(locale, "value") else str(locale)
|
|
554
|
+
|
|
555
|
+
result = {}
|
|
556
|
+
for key, messages in ERROR_MESSAGES.items():
|
|
557
|
+
if locale_code in messages:
|
|
558
|
+
result[key] = messages[locale_code]
|
|
559
|
+
elif "en" in messages:
|
|
560
|
+
result[key] = messages["en"]
|
|
561
|
+
else:
|
|
562
|
+
result[key] = key
|
|
563
|
+
|
|
564
|
+
return result
|