@liascript/exporter
Version:
A generic exporter for LiaScript
172 lines (146 loc) • 5.25 kB
JavaScript
/**
* i18n.js - Internationalization system
* Supports JSON translation files with dot notation keys
*/
class I18n {
constructor() {
this.currentLanguage = 'en'
this.translations = {}
this.fallbackLanguage = 'en'
}
async loadLanguage(lang) {
try {
const response = await fetch(`/locales/${lang}.json`)
if (!response.ok) {
throw new Error(`Failed to load language file: ${lang}`)
}
this.translations[lang] = await response.json()
return true
} catch (error) {
console.error(`Error loading language ${lang}:`, error)
return false
}
}
async setLanguage(lang) {
// Load language if not already loaded
if (!this.translations[lang]) {
const success = await this.loadLanguage(lang)
if (!success && lang !== this.fallbackLanguage) {
// Try fallback
await this.loadLanguage(this.fallbackLanguage)
lang = this.fallbackLanguage
}
}
this.currentLanguage = lang
localStorage.setItem('language', lang)
this.updatePageTranslations()
this.updateLanguageSelector()
this.updateDynamicContent()
}
t(key, fallback = '') {
const translation =
this.translations[this.currentLanguage]?.[key] ||
this.translations[this.fallbackLanguage]?.[key] ||
fallback ||
key
return translation
}
// Update all elements with data-i18n attribute
updatePageTranslations() {
document.querySelectorAll('[data-i18n]').forEach((element) => {
const key = element.getAttribute('data-i18n')
const translation = this.t(key)
if (translation.includes('<') && translation.includes('>')) {
element.innerHTML = translation
} else {
element.textContent = translation
}
})
document.querySelectorAll('[data-i18n-placeholder]').forEach((element) => {
const key = element.getAttribute('data-i18n-placeholder')
element.placeholder = this.t(key)
})
document.querySelectorAll('[data-i18n-title]').forEach((element) => {
const key = element.getAttribute('data-i18n-title')
element.title = this.t(key)
})
document.querySelectorAll('[data-i18n-html]').forEach((element) => {
const key = element.getAttribute('data-i18n-html')
element.innerHTML = this.t(key)
})
document.querySelectorAll('[data-i18n-description]').forEach((element) => {
const key = element.getAttribute('data-i18n-description')
const translation = this.t(key)
element.setAttribute('data-description', translation)
})
}
updateDynamicContent() {
// Update preset description if one is currently selected
const checkedPreset = document.querySelector('input[name="preset"]:checked')
if (checkedPreset && checkedPreset.dataset.presetDescription) {
const descriptionBox = document.getElementById('preset-description')
if (descriptionBox && descriptionBox.style.display !== 'none') {
const descriptionText = descriptionBox.querySelector('p')
if (descriptionText) {
const desc = JSON.parse(checkedPreset.dataset.presetDescription)
const description = desc[this.currentLanguage] || desc['en'] || ''
descriptionText.innerHTML = description
}
}
}
// Update format description if one is currently selected
const checkedFormat = document.querySelector('input[name="format"]:checked')
if (checkedFormat && checkedFormat.dataset.description) {
const descriptionBox = document.getElementById('format-description')
if (descriptionBox && descriptionBox.style.display !== 'none') {
const descriptionText = descriptionBox.querySelector('p')
if (descriptionText) {
const description = checkedFormat.dataset.description
descriptionText.innerHTML = description
}
}
}
// Update file list remove button titles
const removeButtons = document.querySelectorAll('.remove-file')
if (removeButtons.length > 0) {
const removeTitle = this.t('files.remove')
removeButtons.forEach((btn) => {
btn.title = removeTitle
})
}
}
updateLanguageSelector() {
const selector = document.getElementById('language-selector')
if (selector) {
selector.value = this.currentLanguage
}
}
async init() {
const savedLang = localStorage.getItem('language')
let initialLang = savedLang || navigator.language.split('-')[0] || 'en'
const supportedLanguages = ['en', 'de']
if (!supportedLanguages.includes(initialLang)) {
initialLang = 'en'
}
await this.loadLanguage(this.fallbackLanguage)
if (initialLang !== this.fallbackLanguage) {
await this.loadLanguage(initialLang)
}
this.currentLanguage = initialLang
this.updatePageTranslations()
this.updateLanguageSelector()
const selector = document.getElementById('language-selector')
if (selector) {
selector.addEventListener('change', (e) => {
this.setLanguage(e.target.value)
})
}
}
}
const i18n = new I18n()
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => i18n.init())
} else {
i18n.init()
}
window.i18n = i18n