[i18n] Impl i18n context menu translation (#2425)
Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: huchenlei <huchenlei@proton.me>
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
@@ -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
|
||||
|
||||
104
src/hooks/translationHooks.ts
Normal 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
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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": "ブール",
|
||||
|
||||
@@ -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": "논리값",
|
||||
|
||||
@@ -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": "БУЛЕВО",
|
||||
|
||||
@@ -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": "布尔",
|
||||
|
||||