mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 10:59:53 +00:00
Translate command label on top command dropdown menu (#1792)
* collect i18n with playwright * Add command label translation * Normalize i18n object key
This commit is contained in:
@@ -29,7 +29,8 @@
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"locale": "lobe-i18n locale"
|
||||
"locale": "lobe-i18n locale",
|
||||
"collect-i18n": "playwright test --config=playwright.i18n.config.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.7",
|
||||
|
||||
14
playwright.i18n.config.ts
Normal file
14
playwright.i18n.config.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { PlaywrightTestConfig } from '@playwright/test'
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
testDir: './scripts',
|
||||
use: {
|
||||
baseURL: 'http://localhost:5173',
|
||||
headless: true
|
||||
},
|
||||
reporter: 'list',
|
||||
timeout: 10000,
|
||||
testMatch: /collect-i18n\.ts/
|
||||
}
|
||||
|
||||
export default config
|
||||
50
scripts/collect-i18n.ts
Normal file
50
scripts/collect-i18n.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import * as fs from 'fs'
|
||||
import { comfyPageFixture as test } from '../browser_tests/fixtures/ComfyPage'
|
||||
import type { ComfyCommandImpl } from '../src/stores/commandStore'
|
||||
import { CORE_MENU_COMMANDS } from '../src/constants/coreMenuCommands'
|
||||
import { normalizeI18nKey } from '../src/utils/formatUtil'
|
||||
|
||||
const localePath = './src/locales/en.json'
|
||||
const extractMenuCommandLocaleStrings = (): Set<string> => {
|
||||
const labels = new Set<string>()
|
||||
for (const [category, _] of CORE_MENU_COMMANDS) {
|
||||
category.forEach((category) => labels.add(category))
|
||||
}
|
||||
return labels
|
||||
}
|
||||
|
||||
test('collect-i18n', async ({ comfyPage }) => {
|
||||
const commands = await comfyPage.page.evaluate(() => {
|
||||
const workspace = window['app'].extensionManager
|
||||
const commands = workspace.command.commands as ComfyCommandImpl[]
|
||||
return commands.map((command) => ({
|
||||
id: command.id,
|
||||
label: command.label,
|
||||
menubarLabel: command.menubarLabel
|
||||
}))
|
||||
})
|
||||
|
||||
const locale = JSON.parse(fs.readFileSync(localePath, 'utf-8'))
|
||||
const menuLabels = extractMenuCommandLocaleStrings()
|
||||
const commandMenuLabels = new Set(
|
||||
commands.map((command) => command.menubarLabel ?? command.label ?? '')
|
||||
)
|
||||
const allLabels = new Set([...menuLabels, ...commandMenuLabels])
|
||||
allLabels.delete('')
|
||||
|
||||
const allLabelsLocale = Object.fromEntries(
|
||||
Array.from(allLabels).map((label) => [normalizeI18nKey(label), label])
|
||||
)
|
||||
|
||||
fs.writeFileSync(
|
||||
localePath,
|
||||
JSON.stringify(
|
||||
{
|
||||
...locale,
|
||||
menuLabels: allLabelsLocale
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
)
|
||||
})
|
||||
@@ -1,6 +1,5 @@
|
||||
import fs from 'fs'
|
||||
import { CORE_SETTINGS } from '../src/constants/coreSettings'
|
||||
import { CORE_MENU_COMMANDS } from '../src/constants/coreMenuCommands'
|
||||
|
||||
interface SettingLocale {
|
||||
name: string
|
||||
@@ -20,17 +19,8 @@ const extractSettingLocaleStrings = (): Record<string, SettingLocale> => {
|
||||
)
|
||||
}
|
||||
|
||||
const extractMenuCommandLocaleStrings = (): Record<string, string> => {
|
||||
const labels = new Set<string>()
|
||||
for (const [category, _] of CORE_MENU_COMMANDS) {
|
||||
category.forEach((category) => labels.add(category))
|
||||
}
|
||||
return Object.fromEntries(Array.from(labels).map((label) => [label, label]))
|
||||
}
|
||||
|
||||
const main = () => {
|
||||
const settingLocaleStrings = extractSettingLocaleStrings()
|
||||
const menuCommandLocaleStrings = extractMenuCommandLocaleStrings()
|
||||
|
||||
const localePath = './src/locales/en.json'
|
||||
const globalLocale = JSON.parse(fs.readFileSync(localePath, 'utf-8'))
|
||||
@@ -42,10 +32,6 @@ const main = () => {
|
||||
settingsDialog: {
|
||||
...(globalLocale.settingsDialog ?? {}),
|
||||
...settingLocaleStrings
|
||||
},
|
||||
menuLabels: {
|
||||
...(globalLocale.menuLabels ?? {}),
|
||||
...menuCommandLocaleStrings
|
||||
}
|
||||
},
|
||||
null,
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
<script setup lang="ts">
|
||||
import { useMenuItemStore } from '@/stores/menuItemStore'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
import { normalizeI18nKey } from '@/utils/formatUtil'
|
||||
import Menubar from 'primevue/menubar'
|
||||
import type { MenuItem } from 'primevue/menuitem'
|
||||
import { computed } from 'vue'
|
||||
@@ -44,11 +45,9 @@ const dropdownDirection = computed(() =>
|
||||
const menuItemsStore = useMenuItemStore()
|
||||
const { t } = useI18n()
|
||||
const translateMenuItem = (item: MenuItem): MenuItem => {
|
||||
const translatedLabel = item.label
|
||||
? t(
|
||||
`menuLabels.${item.label}`,
|
||||
typeof item.label === 'function' ? item.label() : item.label
|
||||
)
|
||||
const label = typeof item.label === 'function' ? item.label() : item.label
|
||||
const translatedLabel = label
|
||||
? t(`menuLabels.${normalizeI18nKey(label)}`, label)
|
||||
: undefined
|
||||
|
||||
return {
|
||||
|
||||
@@ -490,6 +490,64 @@
|
||||
"menuLabels": {
|
||||
"Workflow": "Workflow",
|
||||
"Edit": "Edit",
|
||||
"Help": "Help"
|
||||
"Help": "Help",
|
||||
"New": "New",
|
||||
"Open": "Open",
|
||||
"Load Default Workflow": "Load Default Workflow",
|
||||
"Save": "Save",
|
||||
"Save As": "Save As",
|
||||
"Export": "Export",
|
||||
"Export (API)": "Export (API)",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo",
|
||||
"Clear Workflow": "Clear Workflow",
|
||||
"Reset View": "Reset View",
|
||||
"Clipspace": "Clipspace",
|
||||
"Refresh Node Definitions": "Refresh Node Definitions",
|
||||
"Interrupt": "Interrupt",
|
||||
"Clear Pending Tasks": "Clear Pending Tasks",
|
||||
"Browse Templates": "Browse Templates",
|
||||
"Zoom In": "Zoom In",
|
||||
"Zoom Out": "Zoom Out",
|
||||
"Fit view to selected nodes": "Fit view to selected nodes",
|
||||
"Toggle Lock": "Toggle Lock",
|
||||
"Toggle Link Visibility": "Toggle Link Visibility",
|
||||
"Queue Prompt": "Queue Prompt",
|
||||
"Queue Prompt (Front)": "Queue Prompt (Front)",
|
||||
"Settings": "Settings",
|
||||
"Group Selected Nodes": "Group Selected Nodes",
|
||||
"Next Opened Workflow": "Next Opened Workflow",
|
||||
"Previous Opened Workflow": "Previous Opened Workflow",
|
||||
"Mute/Unmute Selected Nodes": "Mute/Unmute Selected Nodes",
|
||||
"Bypass/Unbypass Selected Nodes": "Bypass/Unbypass Selected Nodes",
|
||||
"Pin/Unpin Selected Nodes": "Pin/Unpin Selected Nodes",
|
||||
"Pin/Unpin Selected Items": "Pin/Unpin Selected Items",
|
||||
"Collapse/Expand Selected Nodes": "Collapse/Expand Selected Nodes",
|
||||
"Toggle Theme": "Toggle Theme",
|
||||
"Toggle Bottom Panel": "Toggle Bottom Panel",
|
||||
"Toggle Focus Mode": "Toggle Focus Mode",
|
||||
"Fit Group To Contents": "Fit Group To Contents",
|
||||
"ComfyUI Issues": "ComfyUI Issues",
|
||||
"ComfyUI Docs": "ComfyUI Docs",
|
||||
"Comfy-Org Discord": "Comfy-Org Discord",
|
||||
"Queue": "Queue",
|
||||
"Node Library": "Node Library",
|
||||
"Model Library": "Model Library",
|
||||
"Workflows": "Workflows",
|
||||
"Logs": "Logs",
|
||||
"Terminal": "Terminal",
|
||||
"Convert selected nodes to group node": "Convert selected nodes to group node",
|
||||
"Ungroup selected group nodes": "Ungroup selected group nodes",
|
||||
"Manage group nodes": "Manage group nodes",
|
||||
"Open Logs Folder": "Open Logs Folder",
|
||||
"Open Models Folder": "Open Models Folder",
|
||||
"Open Outputs Folder": "Open Outputs Folder",
|
||||
"Open Inputs Folder": "Open Inputs Folder",
|
||||
"Open Custom Nodes Folder": "Open Custom Nodes Folder",
|
||||
"Open extra_model_paths_yaml": "Open extra_model_paths.yaml",
|
||||
"Open DevTools": "Open DevTools",
|
||||
"Feedback": "Feedback",
|
||||
"Reinstall": "Reinstall",
|
||||
"Restart": "Restart"
|
||||
}
|
||||
}
|
||||
@@ -121,9 +121,67 @@
|
||||
"toggleBottomPanel": "下部パネルを切り替え"
|
||||
},
|
||||
"menuLabels": {
|
||||
"Browse Templates": "テンプレートを参照",
|
||||
"Bypass/Unbypass Selected Nodes": "選択したノードのバイパス/バイパス解除",
|
||||
"Clear Pending Tasks": "保留中のタスクをクリア",
|
||||
"Clear Workflow": "ワークフローをクリア",
|
||||
"Clipspace": "クリップスペース",
|
||||
"Collapse/Expand Selected Nodes": "選択したノードの折りたたみ/展開",
|
||||
"Comfy-Org Discord": "Comfy-Org Discord",
|
||||
"ComfyUI Docs": "ComfyUIのドキュメント",
|
||||
"ComfyUI Issues": "ComfyUIの問題",
|
||||
"Convert selected nodes to group node": "選択したノードをグループノードに変換",
|
||||
"Edit": "編集",
|
||||
"Export": "エクスポート",
|
||||
"Export (API)": "エクスポート (API)",
|
||||
"Feedback": "フィードバック",
|
||||
"Fit Group To Contents": "グループを内容に合わせる",
|
||||
"Fit view to selected nodes": "選択したノードにビューを合わせる",
|
||||
"Group Selected Nodes": "選択したノードをグループ化",
|
||||
"Help": "ヘルプ",
|
||||
"Workflow": "ワークフロー"
|
||||
"Interrupt": "中断",
|
||||
"Load Default Workflow": "デフォルトワークフローを読み込む",
|
||||
"Logs": "ログ",
|
||||
"Manage group nodes": "グループノードを管理",
|
||||
"Model Library": "モデルライブラリ",
|
||||
"Mute/Unmute Selected Nodes": "選択したノードのミュート/ミュート解除",
|
||||
"New": "新規",
|
||||
"Next Opened Workflow": "次に開いたワークフロー",
|
||||
"Node Library": "ノードライブラリ",
|
||||
"Open": "開く",
|
||||
"Open Custom Nodes Folder": "カスタムノードフォルダを開く",
|
||||
"Open DevTools": "DevToolsを開く",
|
||||
"Open Inputs Folder": "入力フォルダを開く",
|
||||
"Open Logs Folder": "ログフォルダを開く",
|
||||
"Open Models Folder": "モデルフォルダを開く",
|
||||
"Open Outputs Folder": "出力フォルダを開く",
|
||||
"Open extra_model_paths_yaml": "extra_model_paths.yamlを開く",
|
||||
"Pin/Unpin Selected Items": "選択したアイテムのピン留め/ピン留め解除",
|
||||
"Pin/Unpin Selected Nodes": "選択したノードのピン留め/ピン留め解除",
|
||||
"Previous Opened Workflow": "前に開いたワークフロー",
|
||||
"Queue": "キュー",
|
||||
"Queue Prompt": "キューのプロンプト",
|
||||
"Queue Prompt (Front)": "キューのプロンプト (前面)",
|
||||
"Redo": "やり直す",
|
||||
"Refresh Node Definitions": "ノード定義を更新",
|
||||
"Reinstall": "再インストール",
|
||||
"Reset View": "ビューをリセット",
|
||||
"Restart": "再起動",
|
||||
"Save": "保存",
|
||||
"Save As": "名前を付けて保存",
|
||||
"Settings": "設定",
|
||||
"Terminal": "ターミナル",
|
||||
"Toggle Bottom Panel": "下部パネルの切り替え",
|
||||
"Toggle Focus Mode": "フォーカスモードの切り替え",
|
||||
"Toggle Link Visibility": "リンクの表示/非表示を切り替え",
|
||||
"Toggle Lock": "ロックの切り替え",
|
||||
"Toggle Theme": "テーマの切り替え",
|
||||
"Undo": "元に戻す",
|
||||
"Ungroup selected group nodes": "選択したグループノードのグループ解除",
|
||||
"Workflow": "ワークフロー",
|
||||
"Workflows": "ワークフロー",
|
||||
"Zoom In": "ズームイン",
|
||||
"Zoom Out": "ズームアウト"
|
||||
},
|
||||
"newFolder": "新しいフォルダー",
|
||||
"noResultsFound": "結果が見つかりませんでした",
|
||||
|
||||
@@ -121,9 +121,67 @@
|
||||
"toggleBottomPanel": "Переключить нижнюю панель"
|
||||
},
|
||||
"menuLabels": {
|
||||
"Browse Templates": "Просмотреть шаблоны",
|
||||
"Bypass/Unbypass Selected Nodes": "Обойти/восстановить выбранные узлы",
|
||||
"Clear Pending Tasks": "Очистить ожидающие задачи",
|
||||
"Clear Workflow": "Очистить рабочий процесс",
|
||||
"Clipspace": "Клиппространство",
|
||||
"Collapse/Expand Selected Nodes": "Свернуть/развернуть выбранные узлы",
|
||||
"Comfy-Org Discord": "Discord Comfy-Org",
|
||||
"ComfyUI Docs": "Документация ComfyUI",
|
||||
"ComfyUI Issues": "Проблемы ComfyUI",
|
||||
"Convert selected nodes to group node": "Преобразовать выбранные узлы в групповой узел",
|
||||
"Edit": "Редактировать",
|
||||
"Export": "Экспортировать",
|
||||
"Export (API)": "Экспорт (API)",
|
||||
"Feedback": "Обратная связь",
|
||||
"Fit Group To Contents": "Подогнать группу под содержимое",
|
||||
"Fit view to selected nodes": "Подогнать вид под выбранные узлы",
|
||||
"Group Selected Nodes": "Сгруппировать выбранные узлы",
|
||||
"Help": "Помощь",
|
||||
"Workflow": "Рабочий процесс"
|
||||
"Interrupt": "Прервать",
|
||||
"Load Default Workflow": "Загрузить стандартный рабочий процесс",
|
||||
"Logs": "Журналы",
|
||||
"Manage group nodes": "Управление групповыми узлами",
|
||||
"Model Library": "Библиотека моделей",
|
||||
"Mute/Unmute Selected Nodes": "Отключить/включить звук для выбранных узлов",
|
||||
"New": "Новый",
|
||||
"Next Opened Workflow": "Следующий открытый рабочий процесс",
|
||||
"Node Library": "Библиотека узлов",
|
||||
"Open": "Открыть",
|
||||
"Open Custom Nodes Folder": "Открыть папку пользовательских узлов",
|
||||
"Open DevTools": "Открыть инструменты разработчика",
|
||||
"Open Inputs Folder": "Открыть папку входных данных",
|
||||
"Open Logs Folder": "Открыть папку журналов",
|
||||
"Open Models Folder": "Открыть папку моделей",
|
||||
"Open Outputs Folder": "Открыть папку выходных данных",
|
||||
"Open extra_model_paths.yaml": "Открыть extra_model_paths.yaml",
|
||||
"Pin/Unpin Selected Items": "Закрепить/открепить выбранные элементы",
|
||||
"Pin/Unpin Selected Nodes": "Закрепить/открепить выбранные узлы",
|
||||
"Previous Opened Workflow": "Предыдущий открытый рабочий процесс",
|
||||
"Queue": "Очередь",
|
||||
"Queue Prompt": "Запрос в очереди",
|
||||
"Queue Prompt (Front)": "Запрос в очереди (спереди)",
|
||||
"Redo": "Повторить",
|
||||
"Refresh Node Definitions": "Обновить определения узлов",
|
||||
"Reinstall": "Переустановить",
|
||||
"Reset View": "Сбросить вид",
|
||||
"Restart": "Перезапустить",
|
||||
"Save": "Сохранить",
|
||||
"Save As": "Сохранить как",
|
||||
"Settings": "Настройки",
|
||||
"Terminal": "Терминал",
|
||||
"Toggle Bottom Panel": "Переключить нижнюю панель",
|
||||
"Toggle Focus Mode": "Переключить режим фокуса",
|
||||
"Toggle Link Visibility": "Переключить видимость ссылок",
|
||||
"Toggle Lock": "Переключить блокировку",
|
||||
"Toggle Theme": "Переключить тему",
|
||||
"Undo": "Отменить",
|
||||
"Ungroup selected group nodes": "Разгруппировать выбранные групповые узлы",
|
||||
"Workflow": "Рабочий процесс",
|
||||
"Workflows": "Рабочие процессы",
|
||||
"Zoom In": "Увеличить",
|
||||
"Zoom Out": "Уменьшить"
|
||||
},
|
||||
"newFolder": "Новая папка",
|
||||
"noResultsFound": "Ничего не найдено",
|
||||
|
||||
@@ -121,9 +121,67 @@
|
||||
"toggleBottomPanel": "底部面板"
|
||||
},
|
||||
"menuLabels": {
|
||||
"Browse Templates": "浏览模板",
|
||||
"Bypass/Unbypass Selected Nodes": "旁路/取消旁路选定节点",
|
||||
"Clear Pending Tasks": "清除待处理任务",
|
||||
"Clear Workflow": "清除工作流",
|
||||
"Clipspace": "剪辑空间",
|
||||
"Collapse/Expand Selected Nodes": "折叠/展开选定节点",
|
||||
"Comfy-Org Discord": "Comfy-Org Discord",
|
||||
"ComfyUI Docs": "ComfyUI 文档",
|
||||
"ComfyUI Issues": "ComfyUI 问题",
|
||||
"Convert selected nodes to group node": "将选定节点转换为组节点",
|
||||
"Edit": "编辑",
|
||||
"Export": "导出",
|
||||
"Export (API)": "导出 (API)",
|
||||
"Feedback": "反馈",
|
||||
"Fit Group To Contents": "适应组内容",
|
||||
"Fit view to selected nodes": "适应视图到选定节点",
|
||||
"Group Selected Nodes": "分组选定节点",
|
||||
"Help": "帮助",
|
||||
"Workflow": "工作流"
|
||||
"Interrupt": "中断",
|
||||
"Load Default Workflow": "加载默认工作流",
|
||||
"Logs": "日志",
|
||||
"Manage group nodes": "管理组节点",
|
||||
"Model Library": "模型库",
|
||||
"Mute/Unmute Selected Nodes": "静音/取消静音选定节点",
|
||||
"New": "新建",
|
||||
"Next Opened Workflow": "下一个打开的工作流",
|
||||
"Node Library": "节点库",
|
||||
"Open": "打开",
|
||||
"Open Custom Nodes Folder": "打开自定义节点文件夹",
|
||||
"Open DevTools": "打开开发者工具",
|
||||
"Open Inputs Folder": "打开输入文件夹",
|
||||
"Open Logs Folder": "打开日志文件夹",
|
||||
"Open Models Folder": "打开模型文件夹",
|
||||
"Open Outputs Folder": "打开输出文件夹",
|
||||
"Open extra_model_paths_yaml": "打开 extra_model_paths.yaml",
|
||||
"Pin/Unpin Selected Items": "固定/取消固定选定项目",
|
||||
"Pin/Unpin Selected Nodes": "固定/取消固定选定节点",
|
||||
"Previous Opened Workflow": "上一个打开的工作流",
|
||||
"Queue": "队列",
|
||||
"Queue Prompt": "队列提示",
|
||||
"Queue Prompt (Front)": "队列提示 (前面)",
|
||||
"Redo": "重做",
|
||||
"Refresh Node Definitions": "刷新节点定义",
|
||||
"Reinstall": "重新安装",
|
||||
"Reset View": "重置视图",
|
||||
"Restart": "重启",
|
||||
"Save": "保存",
|
||||
"Save As": "另存为",
|
||||
"Settings": "设置",
|
||||
"Terminal": "终端",
|
||||
"Toggle Bottom Panel": "切换底部面板",
|
||||
"Toggle Focus Mode": "切换专注模式",
|
||||
"Toggle Link Visibility": "切换链接可见性",
|
||||
"Toggle Lock": "切换锁定",
|
||||
"Toggle Theme": "切换主题",
|
||||
"Undo": "撤销",
|
||||
"Ungroup selected group nodes": "取消选定组节点的分组",
|
||||
"Workflow": "工作流",
|
||||
"Workflows": "工作流",
|
||||
"Zoom In": "放大",
|
||||
"Zoom Out": "缩小"
|
||||
},
|
||||
"newFolder": "新建文件夹",
|
||||
"noResultsFound": "未找到结果",
|
||||
|
||||
@@ -20,6 +20,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
|
||||
const toast = computed<ToastManager>(() => useToastStore())
|
||||
const queueSettings = computed(() => useQueueSettingsStore())
|
||||
const command = computed(() => ({
|
||||
commands: useCommandStore().commands,
|
||||
execute: useCommandStore().execute
|
||||
}))
|
||||
const sidebarTab = computed(() => useSidebarTabStore())
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { ComfyCommand } from '@/stores/commandStore'
|
||||
import { Component } from 'vue'
|
||||
|
||||
export interface BaseSidebarTabExtension {
|
||||
@@ -108,5 +109,6 @@ export interface ExtensionManager {
|
||||
}
|
||||
|
||||
export interface CommandManager {
|
||||
commands: ComfyCommand[]
|
||||
execute(command: string, errorHandler?: (error: any) => void): void
|
||||
}
|
||||
|
||||
@@ -127,3 +127,11 @@ export function getPathDetails(path: string) {
|
||||
const fullFilename = path.split('/').pop() ?? path
|
||||
return { directory, fullFilename, ...getFilenameDetails(fullFilename) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a string to be used as an i18n key.
|
||||
* Replaces dots with underscores.
|
||||
*/
|
||||
export function normalizeI18nKey(key: string) {
|
||||
return key.replace(/\./g, '_')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user