fix: avoid compiling node tooltip metadata

This commit is contained in:
jaeone94
2026-05-27 06:01:20 +09:00
parent 5a7b1d6a90
commit a1013f244a
4 changed files with 114 additions and 8 deletions

View File

@@ -13,7 +13,7 @@
import { useEventListener } from '@vueuse/core'
import { nextTick, ref } from 'vue'
import { st } from '@/i18n'
import { stRaw } from '@/i18n'
import {
LiteGraph,
isOverNodeInput,
@@ -84,7 +84,7 @@ function onIdle() {
)
if (inputSlot !== -1) {
const inputName = node.inputs[inputSlot].name
const translatedTooltip = st(
const translatedTooltip = stRaw(
`nodeDefs.${normalizeI18nKey(node.type ?? '')}.inputs.${normalizeI18nKey(inputName)}.tooltip`,
nodeDef?.inputs[inputName]?.tooltip ?? ''
)
@@ -98,7 +98,7 @@ function onIdle() {
[0, 0]
)
if (outputSlot !== -1) {
const translatedTooltip = st(
const translatedTooltip = stRaw(
`nodeDefs.${normalizeI18nKey(node.type ?? '')}.outputs.${outputSlot}.tooltip`,
nodeDef?.outputs[outputSlot]?.tooltip ?? ''
)
@@ -108,7 +108,7 @@ function onIdle() {
const widget = comfyApp.canvas.getWidgetAtCursor()
// Dont show for DOM widgets, these use native browser tooltips as we dont get proper mouse events on these
if (widget && !isDOMWidget(widget)) {
const translatedTooltip = st(
const translatedTooltip = stRaw(
`nodeDefs.${normalizeI18nKey(node.type ?? '')}.inputs.${normalizeI18nKey(widget.name)}.tooltip`,
nodeDef?.inputs[widget.name]?.tooltip ?? ''
)

View File

@@ -155,6 +155,7 @@ export const i18n = createI18n({
/** Convenience shorthand: i18n.global */
export const { t, te, d } = i18n.global
const { tm } = i18n.global
/**
* Safe translation function that returns the fallback message if the key is not found.
@@ -166,3 +167,17 @@ export function st(key: string, fallbackMessage: string) {
// The normal defaultMsg overload fails in some cases for custom nodes
return te(key) ? t(key) : fallbackMessage
}
/**
* Safe raw translation function for strings that may contain i18n syntax.
*
* @param key - The key for the raw locale message.
* @param fallbackMessage - The fallback message to use if the key is not found
* or the locale message is not a string.
*/
export function stRaw(key: string, fallbackMessage: string) {
if (!te(key)) return fallbackMessage
const message = tm(key)
return typeof message === 'string' ? message : fallbackMessage
}

View File

@@ -0,0 +1,91 @@
import { createTestingPinia } from '@pinia/testing'
import { setActivePinia } from 'pinia'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { SafeWidgetData } from '@/composables/graph/useGraphNodeManager'
import { te } from '@/i18n'
import { useSettingStore } from '@/platform/settings/settingStore'
import type { Settings } from '@/schemas/apiSchema'
import type { ComfyNodeDef } from '@/schemas/nodeDefSchema'
import { useNodeDefStore } from '@/stores/nodeDefStore'
import { useNodeTooltips } from './useNodeTooltips'
const jsonTooltip =
'Positive point prompts as JSON [{"x": int, "y": int}, ...] (pixel coords)'
const positiveCoordsTooltipKey =
'nodeDefs.SAM3_Detect.inputs.positive_coords.tooltip'
const positiveCoordsWidget: SafeWidgetData = {
name: 'positive_coords',
type: 'STRING'
}
const sam3DetectNodeDef: ComfyNodeDef = {
name: 'SAM3_Detect',
display_name: 'SAM3 Detect',
category: 'detection/',
python_module: 'comfy_extras.nodes_sam3',
description: '',
input: {
required: {},
optional: {
positive_coords: [
'STRING',
{
tooltip: jsonTooltip,
forceInput: true
}
]
}
},
output: [],
output_node: false,
deprecated: false,
experimental: false
}
describe('useNodeTooltips', () => {
beforeEach(() => {
setActivePinia(createTestingPinia({ stubActions: false }))
vi.spyOn(useSettingStore(), 'get').mockImplementation(
<K extends keyof Settings>(key: K): Settings[K] => {
switch (key) {
case 'Comfy.EnableTooltips':
return true as Settings[K]
case 'LiteGraph.Node.TooltipDelay':
return 500 as Settings[K]
default:
return undefined as Settings[K]
}
}
)
useNodeDefStore().addNodeDef(sam3DetectNodeDef)
})
afterEach(() => {
vi.restoreAllMocks()
})
it('reads JSON examples in node metadata without i18n placeholder errors', () => {
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
const { getInputSlotTooltip } = useNodeTooltips('SAM3_Detect')
// Ensure this exercises the bundled i18n path, not only metadata fallback.
expect(te(positiveCoordsTooltipKey)).toBe(true)
expect(getInputSlotTooltip('positive_coords')).toBe(jsonTooltip)
expect(consoleError).not.toHaveBeenCalled()
})
it('reads input-based widget tooltips without i18n placeholder errors', () => {
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
const { getWidgetTooltip } = useNodeTooltips('SAM3_Detect')
expect(te(positiveCoordsTooltipKey)).toBe(true)
expect(getWidgetTooltip(positiveCoordsWidget)).toBe(jsonTooltip)
expect(consoleError).not.toHaveBeenCalled()
})
})

View File

@@ -6,7 +6,7 @@ import { computed, ref, unref } from 'vue'
import type { MaybeRef } from 'vue'
import type { SafeWidgetData } from '@/composables/graph/useGraphNodeManager'
import { st } from '@/i18n'
import { st, stRaw } from '@/i18n'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useNodeDefStore } from '@/stores/nodeDefStore'
import { normalizeI18nKey } from '@/utils/formatUtil'
@@ -119,7 +119,7 @@ export function useNodeTooltips(nodeType: MaybeRef<string>) {
const key = `nodeDefs.${normalizeI18nKey(unref(nodeType))}.inputs.${normalizeI18nKey(slotName)}.tooltip`
const inputTooltip = nodeDef.value.inputs?.[slotName]?.tooltip ?? ''
return st(key, inputTooltip)
return stRaw(key, inputTooltip)
}
/**
@@ -130,7 +130,7 @@ export function useNodeTooltips(nodeType: MaybeRef<string>) {
const key = `nodeDefs.${normalizeI18nKey(unref(nodeType))}.outputs.${slotIndex}.tooltip`
const outputTooltip = nodeDef.value.outputs?.[slotIndex]?.tooltip ?? ''
return st(key, outputTooltip)
return stRaw(key, outputTooltip)
}
/**
@@ -146,7 +146,7 @@ export function useNodeTooltips(nodeType: MaybeRef<string>) {
// Then try input-based tooltip lookup
const key = `nodeDefs.${normalizeI18nKey(unref(nodeType))}.inputs.${normalizeI18nKey(widget.name)}.tooltip`
const inputTooltip = nodeDef.value.inputs?.[widget.name]?.tooltip ?? ''
return st(key, inputTooltip)
return stRaw(key, inputTooltip)
}
/**