From ce0ac59ec2f8e5967c2285771e828d6d9445c619 Mon Sep 17 00:00:00 2001 From: Staninna <26458805+Staninna@users.noreply.github.com> Date: Sat, 30 Aug 2025 01:24:06 +0200 Subject: [PATCH] test --- Auto-Image.js | 215 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 172 insertions(+), 43 deletions(-) diff --git a/Auto-Image.js b/Auto-Image.js index f3f8a47..840dbe6 100644 --- a/Auto-Image.js +++ b/Auto-Image.js @@ -277,71 +277,159 @@ function applyTheme() { // Available languages const AVAILABLE_LANGUAGES = ['en', 'ru', 'pt', 'vi', 'fr', 'id', 'tr', 'zh-CN', 'zh-TW', 'ja', 'ko', 'uk']; - // Function to load translations from JSON file - const loadTranslations = async (language) => { + // Function to load translations from JSON file with retry mechanism + const loadTranslations = async (language, retryCount = 0) => { if (loadedTranslations[language]) { return loadedTranslations[language]; } // Load translations from CDN const url = `https://staninna.github.io/WPlace-AutoBOT/decoupled-translations/lang/${language}.json`; + const maxRetries = 3; + const baseDelay = 1000; // 1 second try { - console.log(`🔄 Loading ${language} translations from CDN...`); + if (retryCount === 0) { + console.log(`🔄 Loading ${language} translations from CDN...`); + } else { + console.log(`🔄 Retrying ${language} translations (attempt ${retryCount + 1}/${maxRetries + 1})...`); + } + const response = await fetch(url); if (response.ok) { const translations = await response.json(); - loadedTranslations[language] = translations; - console.log(`📚 Loaded ${language} translations successfully from CDN`); - return translations; + + // Validate that translations is an object with keys + if (typeof translations === 'object' && translations !== null && Object.keys(translations).length > 0) { + loadedTranslations[language] = translations; + console.log(`📚 Loaded ${language} translations successfully from CDN (${Object.keys(translations).length} keys)`); + return translations; + } else { + console.warn(`❌ Invalid translation format for ${language}`); + throw new Error('Invalid translation format'); + } } else { console.warn(`❌ CDN returned HTTP ${response.status}: ${response.statusText} for ${language} translations`); + throw new Error(`HTTP ${response.status}: ${response.statusText}`); } } catch (error) { - console.error(`❌ Failed to load ${language} translations from CDN:`, error); + console.error(`❌ Failed to load ${language} translations from CDN (attempt ${retryCount + 1}):`, error); + + // Retry with exponential backoff + if (retryCount < maxRetries) { + const delay = baseDelay * Math.pow(2, retryCount); + console.log(`⏳ Retrying in ${delay}ms...`); + await new Promise(resolve => setTimeout(resolve, delay)); + return loadTranslations(language, retryCount + 1); + } } return null; }; const loadLanguagePreference = async () => { - const savedLanguage = localStorage.getItem("wplace_language") + const savedLanguage = localStorage.getItem("wplace_language"); + const browserLocale = navigator.language; + const browserLanguage = browserLocale.split("-")[0]; - const browserLocale = navigator.language - const browserLanguage = browserLocale.split("-")[0] + let selectedLanguage = "en"; // Default fallback - // Check if we have the saved language available - if (savedLanguage && AVAILABLE_LANGUAGES.includes(savedLanguage)) { - state.language = savedLanguage - await loadTranslations(savedLanguage) - return + try { + // Check if we have the saved language available + if (savedLanguage && AVAILABLE_LANGUAGES.includes(savedLanguage)) { + selectedLanguage = savedLanguage; + console.log(`🔄 Using saved language preference: ${selectedLanguage}`); + } + // Try full locale match (e.g. "zh-CN", "zh-TW" etc) + else if (AVAILABLE_LANGUAGES.includes(browserLocale)) { + selectedLanguage = browserLocale; + localStorage.setItem("wplace_language", browserLocale); + console.log(`🔄 Using browser locale: ${selectedLanguage}`); + } + // Try base language match (e.g. "en" for "en-US" or "en-GB" etc) + else if (AVAILABLE_LANGUAGES.includes(browserLanguage)) { + selectedLanguage = browserLanguage; + localStorage.setItem("wplace_language", browserLanguage); + console.log(`🔄 Using browser language: ${selectedLanguage}`); + } + // Use English as fallback + else { + console.log(`🔄 No matching language found, using English fallback`); + } + + // Set the language in state first + state.language = selectedLanguage; + + // Only load translations if not already loaded and not English (which should already be loaded) + if (selectedLanguage !== "en" && !loadedTranslations[selectedLanguage]) { + const loaded = await loadTranslations(selectedLanguage); + if (!loaded) { + console.warn(`⚠️ Failed to load ${selectedLanguage} translations, falling back to English`); + state.language = "en"; + localStorage.setItem("wplace_language", "en"); + } + } + } catch (error) { + console.error(`❌ Error in loadLanguagePreference:`, error); + state.language = "en"; // Always ensure we have a valid language } - - // Try full locale match (e.g. "zh-CN", "zh-TW" etc) - if (AVAILABLE_LANGUAGES.includes(browserLocale)) { - state.language = browserLocale - localStorage.setItem("wplace_language", browserLocale) - await loadTranslations(browserLocale) - return - } - - // Try base language match (e.g. "en" for "en-US" or "en-GB" etc) - if (AVAILABLE_LANGUAGES.includes(browserLanguage)) { - state.language = browserLanguage - localStorage.setItem("wplace_language", browserLanguage) - await loadTranslations(browserLanguage) - return - } - - // Fallback to English - state.language = "en" - await loadTranslations("en") - } + }; - // Always ensure English is loaded as fallback - if (!loadedTranslations["en"]) { - await loadTranslations("en") - } + // Simple user notification function for critical issues + const showTranslationWarning = (message) => { + try { + // Create a simple temporary notification banner + const warning = document.createElement('div'); + warning.style.cssText = ` + position: fixed; top: 10px; right: 10px; z-index: 10001; + background: rgba(255, 193, 7, 0.95); color: #212529; padding: 12px 16px; + border-radius: 8px; font-size: 14px; font-weight: 500; + box-shadow: 0 4px 12px rgba(0,0,0,0.3); border: 1px solid rgba(255, 193, 7, 0.8); + max-width: 300px; word-wrap: break-word; + `; + warning.textContent = message; + document.body.appendChild(warning); + + // Auto-remove after 8 seconds + setTimeout(() => { + if (warning.parentNode) { + warning.remove(); + } + }, 8000); + } catch (e) { + // If DOM manipulation fails, just log + console.warn("Failed to show translation warning UI:", e); + } + }; + + // Initialize translations function + const initializeTranslations = async () => { + try { + console.log("🌐 Initializing translation system..."); + + // Always ensure English is loaded as fallback first + if (!loadedTranslations["en"]) { + const englishLoaded = await loadTranslations("en"); + if (!englishLoaded) { + console.warn("⚠️ Failed to load English translations from CDN, using fallback"); + showTranslationWarning("⚠️ Translation loading failed, using basic fallbacks"); + } + } + + // Then load user's language preference + await loadLanguagePreference(); + + console.log(`✅ Translation system initialized. Active language: ${state.language}`); + } catch (error) { + console.error("❌ Translation initialization failed:", error); + // Ensure state has a valid language even if loading fails + if (!state.language) { + state.language = "en"; + } + console.warn("⚠️ Using fallback translations due to initialization failure"); + showTranslationWarning("⚠️ Translation system error, using basic English"); + } + }; // Emergency fallback TEXT (minimal) const FALLBACK_TEXT = { @@ -350,10 +438,45 @@ function applyTheme() { settings: "Settings", close: "Close", language: "Language", - loadingError: "Loading translations failed, using fallback" + loadingError: "Loading translations failed, using fallback", + scanColors: "Scan Colors", + uploadImage: "Upload Image", + startPainting: "Start Painting", + stopPainting: "Stop Painting", + progress: "Progress", + pixels: "Pixels", + charges: "Charges", + initMessage: "Click 'Upload Image' to begin" } }; + // Safe translation function with multiple fallback levels + const getText = (key, replacements = {}) => { + // Try current language first + let text = loadedTranslations[state.language]?.[key]; + + // Fallback to English translations + if (!text && state.language !== 'en') { + text = loadedTranslations['en']?.[key]; + } + + // Fallback to hardcoded English + if (!text) { + text = FALLBACK_TEXT['en']?.[key]; + } + + // Last resort - return the key itself + if (!text) { + console.warn(`⚠️ Missing translation for key: ${key}`); + return key; + } + + // Handle string replacements like {count}, {time}, etc. + return Object.entries(replacements).reduce((result, [placeholder, value]) => { + return result.replace(new RegExp(`\\{${placeholder}\\}`, 'g'), value); + }, text); + }; + // GLOBAL STATE const state = { running: false, @@ -1401,8 +1524,14 @@ function applyTheme() { // Final fallback to emergency fallback or key let text = FALLBACK_TEXT[state.language]?.[key] || FALLBACK_TEXT.en?.[key] || key; Object.keys(params).forEach((param) => { - text = text.replace(`{${param}}`, params[param]); + text = text.replace(new RegExp(`\\{${param}\\}`, 'g'), params[param]); }); + + // Log missing translations for debugging + if (text === key && key !== 'undefined') { + console.warn(`⚠️ Missing translation for key: ${key} (language: ${state.language})`); + } + return text; }, @@ -2580,7 +2709,7 @@ function applyTheme() { if (existingResizeOverlay) existingResizeOverlay.remove() loadThemePreference() - await loadLanguagePreference() + await initializeTranslations() const theme = getCurrentTheme() applyTheme() // <- new: set CSS vars and theme class before building UI