Language Translation System
Language Translation System
Section titled “Language Translation System”Overview
Section titled “Overview”The Nursery App supports multiple languages (Kannada, Hindi, Bengali, Tamil, Telugu, Punjabi, Malayalam, Marathi, Assamese, Gujarati) for translating UI text throughout the application.
Key Features
Section titled “Key Features”- Multi-language support (10+ languages)
- Dynamic language switching
- Persistent storage via IndexedDB
- API-driven updates (planned)
- Fallback to English if translation unavailable
Current Implementation
Section titled “Current Implementation”How It Works Now
Section titled “How It Works Now”Current State:
- Uses hardcoded
language_listarray inlanguage.js(22,000+ lines) - Array contains all translations in memory
formatted_language_data.jsonexists but is NOT currently used
Location:
www/scripts/language.js- Containslanguage_listarray (line 8741)www/scripts/formatted_language_data.json- Source file (not loaded)
Translation Function:
// In language.jsfunction translate(text) { const currentLanguage = global("current_language").getValue(); const entry = language_list.find(item => item.english === text); if (entry) { return entry[currentLanguage.toLowerCase()] || text; } return text; // Returns original English if not found}Data Structure:
var language_list = [ { id: 1, type: "image", english: "./images/company_logo_english.png", kannada: "./images/company_logo_kannada.png", hindi: "./images/company_logo_hindi.png", // ... other languages }, { id: 2, type: "text", english: "Nursery", kannada: "ನರ್ಸರಿ", hindi: "नर्सरी", bengali: "নার্সারি", // ... other languages } // ... 26,000+ more entries];Limitations:
- ❌ Requires code deployment to update translations
- ❌ Large memory footprint (entire array loaded)
- ❌ No version control for translations
- ❌ JSON file not being used
New IndexedDB System
Section titled “New IndexedDB System”Purpose
Section titled “Purpose”Move from hardcoded array to IndexedDB for:
- ✅ Dynamic updates without app redeployment
- ✅ API-driven translation updates
- ✅ Persistent storage across sessions
- ✅ Version control for translations
Implementation
Section titled “Implementation”Location:
www/scripts/functions.js-LanguageDataDBUtilClass(line 22016)
Database Structure:
- Database Name:
NurseryLanguageDB - Object Store:
language_data - Version: 2
- Primary Key:
[language_id, text_id](composite key)
Record Format:
{ language_id: "kannada", // Language identifier text_id: 2, // Text entry ID english_value: "Nursery", // English text native_value: "ನರ್ಸರಿ" // Translated text}Available Methods
Section titled “Available Methods”1. Initialize and Load Data
Section titled “1. Initialize and Load Data”// Load from JSON fileawait initializeLanguageDataDB("./scripts/formatted_language_data.json");
// Force reload (clears existing data)await initializeLanguageDataDB("./scripts/formatted_language_data.json", true);2. Store Language Data
Section titled “2. Store Language Data”// Store JSON data directlyconst jsonData = await fetch("./scripts/formatted_language_data.json").then(r => r.json());await LanguageDataDB.storeLanguageData(jsonData, true); // true = clear existing3. Query Translations
Section titled “3. Query Translations”// Get all records for a languageconst kannadaRecords = await LanguageDataDB.getLanguageRecords("kannada");
// Get specific translation by language_id and text_idconst translation = await LanguageDataDB.getTranslation("kannada", 2);// Returns: { language_id: "kannada", text_id: 2, english_value: "Nursery", native_value: "ನರ್ಸರಿ" }
// Get translation by English textconst translated = await LanguageDataDB.getTranslationByEnglish("kannada", "Nursery");// Returns: "ನರ್ಸರಿ"4. Utility Methods
Section titled “4. Utility Methods”// Get total record countconst count = await LanguageDataDB.getRecordCount();
// Clear all dataawait LanguageDataDB.clearAll();Architecture & Flow
Section titled “Architecture & Flow”Current Flow (Array-Based)
Section titled “Current Flow (Array-Based)”App Loads ↓language_list array loaded in memory ↓User selects language (e.g., "kannada") ↓translate("Nursery") called ↓Searches language_list array ↓Returns: "ನರ್ಸರಿ" ↓HTML updated with translated textNew Flow (IndexedDB-Based)
Section titled “New Flow (IndexedDB-Based)”App Loads ↓Check API for language version ↓If new version exists: - Download formatted_language_data.json - Store in IndexedDB ↓User selects language (e.g., "kannada") ↓translate("Nursery") called ↓Query IndexedDB: getTranslationByEnglish("kannada", "Nursery") ↓Returns: "ನರ್ಸರಿ" ↓HTML updated with translated textHybrid Flow (Recommended)
Section titled “Hybrid Flow (Recommended)”App Loads ↓Load current language from IndexedDB into memory cache ↓User selects language ↓translate("Nursery") called ↓Check memory cache first (fast) ↓If not in cache, query IndexedDB ↓Update cache with result ↓Return translated textAPI Update Mechanism
Section titled “API Update Mechanism”Update Flow
Section titled “Update Flow”Step 1: Check for Updates
// On app startup (login page)async function checkLanguageVersion() { const response = await fetch('/api/language/version', { headers: { 'Authorization': `Bearer ${JWT_token}` } }); const data = await response.json(); // Returns: { version: 2, url: "https://.../formatted_language_data.json" } return data;}Step 2: Compare Versions
const storedVersion = localStorage.getItem('language_version') || 1;const apiVersion = await checkLanguageVersion();
if (apiVersion.version > storedVersion) { // Update needed await updateLanguageData(apiVersion.url);}Step 3: Download and Store
async function updateLanguageData(jsonUrl) { try { // Download new JSON const response = await fetch(jsonUrl); const jsonData = await response.json();
// Store in IndexedDB (clears existing) await LanguageDataDB.storeLanguageData(jsonData, true);
// Update version localStorage.setItem('language_version', apiVersion.version);
console.log('Language data updated successfully'); } catch (error) { console.error('Failed to update language data:', error); // App continues with existing translations }}Step 4: Background Update (Non-Blocking)
// On login page loadfunction initLoginPage() { // Show login form immediately showLoginForm();
// Check for updates in background (non-blocking) checkLanguageVersion() .then(data => { if (needsUpdate(data)) { updateLanguageData(data.url); } }) .catch(err => { // Even if update fails, login still works console.error('Language update failed:', err); });}API Endpoint Structure
Section titled “API Endpoint Structure”Expected API Response:
{ "version": 2, "url": "https://api.example.com/language/formatted_language_data.json", "last_updated": "2024-01-15T10:30:00Z", "languages_supported": ["kannada", "hindi", "bengali", "tamil", "telugu", "punjabi", "malayalam", "marathi", "assamese", "gujrati"]}Translation Flow
Section titled “Translation Flow”How translate() Works
Section titled “How translate() Works”Current Implementation:
function translate(text) { // 1. Check if language_list exists if (!Array.isArray(language_list)) { return text; // Fallback to English }
// 2. Get current language const currentLanguage = global("current_language").getValue();
// 3. If English, return original if (currentLanguage === "english") { return text; }
// 4. Search array for translation const entry = language_list.find(item => item.english === text);
// 5. Return translation or original return entry?.[currentLanguage] || text;}Future Implementation (IndexedDB):
// Option 1: Async with cachinglet translationCache = {}; // Memory cache
async function translate(text) { const currentLanguage = global("current_language").getValue();
if (currentLanguage === "english") { return text; }
// Check cache first const cacheKey = `${currentLanguage}_${text}`; if (translationCache[cacheKey]) { return translationCache[cacheKey]; }
// Query IndexedDB try { const translated = await LanguageDataDB.getTranslationByEnglish( currentLanguage, text );
// Update cache translationCache[cacheKey] = translated; return translated; } catch (error) { // Fallback to English return text; }}Option 2: Sync with Pre-loaded Cache
// Load language into memory on language changelet currentLanguageCache = {};
async function loadLanguageCache(languageId) { const records = await LanguageDataDB.getLanguageRecords(languageId); currentLanguageCache = {}; records.forEach(record => { currentLanguageCache[record.english_value] = record.native_value; });}
function translate(text) { const currentLanguage = global("current_language").getValue();
if (currentLanguage === "english") { return text; }
// Fast lookup from memory cache return currentLanguageCache[text] || text;}Where translate() is Used
Section titled “Where translate() is Used”In internal.js:
load_language()- Translates all page elements- Button captions
- Text elements
- Input placeholders
- Menu items
- Alert dialogs
Example Usage:
// Translate buttondocument.getElementById("button_login").innerHTML = translate("Login");
// Translate textdocument.getElementById("text_nursery").innerHTML = translate("Nursery");
// Translate placeholderdocument.getElementById("input_search").placeholder = translate("Search");Implementation Details
Section titled “Implementation Details”IndexedDB Storage Format
Section titled “IndexedDB Storage Format”Transformation: The JSON structure is flattened for efficient querying:
Input (JSON):
{ "id": 2, "type": "text", "english": "Nursery", "kannada": { "value": "ನರ್ಸರಿ", "size": 0, "weight": 0 }, "hindi": { "value": "नर्सरी", "size": 0, "weight": 0 }}Output (IndexedDB):
// Multiple records created:{ language_id: "kannada", text_id: 2, english_value: "Nursery", native_value: "ನರ್ಸರಿ" }{ language_id: "hindi", text_id: 2, english_value: "Nursery", native_value: "नर्सरी" }Batch Processing
Section titled “Batch Processing”Why Batches?
- IndexedDB transactions auto-commit when event loop finishes
- Large datasets (26,000+ records) can cause transaction timeouts
- Processing in batches of 1000 ensures transactions complete successfully
Implementation:
// Process in batches of 1000const batchSize = 1000;for (let i = 0; i < allRecords.length; i += batchSize) { const batch = allRecords.slice(i, i + batchSize); // Open new transaction for each batch // Store batch // Wait for transaction to complete}Indexes Created
Section titled “Indexes Created”For efficient queries:
language_idindex - Fast lookup by languagetext_idindex - Fast lookup by text IDenglish_valueindex - Fast lookup by English text
Migration Strategy
Section titled “Migration Strategy”Phase 1: Setup (Current)
Section titled “Phase 1: Setup (Current)”- ✅ IndexedDB utility class created
- ✅ Data storage methods implemented
- ✅ Query methods available
- ⏳
translate()still uses array
Phase 2: Hybrid Approach (Recommended)
Section titled “Phase 2: Hybrid Approach (Recommended)”- Keep
language_listarray as fallback - Update
translate()to check IndexedDB first - Fall back to array if IndexedDB not ready
- Load current language into memory cache
Implementation:
let useIndexedDB = false;let languageCache = {};
// Check if IndexedDB has dataasync function initTranslation() { const count = await LanguageDataDB.getRecordCount(); if (count > 0) { useIndexedDB = true; await loadLanguageCache(global("current_language").getValue()); }}
function translate(text) { // Use cache if IndexedDB is ready if (useIndexedDB && languageCache[text]) { return languageCache[text]; }
// Fallback to array if (Array.isArray(language_list)) { const entry = language_list.find(item => item.english === text); return entry?.[currentLanguage] || text; }
return text;}Phase 3: Full Migration
Section titled “Phase 3: Full Migration”- Remove
language_listarray translate()uses only IndexedDB- Ensure IndexedDB is always initialized before use
- Implement proper error handling
Phase 4: API Integration
Section titled “Phase 4: API Integration”- Implement version check API call
- Automatic updates on app startup
- Background sync mechanism
FAQs & Common Questions
Section titled “FAQs & Common Questions”Q1: Is the JSON file currently being used?
Section titled “Q1: Is the JSON file currently being used?”A: No. The formatted_language_data.json file exists but is not loaded or used. Everything currently uses the hardcoded language_list array in language.js.
Q2: What happens if I remove the array and IndexedDB isn’t ready?
Section titled “Q2: What happens if I remove the array and IndexedDB isn’t ready?”A: The translate() function will return the original English text. Since HTML elements already contain English text (e.g., <h1>Nursery</h1>), users will see English until IndexedDB is ready. This is a safe fallback.
Q3: Will storing in IndexedDB on login page affect login?
Section titled “Q3: Will storing in IndexedDB on login page affect login?”A: No. IndexedDB operations are asynchronous and non-blocking. The login form appears immediately, and language data stores in the background without affecting login functionality.
Q4: Does cache work in IndexedDB?
Section titled “Q4: Does cache work in IndexedDB?”A: Yes, but there are two approaches:
- IndexedDB cache: Persistent but slower (good for storing user’s frequently used translations)
- Memory cache: Fast but temporary (good for current session’s active language)
- Hybrid: Best of both - load current language into memory, use IndexedDB as source of truth
Q5: How does translation work when user selects a language?
Section titled “Q5: How does translation work when user selects a language?”A:
- User selects language (e.g., “kannada”)
global("current_language").setValue("kannada")is calledload_language()function runs- For each element with
language: true,translate()is called translate()queries IndexedDB (or array) for translation- Element’s innerHTML is updated with translated text
Q6: What’s the difference between the array and JSON file?
Section titled “Q6: What’s the difference between the array and JSON file?”A:
- Array (
language_list): Hardcoded in JavaScript, loaded in memory, requires code deployment to update - JSON file: Source of truth, can be updated via API, needs to be loaded and stored in IndexedDB
Q7: How many records are stored in IndexedDB?
Section titled “Q7: How many records are stored in IndexedDB?”A: Approximately 26,000+ records (26,018 text entries × 10 languages = ~260,180 records)
Q8: What if IndexedDB fails or is not supported?
Section titled “Q8: What if IndexedDB fails or is not supported?”A: The system should fall back to the language_list array. Always implement fallback logic:
try { // Try IndexedDB return await LanguageDataDB.getTranslationByEnglish(language, text);} catch (error) { // Fallback to array const entry = language_list.find(item => item.english === text); return entry?.[language] || text;}Q9: How do I update translations without redeploying?
Section titled “Q9: How do I update translations without redeploying?”A:
- Update
formatted_language_data.jsonon server - Increment version number
- App checks API on startup
- Downloads new JSON if version is higher
- Stores in IndexedDB
- Translations update automatically
Q10: What’s the performance impact?
Section titled “Q10: What’s the performance impact?”A:
- Array lookup: O(n) search, but in memory (very fast)
- IndexedDB query: Async, but uses indexes (fast with proper indexing)
- Memory cache: O(1) lookup (fastest)
- Recommendation: Use memory cache for active language, IndexedDB for storage
Usage Examples
Section titled “Usage Examples”Example 1: Initialize on App Startup
Section titled “Example 1: Initialize on App Startup”// In login page or app initializationasync function initApp() { try { // Check if IndexedDB has data const count = await LanguageDataDB.getRecordCount();
if (count === 0) { // First time - load from JSON await initializeLanguageDataDB("./scripts/formatted_language_data.json"); } else { // Data exists - check for updates checkForLanguageUpdates(); } } catch (error) { console.error("Language initialization failed:", error); // App continues with array fallback }}Example 2: Check for Updates
Section titled “Example 2: Check for Updates”async function checkForLanguageUpdates() { try { const response = await fetch('/api/language/version', { headers: { 'Authorization': `Bearer ${JWT_token}` } }); const apiData = await response.json(); const storedVersion = parseInt(localStorage.getItem('language_version') || '1');
if (apiData.version > storedVersion) { console.log('New language version available:', apiData.version);
// Download and update const jsonData = await fetch(apiData.url).then(r => r.json()); await LanguageDataDB.storeLanguageData(jsonData, true); localStorage.setItem('language_version', apiData.version);
// Reload current language cache if needed await reloadLanguageCache(); } } catch (error) { console.error('Update check failed:', error); }}Example 3: Load Language Cache
Section titled “Example 3: Load Language Cache”let languageCache = {};
async function loadLanguageCache(languageId) { try { const records = await LanguageDataDB.getLanguageRecords(languageId); languageCache = {};
records.forEach(record => { if (record.native_value) { languageCache[record.english_value] = record.native_value; } });
console.log(`Loaded ${Object.keys(languageCache).length} translations for ${languageId}`); } catch (error) { console.error('Failed to load language cache:', error); languageCache = {}; // Empty cache, will fallback to array }}
// Call when language changesfunction onLanguageChange(newLanguage) { global("current_language").setValue(newLanguage); loadLanguageCache(newLanguage).then(() => { load_language(); // Refresh page translations });}Example 4: Enhanced translate() Function
Section titled “Example 4: Enhanced translate() Function”let useIndexedDB = false;let languageCache = {};
// Initialize on app startasync function initTranslationSystem() { const count = await LanguageDataDB.getRecordCount(); if (count > 0) { useIndexedDB = true; const currentLang = global("current_language").getValue(); await loadLanguageCache(currentLang); }}
function translate(text) { // Early returns if (!text) return text;
const currentLanguage = global("current_language").getValue(); if (!currentLanguage || currentLanguage === "english") { return text; }
// Try memory cache first (fastest) if (useIndexedDB && languageCache[text]) { return languageCache[text]; }
// Fallback to array if (Array.isArray(language_list)) { const entry = language_list.find(item => item.english === text); if (entry && entry[currentLanguage]) { return entry[currentLanguage]; } }
// Return original if no translation found return text;}Troubleshooting
Section titled “Troubleshooting”Issue: IndexedDB not created after clearing
Section titled “Issue: IndexedDB not created after clearing”Solution: Increment database version to force recreation:
this.dbVersion = 2; // Change from 1 to 2Issue: TransactionInactiveError
Section titled “Issue: TransactionInactiveError”Solution: Process records in batches (already implemented):
const batchSize = 1000; // Process 1000 records per transactionIssue: Translations not showing
Section titled “Issue: Translations not showing”Check:
- Is IndexedDB initialized?
await LanguageDataDB.getRecordCount() - Is language cache loaded?
console.log(languageCache) - Is current language set?
global("current_language").getValue() - Does translation exist?
await LanguageDataDB.getTranslationByEnglish("kannada", "Nursery")
Issue: Slow translations
Section titled “Issue: Slow translations”Solution: Use memory cache for active language:
// Load current language into memory on language changeawait loadLanguageCache(currentLanguage);Issue: API update fails
Section titled “Issue: API update fails”Solution: Implement proper error handling and fallback:
try { await updateLanguageData(apiUrl);} catch (error) { console.error('Update failed, using existing data:', error); // App continues with current translations}File Structure
Section titled “File Structure”www/├── scripts/│ ├── language.js # Current: language_list array + translate()│ ├── formatted_language_data.json # Source file (not currently used)│ ├── functions.js # New: LanguageDataDBUtilClass│ └── internal.js # Uses translate() for page elements└── index.html # Login page (where initialization happens)Next Steps
Section titled “Next Steps”- ✅ IndexedDB utility created
- ⏳ Update
translate()to use IndexedDB with fallback - ⏳ Implement memory caching
- ⏳ Add API version check
- ⏳ Test on login page
- ⏳ Remove
language_listarray (after full migration)
Support
Section titled “Support”For issues or questions:
- Check console logs (all IndexedDB operations are logged)
- Verify IndexedDB is supported:
window.indexedDB - Check database in DevTools: Application → IndexedDB → NurseryLanguageDB
Last Updated: 2024-01-15 Version: 1.0