mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-26 07:35:44 -03:00
cleanup
This commit is contained in:
@@ -130,18 +130,10 @@ class BaseModelRoutes(ABC):
|
|||||||
'is_initializing': is_initializing,
|
'is_initializing': is_initializing,
|
||||||
'settings': settings,
|
'settings': settings,
|
||||||
'request': request,
|
'request': request,
|
||||||
'user_language': user_language, # 传递语言设置到模板
|
|
||||||
'folders': [],
|
'folders': [],
|
||||||
# 添加服务端翻译函数
|
# 添加服务端翻译函数
|
||||||
't': server_i18n.get_translation,
|
't': server_i18n.get_translation,
|
||||||
'server_i18n': server_i18n,
|
'server_i18n': server_i18n,
|
||||||
# 添加一些常用的翻译到上下文,避免在模板中频繁调用
|
|
||||||
'common_translations': {
|
|
||||||
'loading': server_i18n.get_translation('common.status.loading'),
|
|
||||||
'error': server_i18n.get_translation('common.status.error'),
|
|
||||||
'refresh': server_i18n.get_translation('common.actions.refresh'),
|
|
||||||
'search': server_i18n.get_translation('common.actions.search'),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if not is_initializing:
|
if not is_initializing:
|
||||||
|
|||||||
@@ -149,17 +149,9 @@ class RecipeRoutes:
|
|||||||
is_initializing=False,
|
is_initializing=False,
|
||||||
settings=settings,
|
settings=settings,
|
||||||
request=request,
|
request=request,
|
||||||
user_language=user_language,
|
|
||||||
# 添加服务端翻译函数
|
# 添加服务端翻译函数
|
||||||
t=server_i18n.get_translation,
|
t=server_i18n.get_translation,
|
||||||
server_i18n=server_i18n,
|
server_i18n=server_i18n,
|
||||||
# 添加一些常用的翻译到上下文
|
|
||||||
common_translations={
|
|
||||||
'loading': server_i18n.get_translation('common.status.loading'),
|
|
||||||
'error': server_i18n.get_translation('common.status.error'),
|
|
||||||
'refresh': server_i18n.get_translation('common.actions.refresh'),
|
|
||||||
'search': server_i18n.get_translation('common.actions.search'),
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
except Exception as cache_error:
|
except Exception as cache_error:
|
||||||
logger.error(f"Error loading recipe cache data: {cache_error}")
|
logger.error(f"Error loading recipe cache data: {cache_error}")
|
||||||
@@ -169,15 +161,9 @@ class RecipeRoutes:
|
|||||||
is_initializing=True,
|
is_initializing=True,
|
||||||
settings=settings,
|
settings=settings,
|
||||||
request=request,
|
request=request,
|
||||||
user_language=user_language,
|
|
||||||
# 添加服务端翻译函数
|
# 添加服务端翻译函数
|
||||||
t=server_i18n.get_translation,
|
t=server_i18n.get_translation,
|
||||||
server_i18n=server_i18n,
|
server_i18n=server_i18n,
|
||||||
# 添加一些常用的翻译到上下文
|
|
||||||
common_translations={
|
|
||||||
'loading': server_i18n.get_translation('common.status.loading'),
|
|
||||||
'error': server_i18n.get_translation('common.status.error'),
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
logger.info("Recipe cache error, returning initialization page")
|
logger.info("Recipe cache error, returning initialization page")
|
||||||
|
|
||||||
|
|||||||
@@ -75,16 +75,9 @@ class StatsRoutes:
|
|||||||
is_initializing=is_initializing,
|
is_initializing=is_initializing,
|
||||||
settings=settings,
|
settings=settings,
|
||||||
request=request,
|
request=request,
|
||||||
user_language=user_language,
|
|
||||||
# 添加服务端翻译函数
|
# 添加服务端翻译函数
|
||||||
t=server_i18n.get_translation,
|
t=server_i18n.get_translation,
|
||||||
server_i18n=server_i18n,
|
server_i18n=server_i18n,
|
||||||
# 添加一些常用的翻译到上下文
|
|
||||||
common_translations={
|
|
||||||
'loading': server_i18n.get_translation('common.status.loading'),
|
|
||||||
'error': server_i18n.get_translation('common.status.error'),
|
|
||||||
'refresh': server_i18n.get_translation('common.actions.refresh'),
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return web.Response(
|
return web.Response(
|
||||||
|
|||||||
@@ -33,20 +33,10 @@ class I18nManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get language from user settings with fallback to browser detection
|
* Get language from user settings with fallback to English
|
||||||
* @returns {string} Language code
|
* @returns {string} Language code
|
||||||
*/
|
*/
|
||||||
getLanguageFromSettings() {
|
getLanguageFromSettings() {
|
||||||
// 优先使用后端传递的初始语言
|
|
||||||
if (window.__INITIAL_LANGUAGE__ && this.locales[window.__INITIAL_LANGUAGE__]) {
|
|
||||||
return window.__INITIAL_LANGUAGE__;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查服务端传递的翻译数据
|
|
||||||
if (window.__SERVER_TRANSLATIONS__ && window.__SERVER_TRANSLATIONS__.language && this.locales[window.__SERVER_TRANSLATIONS__.language]) {
|
|
||||||
return window.__SERVER_TRANSLATIONS__.language;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check localStorage for user-selected language
|
// Check localStorage for user-selected language
|
||||||
const STORAGE_PREFIX = 'lora_manager_';
|
const STORAGE_PREFIX = 'lora_manager_';
|
||||||
let userLanguage = null;
|
let userLanguage = null;
|
||||||
@@ -66,8 +56,8 @@ class I18nManager {
|
|||||||
return userLanguage;
|
return userLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to browser language detection for first-time users
|
// Fallback to English
|
||||||
return this.detectLanguage();
|
return 'en';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,29 +113,6 @@ class I18nManager {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Detect browser language with fallback to English (for first-time users)
|
|
||||||
* @returns {string} Language code
|
|
||||||
*/
|
|
||||||
detectLanguage() {
|
|
||||||
// Get browser language
|
|
||||||
const browserLang = navigator.language || navigator.languages[0] || 'en';
|
|
||||||
|
|
||||||
// Check if we have exact match
|
|
||||||
if (this.locales[browserLang]) {
|
|
||||||
return browserLang;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for language without region (e.g., 'zh' from 'zh-CN')
|
|
||||||
const langCode = browserLang.split('-')[0];
|
|
||||||
if (this.locales[langCode]) {
|
|
||||||
return langCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to English
|
|
||||||
return 'en';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get translation for a key with optional parameters
|
* Get translation for a key with optional parameters
|
||||||
* @param {string} key - Translation key (supports dot notation)
|
* @param {string} key - Translation key (supports dot notation)
|
||||||
@@ -255,7 +222,7 @@ class I18nManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize i18n from user settings instead of browser detection
|
* Initialize i18n from user settings
|
||||||
* This prevents language flashing on page load
|
* This prevents language flashing on page load
|
||||||
*/
|
*/
|
||||||
async initializeFromSettings() {
|
async initializeFromSettings() {
|
||||||
|
|||||||
@@ -162,19 +162,10 @@ export function formatNumber(number, options = {}) {
|
|||||||
* This should be called after DOM content is loaded
|
* This should be called after DOM content is loaded
|
||||||
*/
|
*/
|
||||||
export function initializePageI18n() {
|
export function initializePageI18n() {
|
||||||
// 优先使用服务端传递的翻译数据,避免闪烁
|
// Always use the client-side i18n with user settings
|
||||||
if (window.__SERVER_TRANSLATIONS__ && window.__SERVER_TRANSLATIONS__.language) {
|
if (window.i18n) {
|
||||||
// 设置客户端i18n的语言为服务端传递的语言
|
// Translate DOM elements
|
||||||
if (window.i18n && window.i18n.setLanguage) {
|
|
||||||
window.i18n.setLanguage(window.__SERVER_TRANSLATIONS__.language);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 对于剩余的需要动态翻译的元素,仍使用客户端翻译
|
|
||||||
translateDOM();
|
translateDOM();
|
||||||
} else {
|
|
||||||
// 回退到完整的客户端翻译
|
|
||||||
translateDOM();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update search placeholder based on current page
|
// Update search placeholder based on current page
|
||||||
const currentPath = window.location.pathname;
|
const currentPath = window.location.pathname;
|
||||||
@@ -188,6 +179,7 @@ export function initializePageI18n() {
|
|||||||
document.documentElement.setAttribute('dir', 'ltr');
|
document.documentElement.setAttribute('dir', 'ltr');
|
||||||
document.body.classList.remove('rtl');
|
document.body.classList.remove('rtl');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,172 +0,0 @@
|
|||||||
/**
|
|
||||||
* Mixed i18n handler - coordinates server-side and client-side translations
|
|
||||||
* Reduces language flashing by using server-rendered content initially
|
|
||||||
*/
|
|
||||||
|
|
||||||
class MixedI18nHandler {
|
|
||||||
constructor() {
|
|
||||||
this.serverTranslations = window.__SERVER_TRANSLATIONS__ || {};
|
|
||||||
this.currentLanguage = this.serverTranslations.language || 'en';
|
|
||||||
this.initialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize mixed i18n system
|
|
||||||
*/
|
|
||||||
async initialize() {
|
|
||||||
if (this.initialized) return;
|
|
||||||
|
|
||||||
// Import the main i18n module
|
|
||||||
const { i18n } = await import('/loras_static/js/i18n/index.js');
|
|
||||||
this.clientI18n = i18n;
|
|
||||||
|
|
||||||
// Ensure client i18n uses the same language as server
|
|
||||||
if (this.currentLanguage && this.clientI18n.getCurrentLocale() !== this.currentLanguage) {
|
|
||||||
this.clientI18n.setLanguage(this.currentLanguage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translate any remaining elements that need client-side translation
|
|
||||||
this.translateRemainingElements();
|
|
||||||
|
|
||||||
this.initialized = true;
|
|
||||||
|
|
||||||
// Dispatch event to notify that mixed i18n is ready
|
|
||||||
window.dispatchEvent(new CustomEvent('mixedI18nReady', {
|
|
||||||
detail: { language: this.currentLanguage }
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate elements that still need client-side translation
|
|
||||||
* (primarily dynamic content and complex components)
|
|
||||||
*/
|
|
||||||
translateRemainingElements() {
|
|
||||||
if (!this.clientI18n) return;
|
|
||||||
|
|
||||||
// Find all elements with data-i18n attribute that haven't been server-rendered
|
|
||||||
const elements = document.querySelectorAll('[data-i18n]');
|
|
||||||
|
|
||||||
elements.forEach(element => {
|
|
||||||
// Skip if already translated by server (check if content matches key pattern)
|
|
||||||
const key = element.getAttribute('data-i18n');
|
|
||||||
const currentContent = element.textContent || element.value || element.placeholder;
|
|
||||||
|
|
||||||
// If the current content looks like a translation key, translate it
|
|
||||||
if (currentContent === key || currentContent.includes('.') || currentContent === '') {
|
|
||||||
this.translateElement(element, key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate a single element using client-side i18n
|
|
||||||
*/
|
|
||||||
translateElement(element, key) {
|
|
||||||
if (!this.clientI18n) return;
|
|
||||||
|
|
||||||
const params = element.getAttribute('data-i18n-params');
|
|
||||||
let parsedParams = {};
|
|
||||||
|
|
||||||
if (params) {
|
|
||||||
try {
|
|
||||||
parsedParams = JSON.parse(params);
|
|
||||||
} catch (e) {
|
|
||||||
console.warn(`Invalid JSON in data-i18n-params for key ${key}:`, params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get translated text
|
|
||||||
const translatedText = this.clientI18n.t(key, parsedParams);
|
|
||||||
|
|
||||||
// Handle different translation targets
|
|
||||||
const target = element.getAttribute('data-i18n-target') || 'textContent';
|
|
||||||
|
|
||||||
switch (target) {
|
|
||||||
case 'placeholder':
|
|
||||||
element.placeholder = translatedText;
|
|
||||||
break;
|
|
||||||
case 'title':
|
|
||||||
element.title = translatedText;
|
|
||||||
break;
|
|
||||||
case 'alt':
|
|
||||||
element.alt = translatedText;
|
|
||||||
break;
|
|
||||||
case 'innerHTML':
|
|
||||||
element.innerHTML = translatedText;
|
|
||||||
break;
|
|
||||||
case 'textContent':
|
|
||||||
default:
|
|
||||||
element.textContent = translatedText;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current language
|
|
||||||
*/
|
|
||||||
getCurrentLanguage() {
|
|
||||||
return this.currentLanguage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get translation using client-side i18n (for dynamic content)
|
|
||||||
*/
|
|
||||||
t(key, params = {}) {
|
|
||||||
if (this.clientI18n) {
|
|
||||||
return this.clientI18n.t(key, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: check server translations
|
|
||||||
if (this.serverTranslations.common && key.startsWith('common.')) {
|
|
||||||
const subKey = key.substring(7); // Remove 'common.' prefix
|
|
||||||
return this.serverTranslations.common[subKey] || key;
|
|
||||||
}
|
|
||||||
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format file size using client-side i18n
|
|
||||||
*/
|
|
||||||
formatFileSize(bytes, decimals = 2) {
|
|
||||||
if (this.clientI18n) {
|
|
||||||
return this.clientI18n.formatFileSize(bytes, decimals);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple fallback
|
|
||||||
if (bytes === 0) return '0 Bytes';
|
|
||||||
const k = 1024;
|
|
||||||
const dm = decimals < 0 ? 0 : decimals;
|
|
||||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
||||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format date using client-side i18n
|
|
||||||
*/
|
|
||||||
formatDate(date, options = {}) {
|
|
||||||
if (this.clientI18n) {
|
|
||||||
return this.clientI18n.formatDate(date, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple fallback
|
|
||||||
const dateObj = date instanceof Date ? date : new Date(date);
|
|
||||||
return dateObj.toLocaleDateString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create global instance
|
|
||||||
window.mixedI18n = new MixedI18nHandler();
|
|
||||||
|
|
||||||
// Auto-initialize when DOM is ready
|
|
||||||
if (document.readyState === 'loading') {
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
window.mixedI18n.initialize();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
window.mixedI18n.initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Export for module usage
|
|
||||||
export default window.mixedI18n;
|
|
||||||
@@ -50,23 +50,6 @@
|
|||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
(function() {
|
(function() {
|
||||||
// 直接从后端获取语言设置,避免闪烁
|
|
||||||
const userLanguage = '{{ user_language or "en" }}';
|
|
||||||
|
|
||||||
// 设置初始语言到全局变量,供i18n系统使用
|
|
||||||
window.__INITIAL_LANGUAGE__ = userLanguage;
|
|
||||||
|
|
||||||
// 预设服务端翻译的内容,避免初始渲染时的闪烁
|
|
||||||
window.__SERVER_TRANSLATIONS__ = {
|
|
||||||
language: userLanguage,
|
|
||||||
common: {
|
|
||||||
loading: '{{ t("common.status.loading") }}',
|
|
||||||
error: '{{ t("common.status.error") }}',
|
|
||||||
refresh: '{{ t("common.actions.refresh") }}',
|
|
||||||
search: '{{ t("common.actions.search") }}'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Apply theme immediately based on stored preference
|
// Apply theme immediately based on stored preference
|
||||||
const STORAGE_PREFIX = 'lora_manager_';
|
const STORAGE_PREFIX = 'lora_manager_';
|
||||||
const savedTheme = localStorage.getItem(STORAGE_PREFIX + 'theme') || 'auto';
|
const savedTheme = localStorage.getItem(STORAGE_PREFIX + 'theme') || 'auto';
|
||||||
@@ -120,8 +103,6 @@
|
|||||||
<!-- Load initialization JavaScript -->
|
<!-- Load initialization JavaScript -->
|
||||||
<script type="module" src="/loras_static/js/components/initialization.js"></script>
|
<script type="module" src="/loras_static/js/components/initialization.js"></script>
|
||||||
{% else %}
|
{% else %}
|
||||||
<!-- Load mixed i18n handler first for better coordination -->
|
|
||||||
<script type="module" src="/loras_static/js/utils/mixedI18n.js"></script>
|
|
||||||
{% block main_script %}{% endblock %}
|
{% block main_script %}{% endblock %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user