Files
Oxicloud/static/js/languageSelector.js
T

205 lines
6.1 KiB
JavaScript
Raw Normal View History

2025-03-17 21:28:08 +01:00
/**
* Language Selector Component for OxiCloud
2026-02-03 17:59:04 +01:00
* Custom styled dropdown with flags
2025-03-17 21:28:08 +01:00
*/
2026-02-03 17:59:04 +01:00
// Language codes, names, and flag emojis
2025-03-17 21:28:08 +01:00
const languages = [
2026-02-03 17:59:04 +01:00
{ code: 'en', name: 'English', flag: '🇬🇧' },
{ code: 'es', name: 'Español', flag: '🇪🇸' },
{ code: 'zh', name: '中文', flag: '🇨🇳' },
{ code: 'fa', name: 'فارسی', flag: '🦁' }
2025-03-17 21:28:08 +01:00
];
// RTL languages
const rtlLanguages = ['fa']; // ['fa', 'ar']
// Update HTML lang attribute and dir for RTL languages
function updateHtmlAttributes(langCode) {
const htmlElement = document.documentElement;
// Set lang attribute
htmlElement.setAttribute('lang', langCode);
// Set dir attribute for RTL languages
if (rtlLanguages.includes(langCode)) {
htmlElement.setAttribute('dir', 'rtl');
} else {
htmlElement.removeAttribute('dir');
}
}
2025-03-17 21:28:08 +01:00
/**
2026-02-03 17:59:04 +01:00
* Creates and initializes a custom language selector component
2025-03-17 21:28:08 +01:00
* @param {string} containerId - ID of the container element
*/
function createLanguageSelector(containerId = 'language-selector') {
// Get or create container
let container = document.getElementById(containerId);
if (!container) {
console.warn(`Container with ID "${containerId}" not found, creating one.`);
container = document.createElement('div');
container.id = containerId;
document.body.appendChild(container);
}
2026-02-03 17:59:04 +01:00
// Ensure container has the right class
container.className = 'language-selector';
2025-03-17 21:28:08 +01:00
2026-02-03 17:59:04 +01:00
// Get current language
const currentLocale = window.i18n ? window.i18n.getCurrentLocale() : 'en';
const currentLang = languages.find(l => l.code === currentLocale) || languages[0];
// Set initial HTML attributes
updateHtmlAttributes(currentLocale);
2026-02-03 17:59:04 +01:00
// Create toggle button
const toggle = document.createElement('div');
toggle.className = 'language-selector-toggle';
toggle.setAttribute('role', 'button');
toggle.setAttribute('aria-haspopup', 'listbox');
toggle.setAttribute('aria-expanded', 'false');
toggle.setAttribute('tabindex', '0');
toggle.innerHTML = `
<i class="fas fa-globe"></i>
<span class="lang-code">${currentLang.code.toUpperCase()}</span>
<i class="fas fa-chevron-down dropdown-arrow"></i>
`;
// Create dropdown menu
const dropdown = document.createElement('div');
dropdown.className = 'language-selector-dropdown';
dropdown.setAttribute('role', 'listbox');
// Add language options
2025-03-17 21:28:08 +01:00
languages.forEach(lang => {
2026-02-03 17:59:04 +01:00
const option = document.createElement('div');
option.className = `language-option${lang.code === currentLocale ? ' active' : ''}`;
option.setAttribute('role', 'option');
option.setAttribute('data-lang', lang.code);
option.setAttribute('aria-selected', lang.code === currentLocale);
option.innerHTML = `
<span class="lang-flag">${lang.flag}</span>
<span class="lang-name">${lang.name}</span>
<i class="fas fa-check lang-check"></i>
`;
option.addEventListener('click', async (e) => {
e.stopPropagation();
await selectLanguage(lang.code, container);
});
dropdown.appendChild(option);
2025-03-17 21:28:08 +01:00
});
2026-02-03 17:59:04 +01:00
// Clear and build container
container.innerHTML = '';
container.appendChild(toggle);
container.appendChild(dropdown);
// Toggle dropdown on click
toggle.addEventListener('click', (e) => {
e.stopPropagation();
toggleDropdown(container);
});
2025-03-17 21:28:08 +01:00
2026-02-03 17:59:04 +01:00
// Keyboard support
toggle.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
toggleDropdown(container);
} else if (e.key === 'Escape') {
closeDropdown(container);
2025-03-17 21:28:08 +01:00
}
});
2026-02-03 17:59:04 +01:00
// Close dropdown when clicking outside
document.addEventListener('click', (e) => {
if (!container.contains(e.target)) {
closeDropdown(container);
}
});
2025-03-17 21:28:08 +01:00
2026-02-03 17:59:04 +01:00
// Listen for locale changes from i18n system
2025-03-17 21:28:08 +01:00
window.addEventListener('localeChanged', (e) => {
2026-02-03 17:59:04 +01:00
updateSelectedLanguage(e.detail.locale, container);
2025-03-17 21:28:08 +01:00
});
return container;
}
2026-02-03 17:59:04 +01:00
/**
* Toggle dropdown open/closed
*/
function toggleDropdown(container) {
const isOpen = container.classList.contains('open');
if (isOpen) {
closeDropdown(container);
} else {
openDropdown(container);
}
}
/**
* Open dropdown
*/
function openDropdown(container) {
container.classList.add('open');
const toggle = container.querySelector('.language-selector-toggle');
if (toggle) {
toggle.setAttribute('aria-expanded', 'true');
}
}
/**
* Close dropdown
*/
function closeDropdown(container) {
container.classList.remove('open');
const toggle = container.querySelector('.language-selector-toggle');
if (toggle) {
toggle.setAttribute('aria-expanded', 'false');
}
}
/**
* Select a language
*/
async function selectLanguage(langCode, container) {
// Update i18n if available
if (window.i18n) {
await window.i18n.setLocale(langCode);
}
// Update HTML lang attribute and dir for RTL languages
updateHtmlAttributes(langCode);
2026-02-03 17:59:04 +01:00
updateSelectedLanguage(langCode, container);
closeDropdown(container);
}
/**
* Update the UI to reflect selected language
*/
function updateSelectedLanguage(langCode, container) {
const lang = languages.find(l => l.code === langCode) || languages[0];
// Update toggle button text
const langCodeSpan = container.querySelector('.lang-code');
if (langCodeSpan) {
langCodeSpan.textContent = lang.code.toUpperCase();
}
// Update active state on options
const options = container.querySelectorAll('.language-option');
options.forEach(option => {
const isActive = option.getAttribute('data-lang') === langCode;
option.classList.toggle('active', isActive);
option.setAttribute('aria-selected', isActive);
});
}
2025-03-17 21:28:08 +01:00
// Create language selector when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
createLanguageSelector();
});