mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
refactor(i18n): Remove language setting endpoints and related logic from MiscRoutes
This commit is contained in:
@@ -1,193 +0,0 @@
|
||||
# LoRA Manager i18n Implementation Summary
|
||||
|
||||
## 📋 Overview
|
||||
|
||||
Successfully implemented comprehensive internationalization (i18n) support for LoRA Manager UI with automatic browser language detection, supporting English and Simplified Chinese.
|
||||
|
||||
## 🛠 Implementation Details
|
||||
|
||||
### Core System Files
|
||||
|
||||
1. **`static/js/i18n/index.js`** - Main i18n manager
|
||||
- Automatic browser language detection
|
||||
- Translation interpolation with parameters
|
||||
- Locale-aware number, date, and file size formatting
|
||||
- RTL language support framework
|
||||
|
||||
2. **`static/js/i18n/locales/en.js`** - English translations
|
||||
- Complete translation set for all UI elements
|
||||
- Hierarchical key structure (common, header, loras, etc.)
|
||||
|
||||
3. **`static/js/i18n/locales/zh-CN.js`** - Simplified Chinese translations
|
||||
- Full Chinese translation coverage
|
||||
- Cultural adaptation for UI elements
|
||||
|
||||
4. **`static/js/utils/i18nHelpers.js`** - DOM helper utilities
|
||||
- Automatic DOM text replacement with `data-i18n` attributes
|
||||
- Dynamic search placeholder updates
|
||||
- Bulk selection count updates
|
||||
- Element creation helpers
|
||||
|
||||
### Modified Files
|
||||
|
||||
#### JavaScript Files (8 files modified)
|
||||
- `static/js/core.js` - Core app initialization with i18n
|
||||
- `static/js/components/Header.js` - Header component with i18n
|
||||
- `static/js/managers/BulkManager.js` - Bulk operations with i18n
|
||||
- `static/js/loras.js` - LoRA page initialization
|
||||
- `static/js/checkpoints.js` - Checkpoints page initialization
|
||||
- `static/js/embeddings.js` - Embeddings page initialization
|
||||
- `static/js/recipes.js` - Recipes page initialization
|
||||
- `static/js/statistics.js` - Statistics page initialization
|
||||
|
||||
#### HTML Template Files (3 files modified)
|
||||
- `templates/components/header.html` - Navigation and search elements
|
||||
- `templates/components/controls.html` - Page controls and bulk operations
|
||||
- `templates/components/context_menu.html` - Context menu items
|
||||
|
||||
## 🌐 Language Support
|
||||
|
||||
### Supported Languages
|
||||
- **English (en)** - Default language, comprehensive coverage
|
||||
- **Simplified Chinese (zh-CN)** - Complete translation with cultural adaptations
|
||||
- **Fallback Support** - Graceful fallback to English for missing translations
|
||||
|
||||
### Browser Language Detection
|
||||
- Automatically detects browser language preference
|
||||
- Supports both `zh-CN` and `zh` language codes (both map to Simplified Chinese)
|
||||
- Falls back to English for unsupported languages
|
||||
|
||||
## ✨ Features
|
||||
|
||||
### Automatic Translation
|
||||
- HTML elements with `data-i18n` attributes are automatically translated
|
||||
- Support for different target attributes (textContent, placeholder, title, etc.)
|
||||
- Parameter interpolation for dynamic content
|
||||
|
||||
### Formatting Functions
|
||||
- **File Size**: Locale-aware file size formatting (e.g., "1 MB" / "1 兆字节")
|
||||
- **Numbers**: Decimal formatting according to locale standards
|
||||
- **Dates**: Locale-specific date formatting
|
||||
|
||||
### Dynamic Updates
|
||||
- Search placeholders update based on current page
|
||||
- Bulk selection counts update dynamically
|
||||
- Theme toggle tooltips reflect current state
|
||||
|
||||
## 🔧 Usage Examples
|
||||
|
||||
### HTML Template Usage
|
||||
```html
|
||||
<!-- Basic text translation -->
|
||||
<span data-i18n="header.appTitle">LoRA Manager</span>
|
||||
|
||||
<!-- Placeholder translation -->
|
||||
<input data-i18n="header.search.placeholder" data-i18n-target="placeholder" />
|
||||
|
||||
<!-- Title attribute translation -->
|
||||
<button data-i18n="common.actions.refresh" data-i18n-target="title">
|
||||
```
|
||||
|
||||
### JavaScript Usage
|
||||
```javascript
|
||||
import { t, formatFileSize, initializePageI18n } from './utils/i18nHelpers.js';
|
||||
|
||||
// Basic translation
|
||||
const message = t('common.status.loading');
|
||||
|
||||
// Translation with parameters
|
||||
const count = t('loras.bulkOperations.selected', { count: 5 });
|
||||
|
||||
// Format file size
|
||||
const size = formatFileSize(1048576); // "1 MB" or "1 兆字节"
|
||||
|
||||
// Initialize page translations
|
||||
initializePageI18n();
|
||||
```
|
||||
|
||||
## 📁 File Structure
|
||||
|
||||
```
|
||||
static/js/
|
||||
├── i18n/
|
||||
│ ├── index.js # Main i18n manager
|
||||
│ └── locales/
|
||||
│ ├── en.js # English translations
|
||||
│ └── zh-CN.js # Chinese translations
|
||||
├── utils/
|
||||
│ └── i18nHelpers.js # DOM helper utilities
|
||||
├── test/
|
||||
│ └── i18nTest.js # Test suite for i18n functionality
|
||||
└── [existing files modified...]
|
||||
|
||||
docs/
|
||||
└── i18n.md # Comprehensive usage documentation
|
||||
```
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Test File
|
||||
- **`static/js/test/i18nTest.js`** - Comprehensive test suite
|
||||
- Language detection testing
|
||||
- Translation functionality testing
|
||||
- DOM translation testing
|
||||
- Formatting function testing
|
||||
|
||||
### Manual Testing
|
||||
Add `?test=i18n` to any page URL to run automated tests in browser console.
|
||||
|
||||
## 🔄 Integration Points
|
||||
|
||||
### Core Integration
|
||||
- i18n system initializes in `core.js` before any UI components
|
||||
- Available globally as `window.i18n` for debugging and development
|
||||
- Each page calls `initializePageI18n()` after DOM setup
|
||||
|
||||
### Component Integration
|
||||
- Header component updates search placeholders dynamically
|
||||
- Bulk manager uses i18n for selection count updates
|
||||
- Context menus and modals support localized text
|
||||
- All form controls include proper translations
|
||||
|
||||
## 🚀 Next Steps for Extension
|
||||
|
||||
### Adding New Languages
|
||||
1. Create new locale file in `static/js/i18n/locales/`
|
||||
2. Import and register in `static/js/i18n/index.js`
|
||||
3. Test with browser language simulation
|
||||
|
||||
### RTL Language Support
|
||||
- Framework already includes RTL detection
|
||||
- CSS classes automatically applied for RTL languages
|
||||
- Ready for Arabic, Hebrew, or other RTL languages
|
||||
|
||||
### Dynamic Language Switching
|
||||
- Core system supports runtime language changes
|
||||
- Could add language picker UI in settings
|
||||
- Would require `translateDOM()` re-execution
|
||||
|
||||
## ✅ Quality Assurance
|
||||
|
||||
### Code Quality
|
||||
- Comprehensive error handling with fallbacks
|
||||
- Consistent naming conventions
|
||||
- Well-documented API with JSDoc comments
|
||||
- Modular architecture for easy maintenance
|
||||
|
||||
### User Experience
|
||||
- Seamless automatic language detection
|
||||
- No performance impact on page load
|
||||
- Graceful degradation if translations fail
|
||||
- Consistent UI behavior across languages
|
||||
|
||||
### Maintainability
|
||||
- Clear separation of concerns
|
||||
- Hierarchical translation key structure
|
||||
- Comprehensive documentation
|
||||
- Test coverage for core functionality
|
||||
|
||||
---
|
||||
|
||||
**Implementation Status: ✅ Complete**
|
||||
|
||||
The i18n system is fully implemented and ready for production use. All major UI components support both English and Simplified Chinese with automatic browser language detection.
|
||||
@@ -1,75 +0,0 @@
|
||||
# 国际化系统改进总结
|
||||
|
||||
## 概述
|
||||
成功将i18n系统从自动浏览器语言检测改为用户主动设置的方式,避免了页面打开时的语言闪烁问题。
|
||||
|
||||
## 主要改动
|
||||
|
||||
### 1. 新增语言支持
|
||||
- 新增了7种语言的完整翻译文件:
|
||||
- 中文(繁体)- `zh-TW.js`
|
||||
- 俄语 - `ru.js`
|
||||
- 德语 - `de.js`
|
||||
- 日语 - `ja.js`
|
||||
- 韩语 - `ko.js`
|
||||
- 法语 - `fr.js`
|
||||
- 西班牙语 - `es.js`
|
||||
|
||||
### 2. 核心系统修改
|
||||
- **i18n/index.js**:
|
||||
- 修改了初始化逻辑,从设置中读取语言而非浏览器检测
|
||||
- 新增 `initializeFromSettings()` 方法
|
||||
- 完善了 `setLanguage()`, `getLanguageFromSettings()`, `getAvailableLanguages()` 方法
|
||||
|
||||
- **utils/i18nHelpers.js**:
|
||||
- 新增 `switchLanguage()` 函数,支持运行时语言切换
|
||||
- 提供DOM重新翻译和事件分发功能
|
||||
|
||||
### 3. 设置界面集成
|
||||
- **templates/components/modals/settings_modal.html**:
|
||||
- 在Layout Settings部分添加了语言选择下拉菜单
|
||||
- 使用原生语言名称显示9种支持的语言
|
||||
|
||||
- **managers/SettingsManager.js**:
|
||||
- 新增 `saveLanguageSetting()` 方法处理语言设置保存
|
||||
- 在 `loadSettingsToUI()` 中添加语言设置的加载逻辑
|
||||
- 集成i18n切换功能
|
||||
|
||||
### 4. 早期初始化优化
|
||||
- **i18n/early-init.js**:
|
||||
- 创建了早期语言检测脚本,防止FOUC(内容闪烁)
|
||||
- 在页面其他内容加载前设置正确的语言
|
||||
|
||||
- **templates/base.html**:
|
||||
- 在head部分最开始加载early-init.js脚本
|
||||
|
||||
### 5. 核心应用集成
|
||||
- **core.js**:
|
||||
- 修改了初始化流程,使用 `initializeFromSettings()` 而非自动检测
|
||||
|
||||
## 语言支持列表
|
||||
1. **English** (en) - 英语
|
||||
2. **中文(简体)** (zh-CN) - Simplified Chinese
|
||||
3. **中文(繁體)** (zh-TW) - Traditional Chinese
|
||||
4. **Русский** (ru) - Russian
|
||||
5. **Deutsch** (de) - German
|
||||
6. **日本語** (ja) - Japanese
|
||||
7. **한국어** (ko) - Korean
|
||||
8. **Français** (fr) - French
|
||||
9. **Español** (es) - Spanish
|
||||
|
||||
## 用户体验改进
|
||||
- ✅ 消除了页面加载时的语言闪烁问题
|
||||
- ✅ 用户可以手动选择喜好的语言
|
||||
- ✅ 语言设置会保存在localStorage中
|
||||
- ✅ 支持运行时即时语言切换
|
||||
- ✅ 语言选择界面使用原生语言名称显示
|
||||
|
||||
## 技术特点
|
||||
- 保持了模块化架构
|
||||
- 向后兼容现有代码
|
||||
- 优化了初始化性能
|
||||
- 提供了完整的错误处理
|
||||
- 集成了现有的设置管理系统
|
||||
|
||||
所有修改已完成,系统现在支持用户主动选择语言,有效避免了语言闪烁问题。
|
||||
216
docs/i18n.md
216
docs/i18n.md
@@ -1,216 +0,0 @@
|
||||
# LoRA Manager Internationalization (i18n)
|
||||
|
||||
This document explains how to use the internationalization system in LoRA Manager.
|
||||
|
||||
## Features
|
||||
|
||||
- Automatic language detection based on browser language
|
||||
- Support for English (en) and Simplified Chinese (zh-CN)
|
||||
- Fallback to English if the browser language is not supported
|
||||
- Dynamic text replacement in HTML templates
|
||||
- Number, date, and file size formatting according to locale
|
||||
- Right-to-Left (RTL) language support (framework ready)
|
||||
|
||||
## Browser Language Detection
|
||||
|
||||
The system automatically detects the user's browser language using:
|
||||
1. `navigator.language` - Primary browser language
|
||||
2. `navigator.languages[0]` - First language in the user's preferred languages
|
||||
3. Fallback to 'en' if no supported language is found
|
||||
|
||||
### Supported Language Codes
|
||||
|
||||
- `en` - English (default)
|
||||
- `zh-CN` - Simplified Chinese
|
||||
- `zh` - Falls back to Simplified Chinese
|
||||
|
||||
## Usage in HTML Templates
|
||||
|
||||
### Basic Text Translation
|
||||
|
||||
Add the `data-i18n` attribute to any HTML element:
|
||||
|
||||
```html
|
||||
<span data-i18n="header.appTitle">LoRA Manager</span>
|
||||
<button data-i18n="common.actions.save">Save</button>
|
||||
```
|
||||
|
||||
### Placeholder and Attribute Translation
|
||||
|
||||
For form inputs and other attributes:
|
||||
|
||||
```html
|
||||
<input type="text" data-i18n="header.search.placeholder" data-i18n-target="placeholder" placeholder="Search..." />
|
||||
<button data-i18n="loras.controls.refresh.title" data-i18n-target="title" title="Refresh model list">
|
||||
```
|
||||
|
||||
### Translation with Parameters
|
||||
|
||||
For dynamic content with variables:
|
||||
|
||||
```html
|
||||
<span data-i18n="loras.bulkOperations.selected" data-i18n-params='{"count": 5}'>5 selected</span>
|
||||
```
|
||||
|
||||
## Usage in JavaScript
|
||||
|
||||
### Import the i18n Helper
|
||||
|
||||
```javascript
|
||||
import { t, formatFileSize, formatDate, formatNumber } from './utils/i18nHelpers.js';
|
||||
```
|
||||
|
||||
### Basic Translation
|
||||
|
||||
```javascript
|
||||
// Simple translation
|
||||
const message = t('common.status.loading');
|
||||
|
||||
// Translation with parameters
|
||||
const selectedText = t('loras.bulkOperations.selected', { count: 5 });
|
||||
```
|
||||
|
||||
### Dynamic DOM Updates
|
||||
|
||||
```javascript
|
||||
import { setTranslatedText, setTranslatedAttribute, updateBulkSelectionCount } from './utils/i18nHelpers.js';
|
||||
|
||||
// Update text content
|
||||
setTranslatedText('#myButton', 'common.actions.save');
|
||||
|
||||
// Update attributes
|
||||
setTranslatedAttribute('#myInput', 'placeholder', 'header.search.placeholder');
|
||||
|
||||
// Update bulk selection count
|
||||
updateBulkSelectionCount(selectedItems.length);
|
||||
```
|
||||
|
||||
### Formatting Functions
|
||||
|
||||
```javascript
|
||||
// Format file size
|
||||
const sizeText = formatFileSize(1048576); // "1 MB" or "1 兆字节"
|
||||
|
||||
// Format date
|
||||
const dateText = formatDate(new Date(), { year: 'numeric', month: 'long', day: 'numeric' });
|
||||
|
||||
// Format number
|
||||
const numberText = formatNumber(1234.56, { minimumFractionDigits: 2 });
|
||||
```
|
||||
|
||||
## Page Initialization
|
||||
|
||||
Each page should call `initializePageI18n()` after the DOM is loaded:
|
||||
|
||||
```javascript
|
||||
import { initializePageI18n } from './utils/i18nHelpers.js';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Initialize core application
|
||||
await appCore.initialize();
|
||||
|
||||
// Initialize page-specific functionality
|
||||
const myPage = new MyPageManager();
|
||||
await myPage.initialize();
|
||||
|
||||
// Initialize i18n for the page
|
||||
initializePageI18n();
|
||||
});
|
||||
```
|
||||
|
||||
## Translation Key Structure
|
||||
|
||||
Translation keys use dot notation for nested objects:
|
||||
|
||||
```
|
||||
common.actions.save → "Save" / "保存"
|
||||
header.navigation.loras → "LoRAs" / "LoRA 模型"
|
||||
loras.controls.sort.nameAsc → "A - Z" / "A - Z"
|
||||
```
|
||||
|
||||
### Key Categories
|
||||
|
||||
- `common.*` - Shared terms and actions
|
||||
- `header.*` - Header and navigation
|
||||
- `loras.*` - LoRA page specific
|
||||
- `recipes.*` - Recipe page specific
|
||||
- `checkpoints.*` - Checkpoint page specific
|
||||
- `embeddings.*` - Embedding page specific
|
||||
- `statistics.*` - Statistics page specific
|
||||
- `modals.*` - Modal dialogs
|
||||
- `errors.*` - Error messages
|
||||
- `success.*` - Success messages
|
||||
- `keyboard.*` - Keyboard shortcuts
|
||||
- `tooltips.*` - Tooltip text
|
||||
|
||||
## Adding New Languages
|
||||
|
||||
1. Create a new language file in `static/js/i18n/locales/`:
|
||||
|
||||
```javascript
|
||||
// Example: fr.js for French
|
||||
export const fr = {
|
||||
common: {
|
||||
actions: {
|
||||
save: 'Sauvegarder',
|
||||
cancel: 'Annuler',
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
2. Import and register the language in `static/js/i18n/index.js`:
|
||||
|
||||
```javascript
|
||||
import { fr } from './locales/fr.js';
|
||||
|
||||
class I18nManager {
|
||||
constructor() {
|
||||
this.locales = {
|
||||
'en': en,
|
||||
'zh-CN': zhCN,
|
||||
'zh': zhCN,
|
||||
'fr': fr, // Add new language
|
||||
};
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Keep keys descriptive**: Use clear, hierarchical key names
|
||||
2. **Consistent naming**: Follow the established pattern for similar elements
|
||||
3. **Fallback text**: Always provide fallback text in HTML for graceful degradation
|
||||
4. **Context-aware**: Group related translations logically
|
||||
5. **Parameter usage**: Use parameters for dynamic content instead of string concatenation
|
||||
6. **Testing**: Test with different languages to ensure UI layout works properly
|
||||
|
||||
## RTL Language Support
|
||||
|
||||
The system includes framework support for RTL languages:
|
||||
|
||||
```javascript
|
||||
// Check if current language is RTL
|
||||
if (i18n.isRTL()) {
|
||||
document.documentElement.setAttribute('dir', 'rtl');
|
||||
document.body.classList.add('rtl');
|
||||
}
|
||||
```
|
||||
|
||||
Add CSS for RTL support:
|
||||
|
||||
```css
|
||||
.rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.rtl .some-element {
|
||||
text-align: right;
|
||||
margin-right: 0;
|
||||
margin-left: auto;
|
||||
}
|
||||
```
|
||||
@@ -1,155 +0,0 @@
|
||||
# 服务端渲染 I18n 实现总结
|
||||
|
||||
## 问题分析
|
||||
|
||||
原始的纯前端i18n方案存在以下问题:
|
||||
1. **语言闪烁问题**:页面首次加载时会显示英文,然后才切换到用户设置的语言
|
||||
2. **首屏渲染慢**:需要等待JavaScript加载并执行才能显示正确的语言
|
||||
3. **SEO不友好**:搜索引擎爬虫看到的是默认语言内容
|
||||
|
||||
## 解决方案
|
||||
|
||||
实现了**混合式服务端+客户端i18n系统**:
|
||||
|
||||
### 1. 服务端 I18n 管理器 (`py/services/server_i18n.py`)
|
||||
|
||||
**功能**:
|
||||
- 解析JavaScript格式的语言文件(`.js`文件中的`export const`语法)
|
||||
- 提供Jinja2模板过滤器支持
|
||||
- 支持嵌套键值查找(如`header.navigation.loras`)
|
||||
- 支持参数插值(`{param}`和`{{param}}`语法)
|
||||
- 自动回退到英语翻译
|
||||
|
||||
**核心特性**:
|
||||
```python
|
||||
# 设置语言
|
||||
server_i18n.set_locale('zh-CN')
|
||||
|
||||
# 获取翻译
|
||||
title = server_i18n.get_translation('header.appTitle')
|
||||
|
||||
# 创建模板过滤器
|
||||
template_filter = server_i18n.create_template_filter()
|
||||
```
|
||||
|
||||
### 2. 模板层面的改进
|
||||
|
||||
**修改的文件**:
|
||||
- `templates/base.html` - 添加服务端翻译数据预设
|
||||
- `templates/components/header.html` - 使用服务端翻译
|
||||
- `templates/loras.html` - 标题和初始化消息服务端渲染
|
||||
|
||||
**模板语法示例**:
|
||||
```html
|
||||
<!-- 服务端渲染 -->
|
||||
<span class="app-title">{{ t('header.appTitle') }}</span>
|
||||
|
||||
<!-- 动态内容仍使用客户端 -->
|
||||
<span data-i18n="dynamic.content">Content</span>
|
||||
```
|
||||
|
||||
### 3. 路由层面的集成
|
||||
|
||||
**修改的文件**:
|
||||
- `py/routes/base_model_routes.py` - 基础模型路由
|
||||
- `py/routes/recipe_routes.py` - 配方路由
|
||||
- `py/routes/stats_routes.py` - 统计路由
|
||||
- `py/routes/misc_routes.py` - 添加语言设置API
|
||||
|
||||
**路由实现**:
|
||||
```python
|
||||
# 获取用户语言设置
|
||||
user_language = settings.get('language', 'en')
|
||||
|
||||
# 设置服务端i18n语言
|
||||
server_i18n.set_locale(user_language)
|
||||
|
||||
# 为模板环境添加i18n过滤器
|
||||
self.template_env.filters['t'] = server_i18n.create_template_filter()
|
||||
|
||||
# 模板上下文
|
||||
template_context = {
|
||||
'user_language': user_language,
|
||||
't': server_i18n.get_translation,
|
||||
'server_i18n': server_i18n,
|
||||
'common_translations': {
|
||||
'loading': server_i18n.get_translation('common.status.loading'),
|
||||
# ... 其他常用翻译
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 前端混合处理器 (`static/js/utils/mixedI18n.js`)
|
||||
|
||||
**功能**:
|
||||
- 协调服务端和客户端翻译
|
||||
- 避免重复翻译已经服务端渲染的内容
|
||||
- 处理动态内容的客户端翻译
|
||||
- 支持语言切换(触发页面重新加载)
|
||||
|
||||
**工作流程**:
|
||||
1. 检查`window.__SERVER_TRANSLATIONS__`获取服务端预设的翻译
|
||||
2. 导入客户端i18n模块
|
||||
3. 同步客户端和服务端的语言设置
|
||||
4. 只翻译需要客户端处理的剩余元素
|
||||
|
||||
### 5. API支持
|
||||
|
||||
**新增API端点**:
|
||||
- `POST /api/set-language` - 设置用户语言偏好
|
||||
- `GET /api/get-language` - 获取当前语言设置
|
||||
|
||||
### 6. 语言文件扩展
|
||||
|
||||
**新增翻译内容**:
|
||||
```javascript
|
||||
initialization: {
|
||||
loras: {
|
||||
title: 'Initializing LoRA Manager',
|
||||
message: 'Scanning and building LoRA cache...'
|
||||
},
|
||||
checkpoints: {
|
||||
title: 'Initializing Checkpoint Manager',
|
||||
message: 'Scanning and building checkpoint cache...'
|
||||
},
|
||||
// ... 其他模块的初始化消息
|
||||
}
|
||||
```
|
||||
|
||||
## 实现效果
|
||||
|
||||
### 🎯 解决的问题
|
||||
|
||||
1. **✅ 消除语言闪烁**:首屏内容直接以用户设置的语言渲染
|
||||
2. **✅ 提升首屏性能**:关键UI元素无需等待JavaScript即可显示正确语言
|
||||
3. **✅ 改善SEO**:搜索引擎可以抓取到本地化内容
|
||||
4. **✅ 保持兼容性**:动态内容仍使用前端i18n,现有功能不受影响
|
||||
|
||||
### 🔧 技术优势
|
||||
|
||||
1. **渐进式增强**:服务端渲染提供基础体验,客户端增强交互功能
|
||||
2. **智能协调**:避免重复翻译,优化性能
|
||||
3. **回退机制**:如果服务端翻译失败,自动回退到客户端翻译
|
||||
4. **统一管理**:使用相同的语言文件,保持翻译一致性
|
||||
|
||||
### 🎨 用户体验提升
|
||||
|
||||
- **即时显示**:页面打开即显示用户语言,无等待时间
|
||||
- **无缝切换**:语言切换通过页面重载,确保所有内容都正确翻译
|
||||
- **一致性**:服务端和客户端使用相同翻译源,避免不一致
|
||||
|
||||
## 部署说明
|
||||
|
||||
1. 现有的JavaScript语言文件无需修改
|
||||
2. 服务端会自动解析并缓存翻译数据
|
||||
3. 用户的语言偏好保存在`settings.json`中
|
||||
4. 页面刷新后自动应用服务端翻译
|
||||
|
||||
## 兼容性
|
||||
|
||||
- ✅ 保持现有前端i18n功能完整
|
||||
- ✅ 支持所有现有语言(en, zh-CN, zh-TW, ru, de, ja, ko, fr, es)
|
||||
- ✅ 向后兼容现有的`data-i18n`属性
|
||||
- ✅ 支持复杂的动态内容翻译
|
||||
|
||||
此实现完美解决了原始问题,在不破坏现有功能的前提下,显著提升了用户体验和应用性能。
|
||||
@@ -112,10 +112,6 @@ class MiscRoutes:
|
||||
|
||||
# Add new route for checking if a model exists in the library
|
||||
app.router.add_get('/api/check-model-exists', MiscRoutes.check_model_exists)
|
||||
|
||||
# Language settings endpoints
|
||||
app.router.add_post('/api/set-language', MiscRoutes.set_language)
|
||||
app.router.add_get('/api/get-language', MiscRoutes.get_language)
|
||||
|
||||
@staticmethod
|
||||
async def clear_cache(request):
|
||||
@@ -701,69 +697,3 @@ class MiscRoutes:
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}, status=500)
|
||||
|
||||
@staticmethod
|
||||
async def set_language(request):
|
||||
"""
|
||||
Set user language preference
|
||||
|
||||
Expects a JSON body with:
|
||||
{
|
||||
"language": "en" | "zh-CN" | "zh-TW" | "ru" | "de" | "ja" | "ko" | "fr" | "es"
|
||||
}
|
||||
"""
|
||||
try:
|
||||
data = await request.json()
|
||||
language = data.get('language')
|
||||
|
||||
if not language:
|
||||
return web.json_response({
|
||||
'success': False,
|
||||
'error': 'Missing language parameter'
|
||||
}, status=400)
|
||||
|
||||
# Validate language code
|
||||
supported_languages = ['en', 'zh-CN', 'zh-TW', 'ru', 'de', 'ja', 'ko', 'fr', 'es']
|
||||
if language not in supported_languages:
|
||||
return web.json_response({
|
||||
'success': False,
|
||||
'error': f'Unsupported language: {language}. Supported languages: {", ".join(supported_languages)}'
|
||||
}, status=400)
|
||||
|
||||
# Save language setting
|
||||
settings.set('language', language)
|
||||
|
||||
return web.json_response({
|
||||
'success': True,
|
||||
'message': f'Language set to {language}',
|
||||
'language': language
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to set language: {e}", exc_info=True)
|
||||
return web.json_response({
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}, status=500)
|
||||
|
||||
@staticmethod
|
||||
async def get_language(request):
|
||||
"""
|
||||
Get current user language preference
|
||||
|
||||
Returns the current language setting from settings
|
||||
"""
|
||||
try:
|
||||
current_language = settings.get('language', 'en')
|
||||
|
||||
return web.json_response({
|
||||
'success': True,
|
||||
'language': current_language
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get language: {e}", exc_info=True)
|
||||
return web.json_response({
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}, status=500)
|
||||
|
||||
@@ -101,46 +101,6 @@ class MixedI18nHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch language (triggers page reload for server-side re-rendering)
|
||||
*/
|
||||
async switchLanguage(languageCode) {
|
||||
try {
|
||||
// Update server-side setting
|
||||
const response = await fetch('/api/set-language', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ language: languageCode })
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
// Reload page to get server-rendered content in new language
|
||||
window.location.reload();
|
||||
} else {
|
||||
const error = await response.json();
|
||||
console.error('Failed to set language:', error.error);
|
||||
|
||||
// Fallback to client-side only language change
|
||||
if (this.clientI18n) {
|
||||
this.clientI18n.setLanguage(languageCode);
|
||||
this.currentLanguage = languageCode;
|
||||
this.translateRemainingElements();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error switching language:', error);
|
||||
|
||||
// Fallback to client-side only language change
|
||||
if (this.clientI18n) {
|
||||
this.clientI18n.setLanguage(languageCode);
|
||||
this.currentLanguage = languageCode;
|
||||
this.translateRemainingElements();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current language
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user