Add complete server-side internationalization support for non-JavaScript users

This commit extends the existing i18n system to fully support server-side translations
for users who have JavaScript disabled or are using the /table route directly.

Changes:
- Complete server-side Spanish (es-MX) translation support for /table route
- Language selector dropdown in table view with form-based locale switching
- URL parameter support (?locale=es-MX) for direct language selection
- Updated POST form handler to persist locale selection across submissions
- Proper locale detection and fallback for server-rendered pages
- Fixed language selector initialization timing in client-side JS
- Removed unused dependencies (canvas, sharp) to clean up package.json
- Added snowflake emoji to app name in both English and Spanish translations

The /table route now provides a complete non-JavaScript experience in both English
and Spanish, ensuring accessibility for all users regardless of their browser
capabilities or JavaScript preferences.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude Code 2025-07-07 12:57:37 -04:00
parent 8b1787ec47
commit 47b495d8eb
6 changed files with 107 additions and 563 deletions

View file

@ -1,9 +1,4 @@
document.addEventListener('DOMContentLoaded', () => {
// Initialize language selector
if (window.i18n) {
window.i18n.createLanguageSelector('language-selector-container');
}
const map = L.map('map').setView([42.96008, -85.67403], 10);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {

View file

@ -31,6 +31,9 @@ class I18nService {
// Trigger translation update after loading
this.updatePageTranslations();
// Create language selector after translations are loaded
this.createLanguageSelector('language-selector-container');
}
/**
@ -226,10 +229,16 @@ class I18nService {
return;
}
// Clear container first in case it's being recreated
container.innerHTML = '';
const select = document.createElement('select');
select.id = 'language-selector';
select.className = 'language-selector';
select.title = this.t('common.selectLanguage');
// Use fallback title if translations not loaded yet
const titleText = this.translations.size > 0 ? this.t('common.selectLanguage') : 'Select language';
select.title = titleText;
// Add options for each available locale
this.availableLocales.forEach(locale => {