Initial commit: Add MathHomeworkHelper project with web and Android components
Some checks reported errors
continuous-integration/drone Build encountered an error
Some checks reported errors
continuous-integration/drone Build encountered an error
This commit is contained in:
commit
f9558008e1
37 changed files with 5318 additions and 0 deletions
184
translations.js
Normal file
184
translations.js
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
// Translation Manager
|
||||
class TranslationManager {
|
||||
constructor() {
|
||||
this.currentLanguage = 'en'; // Will be set during initialization
|
||||
this.translations = {};
|
||||
this.supportedLanguages = {
|
||||
'en': { name: 'English', flag: '🇬🇧' },
|
||||
'es': { name: 'Español', flag: '🇪🇸' },
|
||||
'sv': { name: 'Svenska', flag: '🇸🇪' },
|
||||
'el': { name: 'Ελληνικά', flag: '🇬🇷' }
|
||||
};
|
||||
|
||||
// Country to language mapping
|
||||
this.countryToLanguage = {
|
||||
// Spanish-speaking countries
|
||||
'ES': 'es', 'MX': 'es', 'AR': 'es', 'CO': 'es', 'PE': 'es', 'VE': 'es',
|
||||
'CL': 'es', 'EC': 'es', 'BO': 'es', 'PY': 'es', 'UY': 'es', 'CU': 'es',
|
||||
'DO': 'es', 'GT': 'es', 'HN': 'es', 'SV': 'es', 'NI': 'es', 'CR': 'es',
|
||||
'PA': 'es', 'BZ': 'es', 'EQ': 'es',
|
||||
// Swedish-speaking countries
|
||||
'SE': 'sv', 'FI': 'sv', 'AX': 'sv',
|
||||
// Greek-speaking countries
|
||||
'GR': 'el', 'CY': 'el',
|
||||
// Default to English for all others
|
||||
};
|
||||
}
|
||||
|
||||
// Detect language with geolocation fallback
|
||||
async detectLanguageWithGeolocation() {
|
||||
// Step 1: Check localStorage for saved preference
|
||||
const savedLanguage = localStorage.getItem('preferredLanguage');
|
||||
if (savedLanguage && this.supportedLanguages[savedLanguage]) {
|
||||
console.log('Using saved language preference:', savedLanguage);
|
||||
return savedLanguage;
|
||||
}
|
||||
|
||||
// Step 2: Try browser language detection
|
||||
const browserLang = this.detectBrowserLanguage();
|
||||
if (browserLang !== 'en') {
|
||||
console.log('Using browser language:', browserLang);
|
||||
return browserLang;
|
||||
}
|
||||
|
||||
// Step 3: Try geolocation API to get country and map to language
|
||||
try {
|
||||
const countryCode = await this.getCountryFromGeolocation();
|
||||
if (countryCode) {
|
||||
const language = this.countryToLanguage[countryCode] || 'en';
|
||||
console.log('Using geolocation-based language:', language, 'from country:', countryCode);
|
||||
return language;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Geolocation failed, continuing with fallback:', error.message);
|
||||
}
|
||||
|
||||
// Step 4: Fallback to English
|
||||
console.log('Falling back to English');
|
||||
return 'en';
|
||||
}
|
||||
|
||||
// Detect browser language
|
||||
detectBrowserLanguage() {
|
||||
const browserLang = navigator.language || navigator.userLanguage;
|
||||
const langCode = browserLang.split('-')[0];
|
||||
|
||||
// Check if the detected language is supported
|
||||
if (this.supportedLanguages[langCode]) {
|
||||
return langCode;
|
||||
}
|
||||
|
||||
// Return 'en' if not supported (will trigger geolocation)
|
||||
return 'en';
|
||||
}
|
||||
|
||||
// Get country code from geolocation API
|
||||
async getCountryFromGeolocation() {
|
||||
const timeout = 5000; // 5 second timeout
|
||||
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
||||
|
||||
// Try ip-api.com (free, no auth required)
|
||||
const response = await fetch('https://ipapi.co/json/', {
|
||||
signal: controller.signal,
|
||||
headers: { 'Accept': 'application/json' }
|
||||
});
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API returned status ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const countryCode = data.country_code;
|
||||
|
||||
if (countryCode && typeof countryCode === 'string') {
|
||||
console.log('Geolocation API returned country:', countryCode);
|
||||
return countryCode;
|
||||
}
|
||||
|
||||
throw new Error('No country code in response');
|
||||
} catch (error) {
|
||||
if (error.name === 'AbortError') {
|
||||
console.warn('Geolocation API request timed out');
|
||||
} else {
|
||||
console.warn('Geolocation API error:', error.message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Load translation file
|
||||
async loadTranslation(language) {
|
||||
try {
|
||||
const response = await fetch(`translations/${language}.json`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load ${language} translation`);
|
||||
}
|
||||
this.translations[language] = await response.json();
|
||||
this.currentLanguage = language;
|
||||
localStorage.setItem('preferredLanguage', language);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error loading translation:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get translated string
|
||||
t(key) {
|
||||
if (this.translations[this.currentLanguage] && this.translations[this.currentLanguage][key]) {
|
||||
return this.translations[this.currentLanguage][key];
|
||||
}
|
||||
// Fallback to English if key not found
|
||||
if (this.translations['en'] && this.translations['en'][key]) {
|
||||
return this.translations['en'][key];
|
||||
}
|
||||
// Return key if no translation found
|
||||
return key;
|
||||
}
|
||||
|
||||
// Get current language
|
||||
getCurrentLanguage() {
|
||||
return this.currentLanguage;
|
||||
}
|
||||
|
||||
// Get all supported languages
|
||||
getSupportedLanguages() {
|
||||
return this.supportedLanguages;
|
||||
}
|
||||
|
||||
// Set language
|
||||
setLanguage(language) {
|
||||
if (this.supportedLanguages[language]) {
|
||||
this.currentLanguage = language;
|
||||
localStorage.setItem('preferredLanguage', language);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize translations
|
||||
async initialize() {
|
||||
// Detect language using geolocation fallback chain
|
||||
this.currentLanguage = await this.detectLanguageWithGeolocation();
|
||||
|
||||
// Load all supported language files
|
||||
const loadPromises = Object.keys(this.supportedLanguages).map(lang =>
|
||||
this.loadTranslation(lang)
|
||||
);
|
||||
|
||||
await Promise.all(loadPromises);
|
||||
|
||||
// Ensure current language is set correctly
|
||||
if (!this.translations[this.currentLanguage]) {
|
||||
this.currentLanguage = 'en';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create global instance
|
||||
const i18n = new TranslationManager();
|
||||
Loading…
Add table
Add a link
Reference in a new issue