[i18n] Add gihtub action to translate custom nodes (#1987)

This commit is contained in:
Chenlei Hu
2024-12-18 17:04:35 -08:00
committed by GitHub
parent b1d02c6a7b
commit 569a131624
3 changed files with 254 additions and 1 deletions

127
.github/workflows/i18n-custom-nodes.yaml vendored Normal file
View 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 }}

2
.gitignore vendored
View File

@@ -40,3 +40,5 @@ browser_tests/*/*-win32.png
.env
dist.zip
/temp/

124
scripts/diff-i18n.ts Normal file
View 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')
}