[i18n] Impl i18n context menu translation (#2425)

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: huchenlei <huchenlei@proton.me>
This commit is contained in:
KarryCharon
2025-02-06 01:07:40 +08:00
committed by GitHub
parent d0e99beaa7
commit 2c12df12ab
14 changed files with 306 additions and 0 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

View File

@@ -44,6 +44,7 @@ import SecondRowWorkflowTabs from '@/components/topbar/SecondRowWorkflowTabs.vue
import { CORE_SETTINGS } from '@/constants/coreSettings'
import { useCanvasDrop } from '@/hooks/canvasDropHooks'
import { useGlobalLitegraph } from '@/hooks/litegraphHooks'
import { useContextMenuTranslation } from '@/hooks/translationHooks'
import { useWorkflowPersistence } from '@/hooks/workflowPersistenceHooks'
import { i18n } from '@/i18n'
import { api } from '@/scripts/api'
@@ -261,6 +262,8 @@ useCanvasDrop(canvasRef)
onMounted(async () => {
useGlobalLitegraph()
useContextMenuTranslation()
comfyApp.vueAppReady = true
workspaceStore.spinner = true

View File

@@ -0,0 +1,104 @@
import type {
IContextMenuOptions,
IContextMenuValue,
INodeInputSlot,
IWidget
} from '@comfyorg/litegraph'
import { LGraphCanvas, LiteGraph } from '@comfyorg/litegraph'
import { st, te } from '@/i18n'
import { normalizeI18nKey } from '@/utils/formatUtil'
/**
* Add translation for litegraph context menu.
*/
export const useContextMenuTranslation = () => {
const f = LGraphCanvas.prototype.getCanvasMenuOptions
const getCanvasCenterMenuOptions = function (
this: LGraphCanvas,
...args: Parameters<typeof f>
) {
const res = f.apply(this, args) as ReturnType<typeof f>
for (const item of res) {
if (item?.content) {
item.content = st(`contextMenu.${item.content}`, item.content)
}
}
return res
}
LGraphCanvas.prototype.getCanvasMenuOptions = getCanvasCenterMenuOptions
function translateMenus(
values: (IContextMenuValue | string)[] | undefined,
options: IContextMenuOptions
) {
if (!values) return
const reInput = /Convert (.*) to input/
const reWidget = /Convert (.*) to widget/
const cvt = st('contextMenu.Convert ', 'Convert ')
const tinp = st('contextMenu. to input', ' to input')
const twgt = st('contextMenu. to widget', ' to widget')
for (const value of values) {
if (typeof value === 'string') continue
translateMenus(value?.submenu?.options, options)
if (!value?.content) {
continue
}
if (te(`contextMenu.${value.content}`)) {
value.content = st(`contextMenu.${value.content}`, value.content)
}
// for capture translation text of input and widget
const extraInfo: any = options.extra || options.parentMenu?.options?.extra
// widgets and inputs
const matchInput = value.content?.match(reInput)
if (matchInput) {
let match = matchInput[1]
extraInfo?.inputs?.find((i: INodeInputSlot) => {
if (i.name != match) return false
match = i.label ? i.label : i.name
})
extraInfo?.widgets?.find((i: IWidget) => {
if (i.name != match) return false
match = i.label ? i.label : i.name
})
value.content = cvt + match + tinp
continue
}
const matchWidget = value.content?.match(reWidget)
if (matchWidget) {
let match = matchWidget[1]
extraInfo?.inputs?.find((i: INodeInputSlot) => {
if (i.name != match) return false
match = i.label ? i.label : i.name
})
extraInfo?.widgets?.find((i: IWidget) => {
if (i.name != match) return false
match = i.label ? i.label : i.name
})
value.content = cvt + match + twgt
continue
}
}
}
const OriginalContextMenu = LiteGraph.ContextMenu
function ContextMenu(
values: (IContextMenuValue | string)[],
options: IContextMenuOptions
) {
if (options.title) {
options.title = st(
`nodeDefs.${normalizeI18nKey(options.title)}.display_name`,
options.title
)
}
translateMenus(values, options)
const ctx = new OriginalContextMenu(values, options)
return ctx
}
LiteGraph.ContextMenu = ContextMenu as unknown as typeof LiteGraph.ContextMenu
}

View File

@@ -101,6 +101,39 @@
"yellow": "Yellow",
"custom": "Custom"
},
"contextMenu": {
"Inputs": "Inputs",
"Outputs": "Outputs",
"Properties": "Properties",
"Properties Panel": "Properties Panel",
"Title": "Title",
"Mode": "Mode",
"Resize": "Resize",
"Collapse": "Collapse",
"Expand": "Expand",
"Pin": "Pin",
"Unpin": "Unpin",
"Clone": "Clone",
"Remove": "Remove",
"Colors": "Colors",
"Shapes": "Shapes",
"Bypass": "Bypass",
"Copy (Clipspace)": "Copy (Clipspace)",
"Convert Widget to Input": "Convert Widget to Input",
"Convert Input to Widget": "Convert Input to Widget",
"Add Node": "Add Node",
"Add Group": "Add Group",
"Convert to Group Node": "Convert to Group Node",
"Manage Group Nodes": "Manage Group Nodes",
"Add Group For Selected Nodes": "Add Group For Selected Nodes",
"Save Selected as Template": "Save Selected as Template",
"Node Templates": "Node Templates",
"Manage": "Manage",
"Convert ": "Convert ",
" to input": " to input",
" to widget": " to widget",
"Search": "Search"
},
"icon": {
"bookmark": "Bookmark",
"folder": "Folder",

View File

@@ -8,6 +8,39 @@
"red": "Rouge",
"yellow": "Jaune"
},
"contextMenu": {
" to input": " en entrée",
" to widget": " en widget",
"Add Group": "Ajouter un Groupe",
"Add Group For Selected Nodes": "Ajouter un Groupe pour les Nœuds Sélectionnés",
"Add Node": "Ajouter un Nœud",
"Bypass": "Contourner",
"Clone": "Cloner",
"Collapse": "Réduire",
"Colors": "Couleurs",
"Convert ": "Convertir ",
"Convert Input to Widget": "Convertir l'Entrée en Widget",
"Convert Widget to Input": "Convertir le Widget en Entrée",
"Convert to Group Node": "Convertir en Nœud de Groupe",
"Copy (Clipspace)": "Copier (Clipspace)",
"Expand": "Développer",
"Inputs": "Entrées",
"Manage": "Gérer",
"Manage Group Nodes": "Gérer les Nœuds de Groupe",
"Mode": "Mode",
"Node Templates": "Modèles de Nœuds",
"Outputs": "Sorties",
"Pin": "Épingler",
"Properties": "Propriétés",
"Properties Panel": "Panneau des Propriétés",
"Remove": "Supprimer",
"Resize": "Redimensionner",
"Save Selected as Template": "Enregistrer la Sélection comme Modèle",
"Search": "Recherche",
"Shapes": "Formes",
"Title": "Titre",
"Unpin": "Désépingler"
},
"dataTypes": {
"AUDIO": "AUDIO",
"BOOLEAN": "BOOLEAN",

View File

@@ -8,6 +8,39 @@
"red": "赤",
"yellow": "黄色"
},
"contextMenu": {
" to input": " 入力へ",
" to widget": " ウィジェットへ",
"Add Group": "グループを追加",
"Add Group For Selected Nodes": "選択したノードのグループを追加",
"Add Node": "ノードを追加",
"Bypass": "バイパス",
"Clone": "クローン",
"Collapse": "折りたたむ",
"Colors": "色",
"Convert ": "変換 ",
"Convert Input to Widget": "入力をウィジェットに変換",
"Convert Widget to Input": "ウィジェットを入力に変換",
"Convert to Group Node": "グループノードに変換",
"Copy (Clipspace)": "コピー (Clipspace)",
"Expand": "展開",
"Inputs": "入力",
"Manage": "管理",
"Manage Group Nodes": "グループノードを管理",
"Mode": "モード",
"Node Templates": "ノードテンプレート",
"Outputs": "出力",
"Pin": "ピン",
"Properties": "プロパティ",
"Properties Panel": "プロパティパネル",
"Remove": "削除",
"Resize": "リサイズ",
"Save Selected as Template": "選択したものをテンプレートとして保存",
"Search": "検索",
"Shapes": "形",
"Title": "タイトル",
"Unpin": "ピン解除"
},
"dataTypes": {
"AUDIO": "オーディオ",
"BOOLEAN": "ブール",

View File

@@ -8,6 +8,39 @@
"red": "빨간색",
"yellow": "노란색"
},
"contextMenu": {
" to input": " 입력으로",
" to widget": " 위젯으로",
"Add Group": "그룹 추가",
"Add Group For Selected Nodes": "선택된 노드에 대한 그룹 추가",
"Add Node": "노드 추가",
"Bypass": "우회",
"Clone": "복제",
"Collapse": "축소",
"Colors": "색상",
"Convert ": "변환 ",
"Convert Input to Widget": "입력을 위젯으로 변환",
"Convert Widget to Input": "위젯을 입력으로 변환",
"Convert to Group Node": "그룹 노드로 변환",
"Copy (Clipspace)": "복사 (Clipspace)",
"Expand": "확장",
"Inputs": "입력",
"Manage": "관리",
"Manage Group Nodes": "그룹 노드 관리",
"Mode": "모드",
"Node Templates": "노드 템플릿",
"Outputs": "출력",
"Pin": "고정",
"Properties": "속성",
"Properties Panel": "속성 패널",
"Remove": "제거",
"Resize": "크기 조정",
"Save Selected as Template": "선택 항목을 템플릿으로 저장",
"Search": "검색",
"Shapes": "형태",
"Title": "제목",
"Unpin": "고정 해제"
},
"dataTypes": {
"AUDIO": "오디오",
"BOOLEAN": "논리값",

View File

@@ -8,6 +8,39 @@
"red": "Красный",
"yellow": "Жёлтый"
},
"contextMenu": {
" to input": " во вход",
" to widget": " в виджет",
"Add Group": "Добавить группу",
"Add Group For Selected Nodes": "Добавить группу для выбранных узлов",
"Add Node": "Добавить узел",
"Bypass": "Обход",
"Clone": "Клонировать",
"Collapse": "Свернуть",
"Colors": "Цвета",
"Convert ": "Преобразовать ",
"Convert Input to Widget": "Преобразовать вход в виджет",
"Convert Widget to Input": "Преобразовать виджет во вход",
"Convert to Group Node": "Преобразовать в групповой узел",
"Copy (Clipspace)": "Копировать (Clipspace)",
"Expand": "Развернуть",
"Inputs": "Входы",
"Manage": "Управлять",
"Manage Group Nodes": "Управление групповыми узлами",
"Mode": "Режим",
"Node Templates": "Шаблоны узлов",
"Outputs": "Выходы",
"Pin": "Закрепить",
"Properties": "Свойства",
"Properties Panel": "Панель свойств",
"Remove": "Удалить",
"Resize": "Изменить размер",
"Save Selected as Template": "Сохранить выбранное как шаблон",
"Search": "Поиск",
"Shapes": "Формы",
"Title": "Заголовок",
"Unpin": "Открепить"
},
"dataTypes": {
"AUDIO": "АУДИО",
"BOOLEAN": "БУЛЕВО",

View File

@@ -8,6 +8,40 @@
"red": "红色",
"yellow": "黄色"
},
"contextMenu": {
"zoomOut": "缩小",
"Inputs": "输入",
"Outputs": "输出",
"Properties": "属性",
"Properties Panel": "属性面板",
"Title": "标题",
"Mode": "模式",
"Resize": "调整大小",
"Collapse": "折叠",
"Expand": "展开",
"Pin": "固定",
"Unpin": "取消固定",
"Clone": "克隆",
"Remove": "删除",
"Colors": "颜色",
"Shapes": "形状",
"Bypass": "绕过",
"Copy (Clipspace)": "复制 (Clipspace)",
"Convert Widget to Input": "将控件转换为输入",
"Convert Input to Widget": "将输入转换为控件",
"Add Node": "添加节点",
"Add Group": "添加组",
"Convert to Group Node": "转换为组节点",
"Manage Group Nodes": "管理组节点",
"Add Group For Selected Nodes": "为选定节点添加组",
"Save Selected as Template": "将选定节点另存为模板",
"Node Templates": "节点模板",
"Manage": "管理",
"Convert ": "转换 ",
" to input": " 为输入",
" to widget": " 为控件",
"Search": "搜索"
},
"dataTypes": {
"AUDIO": "音频",
"BOOLEAN": "布尔",