mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
196 lines
5.6 KiB
TypeScript
196 lines
5.6 KiB
TypeScript
import * as fs from 'fs'
|
|
|
|
import { comfyPageFixture as test } from '../browser_tests/fixtures/ComfyPage'
|
|
import type { ComfyApi } from '../src/scripts/api'
|
|
import { ComfyInputsSpec, ComfyNodeDefImpl } from '../src/stores/nodeDefStore'
|
|
import { normalizeI18nKey } from '../src/utils/formatUtil'
|
|
|
|
const localePath = './src/locales/en/main.json'
|
|
const nodeDefsPath = './src/locales/en/nodeDefs.json'
|
|
|
|
test('collect-i18n-node-defs', async ({ comfyPage }) => {
|
|
const nodeDefs: ComfyNodeDefImpl[] = Object.values(
|
|
await comfyPage.page.evaluate(async () => {
|
|
const api = window['app'].api as ComfyApi
|
|
return await api.getNodeDefs()
|
|
})
|
|
).map((def) => new ComfyNodeDefImpl(def))
|
|
|
|
console.log(`Collected ${nodeDefs.length} node definitions`)
|
|
|
|
const allDataTypesLocale = Object.fromEntries(
|
|
nodeDefs
|
|
.flatMap((nodeDef) => {
|
|
const inputDataTypes = Object.values(nodeDef.inputs.all).map(
|
|
(inputSpec) => inputSpec.type
|
|
)
|
|
const outputDataTypes = nodeDef.outputs.all.map((output) => output.type)
|
|
const allDataTypes = [...inputDataTypes, ...outputDataTypes].flatMap(
|
|
(type: string) => type.split(',')
|
|
)
|
|
return allDataTypes.map((dataType) => [
|
|
normalizeI18nKey(dataType),
|
|
dataType
|
|
])
|
|
})
|
|
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
)
|
|
|
|
async function extractWidgetLabels() {
|
|
const nodeLabels = {}
|
|
|
|
for (const nodeDef of nodeDefs) {
|
|
const labels = await comfyPage.page.evaluate(async (def) => {
|
|
try {
|
|
// Create and add node to graph
|
|
const node = window['LiteGraph'].createNode(
|
|
def.name,
|
|
def.display_name
|
|
)
|
|
window['app'].graph.add(node)
|
|
|
|
// Get node instance and check for widgets
|
|
const nodeInstance = window['app'].graph.getNodeById(node.id)
|
|
if (!nodeInstance?.widgets) return {}
|
|
|
|
const getAllInputNames = (inputs: ComfyInputsSpec) => {
|
|
return [
|
|
...Object.values(inputs?.optional ?? {}),
|
|
...Object.values(inputs?.required ?? {})
|
|
]
|
|
.filter((input) => input && input.name !== undefined)
|
|
.map((input) => input.name)
|
|
}
|
|
|
|
// Get input names for comparison
|
|
const nodeInputNames = getAllInputNames(def.inputs)
|
|
|
|
// Collect runtime-generated widget labels
|
|
const labels = {}
|
|
for (const widget of nodeInstance.widgets) {
|
|
if (!widget?.name) continue
|
|
const isRuntimeGenerated = !nodeInputNames.includes(widget.name)
|
|
if (isRuntimeGenerated) {
|
|
console.warn(widget.label)
|
|
const label = widget.label ?? widget.name
|
|
labels[widget.name] = label
|
|
}
|
|
}
|
|
|
|
return labels
|
|
} finally {
|
|
// Cleanup
|
|
window['app'].graph.clear()
|
|
}
|
|
}, nodeDef)
|
|
|
|
// Format and store labels if any were found
|
|
if (Object.keys(labels ?? {}).length > 0) {
|
|
nodeLabels[nodeDef.name] = Object.fromEntries(
|
|
Object.entries(labels)
|
|
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
.map(([key, value]) => [normalizeI18nKey(key), { name: value }])
|
|
)
|
|
}
|
|
}
|
|
|
|
return nodeLabels
|
|
}
|
|
|
|
const nodeDefLabels = await extractWidgetLabels()
|
|
|
|
function extractInputs(nodeDef: ComfyNodeDefImpl) {
|
|
const inputs = Object.fromEntries(
|
|
nodeDef.inputs.all.flatMap((input) => {
|
|
const name = input.name
|
|
const tooltip = input.tooltip
|
|
|
|
if (name === undefined && tooltip === undefined) {
|
|
return []
|
|
}
|
|
|
|
return [
|
|
[
|
|
normalizeI18nKey(input.name),
|
|
{
|
|
name,
|
|
tooltip
|
|
}
|
|
]
|
|
]
|
|
})
|
|
)
|
|
return Object.keys(inputs).length > 0 ? inputs : undefined
|
|
}
|
|
|
|
function extractOutputs(nodeDef: ComfyNodeDefImpl) {
|
|
const outputs = Object.fromEntries(
|
|
nodeDef.outputs.all.flatMap((output, i) => {
|
|
// Ignore data types if they are already translated in allDataTypesLocale.
|
|
const name = output.name in allDataTypesLocale ? undefined : output.name
|
|
const tooltip = output.tooltip
|
|
|
|
if (name === undefined && tooltip === undefined) {
|
|
return []
|
|
}
|
|
|
|
return [
|
|
[
|
|
i.toString(),
|
|
{
|
|
name,
|
|
tooltip
|
|
}
|
|
]
|
|
]
|
|
})
|
|
)
|
|
return Object.keys(outputs).length > 0 ? outputs : undefined
|
|
}
|
|
|
|
const allNodeDefsLocale = Object.fromEntries(
|
|
nodeDefs
|
|
.sort((a, b) => a.name.localeCompare(b.name))
|
|
.map((nodeDef) => {
|
|
const inputs = {
|
|
...extractInputs(nodeDef),
|
|
...(nodeDefLabels[nodeDef.name] ?? {})
|
|
}
|
|
|
|
return [
|
|
normalizeI18nKey(nodeDef.name),
|
|
{
|
|
display_name: nodeDef.display_name ?? nodeDef.name,
|
|
description: nodeDef.description || undefined,
|
|
inputs: Object.keys(inputs).length > 0 ? inputs : undefined,
|
|
outputs: extractOutputs(nodeDef)
|
|
}
|
|
]
|
|
})
|
|
)
|
|
|
|
const allNodeCategoriesLocale = Object.fromEntries(
|
|
nodeDefs.flatMap((nodeDef) =>
|
|
nodeDef.category
|
|
.split('/')
|
|
.map((category) => [normalizeI18nKey(category), category])
|
|
)
|
|
)
|
|
|
|
const locale = JSON.parse(fs.readFileSync(localePath, 'utf-8'))
|
|
fs.writeFileSync(
|
|
localePath,
|
|
JSON.stringify(
|
|
{
|
|
...locale,
|
|
dataTypes: allDataTypesLocale,
|
|
nodeCategories: allNodeCategoriesLocale
|
|
},
|
|
null,
|
|
2
|
|
)
|
|
)
|
|
|
|
fs.writeFileSync(nodeDefsPath, JSON.stringify(allNodeDefsLocale, null, 2))
|
|
})
|