diff --git a/web/hLanguage.js b/web/hLanguage.js
new file mode 100644
index 0000000..8136d71
--- /dev/null
+++ b/web/hLanguage.js
@@ -0,0 +1,191 @@
+/**
+ * @Artstich_Example
+ * @name ComfyUI_EasyKitHT_NodeAlignPro (ComfyUI Plugin)
+ * @description ComfyUI_EasyKitHT_NodeAlignPro is a lightweight ComfyUI node alignment and node coloring tool for refactoring and rewriting the UI based on the open-source projects Comfyui-Align and Comfyui-Nodealigner.
+ * @author ArtsticH
+ * @see https://registry.comfy.org/zh/nodes/easykit-node-align
+ * @see https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro
+ * @see https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro
+ * @installCommand comfy node install easykit-node-align
+ * @installCommand git clone https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git
+ * @installCommand git clone https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git
+ * @created 2025-04-29 @date 2025-06-15 @version v2.0.3 @lastUpdated 2026-01-24 @license GPL-3.0
+ * @copyright ©2012-2026, All rights reserved. Freely open to use, modify, and distribute in accordance with the GPL-3.0 license.
+ */
+
+// NodeAlignPro 全局国际化配置
+// 在 `window.hLanguage` 对象上提供 `t(key)` 辅助函数和 `lang` 属性(支持getter/setter)
+(function(){
+ 'use strict';
+ const data = {
+ // 格式:{ cn: '中文文本', en: 'English Text' }
+ // 保持单行格式以便于快速编辑
+ NodeAlignPro_Title: {cn: 'Node Align Pro', en: 'Node Align Pro'},
+ // 头部/菜单/标签文字
+ Menu_LogoTitle: {cn: '菜单栏 LOGO', en: 'Menu Logo'},
+ Title_Search: {cn: '搜索节点 Github@ArtsticH...', en: 'Search nodes Github@ArtsticH...'},
+ Aria_ModeSwitch: {cn: '模式切换', en: 'Mode Switch'},
+ Aria_Menu: {cn: '菜单', en: 'Menu'},
+ Label_Align: {cn: '对齐:', en: 'Align:'},
+ Label_Distribute: {cn: '分布:', en: 'Distribute:'},
+ Label_Mode: {cn: '模式', en: 'Mode'},
+ Label_Size: {cn: '尺寸:', en: 'Size:'},
+ Label_Select: {cn: '选择:', en: 'Select:'},
+ Aria_SelectMode: {cn: '框选模式', en: 'Selection Mode'},
+ Aria_GroupMode: {cn: '群组模式', en: 'Group Mode'},
+ Aria_Separator: {cn: '分隔线', en: 'Separator'},
+ Aria_DragMove: {cn: '按住拖移位置', en: 'Hold to drag/move'},
+ ColorPicker_Title: {cn: 'hColorPicker™', en: 'hColorPicker™'},
+ ColorPicker_HexLabel: {cn: '十六进制:', en: 'Hex:'},
+ ColorPicker_RGBLabel: {cn: 'RGB:', en: 'RGB:'},
+ ColorPicker_NodeMode: {cn: '整体色', en: 'Whole Color'},
+ ColorPicker_NodeModeTip: {cn: '👆双击切换上色模式:', en: '👆Double-click to toggle color mode:'},
+ Panel_TestTitle: {cn: 'Node 2.0 Alignment Test', en: 'Node 2.0 Alignment Test'},
+ ColorPicker_HueLabel: {cn: '色相(H):', en: 'Hue (H):'},
+ ColorPicker_SatLabel: {cn: '饱和(S):', en: 'Sat (S):'},
+ ColorPicker_BriLabel: {cn: '亮度(B):', en: 'Bri (B):'},
+ Btn_LeftAlign: {cn: '左对齐', en: 'Left Align'},
+ Btn_RightAlign: {cn: '右对齐', en: 'Right Align'},
+ Btn_TopAlign: {cn: '顶对齐', en: 'Top Align'},
+ Btn_BottomAlign: {cn: '底对齐', en: 'Bottom Align'},
+ Btn_HCenter: {cn: '水平居中', en: 'H Center'},
+ Btn_VCenter: {cn: '垂直居中', en: 'V Center'},
+ Btn_DistH: {cn: '水平等距分布', en: 'Dist H'},
+ Btn_DistV: {cn: '垂直等距分布', en: 'Dist V'},
+ Btn_EqualWidth: {cn: '等宽', en: 'Equal Width'},
+ Btn_EqualHeight: {cn: '等高', en: 'Equal Height'},
+ Picker_ScreenPickUnsupported: {cn: '浏览器不支持屏幕取色功能,请使用最新版Chrome/Edge浏览器', en: 'Browser does not support EyeDropper API; use latest Chrome/Edge.'},
+ Pick_NoSelection: {cn: '未选中任何节点', en: 'No nodes selected'},
+ Setting_ShowOperationLog: {cn: '显示操作日志', en: 'Show Operation Log'},
+ Setting_ForceReset: {cn: '⚠强制重置NodeAlignPro插件', en: '⚠Force reset NodeAlignPro plugin'},
+ Setting_DragMode: {cn: '拖拽方式', en: 'Drag Mode'},
+ Setting_UIScale: {cn: 'UI缩放', en: 'UI Scale'},
+ Setting_WorkMode: {cn: '工作模式', en: 'Work Mode'},
+ Setting_DisplayMode: {cn: '显示模式', en: 'Display Mode'},
+ Setting_AlignBtnColor: {cn: '对齐按钮颜色', en: 'Align Button Color'},
+ Setting_ToolbarBgColor: {cn: '工具栏背景色', en: 'Toolbar Background Color'},
+ Setting_ToolbarOpacity: {cn: '工具栏透明度', en: 'Toolbar Opacity'},
+ Setting_NewVersionTips: {cn: '新版说明', en: 'New Version Tips'},
+ Setting_ColorApplyMode: {cn: '上色模式', en: 'Color Apply Mode'},
+ Setting_Language: {cn: '语言', en: 'Language'},
+ // 选项标签文字
+ Option_Lang_CN: {cn: '中文', en: '中文'},
+ Option_Lang_EN: {cn: 'English', en: 'English'},
+ Option_Lang_Auto: {cn: '自动(Auto)', en: 'Auto'},
+ Option_Drag_Split: {cn: '解 耦', en: 'Split'},
+ Menu_Option_APBall: {cn: 'AP球', en: 'AP Ball'},
+ Menu_Option_Color: {cn: '色 卡', en: 'ColorBar'},
+ Menu_Option_Std: {cn: '标 准', en: 'Standard'},
+ Menu_Option_Pro: {cn: '专 业', en: 'Pro'},
+ Option_Drag_Link: {cn: '联 动', en: 'Link'},
+ Option_Work_Align: {cn: '-对 齐-', en: '-Align-'},
+ Option_Display_Always: {cn: '常驻显示', en: 'Always'},
+ Option_Display_Follow: {cn: '跟随选框', en: 'Follow+'},
+ hNodePreview_Tips: {cn: '👆双击切换上色模式:', en: '👆Dbl-Click this: '},
+ Option_Color_Whole: {cn: '整体色', en: 'Whole Color'},
+ Option_Color_TitleOnly: {cn: '仅标题', en: 'Title Only'},
+ Debug_Tips: {cn: 'v2.0.3_rc新版功能:按Shift、Alt、Ctrl Alt切换不同色卡模式...\nAlt+对齐按钮:对齐到“反向基准”节点^_^(右键菜单>【新版说明】隐藏本提示)', en: 'v2.0.3_rc: Use Shift/Alt/Ctrl+Alt to switch Alignment Mode...\nAlt+Align button: align to reversed reference node ^_^ (HideThis: Right-click > New Tips)'},
+ Aria_ClearColor: {cn: '清除颜色', en: 'Clear Color'},
+ Aria_Pick: {cn: '取色', en: 'Pick Color'},
+ Aria_RandomColor: {cn: '随机颜色', en: 'Random Color'},
+ Aria_ScreenPick: {cn: '屏幕取色', en: 'Screen Pick'},
+ Aria_Prev: {cn: '上个', en: 'Previous'},
+ Aria_Next: {cn: '下个', en: 'Next'},
+ Select_SameColor: {cn: '相同颜色', en: 'Same Color'},
+ Select_SameName: {cn: '相同名称', en: 'Same Name'},
+ Select_SameSize: {cn: '相同尺寸', en: 'Same Size'},
+ Select_DefaultColor: {cn: '默认色', en: 'Default Color'},
+ Select_Colored: {cn: '已上色', en: 'Colored'},
+ Select_State: {cn: '选择状态', en: 'Select State'},
+ Tool_MagicWand: {cn: '魔棒', en: 'Magic Wand'},
+ Aria_Rename: {cn: '重命名', en: 'Rename'},
+ Menu_ResetAll: {cn: '一键重置', en: 'Reset All'},
+ Menu_BugReport: {cn: 'bug反馈', en: 'Bug2Issue'},
+ Menu_Guide: {cn: '使用教程', en: 'Guide'},
+ Menu_NewVersion: {cn: '新版说明', en: 'New Tips'},
+ // 按需添加更多键值
+ };
+
+ // 本插件全局默认光放语言为中文(cn)。,国际友人可自行切换英文,支持'auto'以跟随浏览器/ComfyUI的语言设置
+ // This plugin uses Chinese (cn) as the global default language. International users can switch to English. The 'auto' setting is also supported to follow the browser or ComfyUI's language preference.
+ const state = { lang: 'cn' };
+
+ // 从ComfyUI或浏览器检测实际使用的语言
+ function detectLang() {
+ try {
+ // 优先尝试ComfyUI应用级别的设置(如果可用)
+ if (window.app && window.app.ui && typeof window.app.ui.settings?.getSettingValue === 'function') {
+ const v = window.app.ui.settings.getSettingValue('language') || window.app.ui.settings.getSettingValue('lang');
+ if (v && typeof v === 'string') {
+ const lv = v.toLowerCase();
+ if (lv.startsWith('en')) return 'en';
+ if (lv.startsWith('zh')) return 'cn';
+ }
+ }
+ // 回退到浏览器语言设置
+ const nav = (navigator && (navigator.language || navigator.userLanguage || '')).toLowerCase();
+ if (nav.startsWith('en')) return 'en';
+ if (nav.startsWith('zh')) return 'cn';
+ } catch (e) { /* 忽略 */ }
+ return 'cn';
+ }
+
+ // 简单的翻译函数:t(key)
+ function t(key) {
+ if (!key) return '';
+ const entry = data[key];
+ if (!entry) return key;
+ const langToUse = (state.lang === 'auto') ? detectLang() : (state.lang || 'cn');
+ return entry[langToUse] || entry.cn || Object.values(entry)[0];
+ }
+
+ // 将API暴露在window对象上
+ window.hLanguage = {
+ t,
+ data,
+ getLang() { return state.lang; },
+ setLang(l) { state.lang = (l === 'auto') ? 'auto' : ((l === 'en') ? 'en' : 'cn'); return state.lang; },
+ detectLang,
+ // 通过键值(data-i18n属性)翻译DOM元素文本内容的辅助函数
+ applyToDOM(root = document) {
+ try {
+ // 翻译textContent / placeholder / value属性
+ // 跳过仅需翻译属性(data-i18n-attr)的元素
+ root.querySelectorAll('[data-i18n]').forEach(el => {
+ if (el.hasAttribute('data-i18n-attr')) return; // 保留SVG/图标内容不翻译
+ const key = el.getAttribute('data-i18n');
+ if (!key) return;
+ const text = t(key);
+ if (!text) return;
+ if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') {
+ el.placeholder = text;
+ if (el.type === 'button' || el.type === 'submit') el.value = text;
+ } else {
+ el.textContent = text;
+ }
+ });
+
+ // 通过data-i18n-attr属性翻译aria-label、title等属性
+ root.querySelectorAll('[data-i18n][data-i18n-attr]').forEach(el => {
+ try {
+ const key = el.getAttribute('data-i18n');
+ const attrName = el.getAttribute('data-i18n-attr');
+ if (!key || !attrName) return;
+ const text = t(key);
+ if (!text) return;
+ el.setAttribute(attrName, text);
+ } catch (ee) { /* 忽略单个元素的翻译错误 */ }
+ });
+ } catch (e) { console.warn('hLanguage.applyToDOM failed:', e); }
+ }
+ };
+
+ // DOM内容加载完成后自动应用翻译,更新所有带data-i18n属性的元素
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', () => {
+ window.hLanguage.applyToDOM(document);
+ });
+ } else {
+ setTimeout(() => window.hLanguage.applyToDOM(document), 50);
+ }
+})();
diff --git a/web/hNodeAlignPro.js b/web/hNodeAlignPro.js
index e522d24..992b757 100644
--- a/web/hNodeAlignPro.js
+++ b/web/hNodeAlignPro.js
@@ -461,7 +461,7 @@
setMode(mode) { this.mode = mode; this.saveMode(); return this.mode; }
toggleMode() { this.mode = this.mode === 0 ? 1 : 0; this.saveMode(); return this.mode; }
getMode() { return this.mode; }
- getModeText() { return this.mode === 0 ? '仅标题' : '整体色'; }
+ getModeText() { try { if (window.hLanguage && typeof window.hLanguage.t === 'function') return window.hLanguage.t(this.mode === 0 ? 'Option_Color_TitleOnly' : 'Option_Color_Whole'); } catch (e) {} return this.mode === 0 ? '仅标题' : '整体色'; }
saveMode() { localStorage.setItem('NodeAlignPro_ColorApplyMode', this.mode.toString()); }
loadMode() { const saved = localStorage.getItem('NodeAlignPro_ColorApplyMode'); this.mode = saved !== null ? parseInt(saved) : 1; }
}
@@ -552,9 +552,9 @@
function __hCreateHTML() {
const container = document.createElement('div'); container.id = 'hNodeAlignKit';
container.innerHTML = `
-
v2.0.3_rc新版功能:按Shift、Alt、Ctrl Alt切换不同色卡模式...Alt+对齐按钮:对齐到“反向基准”节点^_^(右键菜单>【新版说明】隐藏本提示)
+v2.0.3_rc新版功能:按Shift、Alt、Ctrl Alt切换不同色卡模式...Alt+对齐按钮:对齐到“反向基准”节点^_^(右键菜单>【新版说明】隐藏本提示)
+
@@ -563,20 +563,20 @@
-
-
-
-
+
+
+
+
@@ -603,7 +603,7 @@
图像
vae
-
+
饱和(S):
@@ -614,102 +614,102 @@
+
-
Node Align Pro
-
-
-
+
Node Align Pro
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
-
-
+
-
-
-
-
+
+
+
+
+
-
-
+
+
+
+
后缀
-
-
-
+
+
+
-
+
AP球
色 卡
-对 齐-
标 准
专 业
+
-
-
-
-
+
+
+
+
`;
return container;
@@ -1923,7 +1923,7 @@
document.getElementById('hReset').addEventListener('click', __hReset__hNAP_State);
const openLinkAndHideMenu = (url) => { window.open(url, '_blank'); window.__hMgr_MenuHide && window.__hMgr_MenuHide.hideMenu(); };
document.getElementById('hBugReport').addEventListener('click', () => openLinkAndHideMenu('https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues'));
- document.getElementById('hGuide').addEventListener('click', () => openLinkAndHideMenu('https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro'));
+ document.getElementById('hGuide').addEventListener('click', () => openLinkAndHideMenu('https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro#readme'));
const backBtn = document.getElementById('hBack');
if (backBtn) backBtn.addEventListener('click', () => { const debugInfo = document.querySelector('.hDebugInfo'); if (debugInfo) { debugInfo.style.display = debugInfo.style.display === 'none' ? 'block' : 'none'; } window.__hMgr_MenuHide && window.__hMgr_MenuHide.hideMenu(); })
}
@@ -2029,7 +2029,17 @@
hide() { const container = document.getElementById('hNodeAlignKit'); container && (container.style.display = 'none'); }
updateMenuButtonText() {
- const menuBtn = document.querySelector('[data-target="hCMP-hSel__display-options"]'); menuBtn && (menuBtn.textContent = this.isPermanent ? '常驻显示' : '跟随选框'); const optionsContainer = document.getElementById('hCMP-hSel__display-options');
+ const menuBtn = document.querySelector('[data-target="hCMP-hSel__display-options"]');
+ try {
+ if (window.hLanguage && typeof window.hLanguage.t === 'function') {
+ const alwaysText = window.hLanguage.t('Option_Display_Always') || '常驻显示';
+ const followText = window.hLanguage.t('Option_Display_Follow') || '跟随选框';
+ menuBtn && (menuBtn.textContent = this.isPermanent ? alwaysText : followText);
+ } else {
+ menuBtn && (menuBtn.textContent = this.isPermanent ? '常驻显示' : '跟随选框');
+ }
+ } catch (e) { menuBtn && (menuBtn.textContent = this.isPermanent ? '常驻显示' : '跟随选框'); }
+ const optionsContainer = document.getElementById('hCMP-hSel__display-options');
optionsContainer && optionsContainer.querySelectorAll('.hCMP-hSel__option').forEach(opt => { opt.classList.remove('selected'); (this.isPermanent && opt.getAttribute('data-value') === 'hDispMode0_Always') || (!this.isPermanent && opt.getAttribute('data-value') === 'hDispMode1_Follow') && opt.classList.add('selected'); });
}
@@ -2056,6 +2066,29 @@
// 【== 初始化流程 ==】
const __hInit_hNAP = () => {
window.__hMgr_Log = new __hMgr_Log(); hLog.info('初始化ComfyUI_EasyKitHT_NodeAlignPro插件完毕, 等待DOM加载...'); const container = __hCreateHTML(); document.body.appendChild(container);
+ try {
+ window.hLanguage && window.hLanguage.applyToDOM && window.hLanguage.applyToDOM(container);
+ // 对没有 data-i18n 属性的元素进行额外的定向翻译
+ if (window.hLanguage) {
+ const HL = window.hLanguage;
+ const titleEl = container.querySelector('#hNAP-Title__Content-Text'); titleEl && (titleEl.textContent = HL.t('NodeAlignPro_Title'));
+ const cpHeader = container.querySelector('#hCPr__header h2'); cpHeader && (cpHeader.textContent = HL.t('ColorPicker_Title'));
+ const hexInput = container.querySelector('#hexInput2'); if (hexInput && hexInput.previousElementSibling) hexInput.previousElementSibling.textContent = HL.t('ColorPicker_HexLabel');
+ const rgbLabel = container.querySelector('.hCPr__rgbLabel'); rgbLabel && (rgbLabel.textContent = HL.t('ColorPicker_RGBLabel'));
+ const nodePreviewTip = container.querySelector('#hCPr__nodePreviewTips'); nodePreviewTip && (nodePreviewTip.textContent = HL.t('ColorPicker_NodeModeTip'));
+ const nodeMode = container.querySelector('#hCPr__nodeMode'); nodeMode && (nodeMode.textContent = HL.t('ColorPicker_NodeMode'));
+ try {
+ // 颜色选择器滑块标签(按顺序)
+ const sliders = Array.from(container.querySelectorAll('.hCPr__hsbBar_sliderLabel'));
+ if (sliders.length >= 3) {
+ sliders[0].textContent = HL.t('ColorPicker_HueLabel');
+ sliders[1].textContent = HL.t('ColorPicker_SatLabel');
+ sliders[2].textContent = HL.t('ColorPicker_BriLabel');
+ }
+ } catch (ee) { /* 忽略 */ }
+ try { const logoAp = container.querySelector('#hBtnY_barLOGO'); if (logoAp) logoAp.setAttribute('aria-label', HL.t('Menu_LogoTitle')); } catch (ee) {}
+ }
+ } catch (e) { console.warn('hLanguage.applyToDOM 失败:', e); }
setTimeout(() => {
hLog.debug('NodeAlignPro核心组件初始化完毕! 请等待其它插件加载...🔥v2.0.3_rc新版教程文档请点击:右键菜单>【使用教程】查看...');
window.containerController = new __hController_hNAPKit(container), window.__hMgr_PopEl__Position = new __hMgr_PopEl__Position(), window.__hMgr_PopEl__Position.init(container), window.__hMgr_MenuHide = new __hMgr_MenuHide(); __hInit_AllIcons(), __hInit_MainInterface(), __hInit_hMenu__Dropdown(); window.__hColor_Module = new __hColor_Module(); __hInit_ColorPicker(); window.NodeAlignProSettingsManager = new __hMgr_Settings(); // 初始化设置管理器
@@ -2169,11 +2202,11 @@
// 更新取色器显示
const nodeModeText = document.getElementById('hCPr__nodeMode');
if (nodeModeText) {
- nodeModeText.textContent = mode === 0 ? '仅标题' : '整体色';
+ try { nodeModeText.textContent = (window.hLanguage && typeof window.hLanguage.t === 'function') ? window.hLanguage.t(mode === 0 ? 'Option_Color_TitleOnly' : 'Option_Color_Whole') : (mode === 0 ? '仅标题' : '整体色'); } catch (e) { nodeModeText.textContent = mode === 0 ? '仅标题' : '整体色'; }
nodeModeText.style.backgroundColor = mode === 0 ? 'rgb(var(--hC_BW3_DeepGray))' : 'rgb(var(--hC_CPr0__PurpleStd))';
}
- hLog.info('--@hSetting', `上色模式已设置为: ${mode === 0 ? '仅标题' : '整体色'}`);
+ try { hLog.info('--@hSetting', `上色模式已设置为: ${(window.hLanguage && typeof window.hLanguage.t === 'function') ? window.hLanguage.t(mode === 0 ? 'Option_Color_TitleOnly' : 'Option_Color_Whole') : (mode === 0 ? '仅标题' : '整体色')}`); } catch (e) { hLog.info('--@hSetting', `上色模式已设置为: ${mode === 0 ? '仅标题' : '整体色'}`); }
}
}
diff --git a/web/hNodeAlignPro_settings.js b/web/hNodeAlignPro_settings.js
index cfb4c51..a191401 100644
--- a/web/hNodeAlignPro_settings.js
+++ b/web/hNodeAlignPro_settings.js
@@ -1,19 +1,56 @@
+/**
+ * @Artstich_Example
+ * @name ComfyUI_EasyKitHT_NodeAlignPro (ComfyUI Plugin)
+ * @description ComfyUI_EasyKitHT_NodeAlignPro is a lightweight ComfyUI node alignment and node coloring tool for refactoring and rewriting the UI based on the open-source projects Comfyui-Align and Comfyui-Nodealigner.
+ * @author ArtsticH
+ * @see https://registry.comfy.org/zh/nodes/easykit-node-align
+ * @see https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro
+ * @see https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro
+ * @installCommand comfy node install easykit-node-align
+ * @installCommand git clone https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git
+ * @installCommand git clone https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git
+ * @created 2025-04-29 @date 2025-06-15 @version v2.0.3 @lastUpdated 2026-01-24 @license GPL-3.0
+ * @copyright ©2012-2026, All rights reserved. Freely open to use, modify, and distribute in accordance with the GPL-3.0 license.
+ */
+
import { app } from "../../scripts/app.js";
+// 简单的国际化助手,当hLanguage未就绪时回退到提供的中文文本
+function h_i18n(key, fallback) {
+ try { return window.hLanguage && typeof window.hLanguage.t === 'function' ? window.hLanguage.t(key) : (fallback || key); } catch (e) { return fallback || key; }
+}
+
+// 辅助函数:安全地调用存在的方法,否则存储待处理的值
+function __hNodeAlignPro_safeCall(target, methodName, keyForPending, value) {
+ try {
+ if (target && typeof target[methodName] === 'function') {
+ target[methodName](value);
+ return true;
+ }
+ } catch (e) { console.warn(`[NodeAlignPro 设置模块] 调用 ${methodName} 失败:`, e); }
+ // 存储待处理值供主模块稍后获取
+ try {
+ window.__hNodeAlignPro_pendingSettings = window.__hNodeAlignPro_pendingSettings || {};
+ window.__hNodeAlignPro_pendingSettings[keyForPending] = value;
+ console.info(`[NodeAlignPro 设置模块] 挂起设置 ${keyForPending}=${value},等待主模块处理`);
+ } catch (e) { /* 忽略 */ }
+ return false;
+}
+
const NodeAlignProSettings = [
{
- id: "hNodeAlignPro.ShowOperationLog", name: "显示操作日志", type: "boolean",
+ id: "hNodeAlignPro.ShowOperationLog", name: h_i18n('Setting_ShowOperationLog','显示操作日志'), type: "boolean",
defaultValue: false,
- category: ["🔥 NodeAlignPro", "Z开发人员选项", "显示操作日志"],
- tooltip: "开启后,插件操作日志将输出到页面左上角,方便进阶用户调试",
+ category: ["🔥 NodeAlignPro", "Z开发人员选项", h_i18n('Setting_ShowOperationLog','显示操作日志')],
+ tooltip: h_i18n('Setting_ShowOperationLog','开启后,插件操作日志将输出到页面左上角,方便进阶用户调试'),
onChange: (value) => { try { if (window.NodeAlignProSettingsManager) { window.NodeAlignProSettingsManager.setShowOperationLog(value); } } catch (error) { console.error('设置操作日志显示失败:', error); } }
},
{
- id: "hNodeAlignPro.hReset", name: "⚠强制重置NodeAlignPro插件", type: "boolean",
+ id: "hNodeAlignPro.hReset", name: h_i18n('Setting_ForceReset','⚠强制重置NodeAlignPro插件'), type: "boolean",
defaultValue: false,
- category: ["🔥 NodeAlignPro", "Z开发人员选项", "⚠强制重置NodeAlignPro插件"],
- tooltip: "⚠此操作会强制刷新页面,请务必先保存工作流! 开启后会强制重建NodeAlignPro插件,仅在插件异常时使用! ",
+ category: ["🔥 NodeAlignPro", "Z开发人员选项", h_i18n('Setting_ForceReset','⚠强制重置NodeAlignPro插件')],
+ tooltip: h_i18n('Setting_ForceReset','⚠此操作会强制刷新页面,请务必先保存工作流! 开启后会强制重建NodeAlignPro插件,仅在插件异常时使用! '),
onChange: (value) => {
if (value) try {
if (typeof __hReset__hNAP_State === 'function') __hReset__hNAP_State(); else resetNodeAlignProManually(); // 1. 调用核心文件中的重置函数。如果核心重置函数不存在,执行手动重置
@@ -21,7 +58,7 @@ const NodeAlignProSettings = [
setTimeout(() => { // 4. 刷新页面以完全重置插件
const isResetEnabled = app.ui?.settings?.getSettingValue?.("hNodeAlignPro.hReset"); // 检查开关是否处于关闭状态
if (isResetEnabled === true) location.reload(); // 只有当开关处于开启状态时才刷新
- else { if (hLog) hLog.info('--@hSetting', '重置操作已完成,开关已自动关闭,无需刷新页面'); console.log('重置操作已完成,开关已自动关闭,无需刷新页面'); } // 如果开关已关闭,则不刷新,仅记录日志
+ else { if (hLog) hLog.info('--@hSetting', '🔥NodeAlignPro已重置!直接可用,无需重复刷新页面'); console.log('🔥NodeAlignPro已重置!直接可用,无需重复刷新页面'); } // 如果开关已关闭,则不刷新,仅记录日志
}, 500);
if (hLog) hLog.info('--@hSetting', '插件已通过设置菜单强制重置,页面将重新加载...');
} catch (error) { console.error('重置插件失败:', error); if (hLog) hLog.error('--@hSetting', '重置失败:', error); }
@@ -31,15 +68,28 @@ const NodeAlignProSettings = [
// { id: "hNodeAlignPro.button_test", name: "测试", type: "input", defaultValue: "测试文本", category: ["🔥 NodeAlignPro", "NodeAlignPro预置颜色", "测试"], onChange: (newVal) => { } },
{
- id: "hNodeAlignPro.linkMode", name: "拖拽方式", type: "combo",
- options: [{ value: "hDragMode1_Split", text: "解 耦(默认)" }, { value: "hDragMode0_Link", text: "联 动" }],
+ id: "hNodeAlignPro.linkMode", name: h_i18n('Setting_DragMode','拖拽方式'), type: "combo",
+ options: [{ value: "hDragMode1_Split", text: h_i18n('Option_Drag_Split','解 耦') }, { value: "hDragMode0_Link", text: h_i18n('Option_Drag_Link','联 动') }],
defaultValue: "hDragMode1_Split",
- category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置", "拖拽方式"],
- tooltip: "切换是否联动[运行/Action]按钮到插件面板(与插件右键菜单设置同步)",
+ category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置", h_i18n('Setting_DragMode','拖拽方式')],
+ tooltip: h_i18n('Setting_DragMode','切换是否联动[运行/Action]按钮到插件面板(与插件右键菜单设置同步)'),
onChange: (value) => {
try {
- const mode = value === "hDragMode0_Link" ? 1 : 0; // 直接调用全局的处理函数。或者通过设置管理器。或者直接调用联动管理器
- (typeof __hMenu_Selection === 'function' && __hMenu_Selection(value)) || (window.NodeAlignProSettingsManager && window.NodeAlignProSettingsManager.setLinkMode(mode)) || (window.__hMgr_ACbar && window.__hMgr_ACbar.setLinkMode(mode)) || console.error('无法找到拖拽方式处理函数');
+ const mode = value === "hDragMode0_Link" ? 1 : 0;
+ // 首先尝试显式的全局处理函数
+ if (typeof __hMenu_Selection === 'function') {
+ try { __hMenu_Selection(value); return; } catch (e) { console.warn('调用 __hMenu_Selection 失败:', e); }
+ }
+ // 如果可用,尝试设置管理器方法
+ if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setLinkMode === 'function') {
+ try { window.NodeAlignProSettingsManager.setLinkMode(mode); return; } catch (e) { console.warn('调用 NodeAlignProSettingsManager.setLinkMode 失败:', e); }
+ }
+ // 尝试ACbar管理器
+ if (window.__hMgr_ACbar && typeof window.__hMgr_ACbar.setLinkMode === 'function') {
+ try { window.__hMgr_ACbar.setLinkMode(mode); return; } catch (e) { console.warn('调用 __hMgr_ACbar.setLinkMode 失败:', e); }
+ }
+ // 回退:存储待处理值供主模块稍后获取
+ __hNodeAlignPro_safeCall(null, null, 'linkMode', mode);
} catch (error) { console.error('设置拖拽方式失败:', error); }
}
},
@@ -50,7 +100,7 @@ const NodeAlignProSettings = [
defaultValue: "hUIScale_1x",
category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置", "UI缩放"],
tooltip: "调整插件UI缩放比例(与插件右键菜单设置同步)",
- onChange: (value) => { try { if (window.NodeAlignProSettingsManager) { window.NodeAlignProSettingsManager.setUIScale(value); } } catch (error) { console.error('设置UI缩放失败:', error); } }
+ onChange: (value) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setUIScale === 'function') { window.NodeAlignProSettingsManager.setUIScale(value); } else __hNodeAlignPro_safeCall(null, null, 'uiScale', value); } catch (error) { console.error('设置UI缩放失败:', error); } }
},
/* {
id: "hNodeAlignPro.UIScale_v2", name: "UI缩放v2", type: "combo",
@@ -74,63 +124,91 @@ const NodeAlignProSettings = [
},
}, */
{
- id: "hNodeAlignPro.WorkMode", name: "工作模式", type: "combo",
- options: [{ value: "hApBar2_Align", text: "-对 齐-" }],
+ id: "hNodeAlignPro.WorkMode", name: h_i18n('Setting_WorkMode','工作模式'), type: "combo",
+ options: [{ value: "hApBar2_Align", text: h_i18n('Option_Work_Align','-对 齐-') }],
defaultValue: "hApBar2_Align",
- category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置", "工作模式"],
- tooltip: "切换插件工作模式(与插件右键菜单设置同步)",
- onChange: (value) => { try { if (window.NodeAlignProSettingsManager) { window.NodeAlignProSettingsManager.setWorkMode(value); } } catch (error) { console.error('设置工作模式失败:', error); } }
+ category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置", h_i18n('Setting_WorkMode','工作模式')],
+ tooltip: h_i18n('Setting_WorkMode','切换插件工作模式(与插件右键菜单设置同步)'),
+ onChange: (value) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setWorkMode === 'function') { window.NodeAlignProSettingsManager.setWorkMode(value); } else __hNodeAlignPro_safeCall(null, null, 'workMode', value); } catch (error) { console.error('设置工作模式失败:', error); } }
},
{
- id: "hNodeAlignPro.DisplayMode", name: "显示模式", type: "combo",
- options: [{ value: "hDispMode0_Always", text: "常驻显示(默认)" }, { value: "hDispMode1_Follow", text: "跟随选框" }],
+ id: "hNodeAlignPro.DisplayMode", name: h_i18n('Setting_DisplayMode','显示模式'), type: "combo",
+ options: [{ value: "hDispMode0_Always", text: h_i18n('Option_Display_Always','常驻显示') }, { value: "hDispMode1_Follow", text: h_i18n('Option_Display_Follow','跟随选框') }],
defaultValue: "hDispMode0_Always",
- category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置", "显示模式"],
- tooltip: "切换插件面板的显示模式(与插件右键菜单设置同步)",
- onChange: (value) => { try { if (window.NodeAlignProSettingsManager) { window.NodeAlignProSettingsManager.setDisplayMode(value); } } catch (error) { console.error('设置显示模式失败:', error); } }
+ category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置", h_i18n('Setting_DisplayMode','显示模式')],
+ tooltip: h_i18n('Setting_DisplayMode','切换插件面板的显示模式(与插件右键菜单设置同步)'),
+ onChange: (value) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setDisplayMode === 'function') { window.NodeAlignProSettingsManager.setDisplayMode(value); } else __hNodeAlignPro_safeCall(null, null, 'displayMode', value); } catch (error) { console.error('设置显示模式失败:', error); } }
+ },
+
+ // 语言选择(优先级高于浏览器语言),切换即刻生效
+ {
+ id: "hNodeAlignPro.Language", name: h_i18n('Setting_Language','语言'), type: "combo",
+ options: [
+ { value: 'auto', text: h_i18n('Option_Lang_Auto','自动(Auto)') },
+ { value: 'cn', text: h_i18n('Option_Lang_CN','中文') },
+ { value: 'en', text: h_i18n('Option_Lang_EN','English') }
+ ],
+ defaultValue: 'cn',
+ category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置", h_i18n('Setting_Language','语言')],
+ tooltip: h_i18n('Setting_Language','选择插件界面语言(优先于浏览器语言设置)'),
+ onChange: (value) => {
+ try {
+ if (window.hLanguage && typeof window.hLanguage.setLang === 'function') {
+ // 'auto'表示不强制特定语言;遵循浏览器/ComfyUI设置
+ if (value === 'auto') window.hLanguage.setLang('auto'); else window.hLanguage.setLang(value);
+ // 立即应用到文档和现有插件容器
+ try { window.hLanguage.applyToDOM(document); } catch (e) { console.warn('应用语言到DOM失败:', e); }
+ // 如果存在插件容器,也应用到该容器
+ try { const c = document.getElementById('hNodeAlignKit'); if (c && window.hLanguage) window.hLanguage.applyToDOM(c); } catch (e) { /* 忽略 */ }
+ console.info('[NodeAlignPro 设置] 语言已切换为', window.hLanguage.getLang());
+ } else {
+ __hNodeAlignPro_safeCall(null, null, 'language', value);
+ }
+ } catch (error) { console.error('设置语言失败:', error); }
+ }
},
{
- id: "hNodeAlignPro.hColor_SVG", name: "对齐按钮颜色", type: "color",
+ id: "hNodeAlignPro.hColor_SVG", name: h_i18n('Setting_AlignBtnColor','对齐按钮颜色'), type: "color",
defaultValue: "6B6B70",
- category: ["🔥 NodeAlignPro", "NodeAlignPro预置颜色", "对齐按钮颜色"],
- tooltip: "控制对齐按钮颜色",
- onChange: (newVal) => { try { if (window.NodeAlignProSettingsManager) { window.NodeAlignProSettingsManager.setAlignButtonColor(newVal); } } catch (error) { console.error('设置对齐按钮颜色失败:', error); } }
+ category: ["🔥 NodeAlignPro", "NodeAlignPro预置颜色", h_i18n('Setting_AlignBtnColor','对齐按钮颜色')],
+ tooltip: h_i18n('Setting_AlignBtnColor','控制对齐按钮颜色'),
+ onChange: (newVal) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setAlignButtonColor === 'function') { window.NodeAlignProSettingsManager.setAlignButtonColor(newVal); } else __hNodeAlignPro_safeCall(null, null, 'alignButtonColor', newVal); } catch (error) { console.error('设置对齐按钮颜色失败:', error); } }
},
{
- id: "hNodeAlignPro.hColor_bg", name: "工具栏背景色", type: "color",
+ id: "hNodeAlignPro.hColor_bg", name: h_i18n('Setting_ToolbarBgColor','工具栏背景色'), type: "color",
defaultValue: "18181B",
- category: ["🔥 NodeAlignPro", "NodeAlignPro预置颜色", "工具栏背景色"],
- tooltip: "控制对齐组件的背景色",
- onChange: (newVal) => { try { if (window.NodeAlignProSettingsManager) { window.NodeAlignProSettingsManager.setToolbarBgColor(newVal); } } catch (error) { console.error('设置工具栏背景色失败:', error); } }
+ category: ["🔥 NodeAlignPro", "NodeAlignPro预置颜色", h_i18n('Setting_ToolbarBgColor','工具栏背景色')],
+ tooltip: h_i18n('Setting_ToolbarBgColor','控制对齐组件的背景色'),
+ onChange: (newVal) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setToolbarBgColor === 'function') { window.NodeAlignProSettingsManager.setToolbarBgColor(newVal); } else __hNodeAlignPro_safeCall(null, null, 'toolbarBgColor', newVal); } catch (error) { console.error('设置工具栏背景色失败:', error); } }
},
{
- id: "hNodeAlignPro.hOpacity", name: "工具栏透明度", type: "slider",
+ id: "hNodeAlignPro.hOpacity", name: h_i18n('Setting_ToolbarOpacity','工具栏透明度'), type: "slider",
defaultValue: 95,
attrs: { min: 0, max: 100, step: 1 },
- category: ["🔥 NodeAlignPro", "NodeAlignPro预置颜色", "工具栏透明度"],
- tooltip: "控制对齐组件的背景透明度",
- onChange: (newVal) => { try { if (window.NodeAlignProSettingsManager) { window.NodeAlignProSettingsManager.setToolbarOpacity(newVal); } } catch (error) { console.error('设置工具栏透明度失败:', error); } }
+ category: ["🔥 NodeAlignPro", "NodeAlignPro预置颜色", h_i18n('Setting_ToolbarOpacity','工具栏透明度')],
+ tooltip: h_i18n('Setting_ToolbarOpacity','控制对齐组件的背景透明度'),
+ onChange: (newVal) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setToolbarOpacity === 'function') { window.NodeAlignProSettingsManager.setToolbarOpacity(newVal); } else __hNodeAlignPro_safeCall(null, null, 'toolbarOpacity', newVal); } catch (error) { console.error('设置工具栏透明度失败:', error); } }
},
{
- id: "hNodeAlignPro.NewVersionTips", name: "新版说明", type: "boolean",
+ id: "hNodeAlignPro.NewVersionTips", name: h_i18n('Setting_NewVersionTips','新版说明'), type: "boolean",
defaultValue: true,
- category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置", "新版说明"],
- tooltip: "v2.0.3_rc新版功能:按Shift、Alt、Ctrl Alt切换不同色卡模式... Alt+对齐按钮:对齐到“反向基准”节点^_^",
- onChange: (value) => { try { if (window.NodeAlignProSettingsManager) { window.NodeAlignProSettingsManager.setNewVersionTips(value); } } catch (error) { console.error('设置新版说明失败:', error); } }
+ category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置", h_i18n('Setting_NewVersionTips','新版说明')],
+ tooltip: h_i18n('Setting_NewVersionTips','v2.0.3_rc新版功能:按Shift、Alt、Ctrl Alt切换不同色卡模式... Alt+对齐按钮:对齐到“反向基准”节点^_^'),
+ onChange: (value) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setNewVersionTips === 'function') { window.NodeAlignProSettingsManager.setNewVersionTips(value); } else __hNodeAlignPro_safeCall(null, null, 'newVersionTips', value); } catch (error) { console.error('设置新版说明失败:', error); } }
},
{
- id: "hNodeAlignPro.ColorApplyMode", name: "上色模式", type: "combo",
- options: [ { value: "1", text: "整体色" }, { value: "0", text: "仅标题" } ],
+ id: "hNodeAlignPro.ColorApplyMode", name: h_i18n('Setting_ColorApplyMode','上色模式'), type: "combo",
+ options: [ { value: "1", text: h_i18n('Option_Color_Whole','整体色') }, { value: "0", text: h_i18n('Option_Color_TitleOnly','仅标题') } ],
defaultValue: "1",
- category: ["🔥 NodeAlignPro", "NodeAlignPro节点设置", "上色模式"],
- tooltip: "设置节点上色模式:整体色(背景+标题)或仅标题色",
- onChange: (value) => { try { if (window.NodeAlignProSettingsManager) window.NodeAlignProSettingsManager.setColorApplyMode(parseInt(value)); } catch (error) { console.error('设置上色模式失败:', error); } }
+ category: ["🔥 NodeAlignPro", "NodeAlignPro节点设置", h_i18n('Setting_ColorApplyMode','上色模式')],
+ tooltip: h_i18n('Setting_ColorApplyMode','设置节点上色模式:整体色(背景+标题)或仅标题色'),
+ onChange: (value) => { try { const intVal = parseInt(value); if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setColorApplyMode === 'function') { window.NodeAlignProSettingsManager.setColorApplyMode(intVal); } else __hNodeAlignPro_safeCall(null, null, 'colorApplyMode', intVal); } catch (error) { console.error('设置上色模式失败:', error); } }
}
];
@@ -147,10 +225,12 @@ function initNodeAlignProSettings() {
app.registerExtension({
name: "NodeAlignPro.Settings", settings: NodeAlignProSettings,
setup() {
- if (app.ui?.settings?.addSetting) {
- NodeAlignProSettings.forEach(setting => { try { app.ui.settings.addSetting(setting); } catch (err) { console.warn(`[NodeAlignPro.Settings] 注册设置项${setting.id}失败:`, err); } }); initNodeAlignProSettings(); // 注册设置项初始化设置
- }
- console.info("[NodeAlignPro.Settings] registered", NodeAlignProSettings.map(s => s.id));
+ try {
+ // ComfyUI会自动注册通过`settings`字段传递的设置
+ // 避免在此处手动调用addSetting,以防止重复注册错误
+ initNodeAlignProSettings(); // 初始化设置管理器和相关回调
+ console.info("[NodeAlignPro 设置模块] 已注册( NodeAlignPro.Settings)", NodeAlignProSettings.map(s => s.id));
+ } catch (e) { console.error('[NodeAlignPro 设置模块] 初始化时发生异常( NodeAlignPro.Settings):', e); }
},
beforeConfigureGraph(graph) { setTimeout(initNodeAlignProSettings, 2000); } // 延迟初始化,确保DOM已准备好
});