mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
Revert "[fix] Automatically fix malformed node def translations" (#4045)
This commit is contained in:
3
.github/workflows/i18n-node-defs.yaml
vendored
3
.github/workflows/i18n-node-defs.yaml
vendored
@@ -32,9 +32,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||||
working-directory: ComfyUI_frontend
|
working-directory: ComfyUI_frontend
|
||||||
- name: Fix malformed outputs in translations
|
|
||||||
run: node scripts/fix-translated-outputs.cjs
|
|
||||||
working-directory: ComfyUI_frontend
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@v7
|
uses: peter-evans/create-pull-request@v7
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
# Node Definition Translation Collection Script
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The `collect-i18n-node-defs.ts` script automatically extracts translatable content from ComfyUI node definitions to generate structured JSON files for internationalization (i18n).
|
|
||||||
|
|
||||||
## What It Does
|
|
||||||
|
|
||||||
- Uses Playwright to load ComfyUI frontend and fetch node definitions via the ComfyUI HTTP API
|
|
||||||
- Extracts data types, node categories, input/output names, and descriptions
|
|
||||||
- Discovers runtime widget labels by creating actual node instances
|
|
||||||
- Normalizes keys for i18n compatibility (replaces dots with underscores)
|
|
||||||
- Generates `src/locales/en/main.json` (data types & categories) and `src/locales/en/nodeDefs.json`
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
1. **Browser Setup**: Uses Playwright to load ComfyUI frontend and access the HTTP API
|
|
||||||
2. **Data Collection**: Fetches node definitions via API and filters out DevTools nodes
|
|
||||||
3. **Widget Discovery**: Creates LiteGraph node instances to find runtime-generated widgets
|
|
||||||
4. **Output Generation**: Writes structured translation files
|
|
||||||
|
|
||||||
## Key Features
|
|
||||||
|
|
||||||
- **Runtime Widget Detection**: Captures dynamically created widgets not in static definitions
|
|
||||||
- **Data Type Deduplication**: Skips output names that already exist as data types
|
|
||||||
- **Special Character Handling**: Normalizes keys with dots for i18n compatibility
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run collect:i18n:nodeDefs
|
|
||||||
```
|
|
||||||
|
|
||||||
## Output Structure
|
|
||||||
|
|
||||||
- **main.json**: Updates `dataTypes` and `nodeCategories` sections
|
|
||||||
- **nodeDefs.json**: Complete node translation structure with inputs, outputs, and metadata
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fix malformed outputs arrays in translated nodeDefs.json files
|
|
||||||
*
|
|
||||||
* The translation service sometimes converts object structures to arrays with null values:
|
|
||||||
*
|
|
||||||
* Expected: { "outputs": { "0": { "name": "image" }, "1": { "name": "mask" } } }
|
|
||||||
* Actual: { "outputs": [ null, null, { "name": "normal" }, { "name": "info" } ] }
|
|
||||||
*
|
|
||||||
* This script converts malformed arrays back to the correct object structure.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fix malformed outputs in a node definition object
|
|
||||||
* @param {Object} nodeDef - Node definition object
|
|
||||||
* @returns {Object} Fixed node definition
|
|
||||||
*/
|
|
||||||
function fixNodeDefOutputs(nodeDef) {
|
|
||||||
if (!nodeDef.outputs) {
|
|
||||||
return nodeDef;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If outputs is already an object, no fix needed
|
|
||||||
if (!Array.isArray(nodeDef.outputs)) {
|
|
||||||
return nodeDef;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert array to object, filtering out nulls
|
|
||||||
const outputsObject = {};
|
|
||||||
nodeDef.outputs.forEach((output, index) => {
|
|
||||||
if (output !== null && output !== undefined) {
|
|
||||||
outputsObject[index.toString()] = output;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
...nodeDef,
|
|
||||||
outputs: outputsObject
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fix malformed outputs in all node definitions in a locale file
|
|
||||||
* @param {Object} localeData - Parsed locale JSON data
|
|
||||||
* @returns {Object} Fixed locale data
|
|
||||||
*/
|
|
||||||
function fixLocaleOutputs(localeData) {
|
|
||||||
const fixed = {};
|
|
||||||
|
|
||||||
for (const [nodeKey, nodeDef] of Object.entries(localeData)) {
|
|
||||||
fixed[nodeKey] = fixNodeDefOutputs(nodeDef);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process a single nodeDefs.json file
|
|
||||||
* @param {string} filePath - Path to the file
|
|
||||||
*/
|
|
||||||
function processFile(filePath) {
|
|
||||||
try {
|
|
||||||
console.log(`Processing: ${filePath}`);
|
|
||||||
|
|
||||||
const content = fs.readFileSync(filePath, 'utf8');
|
|
||||||
const data = JSON.parse(content);
|
|
||||||
|
|
||||||
const fixed = fixLocaleOutputs(data);
|
|
||||||
const fixedContent = JSON.stringify(fixed, null, 2);
|
|
||||||
|
|
||||||
// Only write if content changed
|
|
||||||
if (content !== fixedContent) {
|
|
||||||
fs.writeFileSync(filePath, fixedContent);
|
|
||||||
console.log(` ✓ Fixed malformed outputs in ${filePath}`);
|
|
||||||
} else {
|
|
||||||
console.log(` - No changes needed in ${filePath}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error(` ✗ Error processing ${filePath}:`, error.message);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find all nodeDefs.json files except the English source
|
|
||||||
* @returns {string[]} Array of file paths
|
|
||||||
*/
|
|
||||||
function findTranslatedLocaleFiles() {
|
|
||||||
const localesDir = path.join(process.cwd(), 'src', 'locales');
|
|
||||||
|
|
||||||
if (!fs.existsSync(localesDir)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const files = [];
|
|
||||||
const locales = fs.readdirSync(localesDir, { withFileTypes: true })
|
|
||||||
.filter(dirent => dirent.isDirectory() && dirent.name !== 'en')
|
|
||||||
.map(dirent => dirent.name);
|
|
||||||
|
|
||||||
for (const locale of locales) {
|
|
||||||
const nodeDefsPath = path.join(localesDir, locale, 'nodeDefs.json');
|
|
||||||
if (fs.existsSync(nodeDefsPath)) {
|
|
||||||
files.push(nodeDefsPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main execution
|
|
||||||
*/
|
|
||||||
function main() {
|
|
||||||
try {
|
|
||||||
const files = findTranslatedLocaleFiles();
|
|
||||||
|
|
||||||
if (files.length === 0) {
|
|
||||||
console.log('No translated nodeDefs.json files found to process.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Found ${files.length} translated locale files to process:`);
|
|
||||||
files.forEach(file => console.log(` - ${path.relative(process.cwd(), file)}`));
|
|
||||||
console.log('');
|
|
||||||
|
|
||||||
files.forEach(processFile);
|
|
||||||
|
|
||||||
console.log('\n✓ All files processed successfully');
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error finding files:', error.message);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (require.main === module) {
|
|
||||||
main();
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user