Skip to content

Conversation

huchenlei
Copy link
Contributor

@huchenlei huchenlei commented Jan 21, 2025

This PR adds internationalization (i18n) support for custom nodes in ComfyUI by:

  1. Adding a new /i18n endpoint that serves translations from custom nodes' locales folders
  2. Supporting multiple translation files per custom node (main.json, nodeDefs.json, etc.)
  3. Implementing a recursive JSON merging utility to combine translations from multiple nodes
  4. Adding comprehensive test coverage for translation loading and JSON merging

The changes enable custom node developers to provide translations that are automatically loaded and served through the API.

Example custom node locales directory: https://github.com/huchenlei/ComfyUI-layerdiffuse/tree/main/locales

@DorotaLuna
Copy link

About the translator guide, I have a few thoughts to share.

The biggest problem is identifying untranslated entries. Since all language locale content is released simultaneously with frontend updates, it becomes difficult for translators to determine which entries need updating over time. For instance, when I update the zh locale, I have to manually compare the current locale with the last version I translated, entry by entry. (Or maybe there are Git commands that can easily highlight the changes between translator's versions; I don't use Git a lot, so I'm not sure.)

Secondly, there's the format issue. We need to clarify which kind of entries should be categorized under Main, Command, Settings, etc. While the exact placement isn't crucial since we support recursive JSON merge, NodeDefs definitely require a comprehensive format guide. This should include specific instructions on where to place input sockets, output sockets, widgets, tooltips, and node tips. I've reviewed some translations in the current locales, and they've left me a bit confused. Some output sockets aren't consistently placed in the "outputs" section, and some sockets didn't. And some sockets lack translations yet still display correctly.

And about the matter of third-party extensions.

Some extensions haven't been updated for months, or even years. To support translations for these extensions, I propose we consider creating an official pack or similar mechanism that provides extension translations through the frontend rather than relying solely on the extension authors.

@ltdrdata
Copy link
Collaborator

ltdrdata commented Jan 22, 2025

  1. Before executing git pull, check the hash of the current commit using git log or git status.

  2. If the locale file were updated during git pull, you can compare only the changed items by using a command like

git diff <previous hash> /path/to/xxx.json

@huchenlei
Copy link
Contributor Author

Some extensions haven't been updated for months, or even years. To support translations for these extensions, I propose we consider creating an official pack or similar mechanism that provides extension translations through the frontend rather than relying solely on the extension authors.

We made the decision to store locale in the custom node repo because we want the translation to be updated along side with the custom node code, so if you checkout different versions of custom node code, the locale should match that version of custom node code automatically. The centralized solution does not provide this feature.

We will be using the same mechanism of making a PR bot automatically create PR for custom node repo as we did before for Comfy Registry. It will depend on node author to get these PR merged. I think this is fine, even we lost some coverage on really unmaintained custom node packs.

@huchenlei
Copy link
Contributor Author

Secondly, there's the format issue. We need to clarify which kind of entries should be categorized under Main, Command, Settings, etc. While the exact placement isn't crucial since we support recursive JSON merge, NodeDefs definitely require a comprehensive format guide. This should include specific instructions on where to place input sockets, output sockets, widgets, tooltips, and node tips. I've reviewed some translations in the current locales, and they've left me a bit confused. Some output sockets aren't consistently placed in the "outputs" section, and some sockets didn't. And some sockets lack translations yet still display correctly.

You can reference https://github.com/Comfy-Org/ComfyUI_frontend/blob/main/scripts/collect-i18n-node-defs.ts for how node def are extracted.

Auto generated explanation for the structure:


// Example Node Definition Structure
{
  "normalized_node_name": {  // This is the key, normalized from the original node name
    "display_name": "Human Readable Name",  // Required: Display name shown in UI
    "description": "Detailed description of what this node does",  // Optional: Node description
    
    // Input section - defines all input sockets and their properties
    "inputs": {
      "normalized_input_name": {  // Key is normalized from the original input name
        "name": "Human Readable Input Name",  // Display name for the input socket
        "tooltip": "Detailed description of what this input expects"  // Optional tooltip
      }
    },
    
    // Output section - defines all output sockets and their properties
    "outputs": {
      "0": {  // Key is the output index as string
        "name": "Human Readable Output Name",  // Display name for the output socket
        "tooltip": "Detailed description of what this output produces"  // Optional tooltip
      }
    }
  }
}

Let's break down the organization rules:

  1. Common Data Types:
{
  "dataTypes": {
    "image": "IMAGE",
    "latent": "LATENT",
    "conditioning": "CONDITIONING",
    // ... other data types
  }
}
  1. Node Categories:
{
  "nodeCategories": {
    "sampling": "Sampling",
    "latent": "Latent",
    "conditioning": "Conditioning",
    // ... other categories
  }
}
  1. Complete Node Definition Example:
{
  "stable_diffusion_checkpoint": {
    "display_name": "Load Checkpoint",
    "description": "Loads a Stable Diffusion checkpoint model",
    "inputs": {
      "ckpt_name": {
        "name": "Checkpoint Name",
        "tooltip": "Name of the checkpoint file to load"
      }
    },
    "outputs": {
      "0": {
        "name": "MODEL",
        "tooltip": "The loaded model"
      },
      "1": {
        "name": "CLIP",
        "tooltip": "The CLIP text encoder"
      },
      "2": {
        "name": "VAE",
        "tooltip": "The VAE model"
      }
    }
  }
}

Key Points for Implementation:

  1. Input/Output Sockets:
  • All input sockets should be placed in the inputs object
  • All output sockets should be placed in the outputs object with numeric keys
  • If a socket name matches a common data type, omit the name in the node definition
  • Always include tooltips for better user understanding
  1. Translation Rules:
// Key normalization function
function normalizeI18nKey(key: string): string {
  return key
    .toLowerCase()
    .replace(/[^a-z0-9_]/g, '_')
    .replace(/_{2,}/g, '_')
    .replace(/^_|_$/g, '');
}
  1. Organization Structure:
{
  "main.json": {
    "dataTypes": {}, // Common data types
    "nodeCategories": {}, // Node categories
    // ... other main translations
  },
  "nodeDefs.json": {
    // Individual node definitions
  }
}

@comfyanonymous comfyanonymous merged commit a058f52 into master Jan 22, 2025
6 checks passed
@comfyanonymous comfyanonymous deleted the add_custom_node_i18n branch January 22, 2025 22:15
@xhoxye
Copy link

xhoxye commented Apr 19, 2025

Can comfyui provide a button to help custom nodes without locales files automatically extract and generate translation files,ease users to translate themselves?
comfyui 能不能提供一个按钮,通过点击,帮助没有locales文件的自定义节点生成等待翻译的文件,方便用户自行翻译,只需要修改该文件

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Frontend Issue relates to the frontend UI (litegraph). Important

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants