diff --git a/README.md b/README.md index 600df32..c6d40f8 100644 --- a/README.md +++ b/README.md @@ -50,11 +50,12 @@ https://github.com/user-attachments/assets/1ec662ba-da6c-4712-8be7-61168b08940e ## 贡献者名单 感谢以下贡献者对于ComfyUI中文开源生态的支持 -- msola-ht丶是小张啊丶alinuo666丶猪的飞行梦丶ZXSZS丶tanglangxia丶AIGCZero丶Artistjjw丶henrylaobai丶FanXiangTM丶xuchenxu168丶LovedeHua丶uiiiaiii丶fuxijun-max丶ANe5s丶cnolka 丶XXXAbit7 +- msola-ht丶是小张啊丶alinuo666丶猪的飞行梦丶ZXSZS丶tanglangxia丶AIGCZero丶Artistjjw丶henrylaobai丶FanXiangTM丶xuchenxu168丶LovedeHua丶uiiiaiii丶fuxijun-max丶ANe5s丶cnolka 丶XXXAbit7 丶Yifo98 ## 更新日志 -### v2.0.0(2025-12-08) +### v2.0.0(2025-12-08) 【兼容性更新】 +- 感谢贡献者(Yifo98)提供的新版本兼容示例,修复了ComfyUI Nodes 2.0节点的连线异常问题 - 合并贡献者(cnolka)的PR,现在通过Comfyui原生设置面板来开关翻译,并移除导致BUG的错误翻译文件 - 合并贡献者(cnolka) 对于ComfyUI-Easy-SAM3插件的翻译完善 - 合并贡献者(XXXAbit7)对于Depthflow节点的翻译补全 diff --git a/js/MenuTranslate.js b/js/MenuTranslate.js index 0890af5..8b2fc39 100644 --- a/js/MenuTranslate.js +++ b/js/MenuTranslate.js @@ -1,7 +1,8 @@ import { containsChineseCharacters, nativeTranslatedSettings, - error + error, + isVueNodes2 } from "./utils.js"; /** @@ -170,16 +171,101 @@ class TExe { error("清理观察者出错:", e); } } + + /** + * Safe text replacement for Vue mode (Text nodes and attributes only) + * @param {Node} target + */ + safeReplaceVue(target) { + try { + if (!target) return; + if (!this.T) return; + if (this.tSkip(target)) return; + + // Text Node + if (target.nodeType === Node.TEXT_NODE) { + if (target.nodeValue && !containsChineseCharacters(target.nodeValue)) { + const translated = this.MT(target.nodeValue); + if (translated) { + target.nodeValue = translated; + } + } + return; + } + + // Element Node + if (target.nodeType === Node.ELEMENT_NODE) { + // Skip canvas/graph to avoid layout issues + if (target.tagName === 'CANVAS' || target.classList?.contains('lgraphcanvas')) return; + + // Attributes + if (target.title && !containsChineseCharacters(target.title)) { + const t = this.MT(target.title); + if (t) target.title = t; + } + if (target.placeholder && !containsChineseCharacters(target.placeholder)) { + const t = this.MT(target.placeholder); + if (t) target.placeholder = t; + } + + // Button values (if input type=button) + if (target.tagName === "INPUT" && target.type === "button" && !containsChineseCharacters(target.value)) { + const t = this.MT(target.value); + if (t) target.value = t; + } + + // Recurse + if (target.childNodes && target.childNodes.length) { + Array.from(target.childNodes).forEach(child => this.safeReplaceVue(child)); + } + } + } catch (e) { + // error("Safe replace error:", e); + } + } } // 创建翻译执行器实例 let texe = new TExe(); +function applyVueMenuTranslation(T) { + try { + // 1. Try comfyAPI i18n + if (window.comfyAPI && window.comfyAPI.i18n && window.comfyAPI.i18n.addTranslations) { + window.comfyAPI.i18n.addTranslations('zh-CN', T.Menu); + return; + } + + // 2. Fallback: Safe MutationObserver + texe.safeReplaceVue(document.body); + + const observer = observeFactory(document.body, (mutationsList) => { + for (let mutation of mutationsList) { + if (mutation.type === 'childList') { + mutation.addedNodes.forEach(node => texe.safeReplaceVue(node)); + } else if (mutation.type === 'characterData') { + texe.safeReplaceVue(mutation.target); + } + } + }, true); // subtree true + + if (observer) texe.observers.push(observer); + + } catch (e) { + error("Vue mode translation failed:", e); + } +} + export function applyMenuTranslation(T) { try { texe.cleanupObservers(); texe.T = T; + if (isVueNodes2()) { + applyVueMenuTranslation(T); + return; + } + texe.translateAllText(document.querySelector(".litegraph")); const bodyObserver = observeFactory(document.querySelector("body.litegraph"), (mutationsList) => { diff --git a/js/main.js b/js/main.js index 323629d..ac24848 100644 --- a/js/main.js +++ b/js/main.js @@ -9,7 +9,8 @@ import { isTranslationEnabled, toggleTranslation, initConfig, - error + error, + isVueNodes2 } from "./utils.js"; export class TUtils { @@ -504,7 +505,9 @@ const ext = { async init(app) { try { await initConfig(); - TUtils.enhandeDrawNodeWidgets(); + if (!isVueNodes2()) { + TUtils.enhandeDrawNodeWidgets(); + } await TUtils.syncTranslation(); } catch (e) { error("扩展初始化失败:", e); @@ -514,7 +517,9 @@ const ext = { try { const isComfyUIChineseNative = document.documentElement.lang === 'zh-CN'; - TUtils.addNodeTitleMonitoring(app); + if (!isVueNodes2()) { + TUtils.addNodeTitleMonitoring(app); + } app.ui.settings.addSetting({ id: "🌐翻译设置.语言开关.Enable", @@ -529,17 +534,24 @@ const ext = { }); if (isTranslationEnabled()) { - TUtils.applyNodeTypeTranslation(app); - TUtils.applyContextMenuTranslation(app); + if (!isVueNodes2()) { + TUtils.applyNodeTypeTranslation(app); + TUtils.applyContextMenuTranslation(app); + } + // Menu translation needs to handle both modes internally or be split if (!isComfyUIChineseNative) { TUtils.applyMenuTranslation(app); } - TUtils.addRegisterNodeDefCB(app); + if (!isVueNodes2()) { + TUtils.addRegisterNodeDefCB(app); + } } - TUtils.addPanelButtons(app); + if (!isVueNodes2()) { + TUtils.addPanelButtons(app); + } } catch (e) { error("扩展设置失败:", e); } diff --git a/js/utils.js b/js/utils.js index 28610c6..3ada86e 100644 --- a/js/utils.js +++ b/js/utils.js @@ -144,4 +144,12 @@ export async function toggleTranslation() { } else { error("切换翻译状态失败"); } +} + +/** + * Check if running in ComfyUI Nodes 2.0 (Vue) mode + * @returns {boolean} + */ +export function isVueNodes2() { + return typeof window.comfyAPI !== 'undefined'; } \ No newline at end of file