Refactored modules and updated loader.

This commit is contained in:
2025-04-06 18:35:04 +00:00
parent fc693ae695
commit 0ab639fd25
37 changed files with 3530 additions and 5989 deletions
+254
View File
@@ -0,0 +1,254 @@
/**
* Localization Module for AI Interactive Fiction
* Handles translations and locale settings
*/
import { BaseModule } from './base-module.js';
class LocalizationModule extends BaseModule {
/**
* Create a new localization module
*/
constructor() {
super('localization', 'Localization');
// Current locale
this.translations = {};
this.defaultLocale = 'en-us';
this.currentLocale = this.defaultLocale;
this.dependencies = ['persistence-manager'];
// Available translations
this.languageNames = {
'en-us': 'English (US)',
'en-gb': 'English (UK)',
'de-de': 'Deutsch (Deutschland)'
};
// Bind methods
this.bindMethods([
'setLocale',
'getLocale',
'translate',
'getAvailableLocales',
'getLanguageName',
'getLanguage'
]);
}
/**
* Initialize the module
* @returns {Promise<boolean>} - Resolves with success status
*/
async initialize() {
try {
this.reportProgress(10, "Initializing localization");
// Load default English locale
await this.loadTranslations('en-us');
this.reportProgress(50, "Loaded default locale");
// Get stored locale from persistence manager if available
const persistenceManager = this.getModule('persistence-manager');
if (persistenceManager) {
const storedLocale = persistenceManager.getPreference('app', 'locale');
if (storedLocale) {
console.log(`Localization: Found stored locale: ${storedLocale}`);
await this.loadTranslations(storedLocale);
this.currentLocale = storedLocale;
this.reportProgress(80, `Loaded stored locale: ${storedLocale}`);
} else {
// If no stored locale, ensure en-us is the default and persist it
console.log('Localization: No stored locale found, using default en-us');
persistenceManager.updatePreference('app', 'locale', 'en-us');
persistenceManager.updatePreference('tts', 'language', 'en-us');
this.currentLocale = 'en-us';
this.reportProgress(80, "Using default locale: en-us");
}
} else {
console.log('Localization: Persistence manager not available, using default en-us locale');
this.reportProgress(80, "Using default locale: en-us");
}
// Dispatch event to notify about loaded locale
document.dispatchEvent(new CustomEvent('localization:languageChanged', {
detail: { locale: this.currentLocale }
}));
this.reportProgress(100, "Localization ready");
return true;
} catch (error) {
console.error("Error initializing localization:", error);
this.reportProgress(100, "Localization failed");
return false;
}
}
/**
* Load translations for a locale
* @param {string} locale - Locale to load
* @returns {Promise<void>}
*/
async loadTranslations(locale) {
if (this.translations[locale]) {
return; // Already loaded
}
try {
// Normalize locale
const normalizedLocale = locale.toLowerCase();
// Try to load the exact locale
const response = await fetch(`/locales/${normalizedLocale}.json`);
if (response.ok) {
const translations = await response.json();
this.translations[normalizedLocale] = translations;
} else {
// If exact locale not found, try to load just the language part
const langPart = normalizedLocale.split('-')[0];
if (langPart !== normalizedLocale) {
const langResponse = await fetch(`/locales/${langPart}.json`);
if (langResponse.ok) {
const translations = await langResponse.json();
this.translations[normalizedLocale] = translations;
} else {
console.warn(`No translations found for ${locale} or ${langPart}`);
}
}
}
} catch (error) {
console.error(`Error loading translations for ${locale}:`, error);
throw error;
}
}
/**
* Set the current locale
* @param {string} locale - Locale to set
* @returns {Promise<boolean>} - Success status
*/
async setLocale(locale) {
if (!locale) return false;
try {
// Normalize locale
const normalizedLocale = locale.toLowerCase();
// Load translations if not already loaded
if (!this.translations[normalizedLocale]) {
await this.loadTranslations(normalizedLocale);
}
// Set current locale
this.currentLocale = normalizedLocale;
// Update persistence
const persistenceManager = this.getModule('persistence-manager');
if (persistenceManager) {
persistenceManager.updatePreference('app', 'locale', normalizedLocale);
}
// Dispatch locale change event
this.dispatchEvent('locale-changed', {
locale: normalizedLocale
});
return true;
} catch (error) {
console.error(`Error setting locale to ${locale}:`, error);
return false;
}
}
/**
* Get the current locale
* @returns {string} - Current locale
*/
getLocale() {
return this.currentLocale;
}
/**
* Get the language part of the current locale (e.g., 'en' from 'en-us')
* @returns {string} - Language code
*/
getLanguage() {
return this.currentLocale.split('-')[0];
}
/**
* Get all available locales
* @returns {Array<string>} - Array of locale codes
*/
getAvailableLocales() {
// Return the keys of the language names object
// This is a simplification - in a real app, we would dynamically load available locales
return Object.keys(this.languageNames);
}
/**
* Get the language name for a locale
* @param {string} locale - Locale code
* @returns {string} - Language name
*/
getLanguageName(locale) {
if (!locale) return '';
// Normalize locale
const normalizedLocale = locale.toLowerCase();
// Try exact match
if (this.languageNames[normalizedLocale]) {
return this.languageNames[normalizedLocale];
}
// Try language part only
const langPart = normalizedLocale.split('-')[0];
if (this.languageNames[langPart]) {
return this.languageNames[langPart];
}
// Fallback: return the locale code itself
return locale;
}
/**
* Translate a key
* @param {string} key - Translation key
* @param {Object} params - Parameters for interpolation
* @returns {string} - Translated text
*/
translate(key, params = {}) {
if (!key) return '';
// Get translations for current locale
const translations = this.translations[this.currentLocale] || {};
// Get translation or fallback to key
let translation = translations[key] || key;
// Interpolate parameters
if (params && Object.keys(params).length > 0) {
for (const [param, value] of Object.entries(params)) {
translation = translation.replace(new RegExp(`\{\{${param}\}\}`, 'g'), value);
}
}
return translation;
}
/**
* Clean up when module is disposed
*/
dispose() {
// Clear translations
this.translations = {};
}
}
// Create the singleton instance
const Localization = new LocalizationModule();
// Export the module
export { Localization };