Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[i18n] Impl i18n context menu translation #2425

Merged
merged 9 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/components/graph/GraphCanvas.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -261,6 +262,8 @@ useCanvasDrop(canvasRef)

onMounted(async () => {
useGlobalLitegraph()
useContextMenuTranslation()

comfyApp.vueAppReady = true

workspaceStore.spinner = true
Expand Down
104 changes: 104 additions & 0 deletions src/hooks/translationHooks.ts
Original file line number Diff line number Diff line change
@@ -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
}
33 changes: 33 additions & 0 deletions src/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
31 changes: 31 additions & 0 deletions src/locales/fr/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,37 @@
"workflow": "Flux de travail"
},
"graphCanvasMenu": {
" 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",
"fitView": "Adapter la vue",
"panMode": "Mode panoramique",
"resetView": "Réinitialiser la vue",
Expand Down
31 changes: 31 additions & 0 deletions src/locales/ja/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,37 @@
"workflow": "ワークフロー"
},
"graphCanvasMenu": {
" 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": "ピン解除",
"fitView": "ビューに合わせる",
"panMode": "パンモード",
"resetView": "ビューをリセット",
Expand Down
31 changes: 31 additions & 0 deletions src/locales/ko/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,37 @@
"workflow": "워크플로"
},
"graphCanvasMenu": {
" 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": "고정 해제",
"fitView": "보기 맞춤",
"panMode": "팬 모드",
"resetView": "보기 재설정",
Expand Down
31 changes: 31 additions & 0 deletions src/locales/ru/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,37 @@
"workflow": "Рабочий процесс"
},
"graphCanvasMenu": {
" 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": "Открепить",
"fitView": "Подгонять под выделенные",
"panMode": "Режим панорамирования",
"resetView": "Сбросить вид",
Expand Down
31 changes: 31 additions & 0 deletions src/locales/zh/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,37 @@
"workflow": "工作流"
},
"graphCanvasMenu": {
" 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": "取消固定",
"fitView": "适应视图",
"panMode": "平移模式",
"resetView": "重置视图",
Expand Down
3 changes: 2 additions & 1 deletion src/scripts/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import _ from 'lodash'
import type { ToastMessageOptions } from 'primevue/toast'
import { shallowReactive } from 'vue'

import { st } from '@/i18n'
import { st, te } from '@/i18n'
import { useDialogService } from '@/services/dialogService'
import { useExtensionService } from '@/services/extensionService'
import { useLitegraphService } from '@/services/litegraphService'
Expand All @@ -37,6 +37,7 @@ import {
} from '@/types/comfyWorkflow'
import { ExtensionManager } from '@/types/extensionTypes'
import { ColorAdjustOptions, adjustColor } from '@/utils/colorUtil'
import { normalizeI18nKey } from '@/utils/formatUtil'
import { deserialiseAndCreate } from '@/utils/vintageClipboard'

import { type ComfyApi, api } from './api'
Expand Down
Loading