// 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 }; }