Spaces:
Running
Running
// i18n.js - Utilitaire de traduction pour Kimi APP | |
class KimiI18nManager { | |
constructor() { | |
this.translations = {}; | |
this.currentLang = "en"; | |
this._reloadAttempted = false; | |
} | |
async setLanguage(lang) { | |
this.currentLang = lang; | |
await this.loadTranslations(lang); | |
this.applyTranslations(); | |
} | |
async loadTranslations(lang) { | |
try { | |
const response = await fetch("kimi-locale/" + lang + ".json"); | |
if (!response.ok) throw new Error("Translation file not found"); | |
this.translations = await response.json(); | |
this.currentLang = lang; | |
} catch (e) { | |
this.translations = {}; | |
this.currentLang = "en"; | |
} | |
} | |
t(key, params) { | |
let str = this.translations[key] || key; | |
if (params && typeof str === "string") { | |
for (const [k, v] of Object.entries(params)) { | |
str = str.replace(new RegExp(`{${k}}`, "g"), v); | |
} | |
} | |
return str; | |
} | |
applyTranslations() { | |
const missing = []; | |
document.querySelectorAll("[data-i18n]").forEach(el => { | |
const key = el.getAttribute("data-i18n"); | |
let params = undefined; | |
const paramsAttr = el.getAttribute("data-i18n-params"); | |
if (paramsAttr) { | |
try { | |
params = JSON.parse(paramsAttr); | |
} catch {} | |
} | |
const val = this.t(key, params); | |
if (val === key && this.currentLang !== "en") { | |
missing.push(key); | |
} | |
el.textContent = val; | |
}); | |
// Auto-reload once if new keys were added after initial load | |
if (missing.length > 0 && !this._reloadAttempted) { | |
this._reloadAttempted = true; | |
this.loadTranslations(this.currentLang).then(() => { | |
// Re-apply with fresh file | |
requestAnimationFrame(() => this.applyTranslations()); | |
}); | |
} | |
document.querySelectorAll("[data-i18n-title]").forEach(el => { | |
const key = el.getAttribute("data-i18n-title"); | |
el.setAttribute("title", this.t(key)); | |
}); | |
document.querySelectorAll("[data-i18n-placeholder]").forEach(el => { | |
const key = el.getAttribute("data-i18n-placeholder"); | |
el.setAttribute("placeholder", this.t(key)); | |
}); | |
if (document.title && this.translations["title"]) { | |
document.title = this.translations["title"]; | |
} | |
} | |
detectLanguage() { | |
const nav = (navigator && (navigator.language || (navigator.languages && navigator.languages[0]))) || "en"; | |
const short = String(nav).slice(0, 2).toLowerCase(); | |
return ["en", "fr", "es", "de", "it", "ja", "zh"].includes(short) ? short : "en"; | |
} | |
} | |
window.applyTranslations = function () { | |
if (window.kimiI18nManager && typeof window.kimiI18nManager.applyTranslations === "function") { | |
window.kimiI18nManager.applyTranslations(); | |
} | |
}; | |
if (typeof document !== "undefined") { | |
if (!window.kimiI18nManager) { | |
window.kimiI18nManager = new KimiI18nManager(); | |
} | |
} | |
window.KimiI18nManager = KimiI18nManager; | |