You've already forked Tricky-Addon-Update-Target-List
mirror of
https://github.com/KOWX712/Tricky-Addon-Update-Target-List.git
synced 2025-09-06 06:37:09 +00:00
232 lines
7.7 KiB
JavaScript
232 lines
7.7 KiB
JavaScript
import { applyRippleEffect, linkRedirect } from './main.js';
|
|
|
|
const languageButton = document.querySelector('.language-button');
|
|
const languageMenu = document.querySelector('.language-menu');
|
|
const languageOptions = document.querySelectorAll('.language-option');
|
|
const languageOverlay = document.getElementById('language-overlay');
|
|
const rtlLang = [
|
|
'ar', // Arabic
|
|
'fa', // Persian
|
|
'he', // Hebrew
|
|
'ur', // Urdu
|
|
'ps', // Pashto
|
|
'sd', // Sindhi
|
|
'ku', // Kurdish
|
|
'yi', // Yiddish
|
|
'dv', // Dhivehi
|
|
];
|
|
|
|
export let translations = {};
|
|
let baseTranslations = {};
|
|
let availableLanguages = ['en'];
|
|
let languageNames = {};
|
|
|
|
/**
|
|
* Parse XML translation file into a JavaScript object
|
|
* @param {string} xmlText - The XML content as string
|
|
* @returns {Object} - Parsed translations
|
|
*/
|
|
function parseTranslationsXML(xmlText) {
|
|
const parser = new DOMParser();
|
|
const xmlDoc = parser.parseFromString(xmlText, 'text/xml');
|
|
const strings = xmlDoc.getElementsByTagName('string');
|
|
const translations = {};
|
|
|
|
for (let i = 0; i < strings.length; i++) {
|
|
const string = strings[i];
|
|
const name = string.getAttribute('name');
|
|
const value = string.textContent;
|
|
translations[name] = value;
|
|
}
|
|
|
|
return translations;
|
|
}
|
|
|
|
/**
|
|
* Detect user's default language
|
|
* @returns {Promise<string>} - Detected language code
|
|
*/
|
|
async function detectUserLanguage() {
|
|
const userLang = navigator.language || navigator.userLanguage;
|
|
const langCode = userLang.split('-')[0];
|
|
|
|
try {
|
|
// Fetch available languages
|
|
const availableResponse = await fetch('locales/languages.json');
|
|
const availableData = await availableResponse.json();
|
|
availableLanguages = Object.keys(availableData);
|
|
languageNames = availableData;
|
|
|
|
// Fetch preferred language
|
|
const prefered_language_code = localStorage.getItem('trickyAddonLanguage');
|
|
|
|
// Check if preferred language is valid
|
|
if (prefered_language_code !== 'default' && availableLanguages.includes(prefered_language_code)) {
|
|
return prefered_language_code;
|
|
} else if (availableLanguages.includes(userLang)) {
|
|
return userLang;
|
|
} else if (availableLanguages.includes(langCode)) {
|
|
return langCode;
|
|
} else {
|
|
localStorage.removeItem('trickyAddonLanguage');
|
|
return 'en';
|
|
}
|
|
} catch (error) {
|
|
console.error('Error detecting user language:', error);
|
|
return 'en';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load translations dynamically based on the selected language
|
|
* @returns {Promise<void>}
|
|
*/
|
|
export async function loadTranslations() {
|
|
try {
|
|
// load Englsih as base translations
|
|
const baseResponse = await fetch('locales/strings/en.xml');
|
|
const baseXML = await baseResponse.text();
|
|
baseTranslations = parseTranslationsXML(baseXML);
|
|
|
|
// load user's language if available
|
|
const lang = await detectUserLanguage();
|
|
if (lang !== 'en') {
|
|
const response = await fetch(`locales/strings/${lang}.xml`);
|
|
const userXML = await response.text();
|
|
const userTranslations = parseTranslationsXML(userXML);
|
|
translations = { ...baseTranslations, ...userTranslations };
|
|
} else {
|
|
translations = baseTranslations;
|
|
}
|
|
|
|
// Support for rtl language
|
|
const isRTL = rtlLang.includes(lang.split('-')[0]);
|
|
if (isRTL) {
|
|
document.documentElement.setAttribute('dir', 'rtl');
|
|
document.documentElement.setAttribute('lang', lang);
|
|
|
|
// Load extra rtl css
|
|
fetch('styles/rtl_styles.css')
|
|
.then(res => res.text())
|
|
.then(css => {
|
|
const style = document.createElement('style');
|
|
style.textContent = css;
|
|
document.head.appendChild(style);
|
|
});
|
|
} else {
|
|
document.documentElement.setAttribute('dir', 'ltr');
|
|
document.documentElement.setAttribute('lang', lang);
|
|
}
|
|
|
|
// Generate language menu
|
|
await generateLanguageMenu();
|
|
} catch (error) {
|
|
console.error('Error loading translations:', error);
|
|
translations = baseTranslations;
|
|
}
|
|
applyTranslations();
|
|
applyRippleEffect();
|
|
}
|
|
|
|
/**
|
|
* Apply translations to all elements with data-i18n attributes
|
|
* @returns {void}
|
|
*/
|
|
function applyTranslations() {
|
|
document.querySelectorAll("[data-i18n]").forEach((el) => {
|
|
const key = el.getAttribute("data-i18n");
|
|
const translation = translations[key];
|
|
if (translation) {
|
|
if (el.hasAttribute("placeholder")) {
|
|
el.setAttribute("placeholder", translation);
|
|
} else {
|
|
el.textContent = translation;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function to setup the language menu
|
|
* @returns {void}
|
|
*/
|
|
export function setupLanguageMenu() {
|
|
languageButton.addEventListener("click", (event) => {
|
|
event.stopPropagation();
|
|
const isVisible = languageMenu.classList.contains("show");
|
|
if (isVisible) {
|
|
closeLanguageMenu();
|
|
} else {
|
|
languageOverlay.style.display = 'flex';
|
|
setTimeout(() => languageMenu.classList.add("show"), 10);
|
|
}
|
|
});
|
|
document.addEventListener("click", (event) => {
|
|
if (!languageButton.contains(event.target) && !languageMenu.contains(event.target)) {
|
|
closeLanguageMenu();
|
|
}
|
|
});
|
|
languageOptions.forEach(option => {
|
|
option.addEventListener("click", () => {
|
|
closeLanguageMenu();
|
|
});
|
|
});
|
|
window.addEventListener('scroll', () => {
|
|
if (languageMenu.classList.contains("show")) {
|
|
closeLanguageMenu();
|
|
}
|
|
});
|
|
const closeLanguageMenu = () => {
|
|
setTimeout(() => {
|
|
languageMenu.classList.remove("show");
|
|
languageOverlay.style.display = 'none';
|
|
}, 80)
|
|
}
|
|
languageMenu.addEventListener("click", async (e) => {
|
|
if (e.target.classList.contains("language-option")) {
|
|
const lang = e.target.getAttribute("data-lang");
|
|
if (lang) {
|
|
localStorage.setItem('trickyAddonLanguage', lang);
|
|
window.location.reload();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Generate the language menu dynamically
|
|
* Refer available-lang.json in ./locales for list of languages
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async function generateLanguageMenu() {
|
|
languageMenu.innerHTML = '';
|
|
|
|
// Add System Default option
|
|
const defaultButton = document.createElement('button');
|
|
defaultButton.classList.add('language-option', 'ripple-element');
|
|
defaultButton.setAttribute('data-lang', 'default');
|
|
defaultButton.setAttribute('data-i18n', 'system_default');
|
|
languageMenu.appendChild(defaultButton);
|
|
|
|
// Create and sort language entries
|
|
const sortedLanguages = Object.entries(languageNames)
|
|
.map(([lang, name]) => ({ lang, name }))
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
|
// Add language buttons
|
|
sortedLanguages.forEach(({ lang, name }) => {
|
|
const button = document.createElement('button');
|
|
button.classList.add('language-option', 'ripple-element');
|
|
button.setAttribute('data-lang', lang);
|
|
button.textContent = name;
|
|
languageMenu.appendChild(button);
|
|
});
|
|
|
|
// Add translation guide button
|
|
const moreBtn = document.createElement('button');
|
|
moreBtn.classList.add('language-option', 'ripple-element');
|
|
moreBtn.textContent = translations.more_language;
|
|
moreBtn.onclick = () => linkRedirect('https://github.com/KOWX712/Tricky-Addon-Update-Target-List/blob/main/module/webui/locales/GUIDE.md');
|
|
languageMenu.appendChild(moreBtn);
|
|
}
|