Files
Dontdrunk 74df72e6de 1丶设置面板添加前端UI组件开关
2丶前端新增了一个可拖动的悬浮组件用于快速开关翻译插件(默认开启)
2026-01-24 17:31:23 +08:00

249 lines
7.9 KiB
Python

import os
import json
import platform
import shutil
import atexit
import server
import folder_paths
from aiohttp import web
from pathlib import Path
VERSION = "2.1.1"
ADDON_NAME = "ComfyUI-DD-Translation"
COMFY_PATH = Path(folder_paths.__file__).parent
CUR_PATH = Path(__file__).parent
# 读取配置文件
def load_config():
config_path = CUR_PATH.joinpath("config.json")
default_cfg = {"translation_enabled": True, "need_ui_component": True, "ui_position": None}
if config_path.exists():
try:
config_data = try_get_json(config_path)
if not isinstance(config_data, dict):
return default_cfg
return {
"translation_enabled": config_data.get("translation_enabled", True),
"need_ui_component": config_data.get("need_ui_component", True),
"ui_position": config_data.get("ui_position", None),
}
except Exception:
return default_cfg
return default_cfg
# 全局配置变量
TRANSLATION_ENABLED = load_config().get("translation_enabled", True)
def try_get_json(path: Path):
for coding in ["utf-8", "gbk"]:
try:
return json.loads(path.read_text(encoding=coding))
except Exception:
continue
return {}
def get_translation_by_type(locale, translation_type, fallback_file=None):
"""
通用的翻译获取函数,减少代码重复
Args:
locale: 语言代码
translation_type: 翻译类型 ('Nodes', 'Categories', 'Menus')
fallback_file: 可选的回退文件名
"""
translations = {}
# 从目录中读取所有JSON文件
type_path = CUR_PATH.joinpath(locale, translation_type)
if type_path.exists():
for json_file in type_path.glob("*.json"):
translations.update(try_get_json(json_file))
# 处理回退文件
if fallback_file:
fallback_path = CUR_PATH.joinpath(locale, fallback_file)
if not fallback_path.exists():
fallback_path = CUR_PATH.joinpath("en_US", fallback_file)
if fallback_path.exists():
translations.update(try_get_json(fallback_path))
return translations
def get_nodes_translation(locale):
"""获取节点翻译"""
return get_translation_by_type(locale, "Nodes")
def get_category_translation(locale):
"""获取分类翻译"""
return get_translation_by_type(locale, "Categories", "NodeCategory.json")
def get_menu_translation(locale):
"""获取菜单翻译"""
return get_translation_by_type(locale, "Menus", "Menu.json")
def compile_translation(locale):
nodes_translation = get_nodes_translation(locale)
node_category_translation = get_category_translation(locale)
menu_translation = get_menu_translation(locale)
return json.dumps({
"Nodes": nodes_translation,
"NodeCategory": node_category_translation,
"Menu": menu_translation
}, ensure_ascii=False)
def compress_json(data, method="gzip"):
if method == "gzip":
import gzip
return gzip.compress(data.encode("utf-8"))
return data
@server.PromptServer.instance.routes.post("/agl/get_translation")
async def get_translation(request: web.Request):
post = await request.post()
locale = post.get("locale", "en_US")
accept_encoding = request.headers.get("Accept-Encoding", "")
json_data = "{}"
headers = {}
# 实时检查配置文件中的翻译开关
current_cfg = load_config()
if not current_cfg.get("translation_enabled", True):
return web.Response(status=200, body=json_data, headers=headers)
try:
json_data = compile_translation(locale)
if "gzip" in accept_encoding:
json_data = compress_json(json_data, method="gzip")
headers["Content-Encoding"] = "gzip"
except Exception:
pass
return web.Response(status=200, body=json_data, headers=headers)
@server.PromptServer.instance.routes.get("/agl/get_config")
async def get_config(request: web.Request):
# 实时读取配置文件
config_data = load_config()
return web.Response(status=200, body=json.dumps(config_data), headers={"Content-Type": "application/json"})
@server.PromptServer.instance.routes.post("/agl/set_config")
async def set_config(request: web.Request):
try:
post = await request.post()
enabled = post.get("translation_enabled", None)
ui_needed = post.get("need_ui_component", None)
ui_pos = post.get("ui_position", None)
enabled_val = (str(enabled).lower() == "true") if enabled is not None else None
ui_needed_val = (str(ui_needed).lower() == "true") if ui_needed is not None else None
# ui_position might be a json string or x,y string, keep as string or None
# But if it comes as "null" or empty, treat as None
ui_pos_val = ui_pos if ui_pos and str(ui_pos).lower() != "null" else None
# 更新配置文件
config_path = CUR_PATH.joinpath("config.json")
current_cfg = load_config()
if enabled_val is None:
enabled_val = current_cfg.get("translation_enabled", True)
if ui_needed_val is None:
ui_needed_val = current_cfg.get("need_ui_component", True)
if ui_pos_val is None and "ui_position" in current_cfg:
ui_pos_val = current_cfg.get("ui_position", None)
config_data = {
"translation_enabled": enabled_val,
"need_ui_component": ui_needed_val,
"ui_position": ui_pos_val
}
with open(config_path, 'w', encoding='utf-8') as f:
json.dump(config_data, f, indent=2, ensure_ascii=False)
# 更新全局变量
global TRANSLATION_ENABLED
TRANSLATION_ENABLED = enabled_val
return web.Response(status=200, body=json.dumps({
"success": True,
"translation_enabled": enabled_val,
"need_ui_component": ui_needed_val,
"ui_position": ui_pos_val
}), headers={"Content-Type": "application/json"})
except Exception as e:
return web.Response(status=500, body=json.dumps({"success": False, "error": str(e)}),
headers={"Content-Type": "application/json"})
def rmtree(path: Path):
if not path.exists():
return
if Path(path.resolve()).as_posix() != path.as_posix():
path.unlink()
return
if path.is_file():
path.unlink()
elif path.is_dir():
if path.name == ".git":
if platform.system() == "darwin":
from subprocess import call
call(['rm', '-rf', path.as_posix()])
elif platform.system() == "Windows":
os.system(f'rd/s/q "{path.as_posix()}"')
return
for child in path.iterdir():
rmtree(child)
try:
path.rmdir()
except BaseException:
pass
def register():
import nodes
aigodlike_ext_path = COMFY_PATH.joinpath("web", "extensions", ADDON_NAME)
if hasattr(nodes, "EXTENSION_WEB_DIRS"):
rmtree(aigodlike_ext_path)
return
try:
if os.name == "nt":
try:
import _winapi
_winapi.CreateJunction(CUR_PATH.as_posix(), aigodlike_ext_path.as_posix())
except WindowsError:
shutil.copytree(CUR_PATH.as_posix(), aigodlike_ext_path.as_posix(), ignore=shutil.ignore_patterns(".git"))
else:
shutil.copytree(CUR_PATH.as_posix(), aigodlike_ext_path.as_posix(), ignore=shutil.ignore_patterns(".git"))
except Exception:
pass
def unregister():
aigodlike_ext_path = COMFY_PATH.joinpath("web", "extensions", ADDON_NAME)
try:
rmtree(aigodlike_ext_path)
except BaseException:
pass
register()
atexit.register(unregister)
NODE_CLASS_MAPPINGS = {}
WEB_DIRECTORY = "./js"
__all__ = ["NODE_CLASS_MAPPINGS", "WEB_DIRECTORY"]
__version__ = VERSION