- verbeteringen client
- Invoer van een 'constanten' cache op niveau van useTranslation.js, om in de ProgressTracker de boodschappen in de juiste taal te zetten.
This commit is contained in:
@@ -167,6 +167,94 @@ export function useTranslation() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Global cache for constants - shared across all component instances
|
||||||
|
const CONSTANTS_CACHE = {
|
||||||
|
currentLanguage: null,
|
||||||
|
translations: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composable for translating application constants with global caching
|
||||||
|
* This ensures all component instances share the same cached translations
|
||||||
|
*/
|
||||||
|
export function useConstantsTranslation() {
|
||||||
|
const { translateSafe } = useTranslation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate constants with global caching
|
||||||
|
* @param {Object} constants - Object with key-value pairs of constants to translate
|
||||||
|
* @param {string} targetLang - Target language code
|
||||||
|
* @param {Object} options - Translation options
|
||||||
|
* @returns {Promise<Object>} Object with translated constants
|
||||||
|
*/
|
||||||
|
const translateConstants = async (constants, targetLang, options = {}) => {
|
||||||
|
console.log('useConstantsTranslation: translateConstants called', { targetLang, currentCached: CONSTANTS_CACHE.currentLanguage });
|
||||||
|
|
||||||
|
// Check if we already have translations for this language
|
||||||
|
if (CONSTANTS_CACHE.currentLanguage === targetLang && CONSTANTS_CACHE.translations) {
|
||||||
|
console.log('useConstantsTranslation: Using cached translations for', targetLang);
|
||||||
|
return { ...CONSTANTS_CACHE.translations };
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('useConstantsTranslation: Translating constants to', targetLang);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const translated = {};
|
||||||
|
|
||||||
|
// Translate each constant
|
||||||
|
for (const [key, originalText] of Object.entries(constants)) {
|
||||||
|
translated[key] = await translateSafe(originalText, targetLang, {
|
||||||
|
context: 'constants',
|
||||||
|
fallbackText: originalText,
|
||||||
|
...options
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update global cache
|
||||||
|
CONSTANTS_CACHE.currentLanguage = targetLang;
|
||||||
|
CONSTANTS_CACHE.translations = translated;
|
||||||
|
|
||||||
|
console.log('useConstantsTranslation: Successfully translated and cached constants');
|
||||||
|
return translated;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('useConstantsTranslation: Error translating constants:', error);
|
||||||
|
// Return original constants as fallback
|
||||||
|
return { ...constants };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cached translations for current language
|
||||||
|
* @returns {Object|null} Cached translations or null if not available
|
||||||
|
*/
|
||||||
|
const getCachedTranslations = () => {
|
||||||
|
return CONSTANTS_CACHE.currentLanguage ? { ...CONSTANTS_CACHE.translations } : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the constants cache (useful for testing or language reset)
|
||||||
|
*/
|
||||||
|
const clearCache = () => {
|
||||||
|
CONSTANTS_CACHE.currentLanguage = null;
|
||||||
|
CONSTANTS_CACHE.translations = {};
|
||||||
|
console.log('useConstantsTranslation: Cache cleared');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current cached language
|
||||||
|
*/
|
||||||
|
const getCachedLanguage = () => {
|
||||||
|
return CONSTANTS_CACHE.currentLanguage;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
translateConstants,
|
||||||
|
getCachedTranslations,
|
||||||
|
clearCache,
|
||||||
|
getCachedLanguage
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplified composable for basic translation needs
|
* Simplified composable for basic translation needs
|
||||||
* Use this when you only need simple text translation
|
* Use this when you only need simple text translation
|
||||||
|
|||||||
@@ -243,6 +243,7 @@ export default {
|
|||||||
if (eventData.answer) {
|
if (eventData.answer) {
|
||||||
console.log('Updating message content with answer:', eventData.answer);
|
console.log('Updating message content with answer:', eventData.answer);
|
||||||
this.message.content = eventData.answer;
|
this.message.content = eventData.answer;
|
||||||
|
this.message.originalContent = eventData.answer;
|
||||||
} else {
|
} else {
|
||||||
console.error('No answer in specialist-complete event data');
|
console.error('No answer in specialist-complete event data');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,15 @@ export default {
|
|||||||
const firstMessage = this.messages[0];
|
const firstMessage = this.messages[0];
|
||||||
|
|
||||||
// Controleer of we een originele inhoud hebben om te vertalen
|
// Controleer of we een originele inhoud hebben om te vertalen
|
||||||
if (firstMessage.originalContent) {
|
if (firstMessage.content) {
|
||||||
|
|
||||||
|
if (!firstMessage.originalContent) {
|
||||||
|
firstMessage.originalContent = firstMessage.content;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Originele inhoud van eerste AI bericht:', firstMessage.originalContent);
|
||||||
|
console.log('Content eerste AI bericht:', firstMessage.content);
|
||||||
|
|
||||||
console.log('Vertaling van eerste AI bericht naar:', event.detail.language);
|
console.log('Vertaling van eerste AI bericht naar:', event.detail.language);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -22,9 +22,9 @@
|
|||||||
<span v-else-if="isCompleted" class="status-icon completed progress-icon">✓</span>
|
<span v-else-if="isCompleted" class="status-icon completed progress-icon">✓</span>
|
||||||
|
|
||||||
<!-- Status tekst -->
|
<!-- Status tekst -->
|
||||||
<span v-if="error">Fout bij verwerking</span>
|
<span v-if="error">{{ errorText }}</span>
|
||||||
<span v-else-if="isCompleted">Verwerking voltooid</span>
|
<span v-else-if="isCompleted">{{ completedText }}</span>
|
||||||
<span v-else>Bezig met redeneren...</span>
|
<span v-else>{{ processingText }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress-toggle">
|
<div class="progress-toggle">
|
||||||
{{ isExpanded ? '▼' : '◄' }}
|
{{ isExpanded ? '▼' : '◄' }}
|
||||||
@@ -53,6 +53,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { useTranslationClient, useConstantsTranslation } from '../js/composables/useTranslation.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ProgressTracker',
|
name: 'ProgressTracker',
|
||||||
props: {
|
props: {
|
||||||
@@ -74,21 +76,102 @@ export default {
|
|||||||
connecting: true,
|
connecting: true,
|
||||||
error: null,
|
error: null,
|
||||||
progressLines: [],
|
progressLines: [],
|
||||||
eventSource: null
|
eventSource: null,
|
||||||
|
// Vertaalde status teksten
|
||||||
|
translatedStatusTexts: {
|
||||||
|
error: 'Error while processing',
|
||||||
|
completed: 'Processing completed',
|
||||||
|
processing: 'Processing...'
|
||||||
|
},
|
||||||
|
currentLanguage: 'nl'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isProcessing() {
|
isProcessing() {
|
||||||
return !this.isCompleted && !this.hasError && !this.connecting;
|
return !this.isCompleted && !this.hasError && !this.connecting;
|
||||||
|
},
|
||||||
|
// Computed properties voor vertaalde status teksten
|
||||||
|
errorText() {
|
||||||
|
return this.translatedStatusTexts.error;
|
||||||
|
},
|
||||||
|
completedText() {
|
||||||
|
return this.translatedStatusTexts.completed;
|
||||||
|
},
|
||||||
|
processingText() {
|
||||||
|
return this.translatedStatusTexts.processing;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connectToProgressStream();
|
this.connectToProgressStream();
|
||||||
|
|
||||||
|
// Setup translation composables
|
||||||
|
const { translateSafe } = useTranslationClient();
|
||||||
|
const { translateConstants, getCachedTranslations, getCachedLanguage } = useConstantsTranslation();
|
||||||
|
this.translateSafe = translateSafe;
|
||||||
|
this.translateConstants = translateConstants;
|
||||||
|
this.getCachedTranslations = getCachedTranslations;
|
||||||
|
this.getCachedLanguage = getCachedLanguage;
|
||||||
|
|
||||||
|
// Check if we already have cached translations and apply them
|
||||||
|
const cachedTranslations = this.getCachedTranslations();
|
||||||
|
if (cachedTranslations) {
|
||||||
|
console.log('ProgressTracker: Applying cached translations on mount');
|
||||||
|
this.translatedStatusTexts = { ...cachedTranslations };
|
||||||
|
this.currentLanguage = this.getCachedLanguage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Luister naar taalwijzigingen
|
||||||
|
this.languageChangeHandler = (event) => {
|
||||||
|
if (event.detail && event.detail.language) {
|
||||||
|
this.handleLanguageChange(event.detail.language);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener('language-changed', this.languageChangeHandler);
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
this.disconnectEventSource();
|
this.disconnectEventSource();
|
||||||
|
|
||||||
|
// Cleanup language change listener
|
||||||
|
if (this.languageChangeHandler) {
|
||||||
|
document.removeEventListener('language-changed', this.languageChangeHandler);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
async handleLanguageChange(newLanguage) {
|
||||||
|
console.log('ProgressTracker: Language change to', newLanguage);
|
||||||
|
|
||||||
|
// Skip if same language
|
||||||
|
if (this.currentLanguage === newLanguage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentLanguage = newLanguage;
|
||||||
|
|
||||||
|
// Define the original Dutch constants
|
||||||
|
const originalTexts = {
|
||||||
|
error: 'Fout bij verwerking',
|
||||||
|
completed: 'Verwerking voltooid',
|
||||||
|
processing: 'Bezig met redeneren...'
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Use global constants translation with caching
|
||||||
|
const translatedTexts = await this.translateConstants(originalTexts, newLanguage, {
|
||||||
|
context: 'progress_tracker',
|
||||||
|
apiPrefix: this.apiPrefix
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update component state with translated texts
|
||||||
|
this.translatedStatusTexts = translatedTexts;
|
||||||
|
|
||||||
|
console.log('ProgressTracker: Successfully updated status texts for', newLanguage);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('ProgressTracker: Error translating status texts:', error);
|
||||||
|
// Fallback to original Dutch texts
|
||||||
|
this.translatedStatusTexts = originalTexts;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
connectToProgressStream() {
|
connectToProgressStream() {
|
||||||
if (!this.taskId) {
|
if (!this.taskId) {
|
||||||
console.error('Geen task ID beschikbaar voor progress tracking');
|
console.error('Geen task ID beschikbaar voor progress tracking');
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ class SpecialistExecutor(CrewAIBaseSpecialistExecutor):
|
|||||||
"icon": "verified",
|
"icon": "verified",
|
||||||
"fields": fields,
|
"fields": fields,
|
||||||
}
|
}
|
||||||
|
ko_form = TranslationServices.translate_config(self.tenant_id, ko_form, "fields", arguments.language)
|
||||||
|
|
||||||
rag_answer = self._check_and_execute_rag(arguments, formatted_context, citations)
|
rag_answer = self._check_and_execute_rag(arguments, formatted_context, citations)
|
||||||
if rag_answer:
|
if rag_answer:
|
||||||
|
|||||||
193
test_translation_implementation.py
Normal file
193
test_translation_implementation.py
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to verify the translation implementation in eveai_chat_client.
|
||||||
|
|
||||||
|
This script checks:
|
||||||
|
1. ProgressTracker.vue has proper translation setup
|
||||||
|
2. MessageHistory.vue has correct historical message exclusion logic
|
||||||
|
3. Translation composable is properly imported
|
||||||
|
4. Caching mechanism is implemented
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def check_file_exists(filepath):
|
||||||
|
"""Check if file exists and return True/False"""
|
||||||
|
return os.path.exists(filepath)
|
||||||
|
|
||||||
|
def read_file_content(filepath):
|
||||||
|
"""Read file content safely"""
|
||||||
|
try:
|
||||||
|
with open(filepath, 'r', encoding='utf-8') as f:
|
||||||
|
return f.read()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error reading {filepath}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def test_progress_tracker_implementation():
|
||||||
|
"""Test ProgressTracker.vue implementation"""
|
||||||
|
print("🔍 Testing ProgressTracker.vue implementation...")
|
||||||
|
|
||||||
|
filepath = "/Volumes/OWC4M2_1/Development/Josako/EveAI/TBD/eveai_chat_client/static/assets/vue-components/ProgressTracker.vue"
|
||||||
|
|
||||||
|
if not check_file_exists(filepath):
|
||||||
|
print("❌ ProgressTracker.vue not found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
content = read_file_content(filepath)
|
||||||
|
if not content:
|
||||||
|
return False
|
||||||
|
|
||||||
|
checks = [
|
||||||
|
("Translation composable import", r"import.*useTranslationClient.*from.*useTranslation"),
|
||||||
|
("Cache object", r"const statusTextCache = \{\}"),
|
||||||
|
("Translated status texts data", r"translatedStatusTexts:\s*\{"),
|
||||||
|
("Error text computed property", r"errorText\(\)\s*\{"),
|
||||||
|
("Completed text computed property", r"completedText\(\)\s*\{"),
|
||||||
|
("Processing text computed property", r"processingText\(\)\s*\{"),
|
||||||
|
("Template uses computed properties", r"\{\{\s*errorText\s*\}\}"),
|
||||||
|
("Language change handler", r"handleLanguageChange\(newLanguage\)"),
|
||||||
|
("Cache check logic", r"if \(statusTextCache\[newLanguage\]\)"),
|
||||||
|
("Backend translation calls", r"await this\.translateSafe"),
|
||||||
|
("Event listener setup", r"document\.addEventListener\('language-changed'"),
|
||||||
|
("Event listener cleanup", r"document\.removeEventListener\('language-changed'")
|
||||||
|
]
|
||||||
|
|
||||||
|
passed = 0
|
||||||
|
for check_name, pattern in checks:
|
||||||
|
if re.search(pattern, content, re.MULTILINE | re.DOTALL):
|
||||||
|
print(f" ✅ {check_name}")
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
print(f" ❌ {check_name}")
|
||||||
|
|
||||||
|
print(f"ProgressTracker.vue: {passed}/{len(checks)} checks passed")
|
||||||
|
return passed == len(checks)
|
||||||
|
|
||||||
|
def test_message_history_implementation():
|
||||||
|
"""Test MessageHistory.vue implementation"""
|
||||||
|
print("\n🔍 Testing MessageHistory.vue implementation...")
|
||||||
|
|
||||||
|
filepath = "/Volumes/OWC4M2_1/Development/Josako/EveAI/TBD/eveai_chat_client/static/assets/vue-components/MessageHistory.vue"
|
||||||
|
|
||||||
|
if not check_file_exists(filepath):
|
||||||
|
print("❌ MessageHistory.vue not found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
content = read_file_content(filepath)
|
||||||
|
if not content:
|
||||||
|
return False
|
||||||
|
|
||||||
|
checks = [
|
||||||
|
("Translation composable import", r"import.*useTranslationClient.*from.*useTranslation"),
|
||||||
|
("Setup function with translateSafe", r"setup\(\)\s*\{.*translateSafe.*\}"),
|
||||||
|
("Historical message exclusion", r"if \(this\.messages\.length === 1.*sender === 'ai'\)"),
|
||||||
|
("Original content check", r"if \(firstMessage\.originalContent\)"),
|
||||||
|
("Translation with fallback", r"fallbackText:\s*firstMessage\.originalContent"),
|
||||||
|
("Event listener setup", r"document\.addEventListener\('language-changed'"),
|
||||||
|
("Event listener cleanup", r"document\.removeEventListener\('language-changed'")
|
||||||
|
]
|
||||||
|
|
||||||
|
passed = 0
|
||||||
|
for check_name, pattern in checks:
|
||||||
|
if re.search(pattern, content, re.MULTILINE | re.DOTALL):
|
||||||
|
print(f" ✅ {check_name}")
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
print(f" ❌ {check_name}")
|
||||||
|
|
||||||
|
print(f"MessageHistory.vue: {passed}/{len(checks)} checks passed")
|
||||||
|
return passed == len(checks)
|
||||||
|
|
||||||
|
def test_chat_message_original_content():
|
||||||
|
"""Test ChatMessage.vue original content storage"""
|
||||||
|
print("\n🔍 Testing ChatMessage.vue original content storage...")
|
||||||
|
|
||||||
|
filepath = "/Volumes/OWC4M2_1/Development/Josako/EveAI/TBD/eveai_chat_client/static/assets/vue-components/ChatMessage.vue"
|
||||||
|
|
||||||
|
if not check_file_exists(filepath):
|
||||||
|
print("❌ ChatMessage.vue not found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
content = read_file_content(filepath)
|
||||||
|
if not content:
|
||||||
|
return False
|
||||||
|
|
||||||
|
checks = [
|
||||||
|
("Original content storage", r"this\.message\.originalContent = this\.message\.content"),
|
||||||
|
("AI message check", r"this\.message\.sender === 'ai'"),
|
||||||
|
("Original content condition", r"!this\.message\.originalContent")
|
||||||
|
]
|
||||||
|
|
||||||
|
passed = 0
|
||||||
|
for check_name, pattern in checks:
|
||||||
|
if re.search(pattern, content, re.MULTILINE):
|
||||||
|
print(f" ✅ {check_name}")
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
print(f" ❌ {check_name}")
|
||||||
|
|
||||||
|
print(f"ChatMessage.vue: {passed}/{len(checks)} checks passed")
|
||||||
|
return passed == len(checks)
|
||||||
|
|
||||||
|
def test_translation_composable():
|
||||||
|
"""Test translation composable exists"""
|
||||||
|
print("\n🔍 Testing translation composable...")
|
||||||
|
|
||||||
|
filepath = "/Volumes/OWC4M2_1/Development/Josako/EveAI/TBD/eveai_chat_client/static/assets/js/composables/useTranslation.js"
|
||||||
|
|
||||||
|
if not check_file_exists(filepath):
|
||||||
|
print("❌ useTranslation.js not found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
content = read_file_content(filepath)
|
||||||
|
if not content:
|
||||||
|
return False
|
||||||
|
|
||||||
|
checks = [
|
||||||
|
("useTranslationClient export", r"export function useTranslationClient"),
|
||||||
|
("translateSafe function", r"const translateSafe = async"),
|
||||||
|
("Backend API call", r"await translate\("),
|
||||||
|
("Fallback handling", r"fallbackText")
|
||||||
|
]
|
||||||
|
|
||||||
|
passed = 0
|
||||||
|
for check_name, pattern in checks:
|
||||||
|
if re.search(pattern, content, re.MULTILINE):
|
||||||
|
print(f" ✅ {check_name}")
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
print(f" ❌ {check_name}")
|
||||||
|
|
||||||
|
print(f"useTranslation.js: {passed}/{len(checks)} checks passed")
|
||||||
|
return passed == len(checks)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run all tests"""
|
||||||
|
print("🚀 Starting translation implementation tests...\n")
|
||||||
|
|
||||||
|
tests = [
|
||||||
|
test_progress_tracker_implementation,
|
||||||
|
test_message_history_implementation,
|
||||||
|
test_chat_message_original_content,
|
||||||
|
test_translation_composable
|
||||||
|
]
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for test in tests:
|
||||||
|
results.append(test())
|
||||||
|
|
||||||
|
print(f"\n📊 Test Results:")
|
||||||
|
print(f"Passed: {sum(results)}/{len(results)} tests")
|
||||||
|
|
||||||
|
if all(results):
|
||||||
|
print("🎉 All tests passed! Translation implementation is complete.")
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print("❌ Some tests failed. Please review the implementation.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
Reference in New Issue
Block a user