feat(localization): enhance English and Chinese translations for update notifications and support modal

This commit is contained in:
Will Miao
2025-08-31 21:54:54 +08:00
parent 84d801cf14
commit 63562240c4
6 changed files with 162 additions and 50 deletions

View File

@@ -14,7 +14,9 @@
}, },
"status": { "status": {
"loading": "Loading...", "loading": "Loading...",
"unknown": "Unknown" "unknown": "Unknown",
"date": "Date",
"version": "Version"
}, },
"language": { "language": {
"select": "Select Language", "select": "Select Language",
@@ -696,6 +698,8 @@
}, },
"update": { "update": {
"title": "Check for Updates", "title": "Check for Updates",
"updateAvailable": "Update Available",
"noChangelogAvailable": "No detailed changelog available. Check GitHub for more information.",
"currentVersion": "Current Version", "currentVersion": "Current Version",
"newVersion": "New Version", "newVersion": "New Version",
"commit": "Commit", "commit": "Commit",
@@ -705,7 +709,27 @@
"changelog": "Changelog", "changelog": "Changelog",
"checkingUpdates": "Checking for updates...", "checkingUpdates": "Checking for updates...",
"checkingMessage": "Please wait while we check for the latest version.", "checkingMessage": "Please wait while we check for the latest version.",
"showNotifications": "Show update notifications" "showNotifications": "Show update notifications",
"updateProgress": {
"preparing": "Preparing update...",
"installing": "Installing update...",
"completed": "Update completed successfully!",
"failed": "Update failed: {error}"
},
"status": {
"updating": "Updating...",
"updated": "Updated!",
"updateFailed": "Update Failed"
},
"completion": {
"successMessage": "Successfully updated to {version}!",
"restartMessage": "Please restart ComfyUI or LoRA Manager to apply update.",
"reloadMessage": "Make sure to reload your browser for both LoRA Manager and ComfyUI."
},
"nightly": {
"warning": "Warning: Nightly builds may contain experimental features and could be unstable.",
"enable": "Enable Nightly Updates"
}
}, },
"support": { "support": {
"title": "Support the Project", "title": "Support the Project",
@@ -713,7 +737,27 @@
"feedback": { "feedback": {
"title": "Provide Feedback", "title": "Provide Feedback",
"description": "Your feedback helps shape future updates! Share your thoughts:" "description": "Your feedback helps shape future updates! Share your thoughts:"
} },
"links": {
"submitGithubIssue": "Submit GitHub Issue",
"joinDiscord": "Join Discord",
"youtubeChannel": "YouTube Channel",
"civitaiProfile": "Civitai Profile",
"supportKofi": "Support on Ko-fi",
"supportPatreon": "Support on Patreon"
},
"sections": {
"followUpdates": "Follow for Updates",
"buyMeCoffee": "Buy me a coffee",
"coffeeDescription": "If you'd like to support my work directly:",
"becomePatron": "Become a Patron",
"patronDescription": "Support ongoing development with monthly contributions:",
"wechatSupport": "WeChat Support",
"wechatDescription": "For users in China, you can support via WeChat:",
"showWechatQR": "Show WeChat QR Code",
"hideWechatQR": "Hide WeChat QR Code"
},
"footer": "Thank you for using LoRA Manager! ❤️"
}, },
"toast": { "toast": {
"general": { "general": {
@@ -924,5 +968,14 @@
"exampleImagesDownloadSuccess": "Successfully downloaded example images!", "exampleImagesDownloadSuccess": "Successfully downloaded example images!",
"exampleImagesDownloadFailed": "Failed to download example images: {message}" "exampleImagesDownloadFailed": "Failed to download example images: {message}"
} }
},
"banners": {
"versionMismatch": {
"title": "Application Update Detected",
"content": "Your browser is running an outdated version of LoRA Manager ({storedVersion}). The server has been updated to version {currentVersion}. Please refresh to ensure proper functionality.",
"refreshNow": "Refresh Now",
"refreshingIn": "Refreshing in",
"seconds": "seconds"
}
} }
} }

View File

@@ -14,7 +14,9 @@
}, },
"status": { "status": {
"loading": "加载中...", "loading": "加载中...",
"unknown": "未知" "unknown": "未知",
"date": "日期",
"version": "版本"
}, },
"language": { "language": {
"select": "选择语言", "select": "选择语言",
@@ -697,6 +699,8 @@
"update": { "update": {
"title": "检查更新", "title": "检查更新",
"currentVersion": "当前版本", "currentVersion": "当前版本",
"updateAvailable": "更新可用",
"noChangelogAvailable": "没有详细的更新日志可用。请查看 GitHub 以获取更多信息。",
"newVersion": "新版本", "newVersion": "新版本",
"commit": "提交", "commit": "提交",
"viewOnGitHub": "在 GitHub 查看", "viewOnGitHub": "在 GitHub 查看",
@@ -705,7 +709,27 @@
"changelog": "更新日志", "changelog": "更新日志",
"checkingUpdates": "正在检查更新...", "checkingUpdates": "正在检查更新...",
"checkingMessage": "请稍候,正在检查最新版本。", "checkingMessage": "请稍候,正在检查最新版本。",
"showNotifications": "显示更新通知" "showNotifications": "显示更新通知",
"updateProgress": {
"preparing": "正在准备更新...",
"installing": "正在安装更新...",
"completed": "更新已成功完成!",
"failed": "更新失败:{error}"
},
"status": {
"updating": "正在更新...",
"updated": "已更新!",
"updateFailed": "更新失败"
},
"completion": {
"successMessage": "已成功更新到 {version}",
"restartMessage": "请重启 ComfyUI 或 LoRA 管理器以应用更新。",
"reloadMessage": "请确保刷新浏览器以加载最新的 LoRA 管理器和 ComfyUI。"
},
"nightly": {
"warning": "警告Nightly 版本可能包含实验性功能,可能不稳定。",
"enable": "启用 Nightly 更新"
}
}, },
"support": { "support": {
"title": "支持项目", "title": "支持项目",
@@ -713,7 +737,27 @@
"feedback": { "feedback": {
"title": "反馈建议", "title": "反馈建议",
"description": "你的反馈有助于未来更新!欢迎分享你的想法:" "description": "你的反馈有助于未来更新!欢迎分享你的想法:"
} },
"links": {
"submitGithubIssue": "提交 GitHub 问题",
"joinDiscord": "加入 Discord",
"youtubeChannel": "YouTube 频道",
"civitaiProfile": "Civitai 个人资料",
"supportKofi": "支持 Ko-fi",
"supportPatreon": "支持 Patreon"
},
"sections": {
"followUpdates": "关注更新",
"buyMeCoffee": "请我喝杯咖啡",
"coffeeDescription": "如果你想直接支持我的工作:",
"becomePatron": "成为赞助人",
"patronDescription": "通过每月捐款支持持续开发:",
"wechatSupport": "微信支持",
"wechatDescription": "对于中国用户,你可以通过微信支持:",
"showWechatQR": "显示微信二维码",
"hideWechatQR": "隐藏微信二维码"
},
"footer": "感谢使用 LoRA 管理器!❤️"
}, },
"toast": { "toast": {
"general": { "general": {
@@ -924,5 +968,14 @@
"exampleImagesDownloadSuccess": "示例图片下载成功!", "exampleImagesDownloadSuccess": "示例图片下载成功!",
"exampleImagesDownloadFailed": "示例图片下载失败:{message}" "exampleImagesDownloadFailed": "示例图片下载失败:{message}"
} }
},
"banners": {
"versionMismatch": {
"title": "检测到应用更新",
"content": "你的浏览器正在运行过时的 LoRA 管理器版本({storedVersion})。服务器已更新到版本 {currentVersion}。请刷新以确保正常使用。",
"refreshNow": "立即刷新",
"refreshingIn": "将在",
"seconds": "秒后刷新"
}
} }
} }

View File

@@ -52,13 +52,13 @@ export class HeaderManager {
const currentTheme = getStorageItem('theme') || 'auto'; const currentTheme = getStorageItem('theme') || 'auto';
themeToggle.classList.add(`theme-${currentTheme}`); themeToggle.classList.add(`theme-${currentTheme}`);
// 使用i18nHelpers更新themeToggletitle // Use i18nHelpers to update themeToggle's title
this.updateThemeTooltip(themeToggle, currentTheme); this.updateThemeTooltip(themeToggle, currentTheme);
themeToggle.addEventListener('click', async () => { themeToggle.addEventListener('click', async () => {
if (typeof toggleTheme === 'function') { if (typeof toggleTheme === 'function') {
const newTheme = toggleTheme(); const newTheme = toggleTheme();
// 使用i18nHelpers更新themeToggletitle // Use i18nHelpers to update themeToggle's title
this.updateThemeTooltip(themeToggle, newTheme); this.updateThemeTooltip(themeToggle, newTheme);
} }
}); });

View File

@@ -8,6 +8,7 @@ import {
resetDismissedBanner resetDismissedBanner
} from '../utils/storageHelpers.js'; } from '../utils/storageHelpers.js';
import { bannerService } from './BannerService.js'; import { bannerService } from './BannerService.js';
import { translate } from '../utils/i18nHelpers.js';
export class UpdateService { export class UpdateService {
constructor() { constructor() {
@@ -165,8 +166,8 @@ export class UpdateService {
if (updateToggle) { if (updateToggle) {
updateToggle.title = this.updateNotificationsEnabled && this.updateAvailable updateToggle.title = this.updateNotificationsEnabled && this.updateAvailable
? "Update Available" ? translate('update.updateAvailable')
: "Check Updates"; : translate('update.title');
} }
// Force updating badges visibility based on current state // Force updating badges visibility based on current state
@@ -185,7 +186,9 @@ export class UpdateService {
// Update title based on update availability // Update title based on update availability
const headerTitle = modal.querySelector('.update-header h2'); const headerTitle = modal.querySelector('.update-header h2');
if (headerTitle) { if (headerTitle) {
headerTitle.textContent = this.updateAvailable ? "Update Available" : "Check for Updates"; headerTitle.textContent = this.updateAvailable ?
translate('update.updateAvailable') :
translate('update.title');
} }
// Always update version information, even if updateInfo is null // Always update version information, even if updateInfo is null
@@ -209,9 +212,9 @@ export class UpdateService {
const gitInfoEl = modal.querySelector('.git-info'); const gitInfoEl = modal.querySelector('.git-info');
if (gitInfoEl && this.gitInfo) { if (gitInfoEl && this.gitInfo) {
if (this.gitInfo.short_hash !== 'unknown') { if (this.gitInfo.short_hash !== 'unknown') {
let gitText = `Commit: ${this.gitInfo.short_hash}`; let gitText = `${translate('update.commit')}: ${this.gitInfo.short_hash}`;
if (this.gitInfo.commit_date !== 'unknown') { if (this.gitInfo.commit_date !== 'unknown') {
gitText += ` - Date: ${this.gitInfo.commit_date}`; gitText += ` - ${translate('common.status.date', {}, 'Date')}: ${this.gitInfo.commit_date}`;
} }
gitInfoEl.textContent = gitText; gitInfoEl.textContent = gitText;
gitInfoEl.style.display = 'block'; gitInfoEl.style.display = 'block';
@@ -231,7 +234,7 @@ export class UpdateService {
changelogItem.className = 'changelog-item'; changelogItem.className = 'changelog-item';
const versionHeader = document.createElement('h4'); const versionHeader = document.createElement('h4');
versionHeader.textContent = `Version ${this.latestVersion}`; versionHeader.textContent = `${translate('common.status.version', {}, 'Version')} ${this.latestVersion}`;
changelogItem.appendChild(versionHeader); changelogItem.appendChild(versionHeader);
// Create changelog list // Create changelog list
@@ -247,7 +250,7 @@ export class UpdateService {
} else { } else {
// If no changelog items available // If no changelog items available
const listItem = document.createElement('li'); const listItem = document.createElement('li');
listItem.textContent = "No detailed changelog available. Check GitHub for more information."; listItem.textContent = translate('update.noChangelogAvailable', {}, 'No detailed changelog available. Check GitHub for more information.');
changelogList.appendChild(listItem); changelogList.appendChild(listItem);
} }
@@ -271,11 +274,11 @@ export class UpdateService {
try { try {
this.isUpdating = true; this.isUpdating = true;
this.updateUpdateUI('updating', 'Updating...'); this.updateUpdateUI('updating', translate('update.status.updating'));
this.showUpdateProgress(true); this.showUpdateProgress(true);
// Update progress // Update progress
this.updateProgress(10, 'Preparing update...'); this.updateProgress(10, translate('update.updateProgress.preparing'));
const response = await fetch('/api/perform-update', { const response = await fetch('/api/perform-update', {
method: 'POST', method: 'POST',
@@ -287,13 +290,13 @@ export class UpdateService {
}) })
}); });
this.updateProgress(50, 'Installing update...'); this.updateProgress(50, translate('update.updateProgress.installing'));
const data = await response.json(); const data = await response.json();
if (data.success) { if (data.success) {
this.updateProgress(100, 'Update completed successfully!'); this.updateProgress(100, translate('update.updateProgress.completed'));
this.updateUpdateUI('success', 'Updated!'); this.updateUpdateUI('success', translate('update.status.updated'));
// Show success message and suggest restart // Show success message and suggest restart
setTimeout(() => { setTimeout(() => {
@@ -301,13 +304,13 @@ export class UpdateService {
}, 1000); }, 1000);
} else { } else {
throw new Error(data.error || 'Update failed'); throw new Error(data.error || translate('update.status.updateFailed'));
} }
} catch (error) { } catch (error) {
console.error('Update failed:', error); console.error('Update failed:', error);
this.updateUpdateUI('error', 'Update Failed'); this.updateUpdateUI('error', translate('update.status.updateFailed'));
this.updateProgress(0, `Update failed: ${error.message}`); this.updateProgress(0, translate('update.updateProgress.failed', { error: error.message }));
// Hide progress after error // Hide progress after error
setTimeout(() => { setTimeout(() => {
@@ -369,11 +372,11 @@ export class UpdateService {
progressText.innerHTML = ` progressText.innerHTML = `
<div style="text-align: center; color: var(--lora-success);"> <div style="text-align: center; color: var(--lora-success);">
<i class="fas fa-check-circle" style="margin-right: 8px;"></i> <i class="fas fa-check-circle" style="margin-right: 8px;"></i>
Successfully updated to ${newVersion}! ${translate('update.completion.successMessage', { version: newVersion })}
<br><br> <br><br>
<div style="opacity: 0.95; color: var(--lora-error); font-size: 1em;"> <div style="opacity: 0.95; color: var(--lora-error); font-size: 1em;">
Please restart ComfyUI or LoRA Manager to apply update.<br> ${translate('update.completion.restartMessage')}<br>
Make sure to reload your browser for both LoRA Manager and ComfyUI. ${translate('update.completion.reloadMessage')}
</div> </div>
</div> </div>
`; `;
@@ -470,16 +473,19 @@ export class UpdateService {
registerVersionMismatchBanner() { registerVersionMismatchBanner() {
// Get stored and current version for display // Get stored and current version for display
const storedVersion = getStoredVersionInfo() || 'unknown'; const storedVersion = getStoredVersionInfo() || translate('common.status.unknown');
const currentVersion = this.currentVersionInfo || 'unknown'; const currentVersion = this.currentVersionInfo || translate('common.status.unknown');
bannerService.registerBanner('version-mismatch', { bannerService.registerBanner('version-mismatch', {
id: 'version-mismatch', id: 'version-mismatch',
title: 'Application Update Detected', title: translate('banners.versionMismatch.title', {}, 'Application Update Detected'),
content: `Your browser is running an outdated version of LoRA Manager (${storedVersion}). The server has been updated to version ${currentVersion}. Please refresh to ensure proper functionality.`, content: translate('banners.versionMismatch.content', {
storedVersion,
currentVersion
}, `Your browser is running an outdated version of LoRA Manager (${storedVersion}). The server has been updated to version ${currentVersion}. Please refresh to ensure proper functionality.`),
actions: [ actions: [
{ {
text: 'Refresh Now', text: translate('banners.versionMismatch.refreshNow', {}, 'Refresh Now'),
icon: 'fas fa-sync', icon: 'fas fa-sync',
action: 'hardRefresh', action: 'hardRefresh',
type: 'primary' type: 'primary'
@@ -492,7 +498,7 @@ export class UpdateService {
// Add countdown element // Add countdown element
const countdownEl = document.createElement('div'); const countdownEl = document.createElement('div');
countdownEl.className = 'banner-countdown'; countdownEl.className = 'banner-countdown';
countdownEl.innerHTML = `<span>Refreshing in <strong>15</strong> seconds...</span>`; countdownEl.innerHTML = `<span>${translate('banners.versionMismatch.refreshingIn', {}, 'Refreshing in')} <strong>15</strong> ${translate('banners.versionMismatch.seconds', {}, 'seconds')}...</span>`;
bannerElement.querySelector('.banner-content').appendChild(countdownEl); bannerElement.querySelector('.banner-content').appendChild(countdownEl);
// Start countdown // Start countdown

View File

@@ -15,21 +15,21 @@
<div class="support-links"> <div class="support-links">
<a href="https://github.com/willmiao/ComfyUI-Lora-Manager/issues/new" class="social-link" target="_blank"> <a href="https://github.com/willmiao/ComfyUI-Lora-Manager/issues/new" class="social-link" target="_blank">
<i class="fab fa-github"></i> <i class="fab fa-github"></i>
<span>Submit GitHub Issue</span> <span>{{ t('support.links.submitGithubIssue') }}</span>
</a> </a>
<a href="https://discord.gg/vcqNrWVFvM" class="social-link" target="_blank"> <a href="https://discord.gg/vcqNrWVFvM" class="social-link" target="_blank">
<i class="fab fa-discord"></i> <i class="fab fa-discord"></i>
<span>Join Discord</span> <span>{{ t('support.links.joinDiscord') }}</span>
</a> </a>
</div> </div>
</div> </div>
<div class="support-section"> <div class="support-section">
<h3><i class="fas fa-rss"></i> Follow for Updates</h3> <h3><i class="fas fa-rss"></i> {{ t('support.sections.followUpdates') }}</h3>
<div class="support-links"> <div class="support-links">
<a href="https://www.youtube.com/@pixelpaws-ai" class="social-link" target="_blank"> <a href="https://www.youtube.com/@pixelpaws-ai" class="social-link" target="_blank">
<i class="fab fa-youtube"></i> <i class="fab fa-youtube"></i>
<span>YouTube Channel</span> <span>{{ t('support.links.youtubeChannel') }}</span>
</a> </a>
<a href="https://civitai.com/user/PixelPawsAI" class="social-link civitai-link" target="_blank"> <a href="https://civitai.com/user/PixelPawsAI" class="social-link civitai-link" target="_blank">
<svg class="civitai-icon" viewBox="0 0 225 225" width="20" height="20"> <svg class="civitai-icon" viewBox="0 0 225 225" width="20" height="20">
@@ -45,37 +45,37 @@
95 c91 52 167 94 169 94 2 0 78 -42 168 -92z"/> 95 c91 52 167 94 169 94 2 0 78 -42 168 -92z"/>
</g> </g>
</svg> </svg>
<span>Civitai Profile</span> <span>{{ t('support.links.civitaiProfile') }}</span>
</a> </a>
</div> </div>
</div> </div>
<div class="support-section"> <div class="support-section">
<h3><i class="fas fa-coffee"></i> Buy me a coffee</h3> <h3><i class="fas fa-coffee"></i> {{ t('support.sections.buyMeCoffee') }}</h3>
<p>If you'd like to support my work directly:</p> <p>{{ t('support.sections.coffeeDescription') }}</p>
<a href="https://ko-fi.com/pixelpawsai" class="kofi-button" target="_blank"> <a href="https://ko-fi.com/pixelpawsai" class="kofi-button" target="_blank">
<i class="fas fa-mug-hot"></i> <i class="fas fa-mug-hot"></i>
<span>Support on Ko-fi</span> <span>{{ t('support.links.supportKofi') }}</span>
</a> </a>
</div> </div>
<!-- Patreon Support Section --> <!-- Patreon Support Section -->
<div class="support-section"> <div class="support-section">
<h3><i class="fab fa-patreon"></i> Become a Patron</h3> <h3><i class="fab fa-patreon"></i> {{ t('support.sections.becomePatron') }}</h3>
<p>Support ongoing development with monthly contributions:</p> <p>{{ t('support.sections.patronDescription') }}</p>
<a href="https://patreon.com/PixelPawsAI" class="patreon-button" target="_blank"> <a href="https://patreon.com/PixelPawsAI" class="patreon-button" target="_blank">
<i class="fab fa-patreon"></i> <i class="fab fa-patreon"></i>
<span>Support on Patreon</span> <span>{{ t('support.links.supportPatreon') }}</span>
</a> </a>
</div> </div>
<!-- New section for Chinese payment methods --> <!-- New section for Chinese payment methods -->
<div class="support-section"> <div class="support-section">
<h3><i class="fas fa-qrcode"></i> WeChat Support</h3> <h3><i class="fas fa-qrcode"></i> {{ t('support.sections.wechatSupport') }}</h3>
<p>For users in China, you can support via WeChat:</p> <p>{{ t('support.sections.wechatDescription') }}</p>
<button class="secondary-btn qrcode-toggle" id="toggleQRCode"> <button class="secondary-btn qrcode-toggle" id="toggleQRCode">
<i class="fas fa-qrcode"></i> <i class="fas fa-qrcode"></i>
<span class="toggle-text">Show WeChat QR Code</span> <span class="toggle-text">{{ t('support.sections.showWechatQR') }}</span>
<i class="fas fa-chevron-down toggle-icon"></i> <i class="fas fa-chevron-down toggle-icon"></i>
</button> </button>
<div class="qrcode-container" id="qrCodeContainer"> <div class="qrcode-container" id="qrCodeContainer">
@@ -84,7 +84,7 @@
</div> </div>
<div class="support-footer"> <div class="support-footer">
<p>Thank you for using LoRA Manager! ❤️</p> <p>{{ t('support.footer') }}</p>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -4,7 +4,7 @@
<button class="close" onclick="modalManager.closeModal('updateModal')">&times;</button> <button class="close" onclick="modalManager.closeModal('updateModal')">&times;</button>
<div class="update-header"> <div class="update-header">
<i class="fas fa-bell update-icon"></i> <i class="fas fa-bell update-icon"></i>
<h2>{{ t('update.title') }}</h2> <h2 data-i18n="update.title">{{ t('update.title') }}</h2>
</div> </div>
<div class="update-content"> <div class="update-content">
<div class="update-info"> <div class="update-info">
@@ -26,7 +26,7 @@
</a> </a>
<button id="updateBtn" class="primary-btn disabled"> <button id="updateBtn" class="primary-btn disabled">
<i class="fas fa-download"></i> <i class="fas fa-download"></i>
<span id="updateBtnText">{{ t('update.updateNow') }}</span> <span id="updateBtnText" data-i18n="update.updateNow">{{ t('update.updateNow') }}</span>
</button> </button>
</div> </div>
</div> </div>
@@ -34,7 +34,7 @@
<!-- Update Progress Section --> <!-- Update Progress Section -->
<div class="update-progress" id="updateProgress" style="display: none;"> <div class="update-progress" id="updateProgress" style="display: none;">
<div class="progress-info"> <div class="progress-info">
<div class="progress-text" id="updateProgressText">{{ t('update.preparingUpdate') }}</div> <div class="progress-text" id="updateProgressText" data-i18n="update.preparingUpdate">{{ t('update.preparingUpdate') }}</div>
<div class="update-progress-bar"> <div class="update-progress-bar">
<div class="progress-fill" id="updateProgressFill"></div> <div class="progress-fill" id="updateProgressFill"></div>
</div> </div>