mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
[i18n] Add gihtub action to translate custom nodes (#1987)
This commit is contained in:
127
.github/workflows/i18n-custom-nodes.yaml
vendored
Normal file
127
.github/workflows/i18n-custom-nodes.yaml
vendored
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
name: Update Locales for given custom node repository
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
owner:
|
||||||
|
description: 'Owner of the repository to update locales for'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
repository:
|
||||||
|
description: 'Repository to update locales for'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
fork_owner:
|
||||||
|
description: 'Owner of the forked repository'
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: 'Comfy-Org'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-locales:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout ComfyUI
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: 'comfyanonymous/ComfyUI'
|
||||||
|
path: 'ComfyUI'
|
||||||
|
ref: master
|
||||||
|
- name: Checkout ComfyUI_frontend
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: 'Comfy-Org/ComfyUI_frontend'
|
||||||
|
path: 'ComfyUI_frontend'
|
||||||
|
- name: Checkout ComfyUI_devtools
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: 'Comfy-Org/ComfyUI_devtools'
|
||||||
|
path: 'ComfyUI/custom_nodes/ComfyUI_devtools'
|
||||||
|
- name: Checkout custom node repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: ${{ inputs.owner }}/${{ inputs.repository }}
|
||||||
|
path: 'ComfyUI/custom_nodes/${{ inputs.repository }}'
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: lts/*
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.10'
|
||||||
|
- name: Install ComfyUI requirements
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
|
||||||
|
pip install -r requirements.txt
|
||||||
|
pip install wait-for-it
|
||||||
|
shell: bash
|
||||||
|
working-directory: ComfyUI
|
||||||
|
- name: Install custom node requirements
|
||||||
|
run: |
|
||||||
|
if [ -f "requirements.txt" ]; then
|
||||||
|
pip install -r requirements.txt
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
working-directory: ComfyUI/custom_nodes/${{ inputs.repository }}
|
||||||
|
- name: Build & Install ComfyUI_frontend
|
||||||
|
run: |
|
||||||
|
npm ci
|
||||||
|
npm run build
|
||||||
|
rm -rf ../ComfyUI/web/*
|
||||||
|
mv dist/* ../ComfyUI/web/
|
||||||
|
shell: bash
|
||||||
|
working-directory: ComfyUI_frontend
|
||||||
|
- name: Start ComfyUI server
|
||||||
|
run: |
|
||||||
|
python main.py --cpu --multi-user &
|
||||||
|
wait-for-it --service 127.0.0.1:8188 -t 600
|
||||||
|
working-directory: ComfyUI
|
||||||
|
shell: bash
|
||||||
|
- name: Install Playwright Browsers
|
||||||
|
run: npx playwright install chromium --with-deps
|
||||||
|
working-directory: ComfyUI_frontend
|
||||||
|
- name: Start dev server
|
||||||
|
# Run electron dev server as it is a superset of the web dev server
|
||||||
|
# We do want electron specific UIs to be translated.
|
||||||
|
run: npm run dev:electron &
|
||||||
|
working-directory: ComfyUI_frontend
|
||||||
|
- name: Capture base i18n
|
||||||
|
run: npx tsx scripts/diff-i18n capture
|
||||||
|
working-directory: ComfyUI_frontend
|
||||||
|
- name: Update en.json
|
||||||
|
run: npm run collect-i18n
|
||||||
|
env:
|
||||||
|
PLAYWRIGHT_TEST_URL: http://localhost:5173
|
||||||
|
working-directory: ComfyUI_frontend
|
||||||
|
- name: Update translations
|
||||||
|
run: npm run locale
|
||||||
|
env:
|
||||||
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||||
|
working-directory: ComfyUI_frontend
|
||||||
|
- name: Diff base vs updated i18n
|
||||||
|
run: npx tsx scripts/diff-i18n diff
|
||||||
|
working-directory: ComfyUI_frontend
|
||||||
|
- name: Update i18n in custom node repository
|
||||||
|
run: |
|
||||||
|
LOCALE_DIR=ComfyUI/custom_nodes/${{ inputs.repository }}/locales/
|
||||||
|
install -d "$LOCALE_DIR"
|
||||||
|
cp -rf ComfyUI_frontend/temp/diff/* "$LOCALE_DIR"
|
||||||
|
- name: Check and create fork of custom node repository
|
||||||
|
run: |
|
||||||
|
gh repo fork ${{ inputs.owner }}/${{ inputs.repository }} --clone=false || {
|
||||||
|
echo "Fork failed - repository might already be forked"
|
||||||
|
# Exit 0 to prevent the workflow from failing
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
- name: Commit and push changes
|
||||||
|
run: |
|
||||||
|
git checkout -b update-locales
|
||||||
|
git add -A
|
||||||
|
git commit -m "Update locales"
|
||||||
|
git remote add org_fork git@github.com:${{ inputs.fork_owner }}/${{ inputs.repository }}.git
|
||||||
|
git push org_fork update-locales
|
||||||
|
gh pr create --title "Update locales for ${{ inputs.repository }}" --repo ${{ inputs.owner }}/${{ inputs.repository }} --head ${{ inputs.fork_owner }}:update-locales
|
||||||
|
working-directory: ComfyUI/custom_nodes/${{ inputs.repository }}
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -39,4 +39,6 @@ browser_tests/*/*-win32.png
|
|||||||
|
|
||||||
.env
|
.env
|
||||||
|
|
||||||
dist.zip
|
dist.zip
|
||||||
|
|
||||||
|
/temp/
|
||||||
124
scripts/diff-i18n.ts
Normal file
124
scripts/diff-i18n.ts
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import {
|
||||||
|
readFileSync,
|
||||||
|
writeFileSync,
|
||||||
|
readdirSync,
|
||||||
|
mkdirSync,
|
||||||
|
existsSync,
|
||||||
|
rmSync
|
||||||
|
} from 'fs'
|
||||||
|
import { join, dirname } from 'path'
|
||||||
|
|
||||||
|
// Ensure directories exist
|
||||||
|
function ensureDir(dir: string) {
|
||||||
|
if (!existsSync(dir)) {
|
||||||
|
mkdirSync(dir, { recursive: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read JSON file
|
||||||
|
function readJsonFile(path: string) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(readFileSync(path, 'utf-8'))
|
||||||
|
} catch {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all JSON files recursively
|
||||||
|
function getAllJsonFiles(dir: string): string[] {
|
||||||
|
const files: string[] = []
|
||||||
|
const items = readdirSync(dir, { withFileTypes: true })
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
const path = join(dir, item.name)
|
||||||
|
if (item.isDirectory()) {
|
||||||
|
files.push(...getAllJsonFiles(path))
|
||||||
|
} else if (item.name.endsWith('.json')) {
|
||||||
|
files.push(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find additions in new object compared to base
|
||||||
|
function findAdditions(base: any, updated: any): Record<string, any> {
|
||||||
|
const additions: Record<string, any> = {}
|
||||||
|
|
||||||
|
for (const key in updated) {
|
||||||
|
if (!(key in base)) {
|
||||||
|
additions[key] = updated[key]
|
||||||
|
} else if (
|
||||||
|
typeof updated[key] === 'object' &&
|
||||||
|
!Array.isArray(updated[key]) &&
|
||||||
|
typeof base[key] === 'object' &&
|
||||||
|
!Array.isArray(base[key])
|
||||||
|
) {
|
||||||
|
const nestedAdditions = findAdditions(base[key], updated[key])
|
||||||
|
if (Object.keys(nestedAdditions).length > 0) {
|
||||||
|
additions[key] = nestedAdditions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return additions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture command
|
||||||
|
function capture(srcLocaleDir: string, tempBaseDir: string) {
|
||||||
|
ensureDir(tempBaseDir)
|
||||||
|
const files = getAllJsonFiles(srcLocaleDir)
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const relativePath = file.replace(srcLocaleDir, '')
|
||||||
|
const targetPath = join(tempBaseDir, relativePath)
|
||||||
|
ensureDir(dirname(targetPath))
|
||||||
|
writeFileSync(targetPath, readFileSync(file))
|
||||||
|
}
|
||||||
|
console.log('Captured current locale files to temp/base/')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diff command
|
||||||
|
function diff(srcLocaleDir: string, tempBaseDir: string, tempDiffDir: string) {
|
||||||
|
ensureDir(tempDiffDir)
|
||||||
|
const files = getAllJsonFiles(srcLocaleDir)
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const relativePath = file.replace(srcLocaleDir, '')
|
||||||
|
const basePath = join(tempBaseDir, relativePath)
|
||||||
|
const diffPath = join(tempDiffDir, relativePath)
|
||||||
|
|
||||||
|
const baseContent = readJsonFile(basePath)
|
||||||
|
const updatedContent = readJsonFile(file)
|
||||||
|
|
||||||
|
const additions = findAdditions(baseContent, updatedContent)
|
||||||
|
if (Object.keys(additions).length > 0) {
|
||||||
|
ensureDir(dirname(diffPath))
|
||||||
|
writeFileSync(diffPath, JSON.stringify(additions, null, 2))
|
||||||
|
console.log(`Wrote diff to ${diffPath}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command handling
|
||||||
|
const command = process.argv[2]
|
||||||
|
const SRC_LOCALE_DIR = 'src/locales'
|
||||||
|
const TEMP_BASE_DIR = 'temp/base'
|
||||||
|
const TEMP_DIFF_DIR = 'temp/diff'
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case 'capture':
|
||||||
|
capture(SRC_LOCALE_DIR, TEMP_BASE_DIR)
|
||||||
|
break
|
||||||
|
case 'diff':
|
||||||
|
diff(SRC_LOCALE_DIR, TEMP_BASE_DIR, TEMP_DIFF_DIR)
|
||||||
|
break
|
||||||
|
case 'clean':
|
||||||
|
// Remove temp directory recursively
|
||||||
|
if (existsSync('temp')) {
|
||||||
|
rmSync('temp', { recursive: true, force: true })
|
||||||
|
console.log('Removed temp directory')
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.log('Please specify either "capture" or "diff" command')
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user