- verbeteringen client
- Enkel nog probleem met vertaling van de ProgressTracker constanten
This commit is contained in:
@@ -116,6 +116,20 @@ class TranslationServices:
|
|||||||
if translated_ctx:
|
if translated_ctx:
|
||||||
translated_config[field_config][field_name]['context'] = translated_ctx.translated_text
|
translated_config[field_config][field_name]['context'] = translated_ctx.translated_text
|
||||||
|
|
||||||
|
# vertaal allowed values als het veld bestaat en de waarden niet leeg zijn.
|
||||||
|
if 'allowed_values' in field_data and field_data['allowed_values']:
|
||||||
|
translated_allowed_values = []
|
||||||
|
for allowed_value in field_data['allowed_values']:
|
||||||
|
translated_allowed_value = cache_manager.translation_cache.get_translation(
|
||||||
|
text=allowed_value,
|
||||||
|
target_lang=target_language,
|
||||||
|
source_lang=source_language,
|
||||||
|
context=context
|
||||||
|
)
|
||||||
|
translated_allowed_values.append(translated_allowed_value.translated_text)
|
||||||
|
if translated_allowed_values:
|
||||||
|
translated_config[field_config][field_name]['allowed_values'] = translated_allowed_values
|
||||||
|
|
||||||
return translated_config
|
return translated_config
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { ref, computed, onMounted } from 'vue';
|
|||||||
*/
|
*/
|
||||||
export function useTranslation() {
|
export function useTranslation() {
|
||||||
const isTranslationReady = ref(false);
|
const isTranslationReady = ref(false);
|
||||||
const currentLanguage = ref('nl');
|
const currentLanguage = ref('en');
|
||||||
const isTranslating = ref(false);
|
const isTranslating = ref(false);
|
||||||
const lastError = ref(null);
|
const lastError = ref(null);
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ export function useTranslation() {
|
|||||||
* Get current language from chatConfig or fallback
|
* Get current language from chatConfig or fallback
|
||||||
*/
|
*/
|
||||||
const getCurrentLanguage = () => {
|
const getCurrentLanguage = () => {
|
||||||
return window.chatConfig?.language || currentLanguage.value || 'nl';
|
return window.chatConfig?.language || currentLanguage.value || 'en';
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,6 +215,8 @@ export function useConstantsTranslation() {
|
|||||||
CONSTANTS_CACHE.translations = translated;
|
CONSTANTS_CACHE.translations = translated;
|
||||||
|
|
||||||
console.log('useConstantsTranslation: Successfully translated and cached constants');
|
console.log('useConstantsTranslation: Successfully translated and cached constants');
|
||||||
|
console.log('useConstantsTranslation: Current language:', CONSTANTS_CACHE.currentLanguage);
|
||||||
|
console.log('useConstantsTranslation: Cached translations:', CONSTANTS_CACHE.translations);
|
||||||
return translated;
|
return translated;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('useConstantsTranslation: Error translating constants:', error);
|
console.error('useConstantsTranslation: Error translating constants:', error);
|
||||||
|
|||||||
@@ -1,238 +0,0 @@
|
|||||||
// eveai_chat_client/static/assets/js/composables/useTranslation.js
|
|
||||||
|
|
||||||
import { ref, computed, onMounted } from 'vue';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Vue 3 Composable for translation management
|
|
||||||
* Provides modern alternative to window.TranslationClient
|
|
||||||
*/
|
|
||||||
export function useTranslation() {
|
|
||||||
const isTranslationReady = ref(false);
|
|
||||||
const currentLanguage = ref('nl');
|
|
||||||
const isTranslating = ref(false);
|
|
||||||
const lastError = ref(null);
|
|
||||||
|
|
||||||
// Check if translation system is available with retry mechanism
|
|
||||||
const checkTranslationReady = () => {
|
|
||||||
if (window.TranslationClient && typeof window.TranslationClient.translate === 'function') {
|
|
||||||
isTranslationReady.value = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// Initial check
|
|
||||||
if (checkTranslationReady()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retry mechanism - wait for TranslationClient to become available
|
|
||||||
let retryCount = 0;
|
|
||||||
const maxRetries = 10;
|
|
||||||
const retryInterval = 100; // 100ms
|
|
||||||
|
|
||||||
const retryCheck = () => {
|
|
||||||
if (checkTranslationReady()) {
|
|
||||||
return; // Success!
|
|
||||||
}
|
|
||||||
|
|
||||||
retryCount++;
|
|
||||||
if (retryCount < maxRetries) {
|
|
||||||
setTimeout(retryCheck, retryInterval);
|
|
||||||
} else {
|
|
||||||
console.warn('TranslationClient is not available after retries');
|
|
||||||
isTranslationReady.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Start retry process
|
|
||||||
setTimeout(retryCheck, retryInterval);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate text to target language
|
|
||||||
* @param {string} text - Text to translate
|
|
||||||
* @param {string} targetLang - Target language code
|
|
||||||
* @param {string|null} sourceLang - Source language code (optional)
|
|
||||||
* @param {string|null} context - Translation context (optional)
|
|
||||||
* @param {string} apiPrefix - API prefix for tenant routing
|
|
||||||
* @returns {Promise<object>} Translation result
|
|
||||||
*/
|
|
||||||
const translate = async (text, targetLang, sourceLang = null, context = null, apiPrefix = '') => {
|
|
||||||
if (!isTranslationReady.value || !window.TranslationClient) {
|
|
||||||
const error = new Error('Translation system not ready');
|
|
||||||
lastError.value = error;
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!text || !text.trim()) {
|
|
||||||
const error = new Error('No text provided for translation');
|
|
||||||
lastError.value = error;
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
isTranslating.value = true;
|
|
||||||
lastError.value = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await window.TranslationClient.translate(
|
|
||||||
text,
|
|
||||||
targetLang,
|
|
||||||
sourceLang,
|
|
||||||
context,
|
|
||||||
apiPrefix
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update current language if translation was successful
|
|
||||||
if (result.success) {
|
|
||||||
currentLanguage.value = targetLang;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Translation error in composable:', error);
|
|
||||||
lastError.value = error;
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
isTranslating.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate text with automatic error handling and loading state
|
|
||||||
* @param {string} text - Text to translate
|
|
||||||
* @param {string} targetLang - Target language code
|
|
||||||
* @param {Object} options - Translation options
|
|
||||||
* @returns {Promise<string|null>} Translated text or null on error
|
|
||||||
*/
|
|
||||||
const translateSafe = async (text, targetLang, options = {}) => {
|
|
||||||
const {
|
|
||||||
sourceLang = null,
|
|
||||||
context = null,
|
|
||||||
apiPrefix = '',
|
|
||||||
fallbackText = text
|
|
||||||
} = options;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await translate(text, targetLang, sourceLang, context, apiPrefix);
|
|
||||||
return result.success ? result.translated_text : fallbackText;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('Safe translation failed, using fallback:', error.message);
|
|
||||||
return fallbackText;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Batch translate multiple texts
|
|
||||||
* @param {Array<string>} texts - Array of texts to translate
|
|
||||||
* @param {string} targetLang - Target language code
|
|
||||||
* @param {Object} options - Translation options
|
|
||||||
* @returns {Promise<Array<string>>} Array of translated texts
|
|
||||||
*/
|
|
||||||
const translateBatch = async (texts, targetLang, options = {}) => {
|
|
||||||
const results = await Promise.allSettled(
|
|
||||||
texts.map(text => translateSafe(text, targetLang, options))
|
|
||||||
);
|
|
||||||
|
|
||||||
return results.map((result, index) =>
|
|
||||||
result.status === 'fulfilled' ? result.value : texts[index]
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current language from chatConfig or fallback
|
|
||||||
*/
|
|
||||||
const getCurrentLanguage = () => {
|
|
||||||
return window.chatConfig?.language || currentLanguage.value;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get API prefix from chatConfig or fallback
|
|
||||||
*/
|
|
||||||
const getApiPrefix = () => {
|
|
||||||
return window.chatConfig?.apiPrefix || '';
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
// State
|
|
||||||
isTranslationReady,
|
|
||||||
currentLanguage: computed(() => getCurrentLanguage()),
|
|
||||||
isTranslating,
|
|
||||||
lastError,
|
|
||||||
|
|
||||||
// Methods
|
|
||||||
translate,
|
|
||||||
translateSafe,
|
|
||||||
translateBatch,
|
|
||||||
|
|
||||||
// Utilities
|
|
||||||
getCurrentLanguage,
|
|
||||||
getApiPrefix
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simplified composable for basic translation needs
|
|
||||||
* Use this when you only need simple text translation
|
|
||||||
*/
|
|
||||||
export function useTranslationClient() {
|
|
||||||
const { translate, translateSafe, isTranslationReady, isTranslating, lastError } = useTranslation();
|
|
||||||
|
|
||||||
return {
|
|
||||||
translate,
|
|
||||||
translateSafe,
|
|
||||||
isTranslationReady,
|
|
||||||
isTranslating,
|
|
||||||
lastError
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Composable for reactive text translation
|
|
||||||
* Automatically translates text when language changes
|
|
||||||
*/
|
|
||||||
export function useReactiveTranslation(text, options = {}) {
|
|
||||||
const { translateSafe, currentLanguage } = useTranslation();
|
|
||||||
const translatedText = ref(text);
|
|
||||||
const isLoading = ref(false);
|
|
||||||
|
|
||||||
const {
|
|
||||||
context = null,
|
|
||||||
sourceLang = null,
|
|
||||||
autoTranslate = true
|
|
||||||
} = options;
|
|
||||||
|
|
||||||
// Watch for language changes and auto-translate
|
|
||||||
if (autoTranslate) {
|
|
||||||
// We'll implement this when we have proper reactivity setup
|
|
||||||
// For now, provide manual translation method
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateTranslation = async (newLanguage = null) => {
|
|
||||||
const targetLang = newLanguage || currentLanguage.value;
|
|
||||||
|
|
||||||
if (!text || targetLang === sourceLang) {
|
|
||||||
translatedText.value = text;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
isLoading.value = true;
|
|
||||||
try {
|
|
||||||
const result = await translateSafe(text, targetLang, {
|
|
||||||
sourceLang,
|
|
||||||
context,
|
|
||||||
apiPrefix: window.chatConfig?.apiPrefix || ''
|
|
||||||
});
|
|
||||||
translatedText.value = result;
|
|
||||||
} finally {
|
|
||||||
isLoading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
translatedText,
|
|
||||||
isLoading,
|
|
||||||
updateTranslation
|
|
||||||
};
|
|
||||||
}
|
|
||||||
181
eveai_chat_client/static/assets/js/services/LanguageProvider.js
Normal file
181
eveai_chat_client/static/assets/js/services/LanguageProvider.js
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
// LanguageProvider.js - Central language management system
|
||||||
|
import { ref, reactive, computed, provide, inject } from 'vue';
|
||||||
|
import { useConstantsTranslation } from '../composables/useTranslation.js';
|
||||||
|
|
||||||
|
// Injection key for type safety
|
||||||
|
export const LANGUAGE_PROVIDER_KEY = Symbol('LanguageProvider');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Language Provider Service
|
||||||
|
* Central management of language state and translations
|
||||||
|
*/
|
||||||
|
export function createLanguageProvider(initialLanguage = 'en', apiPrefix = '') {
|
||||||
|
// Reactive state
|
||||||
|
const currentLanguage = ref(initialLanguage);
|
||||||
|
const isTranslating = ref(false);
|
||||||
|
const translationError = ref(null);
|
||||||
|
|
||||||
|
// Translation composable
|
||||||
|
const { translateConstants, getCachedTranslations, clearCache } = useConstantsTranslation();
|
||||||
|
|
||||||
|
// Component-specific translations cache
|
||||||
|
const componentTranslations = reactive({});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a component for translations with component-specific caching
|
||||||
|
*/
|
||||||
|
const registerComponent = (componentName, originalTexts) => {
|
||||||
|
console.log(`LanguageProvider: Registering component ${componentName} with language ${currentLanguage.value}`);
|
||||||
|
|
||||||
|
if (!componentTranslations[componentName]) {
|
||||||
|
componentTranslations[componentName] = reactive({
|
||||||
|
original: originalTexts,
|
||||||
|
translated: { ...originalTexts }, // Start with original English texts
|
||||||
|
isLoading: false,
|
||||||
|
error: null
|
||||||
|
});
|
||||||
|
|
||||||
|
// Force initial translation if current language is not English
|
||||||
|
if (currentLanguage.value !== 'en') {
|
||||||
|
console.log(`LanguageProvider: Component ${componentName} needs initial translation to ${currentLanguage.value}`);
|
||||||
|
translateComponentTexts(componentName, currentLanguage.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return componentTranslations[componentName];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate texts for a specific component
|
||||||
|
*/
|
||||||
|
const translateComponentTexts = async (componentName, targetLanguage) => {
|
||||||
|
const component = componentTranslations[componentName];
|
||||||
|
if (!component) {
|
||||||
|
console.warn(`LanguageProvider: Component ${componentName} not found for translation`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
component.isLoading = true;
|
||||||
|
component.error = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (targetLanguage === 'en') {
|
||||||
|
// For English, use original texts (no translation needed)
|
||||||
|
component.translated = { ...component.original };
|
||||||
|
console.log(`LanguageProvider: Using original English texts for ${componentName}`);
|
||||||
|
} else {
|
||||||
|
// For other languages, translate from English
|
||||||
|
console.log(`LanguageProvider: Translating ${componentName} from English to ${targetLanguage}`);
|
||||||
|
const translatedTexts = await translateConstants(
|
||||||
|
component.original,
|
||||||
|
targetLanguage,
|
||||||
|
{
|
||||||
|
context: componentName,
|
||||||
|
apiPrefix
|
||||||
|
}
|
||||||
|
);
|
||||||
|
component.translated = translatedTexts;
|
||||||
|
console.log(`LanguageProvider: Successfully translated ${componentName} to ${targetLanguage}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`LanguageProvider: Translation error for ${componentName}:`, error);
|
||||||
|
component.error = error;
|
||||||
|
// Fallback to original English texts
|
||||||
|
component.translated = { ...component.original };
|
||||||
|
} finally {
|
||||||
|
component.isLoading = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update language for all registered components
|
||||||
|
*/
|
||||||
|
const setLanguage = async (newLanguage) => {
|
||||||
|
if (currentLanguage.value === newLanguage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('LanguageProvider: Setting language to', newLanguage);
|
||||||
|
currentLanguage.value = newLanguage;
|
||||||
|
isTranslating.value = true;
|
||||||
|
translationError.value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Update all registered components
|
||||||
|
const translationPromises = Object.keys(componentTranslations).map(componentName =>
|
||||||
|
translateComponentTexts(componentName, newLanguage)
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(translationPromises);
|
||||||
|
console.log(`LanguageProvider: Successfully updated all components to ${newLanguage}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('LanguageProvider: Error setting language:', error);
|
||||||
|
translationError.value = error;
|
||||||
|
} finally {
|
||||||
|
isTranslating.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get translations voor een specifieke component
|
||||||
|
*/
|
||||||
|
const getComponentTranslations = (componentName) => {
|
||||||
|
return componentTranslations[componentName] || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear alle caches
|
||||||
|
*/
|
||||||
|
const clearAllCaches = () => {
|
||||||
|
clearCache();
|
||||||
|
Object.keys(componentTranslations).forEach(key => {
|
||||||
|
delete componentTranslations[key];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
// State
|
||||||
|
currentLanguage: computed(() => currentLanguage.value),
|
||||||
|
isTranslating: computed(() => isTranslating.value),
|
||||||
|
translationError: computed(() => translationError.value),
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
registerComponent,
|
||||||
|
setLanguage,
|
||||||
|
getComponentTranslations,
|
||||||
|
clearAllCaches,
|
||||||
|
|
||||||
|
// Computed
|
||||||
|
componentTranslations: computed(() => componentTranslations)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composable voor het gebruiken van de Language Provider
|
||||||
|
*/
|
||||||
|
export function useLanguageProvider() {
|
||||||
|
const provider = inject(LANGUAGE_PROVIDER_KEY);
|
||||||
|
|
||||||
|
if (!provider) {
|
||||||
|
throw new Error('useLanguageProvider must be used within a LanguageProvider');
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composable voor component-specifieke vertalingen
|
||||||
|
*/
|
||||||
|
export function useComponentTranslations(componentName, originalTexts) {
|
||||||
|
const provider = useLanguageProvider();
|
||||||
|
|
||||||
|
// Registreer component bij eerste gebruik
|
||||||
|
const translations = provider.registerComponent(componentName, originalTexts);
|
||||||
|
|
||||||
|
return {
|
||||||
|
translations: computed(() => translations.translated),
|
||||||
|
isLoading: computed(() => translations.isLoading),
|
||||||
|
error: computed(() => translations.error),
|
||||||
|
currentLanguage: provider.currentLanguage
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -43,6 +43,10 @@ import ProgressTracker from './ProgressTracker.vue';
|
|||||||
import LanguageSelector from './LanguageSelector.vue';
|
import LanguageSelector from './LanguageSelector.vue';
|
||||||
import ChatInput from './ChatInput.vue';
|
import ChatInput from './ChatInput.vue';
|
||||||
|
|
||||||
|
// Import language provider
|
||||||
|
import { createLanguageProvider, LANGUAGE_PROVIDER_KEY } from '../js/services/LanguageProvider.js';
|
||||||
|
import { provide } from 'vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ChatApp',
|
name: 'ChatApp',
|
||||||
components: {
|
components: {
|
||||||
@@ -54,12 +58,28 @@ export default {
|
|||||||
ProgressTracker,
|
ProgressTracker,
|
||||||
ChatInput
|
ChatInput
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
// Haal initiële taal uit chatConfig
|
||||||
|
const initialLanguage = window.chatConfig?.language || 'nl';
|
||||||
|
const apiPrefix = window.chatConfig?.apiPrefix || '';
|
||||||
|
|
||||||
|
// Creëer language provider
|
||||||
|
const languageProvider = createLanguageProvider(initialLanguage, apiPrefix);
|
||||||
|
|
||||||
|
// Provide aan alle child components
|
||||||
|
provide(LANGUAGE_PROVIDER_KEY, languageProvider);
|
||||||
|
|
||||||
|
return {
|
||||||
|
languageProvider
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
// Maak een lokale kopie van de chatConfig om undefined errors te voorkomen
|
// Maak een lokale kopie van de chatConfig om undefined errors te voorkomen
|
||||||
const chatConfig = window.chatConfig || {};
|
const chatConfig = window.chatConfig || {};
|
||||||
const settings = chatConfig.settings || {};
|
const settings = chatConfig.settings || {};
|
||||||
const initialLanguage = chatConfig.language || 'nl';
|
const initialLanguage = chatConfig.language || 'en';
|
||||||
const originalExplanation = chatConfig.explanation || '';
|
const originalExplanation = chatConfig.explanation || '';
|
||||||
const tenantMake = chatConfig.tenantMake || {};
|
const tenantMake = chatConfig.tenantMake || {};
|
||||||
|
|
||||||
@@ -331,7 +351,7 @@ export default {
|
|||||||
// Add a placeholder AI message that will be updated by the progress tracker
|
// Add a placeholder AI message that will be updated by the progress tracker
|
||||||
const placeholderMessage = {
|
const placeholderMessage = {
|
||||||
id: this.messageIdCounter++,
|
id: this.messageIdCounter++,
|
||||||
content: 'Bezig met verwerken...',
|
// content: 'Bezig met verwerken...',
|
||||||
sender: 'ai',
|
sender: 'ai',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
|
|||||||
@@ -97,7 +97,7 @@
|
|||||||
{{ message.content }}
|
{{ message.content }}
|
||||||
</div>
|
</div>
|
||||||
<button v-if="message.retryable" @click="$emit('retry-message', message.id)" class="retry-btn">
|
<button v-if="message.retryable" @click="$emit('retry-message', message.id)" class="retry-btn">
|
||||||
Opnieuw proberen
|
{{ messageTexts.retry }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -116,6 +116,7 @@
|
|||||||
import DynamicForm from './DynamicForm.vue';
|
import DynamicForm from './DynamicForm.vue';
|
||||||
import ProgressTracker from './ProgressTracker.vue';
|
import ProgressTracker from './ProgressTracker.vue';
|
||||||
import { useIconManager } from '../js/composables/useIconManager.js';
|
import { useIconManager } from '../js/composables/useIconManager.js';
|
||||||
|
import { useComponentTranslations } from '../js/services/LanguageProvider.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ChatMessage',
|
name: 'ChatMessage',
|
||||||
@@ -129,7 +130,25 @@ export default {
|
|||||||
// Watch message.formData.icon for automatic icon loading
|
// Watch message.formData.icon for automatic icon loading
|
||||||
watchIcon(() => props.message.formData?.icon);
|
watchIcon(() => props.message.formData?.icon);
|
||||||
|
|
||||||
return {};
|
// Use component translations from provider (English as base language)
|
||||||
|
const originalTexts = {
|
||||||
|
retry: 'Try again',
|
||||||
|
copy: 'Copy',
|
||||||
|
timestamp: 'Timestamp',
|
||||||
|
errorMessage: 'An error occurred while processing your request.'
|
||||||
|
};
|
||||||
|
|
||||||
|
const { translations, isLoading, error, currentLanguage } = useComponentTranslations(
|
||||||
|
'chat_message',
|
||||||
|
originalTexts
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
messageTexts: translations,
|
||||||
|
translationLoading: isLoading,
|
||||||
|
translationError: error,
|
||||||
|
currentLanguage
|
||||||
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
message: {
|
message: {
|
||||||
@@ -163,12 +182,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
// Luister naar taalwijzigingen
|
// Component initialization if needed
|
||||||
document.addEventListener('language-changed', this.handleLanguageChange);
|
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
// Verwijder event listener bij verwijderen component
|
// Component cleanup if needed
|
||||||
document.removeEventListener('language-changed', this.handleLanguageChange);
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
hasFormData() {
|
hasFormData() {
|
||||||
@@ -214,22 +231,17 @@ export default {
|
|||||||
return hasActualValues;
|
return hasActualValues;
|
||||||
},
|
},
|
||||||
|
|
||||||
async handleLanguageChange(event) {
|
|
||||||
// Controleer of dit het eerste bericht is in een gesprek met maar één bericht
|
|
||||||
// Dit wordt al afgehandeld door MessageHistory component, dus we hoeven hier niets te doen
|
|
||||||
// De implementatie hiervan blijft in MessageHistory om dubbele vertaling te voorkomen
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSpecialistError(eventData) {
|
handleSpecialistError(eventData) {
|
||||||
console.log('ChatMessage received specialist-error event:', eventData);
|
console.log('ChatMessage received specialist-error event:', eventData);
|
||||||
|
|
||||||
// Creëer een error message met correcte styling
|
// Create an error message with correct styling
|
||||||
this.message.type = 'error';
|
this.message.type = 'error';
|
||||||
this.message.content = eventData.message || 'Er is een fout opgetreden bij het verwerken van uw verzoek.';
|
this.message.content = eventData.message || this.messageTexts.errorMessage;
|
||||||
this.message.retryable = true;
|
this.message.retryable = true;
|
||||||
this.message.error = true; // Voeg error flag toe voor styling
|
this.message.error = true; // Add error flag for styling
|
||||||
|
|
||||||
// Bubble up naar parent component voor verdere afhandeling
|
// Bubble up to parent component for further handling
|
||||||
this.$emit('specialist-error', {
|
this.$emit('specialist-error', {
|
||||||
messageId: this.message.id,
|
messageId: this.message.id,
|
||||||
...eventData
|
...eventData
|
||||||
|
|||||||
@@ -21,12 +21,26 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { useLanguageProvider } from '../js/services/LanguageProvider.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'LanguageSelector',
|
name: 'LanguageSelector',
|
||||||
|
setup() {
|
||||||
|
// Optionally use provider for reactive current language
|
||||||
|
try {
|
||||||
|
const provider = useLanguageProvider();
|
||||||
|
return {
|
||||||
|
providerLanguage: provider.currentLanguage
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
// Provider not available, use props
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
initialLanguage: {
|
initialLanguage: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'nl'
|
default: 'en'
|
||||||
},
|
},
|
||||||
currentLanguage: {
|
currentLanguage: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -53,11 +67,17 @@ export default {
|
|||||||
this.$emit('language-changed', this.selectedLanguage);
|
this.$emit('language-changed', this.selectedLanguage);
|
||||||
|
|
||||||
// DOM event
|
// DOM event
|
||||||
const event = new CustomEvent('vue:language-changed', {
|
const event = new CustomEvent('language-changed', {
|
||||||
detail: { language: this.selectedLanguage }
|
detail: { language: this.selectedLanguage }
|
||||||
});
|
});
|
||||||
document.dispatchEvent(event);
|
document.dispatchEvent(event);
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
// Use provider language if available, otherwise use props
|
||||||
|
effectiveCurrentLanguage() {
|
||||||
|
return this.providerLanguage || this.currentLanguage || this.initialLanguage;
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getAvailableLanguages() {
|
getAvailableLanguages() {
|
||||||
const languages = [];
|
const languages = [];
|
||||||
@@ -109,7 +129,7 @@ export default {
|
|||||||
this.$emit('language-changed', languageCode);
|
this.$emit('language-changed', languageCode);
|
||||||
|
|
||||||
// DOM event
|
// DOM event
|
||||||
const event = new CustomEvent('vue:language-changed', {
|
const event = new CustomEvent('language-changed', {
|
||||||
detail: { language: languageCode }
|
detail: { language: languageCode }
|
||||||
});
|
});
|
||||||
document.dispatchEvent(event);
|
document.dispatchEvent(event);
|
||||||
|
|||||||
@@ -53,10 +53,34 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useTranslationClient, useConstantsTranslation } from '../js/composables/useTranslation.js';
|
import { useComponentTranslations } from '../js/services/LanguageProvider.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ProgressTracker',
|
name: 'ProgressTracker',
|
||||||
|
setup() {
|
||||||
|
// Define original English texts (base language for developers)
|
||||||
|
const originalTexts = {
|
||||||
|
error: 'Error while processing',
|
||||||
|
completed: 'Processing completed',
|
||||||
|
processing: 'Processing...'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gebruik component translations
|
||||||
|
const { translations, isLoading, error, currentLanguage } = useComponentTranslations(
|
||||||
|
'progress_tracker',
|
||||||
|
originalTexts
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('Translations:', translations);
|
||||||
|
console.log('Current language:', currentLanguage);
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusTexts: translations,
|
||||||
|
translationLoading: isLoading,
|
||||||
|
translationError: error,
|
||||||
|
currentLanguage
|
||||||
|
};
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
taskId: {
|
taskId: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -76,99 +100,56 @@ 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
|
// Computed properties voor vertaalde status teksten uit provider
|
||||||
errorText() {
|
errorText() {
|
||||||
return this.translatedStatusTexts.error;
|
return this.statusTexts.error;
|
||||||
},
|
},
|
||||||
completedText() {
|
completedText() {
|
||||||
return this.translatedStatusTexts.completed;
|
return this.statusTexts.completed;
|
||||||
},
|
},
|
||||||
processingText() {
|
processingText() {
|
||||||
return this.translatedStatusTexts.processing;
|
return this.statusTexts.processing;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
// Create named handler for language changes
|
||||||
|
this.languageChangeHandler = (event) => {
|
||||||
|
if (event.detail && event.detail.language) {
|
||||||
|
console.log('ProgressTracker: Received language change event:', event.detail.language);
|
||||||
|
// The LanguageProvider will automatically handle the translation update
|
||||||
|
// We just need to ensure the component is aware of the change
|
||||||
|
this.handleLanguageChange(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Listen for language changes
|
||||||
|
document.addEventListener('language-changed', this.languageChangeHandler);
|
||||||
|
},
|
||||||
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
|
// Remove language change event listener
|
||||||
if (this.languageChangeHandler) {
|
if (this.languageChangeHandler) {
|
||||||
document.removeEventListener('language-changed', this.languageChangeHandler);
|
document.removeEventListener('language-changed', this.languageChangeHandler);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async handleLanguageChange(newLanguage) {
|
handleLanguageChange(event) {
|
||||||
console.log('ProgressTracker: Language change to', newLanguage);
|
if (event.detail && event.detail.language) {
|
||||||
|
console.log(`ProgressTracker: Language changed to ${event.detail.language}`);
|
||||||
// Skip if same language
|
// The LanguageProvider automatically updates translations through reactive system
|
||||||
if (this.currentLanguage === newLanguage) {
|
// Force component update to ensure UI reflects the new translations
|
||||||
return;
|
this.$forceUpdate();
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -205,7 +186,7 @@ export default {
|
|||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to create EventSource:', error);
|
console.error('Failed to create EventSource:', error);
|
||||||
this.error = 'Kan geen verbinding maken met de voortgangsstream.';
|
this.error = 'Unable to connect to the server SSE stream.';
|
||||||
this.connecting = false;
|
this.connecting = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -343,7 +324,7 @@ export default {
|
|||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error parsing specialist error data:', error);
|
console.error('Error parsing specialist error data:', error);
|
||||||
this.error = 'Er is een onbekende fout opgetreden.';
|
this.error = 'An unknown error occurred while processing your request.';
|
||||||
this.isCompleted = true;
|
this.isCompleted = true;
|
||||||
this.hasError = true;
|
this.hasError = true;
|
||||||
this.connecting = false;
|
this.connecting = false;
|
||||||
@@ -351,7 +332,7 @@ export default {
|
|||||||
|
|
||||||
// Emit generic error
|
// Emit generic error
|
||||||
this.$emit('specialist-error', {
|
this.$emit('specialist-error', {
|
||||||
message: 'Er is een onbekende fout opgetreden.',
|
message: 'An unknown error occurred while processing your request.',
|
||||||
originalError: 'Failed to parse error data',
|
originalError: 'Failed to parse error data',
|
||||||
taskId: this.taskId
|
taskId: this.taskId
|
||||||
});
|
});
|
||||||
@@ -360,7 +341,7 @@ export default {
|
|||||||
|
|
||||||
handleError(event) {
|
handleError(event) {
|
||||||
console.error('SSE Error event:', event);
|
console.error('SSE Error event:', event);
|
||||||
this.error = 'Er is een fout opgetreden bij het verwerken van updates.';
|
this.error = 'An unknown error occurred while connecting to the server. Please try again later.';
|
||||||
this.connecting = false;
|
this.connecting = false;
|
||||||
|
|
||||||
// Try to parse error data
|
// Try to parse error data
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
initialLanguage: {
|
initialLanguage: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'nl'
|
default: 'en'
|
||||||
},
|
},
|
||||||
supportedLanguageDetails: {
|
supportedLanguageDetails: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, watch, onMounted } from 'vue';
|
import { ref, computed, watch, onMounted } from 'vue';
|
||||||
import { useTranslationClient } from '../js/composables/useTranslation.js';
|
import { useComponentTranslations } from '../js/services/LanguageProvider.js';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
originalText: {
|
originalText: {
|
||||||
@@ -26,7 +26,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
currentLanguage: {
|
currentLanguage: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'nl'
|
default: 'en'
|
||||||
},
|
},
|
||||||
apiPrefix: {
|
apiPrefix: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -34,9 +34,17 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { translateSafe } = useTranslationClient();
|
// Use component translations from provider
|
||||||
const translatedText = ref(props.originalText);
|
const originalTexts = computed(() => ({
|
||||||
const isLoading = ref(false);
|
explanation: props.originalText || ''
|
||||||
|
}));
|
||||||
|
|
||||||
|
const { translations, isLoading, error, currentLanguage } = useComponentTranslations(
|
||||||
|
'sidebar_explanation',
|
||||||
|
originalTexts.value
|
||||||
|
);
|
||||||
|
|
||||||
|
const translatedText = computed(() => translations.value.explanation || props.originalText);
|
||||||
|
|
||||||
// Render markdown content
|
// Render markdown content
|
||||||
const renderedExplanation = computed(() => {
|
const renderedExplanation = computed(() => {
|
||||||
@@ -52,41 +60,12 @@ const renderedExplanation = computed(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Watch for language changes
|
// Watch for text changes to update the provider
|
||||||
watch(() => props.currentLanguage, async (newLanguage) => {
|
watch(() => props.originalText, () => {
|
||||||
await updateTranslation(newLanguage);
|
// Update original texts when prop changes
|
||||||
});
|
originalTexts.value = {
|
||||||
|
explanation: props.originalText || ''
|
||||||
// Watch for text changes
|
};
|
||||||
watch(() => props.originalText, async () => {
|
|
||||||
await updateTranslation(props.currentLanguage);
|
|
||||||
});
|
|
||||||
|
|
||||||
const updateTranslation = async (targetLanguage) => {
|
|
||||||
if (!props.originalText || targetLanguage === 'nl') {
|
|
||||||
translatedText.value = props.originalText;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
isLoading.value = true;
|
|
||||||
try {
|
|
||||||
const result = await translateSafe(props.originalText, targetLanguage, {
|
|
||||||
context: 'sidebar_explanation',
|
|
||||||
apiPrefix: props.apiPrefix,
|
|
||||||
fallbackText: props.originalText
|
|
||||||
});
|
|
||||||
|
|
||||||
translatedText.value = result;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('Sidebar explanation translation failed:', error);
|
|
||||||
translatedText.value = props.originalText;
|
|
||||||
} finally {
|
|
||||||
isLoading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
updateTranslation(props.currentLanguage);
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
allowReactions: {{ settings.allow_reactions|default('true')|lower }}
|
allowReactions: {{ settings.allow_reactions|default('true')|lower }}
|
||||||
},
|
},
|
||||||
apiPrefix: '{{ request.headers.get("X-Forwarded-Prefix", "") }}/chat',
|
apiPrefix: '{{ request.headers.get("X-Forwarded-Prefix", "") }}/chat',
|
||||||
language: '{{ session.magic_link.specialist_args.language|default("nl") }}',
|
language: '{{ session.magic_link.specialist_args.language|default("en") }}',
|
||||||
supportedLanguageDetails: {{ config.SUPPORTED_LANGUAGE_DETAILS|tojson|safe }},
|
supportedLanguageDetails: {{ config.SUPPORTED_LANGUAGE_DETAILS|tojson|safe }},
|
||||||
allowedLanguages: {{ tenant_make.allowed_languages|tojson|safe }},
|
allowedLanguages: {{ tenant_make.allowed_languages|tojson|safe }},
|
||||||
tenantMake: {
|
tenantMake: {
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ class SpecialistExecutor(CrewAIBaseSpecialistExecutor):
|
|||||||
for criterium, answer in arguments.form_values.items():
|
for criterium, answer in arguments.form_values.items():
|
||||||
for qa in previous_ko_questions:
|
for qa in previous_ko_questions:
|
||||||
if qa.title == criterium:
|
if qa.title == criterium:
|
||||||
if qa.answer_positive != answer:
|
if TranslationServices.translate(self.tenant_id, qa.answer_positive, arguments.language) != answer:
|
||||||
evaluation = "negative"
|
evaluation = "negative"
|
||||||
break
|
break
|
||||||
if evaluation == "negative":
|
if evaluation == "negative":
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import { createApp, version } from 'vue';
|
|||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
import { FormField } from '../../../../../../../../../Users/josako/Library/Application Support/JetBrains/PyCharm2025.1/scratches/old js files/FormField.js';
|
import { FormField } from '../../../../../../../../../Users/josako/Library/Application Support/JetBrains/PyCharm2025.1/scratches/old js files/FormField.js';
|
||||||
|
|
||||||
|
// Import LanguageProvider for sidebar translation support
|
||||||
|
import { createLanguageProvider, LANGUAGE_PROVIDER_KEY } from '../../../eveai_chat_client/static/assets/js/services/LanguageProvider.js';
|
||||||
|
|
||||||
// Vue en andere bibliotheken beschikbaar maken
|
// Vue en andere bibliotheken beschikbaar maken
|
||||||
window.Vue = { createApp, version };
|
window.Vue = { createApp, version };
|
||||||
window.marked = marked;
|
window.marked = marked;
|
||||||
@@ -78,6 +81,12 @@ function initializeSidebar() {
|
|||||||
// Mount de component
|
// Mount de component
|
||||||
const app = createApp(SideBar, props);
|
const app = createApp(SideBar, props);
|
||||||
|
|
||||||
|
// Create and provide LanguageProvider for sidebar components
|
||||||
|
const initialLanguage = window.chatConfig?.language || 'nl';
|
||||||
|
const apiPrefix = window.chatConfig?.apiPrefix || '';
|
||||||
|
const languageProvider = createLanguageProvider(initialLanguage, apiPrefix);
|
||||||
|
app.provide(LANGUAGE_PROVIDER_KEY, languageProvider);
|
||||||
|
|
||||||
// Error handler
|
// Error handler
|
||||||
app.config.errorHandler = (err, vm, info) => {
|
app.config.errorHandler = (err, vm, info) => {
|
||||||
console.error('🚨 [Vue Error in Sidebar]', err);
|
console.error('🚨 [Vue Error in Sidebar]', err);
|
||||||
@@ -87,7 +96,19 @@ function initializeSidebar() {
|
|||||||
|
|
||||||
const mountedApp = app.mount(container);
|
const mountedApp = app.mount(container);
|
||||||
|
|
||||||
console.log('✅ Sidebar component successfully mounted');
|
// Listen to language change events and update the sidebar's language provider
|
||||||
|
const languageChangeHandler = (event) => {
|
||||||
|
if (event.detail && event.detail.language) {
|
||||||
|
console.log('Sidebar: Received language change event:', event.detail.language);
|
||||||
|
languageProvider.setLanguage(event.detail.language);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener('language-changed', languageChangeHandler);
|
||||||
|
|
||||||
|
// Store the handler for cleanup if needed
|
||||||
|
mountedApp._languageChangeHandler = languageChangeHandler;
|
||||||
|
|
||||||
|
console.log('✅ Sidebar component successfully mounted with LanguageProvider');
|
||||||
return mountedApp;
|
return mountedApp;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('🚨 [CRITICAL ERROR] Bij initialiseren sidebar:', error);
|
console.error('🚨 [CRITICAL ERROR] Bij initialiseren sidebar:', error);
|
||||||
|
|||||||
244
test_english_base_language_implementation.py
Normal file
244
test_english_base_language_implementation.py
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to validate the English base language implementation
|
||||||
|
Tests component-specific translations and initial language checks
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Add project root to path
|
||||||
|
project_root = Path(__file__).parent
|
||||||
|
sys.path.append(str(project_root))
|
||||||
|
|
||||||
|
def test_file_contains(file_path, search_terms, description):
|
||||||
|
"""Test if a file contains specific terms"""
|
||||||
|
full_path = project_root / file_path
|
||||||
|
if not full_path.exists():
|
||||||
|
print(f"❌ FAIL - {description}: File not found - {file_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
content = full_path.read_text(encoding='utf-8')
|
||||||
|
all_found = all(term in content for term in search_terms)
|
||||||
|
status = "✅ PASS" if all_found else "❌ FAIL"
|
||||||
|
print(f"{status} - {description}")
|
||||||
|
|
||||||
|
if not all_found:
|
||||||
|
missing = [term for term in search_terms if term not in content]
|
||||||
|
print(f" Missing terms: {missing}")
|
||||||
|
|
||||||
|
return all_found
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ FAIL - {description}: Error reading file - {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_file_not_contains(file_path, search_terms, description):
|
||||||
|
"""Test if a file does NOT contain specific terms"""
|
||||||
|
full_path = project_root / file_path
|
||||||
|
if not full_path.exists():
|
||||||
|
print(f"❌ FAIL - {description}: File not found - {file_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
content = full_path.read_text(encoding='utf-8')
|
||||||
|
none_found = not any(term in content for term in search_terms)
|
||||||
|
status = "✅ PASS" if none_found else "❌ FAIL"
|
||||||
|
print(f"{status} - {description}")
|
||||||
|
|
||||||
|
if not none_found:
|
||||||
|
found = [term for term in search_terms if term in content]
|
||||||
|
print(f" Found unwanted terms: {found}")
|
||||||
|
|
||||||
|
return none_found
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ FAIL - {description}: Error reading file - {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def run_tests():
|
||||||
|
"""Run all tests for the English base language implementation"""
|
||||||
|
print("🧪 Testing English Base Language Implementation")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
tests_passed = 0
|
||||||
|
total_tests = 0
|
||||||
|
|
||||||
|
# Test 1: LanguageProvider uses English as default
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/js/services/LanguageProvider.js",
|
||||||
|
["initialLanguage = 'en'", "Central language management system"],
|
||||||
|
"LanguageProvider uses English as default language"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 2: LanguageProvider has component-specific translation function
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/js/services/LanguageProvider.js",
|
||||||
|
["translateComponentTexts", "component-specific", "targetLanguage === 'en'"],
|
||||||
|
"LanguageProvider has component-specific translation logic"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 3: LanguageProvider forces initial translation for non-English languages
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/js/services/LanguageProvider.js",
|
||||||
|
["currentLanguage.value !== 'en'", "needs initial translation", "translateComponentTexts(componentName, currentLanguage.value)"],
|
||||||
|
"LanguageProvider forces initial translation for non-English languages"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 4: ProgressTracker uses English original texts
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/vue-components/ProgressTracker.vue",
|
||||||
|
["Error while processing", "Processing completed", "Processing..."],
|
||||||
|
"ProgressTracker uses English original texts"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 5: ProgressTracker does NOT use Dutch texts
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_not_contains("eveai_chat_client/static/assets/vue-components/ProgressTracker.vue",
|
||||||
|
["Fout bij verwerking", "Verwerking voltooid", "Bezig met redeneren"],
|
||||||
|
"ProgressTracker does not use Dutch texts"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 6: ChatMessage uses English original texts
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/vue-components/ChatMessage.vue",
|
||||||
|
["Try again", "Copy", "Timestamp", "An error occurred while processing"],
|
||||||
|
"ChatMessage uses English original texts"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 7: ChatMessage does NOT use Dutch texts
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_not_contains("eveai_chat_client/static/assets/vue-components/ChatMessage.vue",
|
||||||
|
["Opnieuw proberen", "Kopiëren", "Tijdstempel", "Er is een fout opgetreden"],
|
||||||
|
"ChatMessage does not use Dutch texts"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 8: SideBarExplanation uses English as default language
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/vue-components/SideBarExplanation.vue",
|
||||||
|
["default: 'en'", "Translating..."],
|
||||||
|
"SideBarExplanation uses English as default language"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 9: LanguageProvider handles English base language correctly
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/js/services/LanguageProvider.js",
|
||||||
|
["For English, use original texts", "no translation needed", "Start with original English texts"],
|
||||||
|
"LanguageProvider handles English base language correctly"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 10: LanguageProvider has proper logging for debugging
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/js/services/LanguageProvider.js",
|
||||||
|
["console.log", "Registering component", "needs initial translation", "Successfully translated"],
|
||||||
|
"LanguageProvider has proper logging for debugging"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print(f"🧪 Test Results: {tests_passed}/{total_tests} tests passed")
|
||||||
|
|
||||||
|
if tests_passed == total_tests:
|
||||||
|
print("🎉 All tests passed! English base language implementation looks good.")
|
||||||
|
print("\n✅ Key improvements implemented:")
|
||||||
|
print(" - English is now the base language for all components")
|
||||||
|
print(" - Component-specific caching prevents cross-contamination")
|
||||||
|
print(" - Initial language translation works at component registration")
|
||||||
|
print(" - No fallback to Dutch - English is the source language")
|
||||||
|
print(" - Proper logging for debugging translation issues")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"⚠️ {total_tests - tests_passed} tests failed. Please review the implementation.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def check_cache_logic():
|
||||||
|
"""Check the cache logic implementation"""
|
||||||
|
print("\n🔍 Checking Cache Logic Implementation")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
issues_found = 0
|
||||||
|
|
||||||
|
# Check if global cache is still being used incorrectly
|
||||||
|
language_provider_path = project_root / "eveai_chat_client/static/assets/js/services/LanguageProvider.js"
|
||||||
|
if language_provider_path.exists():
|
||||||
|
content = language_provider_path.read_text(encoding='utf-8')
|
||||||
|
|
||||||
|
# Check for component-specific cache
|
||||||
|
if 'componentTranslations[componentName]' in content:
|
||||||
|
print("✅ Component-specific cache implementation found")
|
||||||
|
else:
|
||||||
|
print("⚠️ Component-specific cache not properly implemented")
|
||||||
|
issues_found += 1
|
||||||
|
|
||||||
|
# Check for proper English base language handling
|
||||||
|
if "targetLanguage === 'en'" in content:
|
||||||
|
print("✅ English base language handling found")
|
||||||
|
else:
|
||||||
|
print("⚠️ English base language handling not found")
|
||||||
|
issues_found += 1
|
||||||
|
|
||||||
|
# Check for initial translation logic
|
||||||
|
if "needs initial translation" in content:
|
||||||
|
print("✅ Initial translation logic found")
|
||||||
|
else:
|
||||||
|
print("⚠️ Initial translation logic not found")
|
||||||
|
issues_found += 1
|
||||||
|
|
||||||
|
if issues_found == 0:
|
||||||
|
print("✅ Cache logic implementation looks good")
|
||||||
|
else:
|
||||||
|
print(f"⚠️ {issues_found} issue(s) found in cache logic")
|
||||||
|
|
||||||
|
return issues_found == 0
|
||||||
|
|
||||||
|
def check_startup_behavior():
|
||||||
|
"""Check startup behavior for different language scenarios"""
|
||||||
|
print("\n🔍 Checking Startup Behavior")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
print("📋 Expected startup behavior:")
|
||||||
|
print(" 1. App starts with chatConfig.language (e.g., 'nl', 'fr', 'de')")
|
||||||
|
print(" 2. Components register with English original texts")
|
||||||
|
print(" 3. If initial language ≠ 'en', automatic translation is triggered")
|
||||||
|
print(" 4. Cache is populated with correct translations for initial language")
|
||||||
|
print(" 5. No fallback to Dutch - English is always the source")
|
||||||
|
|
||||||
|
# Check chat.html for language configuration
|
||||||
|
chat_html_path = project_root / "eveai_chat_client/templates/chat.html"
|
||||||
|
if chat_html_path.exists():
|
||||||
|
content = chat_html_path.read_text(encoding='utf-8')
|
||||||
|
if "language: '{{ session.magic_link.specialist_args.language|default(" in content:
|
||||||
|
print("✅ Dynamic language configuration found in chat.html")
|
||||||
|
if '|default("nl")' in content:
|
||||||
|
print("⚠️ Default language in chat.html is still 'nl' - consider changing to 'en'")
|
||||||
|
elif '|default("en")' in content:
|
||||||
|
print("✅ Default language in chat.html is 'en'")
|
||||||
|
else:
|
||||||
|
print("⚠️ Language configuration not found in chat.html")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("🚀 English Base Language Implementation Test Suite")
|
||||||
|
print("Testing component-specific translations with English as base language")
|
||||||
|
print("=" * 70)
|
||||||
|
|
||||||
|
# Run main tests
|
||||||
|
success = run_tests()
|
||||||
|
|
||||||
|
# Check cache logic
|
||||||
|
cache_ok = check_cache_logic()
|
||||||
|
|
||||||
|
# Check startup behavior
|
||||||
|
startup_ok = check_startup_behavior()
|
||||||
|
|
||||||
|
if success and cache_ok and startup_ok:
|
||||||
|
print("\n✅ Implementation validation successful!")
|
||||||
|
print("🎯 The system now uses English as the base language with proper component-specific caching.")
|
||||||
|
print("🔧 Initial language translation should work correctly at startup.")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print("\n❌ Implementation validation failed!")
|
||||||
|
print("Please review and fix the issues before testing in browser.")
|
||||||
|
sys.exit(1)
|
||||||
219
test_language_provider_implementation.py
Normal file
219
test_language_provider_implementation.py
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to validate the Language Provider implementation
|
||||||
|
Tests the provider/inject pattern for translation management
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Add project root to path
|
||||||
|
project_root = Path(__file__).parent
|
||||||
|
sys.path.append(str(project_root))
|
||||||
|
|
||||||
|
def test_file_exists(file_path, description):
|
||||||
|
"""Test if a file exists"""
|
||||||
|
full_path = project_root / file_path
|
||||||
|
exists = full_path.exists()
|
||||||
|
status = "✅ PASS" if exists else "❌ FAIL"
|
||||||
|
print(f"{status} - {description}: {file_path}")
|
||||||
|
return exists
|
||||||
|
|
||||||
|
def test_file_contains(file_path, search_terms, description):
|
||||||
|
"""Test if a file contains specific terms"""
|
||||||
|
full_path = project_root / file_path
|
||||||
|
if not full_path.exists():
|
||||||
|
print(f"❌ FAIL - {description}: File not found - {file_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
content = full_path.read_text(encoding='utf-8')
|
||||||
|
all_found = all(term in content for term in search_terms)
|
||||||
|
status = "✅ PASS" if all_found else "❌ FAIL"
|
||||||
|
print(f"{status} - {description}")
|
||||||
|
|
||||||
|
if not all_found:
|
||||||
|
missing = [term for term in search_terms if term not in content]
|
||||||
|
print(f" Missing terms: {missing}")
|
||||||
|
|
||||||
|
return all_found
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ FAIL - {description}: Error reading file - {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_javascript_syntax(file_path, description):
|
||||||
|
"""Test JavaScript syntax using Node.js if available"""
|
||||||
|
full_path = project_root / file_path
|
||||||
|
if not full_path.exists():
|
||||||
|
print(f"❌ FAIL - {description}: File not found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Try to check syntax with node if available
|
||||||
|
result = subprocess.run(['node', '-c', str(full_path)],
|
||||||
|
capture_output=True, text=True, timeout=10)
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(f"✅ PASS - {description}: JavaScript syntax valid")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"❌ FAIL - {description}: JavaScript syntax error")
|
||||||
|
print(f" Error: {result.stderr}")
|
||||||
|
return False
|
||||||
|
except (subprocess.TimeoutExpired, FileNotFoundError):
|
||||||
|
print(f"⚠️ SKIP - {description}: Node.js not available for syntax check")
|
||||||
|
return True # Don't fail if Node.js is not available
|
||||||
|
|
||||||
|
def run_tests():
|
||||||
|
"""Run all tests for the Language Provider implementation"""
|
||||||
|
print("🧪 Testing Language Provider Implementation")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
tests_passed = 0
|
||||||
|
total_tests = 0
|
||||||
|
|
||||||
|
# Test 1: LanguageProvider service exists
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_exists("eveai_chat_client/static/assets/js/services/LanguageProvider.js",
|
||||||
|
"LanguageProvider service file exists"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 2: LanguageProvider contains required exports
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/js/services/LanguageProvider.js",
|
||||||
|
["createLanguageProvider", "useLanguageProvider", "useComponentTranslations", "LANGUAGE_PROVIDER_KEY"],
|
||||||
|
"LanguageProvider exports required functions"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 3: ChatApp.vue provides the language provider
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/vue-components/ChatApp.vue",
|
||||||
|
["createLanguageProvider", "provide", "LANGUAGE_PROVIDER_KEY"],
|
||||||
|
"ChatApp.vue provides language provider"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 4: ProgressTracker uses component translations
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/vue-components/ProgressTracker.vue",
|
||||||
|
["useComponentTranslations", "progress_tracker"],
|
||||||
|
"ProgressTracker uses component translations"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 5: SideBarExplanation uses component translations
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/vue-components/SideBarExplanation.vue",
|
||||||
|
["useComponentTranslations", "sidebar_explanation"],
|
||||||
|
"SideBarExplanation uses component translations"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 6: ChatMessage uses component translations
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/vue-components/ChatMessage.vue",
|
||||||
|
["useComponentTranslations", "chat_message"],
|
||||||
|
"ChatMessage uses component translations"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 7: LanguageSelector optionally uses provider
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/vue-components/LanguageSelector.vue",
|
||||||
|
["useLanguageProvider", "providerLanguage", "effectiveCurrentLanguage"],
|
||||||
|
"LanguageSelector optionally uses provider"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 8: Check JavaScript syntax of LanguageProvider
|
||||||
|
total_tests += 1
|
||||||
|
if test_javascript_syntax("eveai_chat_client/static/assets/js/services/LanguageProvider.js",
|
||||||
|
"LanguageProvider JavaScript syntax"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 9: Verify old event-based code is removed from ProgressTracker
|
||||||
|
total_tests += 1
|
||||||
|
progress_tracker_path = "eveai_chat_client/static/assets/vue-components/ProgressTracker.vue"
|
||||||
|
full_path = project_root / progress_tracker_path
|
||||||
|
if full_path.exists():
|
||||||
|
content = full_path.read_text(encoding='utf-8')
|
||||||
|
old_patterns = ["handleLanguageChange", "language-changed", "translateConstants"]
|
||||||
|
has_old_code = any(pattern in content for pattern in old_patterns)
|
||||||
|
if not has_old_code:
|
||||||
|
print("✅ PASS - ProgressTracker: Old event-based translation code removed")
|
||||||
|
tests_passed += 1
|
||||||
|
else:
|
||||||
|
print("❌ FAIL - ProgressTracker: Still contains old event-based translation code")
|
||||||
|
else:
|
||||||
|
print("❌ FAIL - ProgressTracker: File not found")
|
||||||
|
|
||||||
|
# Test 10: Verify old event-based code is removed from ChatMessage
|
||||||
|
total_tests += 1
|
||||||
|
chat_message_path = "eveai_chat_client/static/assets/vue-components/ChatMessage.vue"
|
||||||
|
full_path = project_root / chat_message_path
|
||||||
|
if full_path.exists():
|
||||||
|
content = full_path.read_text(encoding='utf-8')
|
||||||
|
old_patterns = ["handleLanguageChange", "language-changed"]
|
||||||
|
has_old_code = any(pattern in content for pattern in old_patterns)
|
||||||
|
if not has_old_code:
|
||||||
|
print("✅ PASS - ChatMessage: Old event-based translation code removed")
|
||||||
|
tests_passed += 1
|
||||||
|
else:
|
||||||
|
print("❌ FAIL - ChatMessage: Still contains old event-based translation code")
|
||||||
|
else:
|
||||||
|
print("❌ FAIL - ChatMessage: File not found")
|
||||||
|
|
||||||
|
print("\n" + "=" * 50)
|
||||||
|
print(f"🧪 Test Results: {tests_passed}/{total_tests} tests passed")
|
||||||
|
|
||||||
|
if tests_passed == total_tests:
|
||||||
|
print("🎉 All tests passed! Language Provider implementation looks good.")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"⚠️ {total_tests - tests_passed} tests failed. Please review the implementation.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def check_implementation_completeness():
|
||||||
|
"""Check if the implementation is complete"""
|
||||||
|
print("\n🔍 Checking Implementation Completeness")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
# Check if all required files exist
|
||||||
|
required_files = [
|
||||||
|
"eveai_chat_client/static/assets/js/services/LanguageProvider.js",
|
||||||
|
"eveai_chat_client/static/assets/vue-components/ChatApp.vue",
|
||||||
|
"eveai_chat_client/static/assets/vue-components/ProgressTracker.vue",
|
||||||
|
"eveai_chat_client/static/assets/vue-components/SideBarExplanation.vue",
|
||||||
|
"eveai_chat_client/static/assets/vue-components/ChatMessage.vue",
|
||||||
|
"eveai_chat_client/static/assets/vue-components/LanguageSelector.vue"
|
||||||
|
]
|
||||||
|
|
||||||
|
all_exist = True
|
||||||
|
for file_path in required_files:
|
||||||
|
full_path = project_root / file_path
|
||||||
|
if full_path.exists():
|
||||||
|
print(f"✅ {file_path}")
|
||||||
|
else:
|
||||||
|
print(f"❌ {file_path} - MISSING")
|
||||||
|
all_exist = False
|
||||||
|
|
||||||
|
return all_exist
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("🚀 Language Provider Implementation Test Suite")
|
||||||
|
print("Testing provider/inject pattern for translation management")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
# Check completeness first
|
||||||
|
if not check_implementation_completeness():
|
||||||
|
print("\n❌ Implementation incomplete. Please ensure all files exist.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
success = run_tests()
|
||||||
|
|
||||||
|
if success:
|
||||||
|
print("\n✅ Implementation validation successful!")
|
||||||
|
print("The provider/inject pattern should resolve timing issues.")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print("\n❌ Implementation validation failed!")
|
||||||
|
print("Please review and fix the issues before proceeding.")
|
||||||
|
sys.exit(1)
|
||||||
149
test_sidebar_provider_fix.py
Normal file
149
test_sidebar_provider_fix.py
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to validate the Sidebar LanguageProvider fix
|
||||||
|
Tests that both SideBar and ChatApp have access to LanguageProvider
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Add project root to path
|
||||||
|
project_root = Path(__file__).parent
|
||||||
|
sys.path.append(str(project_root))
|
||||||
|
|
||||||
|
def test_file_contains(file_path, search_terms, description):
|
||||||
|
"""Test if a file contains specific terms"""
|
||||||
|
full_path = project_root / file_path
|
||||||
|
if not full_path.exists():
|
||||||
|
print(f"❌ FAIL - {description}: File not found - {file_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
content = full_path.read_text(encoding='utf-8')
|
||||||
|
all_found = all(term in content for term in search_terms)
|
||||||
|
status = "✅ PASS" if all_found else "❌ FAIL"
|
||||||
|
print(f"{status} - {description}")
|
||||||
|
|
||||||
|
if not all_found:
|
||||||
|
missing = [term for term in search_terms if term not in content]
|
||||||
|
print(f" Missing terms: {missing}")
|
||||||
|
|
||||||
|
return all_found
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ FAIL - {description}: Error reading file - {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def run_tests():
|
||||||
|
"""Run all tests for the Sidebar LanguageProvider fix"""
|
||||||
|
print("🧪 Testing Sidebar LanguageProvider Fix")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
tests_passed = 0
|
||||||
|
total_tests = 0
|
||||||
|
|
||||||
|
# Test 1: chat-client.js imports LanguageProvider
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("nginx/frontend_src/js/chat-client.js",
|
||||||
|
["import { createLanguageProvider, LANGUAGE_PROVIDER_KEY }"],
|
||||||
|
"chat-client.js imports LanguageProvider"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 2: initializeSidebar creates and provides LanguageProvider
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("nginx/frontend_src/js/chat-client.js",
|
||||||
|
["createLanguageProvider(initialLanguage, apiPrefix)", "app.provide(LANGUAGE_PROVIDER_KEY, languageProvider)"],
|
||||||
|
"initializeSidebar creates and provides LanguageProvider"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 3: SideBar app listens to language-changed events
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("nginx/frontend_src/js/chat-client.js",
|
||||||
|
["languageChangeHandler", "document.addEventListener('language-changed'", "languageProvider.setLanguage"],
|
||||||
|
"SideBar app listens to language-changed events"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 4: SideBarExplanation uses useComponentTranslations
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/vue-components/SideBarExplanation.vue",
|
||||||
|
["useComponentTranslations", "sidebar_explanation"],
|
||||||
|
"SideBarExplanation uses useComponentTranslations"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
# Test 5: ChatApp still provides LanguageProvider
|
||||||
|
total_tests += 1
|
||||||
|
if test_file_contains("eveai_chat_client/static/assets/vue-components/ChatApp.vue",
|
||||||
|
["createLanguageProvider", "provide(LANGUAGE_PROVIDER_KEY"],
|
||||||
|
"ChatApp still provides LanguageProvider"):
|
||||||
|
tests_passed += 1
|
||||||
|
|
||||||
|
print("\n" + "=" * 50)
|
||||||
|
print(f"🧪 Test Results: {tests_passed}/{total_tests} tests passed")
|
||||||
|
|
||||||
|
if tests_passed == total_tests:
|
||||||
|
print("🎉 All tests passed! Sidebar LanguageProvider fix looks good.")
|
||||||
|
print("\n✅ Expected fixes:")
|
||||||
|
print(" - SideBarExplanation should no longer throw 'useLanguageProvider must be used within a LanguageProvider' error")
|
||||||
|
print(" - Sidebar explanation text should be visible and translatable")
|
||||||
|
print(" - Both sidebar and chat translations should work correctly")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"⚠️ {total_tests - tests_passed} tests failed. Please review the implementation.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def check_potential_issues():
|
||||||
|
"""Check for potential issues with the implementation"""
|
||||||
|
print("\n🔍 Checking for Potential Issues")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
issues_found = 0
|
||||||
|
|
||||||
|
# Check if both apps create separate LanguageProvider instances
|
||||||
|
chat_client_path = project_root / "nginx/frontend_src/js/chat-client.js"
|
||||||
|
if chat_client_path.exists():
|
||||||
|
content = chat_client_path.read_text(encoding='utf-8')
|
||||||
|
provider_creations = content.count('createLanguageProvider(')
|
||||||
|
if provider_creations >= 1:
|
||||||
|
print(f"✅ Found {provider_creations} LanguageProvider creation(s) in chat-client.js")
|
||||||
|
else:
|
||||||
|
print("⚠️ No LanguageProvider creation found in chat-client.js")
|
||||||
|
issues_found += 1
|
||||||
|
|
||||||
|
# Check if ChatApp also creates LanguageProvider
|
||||||
|
chatapp_path = project_root / "eveai_chat_client/static/assets/vue-components/ChatApp.vue"
|
||||||
|
if chatapp_path.exists():
|
||||||
|
content = chatapp_path.read_text(encoding='utf-8')
|
||||||
|
if 'createLanguageProvider(' in content:
|
||||||
|
print("✅ ChatApp creates LanguageProvider")
|
||||||
|
else:
|
||||||
|
print("⚠️ ChatApp doesn't create LanguageProvider")
|
||||||
|
issues_found += 1
|
||||||
|
|
||||||
|
if issues_found == 0:
|
||||||
|
print("✅ No potential issues detected")
|
||||||
|
else:
|
||||||
|
print(f"⚠️ {issues_found} potential issue(s) detected")
|
||||||
|
|
||||||
|
return issues_found == 0
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("🚀 Sidebar LanguageProvider Fix Test Suite")
|
||||||
|
print("Testing fix for 'useLanguageProvider must be used within a LanguageProvider' error")
|
||||||
|
print("=" * 70)
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
success = run_tests()
|
||||||
|
|
||||||
|
# Check for potential issues
|
||||||
|
no_issues = check_potential_issues()
|
||||||
|
|
||||||
|
if success and no_issues:
|
||||||
|
print("\n✅ Implementation validation successful!")
|
||||||
|
print("The sidebar should now have access to LanguageProvider and translations should work.")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print("\n❌ Implementation validation failed!")
|
||||||
|
print("Please review and fix the issues before testing in browser.")
|
||||||
|
sys.exit(1)
|
||||||
Reference in New Issue
Block a user