- 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:
|
||||
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
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -8,7 +8,7 @@ import { ref, computed, onMounted } from 'vue';
|
||||
*/
|
||||
export function useTranslation() {
|
||||
const isTranslationReady = ref(false);
|
||||
const currentLanguage = ref('nl');
|
||||
const currentLanguage = ref('en');
|
||||
const isTranslating = ref(false);
|
||||
const lastError = ref(null);
|
||||
|
||||
@@ -139,7 +139,7 @@ export function useTranslation() {
|
||||
* Get current language from chatConfig or fallback
|
||||
*/
|
||||
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;
|
||||
|
||||
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;
|
||||
} catch (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 ChatInput from './ChatInput.vue';
|
||||
|
||||
// Import language provider
|
||||
import { createLanguageProvider, LANGUAGE_PROVIDER_KEY } from '../js/services/LanguageProvider.js';
|
||||
import { provide } from 'vue';
|
||||
|
||||
export default {
|
||||
name: 'ChatApp',
|
||||
components: {
|
||||
@@ -54,12 +58,28 @@ export default {
|
||||
ProgressTracker,
|
||||
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() {
|
||||
// Maak een lokale kopie van de chatConfig om undefined errors te voorkomen
|
||||
const chatConfig = window.chatConfig || {};
|
||||
const settings = chatConfig.settings || {};
|
||||
const initialLanguage = chatConfig.language || 'nl';
|
||||
const initialLanguage = chatConfig.language || 'en';
|
||||
const originalExplanation = chatConfig.explanation || '';
|
||||
const tenantMake = chatConfig.tenantMake || {};
|
||||
|
||||
@@ -331,7 +351,7 @@ export default {
|
||||
// Add a placeholder AI message that will be updated by the progress tracker
|
||||
const placeholderMessage = {
|
||||
id: this.messageIdCounter++,
|
||||
content: 'Bezig met verwerken...',
|
||||
// content: 'Bezig met verwerken...',
|
||||
sender: 'ai',
|
||||
type: 'text',
|
||||
timestamp: new Date().toISOString(),
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
{{ message.content }}
|
||||
</div>
|
||||
<button v-if="message.retryable" @click="$emit('retry-message', message.id)" class="retry-btn">
|
||||
Opnieuw proberen
|
||||
{{ messageTexts.retry }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -116,6 +116,7 @@
|
||||
import DynamicForm from './DynamicForm.vue';
|
||||
import ProgressTracker from './ProgressTracker.vue';
|
||||
import { useIconManager } from '../js/composables/useIconManager.js';
|
||||
import { useComponentTranslations } from '../js/services/LanguageProvider.js';
|
||||
|
||||
export default {
|
||||
name: 'ChatMessage',
|
||||
@@ -129,7 +130,25 @@ export default {
|
||||
// Watch message.formData.icon for automatic icon loading
|
||||
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: {
|
||||
message: {
|
||||
@@ -163,12 +182,10 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// Luister naar taalwijzigingen
|
||||
document.addEventListener('language-changed', this.handleLanguageChange);
|
||||
// Component initialization if needed
|
||||
},
|
||||
beforeUnmount() {
|
||||
// Verwijder event listener bij verwijderen component
|
||||
document.removeEventListener('language-changed', this.handleLanguageChange);
|
||||
// Component cleanup if needed
|
||||
},
|
||||
computed: {
|
||||
hasFormData() {
|
||||
@@ -214,22 +231,17 @@ export default {
|
||||
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) {
|
||||
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.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.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', {
|
||||
messageId: this.message.id,
|
||||
...eventData
|
||||
|
||||
@@ -21,12 +21,26 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useLanguageProvider } from '../js/services/LanguageProvider.js';
|
||||
|
||||
export default {
|
||||
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: {
|
||||
initialLanguage: {
|
||||
type: String,
|
||||
default: 'nl'
|
||||
default: 'en'
|
||||
},
|
||||
currentLanguage: {
|
||||
type: String,
|
||||
@@ -53,11 +67,17 @@ export default {
|
||||
this.$emit('language-changed', this.selectedLanguage);
|
||||
|
||||
// DOM event
|
||||
const event = new CustomEvent('vue:language-changed', {
|
||||
const event = new CustomEvent('language-changed', {
|
||||
detail: { language: this.selectedLanguage }
|
||||
});
|
||||
document.dispatchEvent(event);
|
||||
},
|
||||
computed: {
|
||||
// Use provider language if available, otherwise use props
|
||||
effectiveCurrentLanguage() {
|
||||
return this.providerLanguage || this.currentLanguage || this.initialLanguage;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getAvailableLanguages() {
|
||||
const languages = [];
|
||||
@@ -109,7 +129,7 @@ export default {
|
||||
this.$emit('language-changed', languageCode);
|
||||
|
||||
// DOM event
|
||||
const event = new CustomEvent('vue:language-changed', {
|
||||
const event = new CustomEvent('language-changed', {
|
||||
detail: { language: languageCode }
|
||||
});
|
||||
document.dispatchEvent(event);
|
||||
|
||||
@@ -53,10 +53,34 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useTranslationClient, useConstantsTranslation } from '../js/composables/useTranslation.js';
|
||||
import { useComponentTranslations } from '../js/services/LanguageProvider.js';
|
||||
|
||||
export default {
|
||||
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: {
|
||||
taskId: {
|
||||
type: String,
|
||||
@@ -76,99 +100,56 @@ export default {
|
||||
connecting: true,
|
||||
error: null,
|
||||
progressLines: [],
|
||||
eventSource: null,
|
||||
// Vertaalde status teksten
|
||||
translatedStatusTexts: {
|
||||
error: 'Error while processing',
|
||||
completed: 'Processing completed',
|
||||
processing: 'Processing...'
|
||||
},
|
||||
currentLanguage: 'nl'
|
||||
eventSource: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isProcessing() {
|
||||
return !this.isCompleted && !this.hasError && !this.connecting;
|
||||
},
|
||||
// Computed properties voor vertaalde status teksten
|
||||
// Computed properties voor vertaalde status teksten uit provider
|
||||
errorText() {
|
||||
return this.translatedStatusTexts.error;
|
||||
return this.statusTexts.error;
|
||||
},
|
||||
completedText() {
|
||||
return this.translatedStatusTexts.completed;
|
||||
return this.statusTexts.completed;
|
||||
},
|
||||
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() {
|
||||
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() {
|
||||
this.disconnectEventSource();
|
||||
|
||||
// Cleanup language change listener
|
||||
// Remove language change event listener
|
||||
if (this.languageChangeHandler) {
|
||||
document.removeEventListener('language-changed', this.languageChangeHandler);
|
||||
}
|
||||
},
|
||||
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;
|
||||
handleLanguageChange(event) {
|
||||
if (event.detail && event.detail.language) {
|
||||
console.log(`ProgressTracker: Language changed to ${event.detail.language}`);
|
||||
// The LanguageProvider automatically updates translations through reactive system
|
||||
// Force component update to ensure UI reflects the new translations
|
||||
this.$forceUpdate();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -205,7 +186,7 @@ export default {
|
||||
|
||||
} catch (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;
|
||||
}
|
||||
},
|
||||
@@ -343,7 +324,7 @@ export default {
|
||||
});
|
||||
} catch (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.hasError = true;
|
||||
this.connecting = false;
|
||||
@@ -351,7 +332,7 @@ export default {
|
||||
|
||||
// Emit generic 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',
|
||||
taskId: this.taskId
|
||||
});
|
||||
@@ -360,7 +341,7 @@ export default {
|
||||
|
||||
handleError(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;
|
||||
|
||||
// Try to parse error data
|
||||
|
||||
@@ -49,7 +49,7 @@ const props = defineProps({
|
||||
},
|
||||
initialLanguage: {
|
||||
type: String,
|
||||
default: 'nl'
|
||||
default: 'en'
|
||||
},
|
||||
supportedLanguageDetails: {
|
||||
type: Object,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, onMounted } from 'vue';
|
||||
import { useTranslationClient } from '../js/composables/useTranslation.js';
|
||||
import { useComponentTranslations } from '../js/services/LanguageProvider.js';
|
||||
|
||||
const props = defineProps({
|
||||
originalText: {
|
||||
@@ -26,7 +26,7 @@ const props = defineProps({
|
||||
},
|
||||
currentLanguage: {
|
||||
type: String,
|
||||
default: 'nl'
|
||||
default: 'en'
|
||||
},
|
||||
apiPrefix: {
|
||||
type: String,
|
||||
@@ -34,9 +34,17 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const { translateSafe } = useTranslationClient();
|
||||
const translatedText = ref(props.originalText);
|
||||
const isLoading = ref(false);
|
||||
// Use component translations from provider
|
||||
const originalTexts = computed(() => ({
|
||||
explanation: props.originalText || ''
|
||||
}));
|
||||
|
||||
const { translations, isLoading, error, currentLanguage } = useComponentTranslations(
|
||||
'sidebar_explanation',
|
||||
originalTexts.value
|
||||
);
|
||||
|
||||
const translatedText = computed(() => translations.value.explanation || props.originalText);
|
||||
|
||||
// Render markdown content
|
||||
const renderedExplanation = computed(() => {
|
||||
@@ -52,41 +60,12 @@ const renderedExplanation = computed(() => {
|
||||
}
|
||||
});
|
||||
|
||||
// Watch for language changes
|
||||
watch(() => props.currentLanguage, async (newLanguage) => {
|
||||
await updateTranslation(newLanguage);
|
||||
});
|
||||
|
||||
// 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);
|
||||
// Watch for text changes to update the provider
|
||||
watch(() => props.originalText, () => {
|
||||
// Update original texts when prop changes
|
||||
originalTexts.value = {
|
||||
explanation: props.originalText || ''
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
allowReactions: {{ settings.allow_reactions|default('true')|lower }}
|
||||
},
|
||||
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 }},
|
||||
allowedLanguages: {{ tenant_make.allowed_languages|tojson|safe }},
|
||||
tenantMake: {
|
||||
|
||||
@@ -222,7 +222,7 @@ class SpecialistExecutor(CrewAIBaseSpecialistExecutor):
|
||||
for criterium, answer in arguments.form_values.items():
|
||||
for qa in previous_ko_questions:
|
||||
if qa.title == criterium:
|
||||
if qa.answer_positive != answer:
|
||||
if TranslationServices.translate(self.tenant_id, qa.answer_positive, arguments.language) != answer:
|
||||
evaluation = "negative"
|
||||
break
|
||||
if evaluation == "negative":
|
||||
|
||||
@@ -13,6 +13,9 @@ import { createApp, version } from 'vue';
|
||||
import { marked } from 'marked';
|
||||
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
|
||||
window.Vue = { createApp, version };
|
||||
window.marked = marked;
|
||||
@@ -78,6 +81,12 @@ function initializeSidebar() {
|
||||
// Mount de component
|
||||
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
|
||||
app.config.errorHandler = (err, vm, info) => {
|
||||
console.error('🚨 [Vue Error in Sidebar]', err);
|
||||
@@ -87,7 +96,19 @@ function initializeSidebar() {
|
||||
|
||||
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;
|
||||
} catch (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