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 all 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
33 changes: 33 additions & 0 deletions src/locales/fr/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
33 changes: 33 additions & 0 deletions src/locales/ja/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "ブール",
Expand Down
33 changes: 33 additions & 0 deletions src/locales/ko/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "논리값",
Expand Down
33 changes: 33 additions & 0 deletions src/locales/ru/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "БУЛЕВО",
Expand Down
34 changes: 34 additions & 0 deletions src/locales/zh/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "布尔",
Expand Down
Loading