Spaces:
Paused
Paused
File size: 15,674 Bytes
6c84841 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
"""
这个文件提供了将UI翻译应用到Gradio组件的功能
"""
import gradio as gr
from typing import Dict, Any, List, Tuple, Optional, Union, Callable
import json
# 避免循环导入
_ui_translations = None
_preserve_terms = None
_special_translations = {}
def _load_translations():
"""延迟加载翻译数据以避免循环导入"""
global _ui_translations, _preserve_terms, _special_translations
if _ui_translations is None:
from translations import (
UI_TRANSLATIONS, PRESERVE_TERMS, CIVITAI_BASEMODEL_CN, INTERFACE_MODES_CN,
MODEL_TYPES_CN, GENRE_CN, SPEED_CN, TAG_TYPES_CN, TASK_TYPES_CN,
IP_ADAPTER_MODES_CN, RECOM_PROMPT_TYPES_CN, RATING_CN, ASPECT_RATIO_CN,
LENGTH_CN, IDENTITY_CN
)
_ui_translations = UI_TRANSLATIONS
_preserve_terms = PRESERVE_TERMS
_special_translations = {
"interface_modes": INTERFACE_MODES_CN,
"model_types": MODEL_TYPES_CN,
"genre": GENRE_CN,
"speed": SPEED_CN,
"tag_types": TAG_TYPES_CN,
"task_types": TASK_TYPES_CN,
"ip_adapter_modes": IP_ADAPTER_MODES_CN,
"recom_prompt_types": RECOM_PROMPT_TYPES_CN,
"rating": RATING_CN,
"aspect_ratio": ASPECT_RATIO_CN,
"length": LENGTH_CN,
"identity": IDENTITY_CN,
"civitai_basemodel": CIVITAI_BASEMODEL_CN,
}
def translate_text(text: str) -> str:
"""翻译文本,保留特定术语"""
if not text or not isinstance(text, str):
return text
# 确保翻译数据已加载
if _ui_translations is None:
_load_translations()
# 直接翻译
if text in _ui_translations:
return _ui_translations[text]
# 对于包含保留术语的文本,确保术语不被翻译
result = text
for term in _preserve_terms:
# 避免替换部分单词,确保是完整单词或由空格/标点分隔
if term in result and (
term == result or
result.startswith(f"{term} ") or
result.endswith(f" {term}") or
f" {term} " in result or
result.startswith(f"{term},") or
result.endswith(f", {term}") or
f", {term}," in result
):
# 保留这个术语
pass
return result
def translate_dropdown_choices(choices: List) -> List:
"""翻译下拉菜单选项"""
if not choices:
return choices
if isinstance(choices[0], tuple):
# 如果是元组列表 [(label, value), ...]
return [(translate_text(label), value) for label, value in choices]
else:
# 如果是简单列表 [value1, value2, ...]
return [translate_text(choice) for choice in choices]
def translate_dict_choices(choices: Dict) -> Dict:
"""翻译字典选项的键"""
if not choices:
return choices
return {translate_text(k): v for k, v in choices.items()}
def apply_translation_to_component(component: Any) -> Any:
"""将翻译应用到单个Gradio组件"""
if not component:
return component
# 确保翻译数据已加载
if _ui_translations is None:
_load_translations()
# 不同类型组件的翻译逻辑
if isinstance(component, (gr.Button, gr.UploadButton)):
if hasattr(component, 'value') and component.value:
component.value = translate_text(component.value)
elif isinstance(component, (gr.Textbox, gr.Number, gr.Slider, gr.Radio, gr.Checkbox,
gr.Dropdown, gr.Image, gr.Gallery, gr.CheckboxGroup)):
if hasattr(component, 'label') and component.label:
component.label = translate_text(component.label)
if hasattr(component, 'info') and component.info:
component.info = translate_text(component.info)
# 对于有choices属性的组件
if hasattr(component, 'choices') and component.choices:
# 处理不同类型的选项
if isinstance(component, gr.Radio):
# 特殊类型翻译
if set(component.choices) == set(["Simple", "Standard", "Fast", "LoRA"]):
component.choices = [_special_translations["interface_modes"].get(c, c) for c in component.choices]
elif set(component.choices) == set(["None", "Auto", "Animagine", "Pony"]):
component.choices = [_special_translations["model_types"].get(c, c) for c in component.choices]
elif set(component.choices) == set(["Anime", "Photo"]):
component.choices = [_special_translations["genre"].get(c, c) for c in component.choices]
elif set(component.choices) == set(["Fast", "Standard", "Heavy"]):
component.choices = [_special_translations["speed"].get(c, c) for c in component.choices]
elif set(component.choices) & set(["danbooru", "e621", "body", "dress", "all"]):
component.choices = [_special_translations["tag_types"].get(c, c) for c in component.choices]
elif set(component.choices) & set(["original", "style"]):
component.choices = [_special_translations["ip_adapter_modes"].get(c, c) for c in component.choices]
elif set(component.choices) & set(["None", "Auto", "Animagine", "Pony"]):
component.choices = [_special_translations["recom_prompt_types"].get(c, c) for c in component.choices]
else:
component.choices = [translate_text(c) for c in component.choices]
elif isinstance(component, gr.CheckboxGroup):
if any(c in _special_translations["civitai_basemodel"] for c in component.choices):
component.choices = [_special_translations["civitai_basemodel"].get(c, c) for c in component.choices]
else:
component.choices = [translate_text(c) for c in component.choices]
else:
component.choices = translate_dropdown_choices(component.choices)
# 对于有值的组件
if hasattr(component, 'placeholder') and component.placeholder:
component.placeholder = translate_text(component.placeholder)
elif isinstance(component, gr.Markdown):
if hasattr(component, 'value') and component.value:
component.value = translate_text(component.value)
return component
def apply_translation_to_ui(block: gr.Blocks) -> None:
"""递归地将翻译应用到整个UI"""
if not block:
return
# 如果是Blocks实例处理其子项
if isinstance(block, gr.Blocks):
for child in block.children:
apply_translation_to_ui(child)
# 如果是Row, Column, Group等容器
elif hasattr(block, 'children'):
for child in block.children:
apply_translation_to_ui(child)
# 如果是Accordion、Tab等特殊容器
elif isinstance(block, (gr.Accordion, gr.Tab, gr.TabItem)):
# 翻译标签
if hasattr(block, 'label') and block.label:
block.label = translate_text(block.label)
# 处理子项
if hasattr(block, 'children'):
for child in block.children:
apply_translation_to_ui(child)
# 如果是具体的组件
else:
apply_translation_to_component(block)
def translate_task_choices(task_choices: List[str]) -> List[str]:
"""翻译任务选项"""
return [TASK_TYPES_CN.get(task, task) for task in task_choices]
def create_translating_app(original_app: gr.Blocks) -> gr.Blocks:
"""创建应用翻译后的版本"""
# 复制原始app
app_copy = original_app
# 应用翻译
apply_translation_to_ui(app_copy)
return app_copy
def monkey_patch_gradio():
"""猴子补丁Gradio组件以自动翻译"""
# 确保翻译数据已加载
if _ui_translations is None:
_load_translations()
# 保存原始方法
original_textbox = gr.Textbox
original_button = gr.Button
original_checkbox = gr.Checkbox
original_radio = gr.Radio
original_slider = gr.Slider
original_dropdown = gr.Dropdown
original_markdown = gr.Markdown
original_tab = gr.Tab
original_accordion = gr.Accordion
# 替换方法
def patched_textbox(*args, **kwargs):
if 'label' in kwargs and kwargs['label']:
kwargs['label'] = translate_text(kwargs['label'])
if 'placeholder' in kwargs and kwargs['placeholder']:
kwargs['placeholder'] = translate_text(kwargs['placeholder'])
if 'info' in kwargs and kwargs['info']:
kwargs['info'] = translate_text(kwargs['info'])
return original_textbox(*args, **kwargs)
def patched_button(*args, **kwargs):
if 'value' in kwargs and kwargs['value']:
kwargs['value'] = translate_text(kwargs['value'])
return original_button(*args, **kwargs)
def patched_checkbox(*args, **kwargs):
if 'label' in kwargs and kwargs['label']:
kwargs['label'] = translate_text(kwargs['label'])
if 'info' in kwargs and kwargs['info']:
kwargs['info'] = translate_text(kwargs['info'])
return original_checkbox(*args, **kwargs)
def patched_radio(*args, **kwargs):
if 'label' in kwargs and kwargs['label']:
kwargs['label'] = translate_text(kwargs['label'])
if 'info' in kwargs and kwargs['info']:
kwargs['info'] = translate_text(kwargs['info'])
if 'choices' in kwargs and kwargs['choices']:
# 特殊类型翻译
if set(kwargs['choices']) == set(["Simple", "Standard", "Fast", "LoRA"]):
kwargs['choices'] = [_special_translations["interface_modes"].get(c, c) for c in kwargs['choices']]
elif set(kwargs['choices']) == set(["None", "Auto", "Animagine", "Pony"]):
kwargs['choices'] = [_special_translations["model_types"].get(c, c) for c in kwargs['choices']]
elif set(kwargs['choices']) == set(["Anime", "Photo"]):
kwargs['choices'] = [_special_translations["genre"].get(c, c) for c in kwargs['choices']]
elif set(kwargs['choices']) == set(["Fast", "Standard", "Heavy"]):
kwargs['choices'] = [_special_translations["speed"].get(c, c) for c in kwargs['choices']]
elif set(kwargs['choices']) & set(["danbooru", "e621", "body", "dress", "all"]):
kwargs['choices'] = [_special_translations["tag_types"].get(c, c) for c in kwargs['choices']]
elif set(kwargs['choices']) & set(["original", "style"]):
kwargs['choices'] = [_special_translations["ip_adapter_modes"].get(c, c) for c in kwargs['choices']]
elif set(kwargs['choices']) & set(["None", "Auto", "Animagine", "Pony"]):
kwargs['choices'] = [_special_translations["recom_prompt_types"].get(c, c) for c in kwargs['choices']]
else:
kwargs['choices'] = [translate_text(c) for c in kwargs['choices']]
return original_radio(*args, **kwargs)
def patched_slider(*args, **kwargs):
if 'label' in kwargs and kwargs['label']:
kwargs['label'] = translate_text(kwargs['label'])
if 'info' in kwargs and kwargs['info']:
kwargs['info'] = translate_text(kwargs['info'])
return original_slider(*args, **kwargs)
def patched_dropdown(*args, **kwargs):
if 'label' in kwargs and kwargs['label']:
kwargs['label'] = translate_text(kwargs['label'])
if 'info' in kwargs and kwargs['info']:
kwargs['info'] = translate_text(kwargs['info'])
if 'choices' in kwargs and kwargs['choices']:
# 识别并保留特殊的选择项
if isinstance(kwargs['choices'], list) and len(kwargs['choices']) > 0:
if isinstance(kwargs['choices'][0], tuple):
# 如果是元组列表 [(label, value), ...]
kwargs['choices'] = [(translate_text(label), value) for label, value in kwargs['choices']]
else:
# 如果是简单列表 [value1, value2, ...]
kwargs['choices'] = [translate_text(choice) for choice in kwargs['choices']]
return original_dropdown(*args, **kwargs)
def patched_markdown(*args, **kwargs):
if args and isinstance(args[0], str):
args = list(args)
args[0] = translate_text(args[0])
args = tuple(args)
if 'value' in kwargs and kwargs['value']:
kwargs['value'] = translate_text(kwargs['value'])
return original_markdown(*args, **kwargs)
def patched_tab(*args, **kwargs):
if 'label' in kwargs and kwargs['label']:
kwargs['label'] = translate_text(kwargs['label'])
return original_tab(*args, **kwargs)
def patched_accordion(*args, **kwargs):
if 'label' in kwargs and kwargs['label']:
kwargs['label'] = translate_text(kwargs['label'])
return original_accordion(*args, **kwargs)
# 应用补丁
gr.Textbox = patched_textbox
gr.Button = patched_button
gr.Checkbox = patched_checkbox
gr.Radio = patched_radio
gr.Slider = patched_slider
gr.Dropdown = patched_dropdown
gr.Markdown = patched_markdown
gr.Tab = patched_tab
gr.Accordion = patched_accordion
def translate_special_list(choice_list, list_type):
"""翻译特殊列表,如Civitai排序、时间段等"""
# 确保翻译数据已加载
if _ui_translations is None:
_load_translations()
# 处理已知的特殊列表
if list_type == "civitai_sort":
translations = {
"Highest Rated": "最高评分",
"Most Downloaded": "最多下载",
"Most Liked": "最多点赞",
"Most Discussed": "最多讨论",
"Most Collected": "最多收藏",
"Most Buzz": "最多热度",
"Newest": "最新"
}
return [translations.get(item, item) for item in choice_list]
elif list_type == "civitai_period":
translations = {
"AllTime": "所有时间",
"Year": "年",
"Month": "月",
"Week": "周",
"Day": "日"
}
return [translations.get(item, item) for item in choice_list]
elif list_type == "civitai_basemodel":
# 这些通常保持不变
return choice_list
# 默认直接翻译每一项
return [translate_text(item) for item in choice_list]
def get_translated_constants():
"""获取预先翻译好的常量"""
from modutils import CIVITAI_SORT, CIVITAI_PERIOD, CIVITAI_BASEMODEL
global _translated_civitai_sort, _translated_civitai_period
_translated_civitai_sort = translate_special_list(CIVITAI_SORT, "civitai_sort")
_translated_civitai_period = translate_special_list(CIVITAI_PERIOD, "civitai_period")
# CIVITAI_BASEMODEL通常不需要翻译 |