feat(i18n): add language selector UI to docs page
Added interactive language switcher dropdown to make translations accessible: UI Changes: - Added language selector dropdown to docs.html header - Flag emojis + language names (🇬🇧 English, 🇩🇪 Deutsch, 🇫🇷 Français) - Positioned next to search button in page header Functionality: - Detect language from URL param, localStorage, or default to English - Save language choice to localStorage for persistence - Auto-reload document when language changes - Update URL with ?lang= parameter - Preserves selected document when switching languages Implementation: - Enhanced detectLanguage() to check URL > localStorage > i18n > default - Added initLanguageSelector() IIFE to wire up dropdown - Dropdown reflects current language on page load User Experience: - One-click language switching - Language persists across page reloads - Seamless document reload in new language - URL updates to reflect language choice 🌐 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
1531a47cc0
commit
0982cc247d
2 changed files with 71 additions and 10 deletions
|
|
@ -495,12 +495,25 @@
|
||||||
<h1 class="text-3xl font-bold text-gray-900">Framework Documentation</h1>
|
<h1 class="text-3xl font-bold text-gray-900">Framework Documentation</h1>
|
||||||
<p class="text-gray-600 mt-2">Technical specifications, guides, and reference materials</p>
|
<p class="text-gray-600 mt-2">Technical specifications, guides, and reference materials</p>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" id="open-search-modal-btn" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition flex items-center gap-2" aria-label="Open search">
|
<div class="flex items-center gap-3">
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<!-- Language Selector -->
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
|
<div class="relative">
|
||||||
</svg>
|
<select id="language-selector"
|
||||||
<span>Search</span>
|
class="px-4 py-2 bg-white border border-gray-300 rounded-lg hover:border-gray-400 transition text-sm font-medium text-gray-700 cursor-pointer focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
</button>
|
aria-label="Select language">
|
||||||
|
<option value="en">🇬🇧 English</option>
|
||||||
|
<option value="de">🇩🇪 Deutsch</option>
|
||||||
|
<option value="fr">🇫🇷 Français</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<!-- Search Button -->
|
||||||
|
<button type="button" id="open-search-modal-btn" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition flex items-center gap-2" aria-label="Open search">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
|
||||||
|
</svg>
|
||||||
|
<span>Search</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,28 @@ if (typeof DocumentCards !== 'undefined') {
|
||||||
documentCards = new DocumentCards('document-content');
|
documentCards = new DocumentCards('document-content');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect language from i18n system
|
// Detect language from URL, localStorage, or i18n system
|
||||||
function detectLanguage() {
|
function detectLanguage() {
|
||||||
|
// Priority 1: URL parameter
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const urlLang = urlParams.get('lang');
|
||||||
|
if (urlLang) {
|
||||||
|
return urlLang;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priority 2: localStorage
|
||||||
|
const storedLang = localStorage.getItem('tractatus_language');
|
||||||
|
if (storedLang) {
|
||||||
|
return storedLang;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priority 3: i18n system
|
||||||
if (window.I18n && window.I18n.currentLang) {
|
if (window.I18n && window.I18n.currentLang) {
|
||||||
return window.I18n.currentLang;
|
return window.I18n.currentLang;
|
||||||
}
|
}
|
||||||
// Fallback: Check URL parameter
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
// Default: English
|
||||||
return urlParams.get('lang') || 'en';
|
return 'en';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update URL with language parameter
|
// Update URL with language parameter
|
||||||
|
|
@ -627,6 +641,40 @@ function closeToCModal() {
|
||||||
// Initialize
|
// Initialize
|
||||||
loadDocuments();
|
loadDocuments();
|
||||||
|
|
||||||
|
// Initialize language selector
|
||||||
|
(function initLanguageSelector() {
|
||||||
|
const selector = document.getElementById('language-selector');
|
||||||
|
if (!selector) return;
|
||||||
|
|
||||||
|
// Set initial value from current language
|
||||||
|
const initialLang = detectLanguage();
|
||||||
|
selector.value = initialLang;
|
||||||
|
currentLanguage = initialLang;
|
||||||
|
|
||||||
|
// Handle language change
|
||||||
|
selector.addEventListener('change', (e) => {
|
||||||
|
const newLang = e.target.value;
|
||||||
|
|
||||||
|
// Save to localStorage
|
||||||
|
localStorage.setItem('tractatus_language', newLang);
|
||||||
|
|
||||||
|
// Update current language
|
||||||
|
currentLanguage = newLang;
|
||||||
|
|
||||||
|
// Reload current document in new language
|
||||||
|
if (currentDocument) {
|
||||||
|
loadDocument(currentDocument.slug, newLang);
|
||||||
|
} else {
|
||||||
|
// If no document loaded yet, just update URL
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const currentDoc = urlParams.get('doc');
|
||||||
|
if (currentDoc) {
|
||||||
|
loadDocument(currentDoc, newLang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
// Add ESC key listener for closing modal
|
// Add ESC key listener for closing modal
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener('keydown', (e) => {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue