From 2542a6bf93ecb27054f639517621142fcc1d8a62 Mon Sep 17 00:00:00 2001 From: xbol0 Date: Tue, 8 Aug 2023 07:50:57 +0000 Subject: [PATCH] init i18n extension --- .gitignore | 1 + web/extensions/core/colorPalette.js | 10 +- web/extensions/core/i18n.js | 46 + web/extensions/core/widgetInputs.js | 1 + web/i18n/en_US.js | 125 ++ web/i18n/zh_CN.js | 125 ++ web/index.html | 2 + web/lib/i18next.js | 2265 +++++++++++++++++++++ web/lib/i18nextBrowserLanguageDetector.js | 422 ++++ web/lib/litegraph.core.js | 8 +- web/scripts/app.js | 132 +- web/scripts/ui.js | 80 +- 12 files changed, 3109 insertions(+), 108 deletions(-) create mode 100644 web/extensions/core/i18n.js create mode 100644 web/i18n/en_US.js create mode 100644 web/i18n/zh_CN.js create mode 100644 web/lib/i18next.js create mode 100644 web/lib/i18nextBrowserLanguageDetector.js diff --git a/.gitignore b/.gitignore index 0177e1d7d..6b28b976f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ venv/ web/extensions/* !web/extensions/logging.js.example !web/extensions/core/ +!web/extensions/i18n/ diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index 3695b08e2..d414d4298 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -435,7 +435,7 @@ app.registerExtension({ $el("td", [ $el("label", { for: id.replaceAll(".", "-"), - textContent: "Color palette", + textContent: i18next.t("settings.Comfy.ColorPalette"), }), ]), $el("td", [ @@ -449,7 +449,7 @@ app.registerExtension({ }, [ $el("input", { type: "button", - value: "Export", + value: i18next.t("settings.Comfy.ColorPalette.export"), onclick: async () => { const colorPaletteId = app.ui.settings.getSettingValue(id, defaultColorPaletteId); const colorPalette = await completeColorPalette(getColorPalette(colorPaletteId)); @@ -471,14 +471,14 @@ app.registerExtension({ }), $el("input", { type: "button", - value: "Import", + value: i18next.t("settings.Comfy.ColorPalette.import"), onclick: () => { fileInput.click(); } }), $el("input", { type: "button", - value: "Template", + value: i18next.t("settings.Comfy.ColorPalette.template"), onclick: async () => { const colorPalette = await getColorPaletteTemplate(); const json = JSON.stringify(colorPalette, null, 2); // convert the data to a JSON string @@ -499,7 +499,7 @@ app.registerExtension({ }), $el("input", { type: "button", - value: "Delete", + value: i18next.t("settings.Comfy.ColorPalette.delete"), onclick: async () => { let colorPaletteId = app.ui.settings.getSettingValue(id, defaultColorPaletteId); diff --git a/web/extensions/core/i18n.js b/web/extensions/core/i18n.js new file mode 100644 index 000000000..883fed988 --- /dev/null +++ b/web/extensions/core/i18n.js @@ -0,0 +1,46 @@ +import { app } from "../../scripts/app.js"; + +app.registerExtension({ + name: "i18next", + addCustomNodeDefs(defs) { + for (const k in defs) { + defs[k].display_name = i18next.t(`node.title.${k}`) + + if ("input" in defs[k] && defs[k].input.required) { + for (const i in defs[k].input.required) { + if (defs[k].input.required[i].length > 1) { + defs[k].input.required[i][1].label = i18next.t(`node.input.${k}.${i}`) + } else { + defs[k].input.required[i].push({ label: i18next.t(`node.input.${k}.${i}`) }) + } + } + } + } + }, + nodeCreated(node) { + if ("inputs" in node) { + for (const item of node.inputs) { + item.label = i18next.t(`node.input.${node.comfyClass}.${item.name}`) + } + } + + if ("widgets" in node) { + for (const item of node.widgets) { + item.label = i18next.t(`node.input.${node.comfyClass}.${item.name}`) + } + } + + if ("outputs" in node) { + for (const item of node.outputs) { + item.label = i18next.t(`node.output.${node.comfyClass}.${item.name}`) + } + } + }, + afterNodesRegistrations() { + const defs = LiteGraph.registered_node_types + + for (const k in defs) { + defs[k].category = i18next.t(`category.${defs[k].category}`) + } + } +}) \ No newline at end of file diff --git a/web/extensions/core/widgetInputs.js b/web/extensions/core/widgetInputs.js index d9eaf8a0c..e4ab088dd 100644 --- a/web/extensions/core/widgetInputs.js +++ b/web/extensions/core/widgetInputs.js @@ -57,6 +57,7 @@ function convertToInput(node, widget, config) { const sz = node.size; node.addInput(widget.name, linkType, { widget: { name: widget.name, config }, + label: config?.[1] ? i18next.t(config?.[1].label) : void 0, }); for (const widget of node.widgets) { diff --git a/web/i18n/en_US.js b/web/i18n/en_US.js new file mode 100644 index 000000000..4012f47a6 --- /dev/null +++ b/web/i18n/en_US.js @@ -0,0 +1,125 @@ +export default { + translation: { + "ui.queue_btn": "Queue Prompt", + "ui.queue_front_btn": "Queue Front", + "ui.view_queue_btn": "View Queue", + "ui.view_history_btn": "View History", + "ui.save_btn": "Save", + "ui.load_btn": "Load", + "ui.refresh_btn": "Refresh", + "ui.clipspace_btn": "Clipspace", + "ui.clear_btn": "Clear", + "ui.load_default_btn": "Load Default", + "ui.close_btn": "Close", + "ui.queue_size": "Queue size: ", + "ui.extra_options": "Extra options", + + "ui.settings.title": "Settings", + + "ui.canvas_menu_add_node": "Add Node", + "ui.canvas_menu_add_group": "Add Group", + + "ui.node_panel.header.properties": "Properties", + "ui.node_panel.header.title": "Title", + "ui.node_panel.header.mode": "Mode", + "ui.node_panel.header.color": "Color", + + "node.title.KSampler": "KSampler", + "node.title.KSamplerAdvanced": "KSampler (Advanced)", + // Loaders + "node.title.CheckpointLoader": "Load Checkpoint (With Config)", + "node.title.CheckpointLoaderSimple": "Load Checkpoint", + "node.title.VAELoader": "Load VAE", + "node.title.LoraLoader": "Load LoRA", + "node.title.CLIPLoader": "Load CLIP", + "node.title.ControlNetLoader": "Load ControlNet Model", + "node.title.DiffControlNetLoader": "Load ControlNet Model (diff)", + "node.title.StyleModelLoader": "Load Style Model", + "node.title.CLIPVisionLoader": "Load CLIP Vision", + "node.title.UpscaleModelLoader": "Load Upscale Model", + // Conditioning + "node.title.CLIPVisionEncode": "CLIP Vision Encode", + "node.title.StyleModelApply": "Apply Style Model", + "node.title.CLIPTextEncode": "CLIP Text Encode (Prompt)", + "node.title.CLIPSetLastLayer": "CLIP Set Last Layer", + "node.title.ConditioningCombine": "Conditioning (Combine)", + "node.title.ConditioningAverage ": "Conditioning (Average)", + "node.title.ConditioningConcat": "Conditioning (Concat)", + "node.title.ConditioningSetArea": "Conditioning (Set Area)", + "node.title.ConditioningSetMask": "Conditioning (Set Mask)", + "node.title.ControlNetApply": "Apply ControlNet", + "node.title.ControlNetApplyAdvanced": "Apply ControlNet (Advanced)", + // Latent + "node.title.VAEEncodeForInpaint": "VAE Encode (for Inpainting)", + "node.title.SetLatentNoiseMask": "Set Latent Noise Mask", + "node.title.VAEDecode": "VAE Decode", + "node.title.VAEEncode": "VAE Encode", + "node.title.LatentRotate": "Rotate Latent", + "node.title.LatentFlip": "Flip Latent", + "node.title.LatentCrop": "Crop Latent", + "node.title.EmptyLatentImage": "Empty Latent Image", + "node.title.LatentUpscale": "Upscale Latent", + "node.title.LatentUpscaleBy": "Upscale Latent By", + "node.title.LatentComposite": "Latent Composite", + "node.title.LatentBlend": "Latent Blend", + "LatentFromBatch": "Latent From Batch", + "node.title.RepeatLatentBatch": "Repeat Latent Batch", + // Image + "node.title.SaveImage": "Save Image", + "node.title.PreviewImage": "Preview Image", + "node.title.LoadImage": "Load Image", + "node.title.LoadImageMask": "Load Image (as Mask)", + "node.title.ImageScale": "Upscale Image", + "node.title.ImageScaleBy": "Upscale Image By", + "node.title.ImageUpscaleWithModel": "Upscale Image (using Model)", + "node.title.ImageInvert": "Invert Image", + "node.title.ImagePadForOutpaint": "Pad Image for Outpainting", + // _for_testing + "node.title.VAEDecodeTiled": "VAE Decode (Tiled)", + "node.title.VAEEncodeTiled": "VAE Encode (Tiled)", + + "node.input.SaveImage.filename_prefix": "filename_prefix", + "node.input.SaveImage.images": "images", + + "node.output.CheckpointLoaderSimple.MODEL": "MODEL", + + "category.conditioning": "conditioning", + "category.loaders": "loaders", + "category.latent": "latent", + "category.latent/inpaint": "latent/inpaint", + "category.latent/batch": "latent/batch", + "category.image": "image", + "category.mask": "mask", + "category.image/upscaling": "image/upscaling", + "category.sampling": "sampling", + "category._for_testing": "_for_testing", + "category.latent/transform": "latent/transform", + "category.advanced/loaders": "advanced/loaders", + "category.conditioning/style_model": "conditioning/style_model", + "category.conditioning/gligen": "conditioning/gligen", + "category.advanced/loaders/deprecated": "advanced/loaders/deprecated", + "category.advanced/conditioning": "advanced/conditioning", + "category.image/postprocessing": "image/postprocessing", + "category.advanced/model_merging": "advanced/model_merging", + "category.image/preprocessors": "image/preprocessors", + "category.utils": "utils", + + "settings.Comfy.ConfirmClear": "Require confirmation when clearing workflow", + "settings.Comfy.PromptFilename": "Prompt for filename when saving workflow", + "settings.Comfy.PreviewFormat": "When displaying a preview in the image widget, convert it to a lightweight image, e.g. webp, jpeg, webp;50, etc.", + "settings.Comfy.DisableSliders": "Disable sliders.", + "settings.Comfy.DevMode": "Enable Dev mode Options", + "settings.Comfy.ColorPalette": "Color Palette", + "settings.Comfy.EditAttention.Delta": "Ctrl+up/down precision", + "settings.Comfy.InvertMenuScrolling": "Invert Menu Scrolling", + "settings.Comfy.LinkRenderMode": "Link Render Mode", + "settings.Comfy.NodeSuggestions.number": "Number of nodes suggestions", + "settings.Comfy.SnapToGrid.GridSize": "Grid Size", + "settings.Comfy.Logging.Enabled": "Comfy.Logging.Enabled", + "settings.Comfy.MenuPosition": "Save menu position", + "settings.Comfy.ColorPalette.export": "Export", + "settings.Comfy.ColorPalette.import": "Import", + "settings.Comfy.ColorPalette.template": "Template", + "settings.Comfy.ColorPalette.delete": "Delete", + } +} \ No newline at end of file diff --git a/web/i18n/zh_CN.js b/web/i18n/zh_CN.js new file mode 100644 index 000000000..b018a668e --- /dev/null +++ b/web/i18n/zh_CN.js @@ -0,0 +1,125 @@ +export default { + translation: { + "ui.queue_btn": "冲冲冲", + "ui.queue_front_btn": "插队冲冲冲", + "ui.view_queue_btn": "查看队列", + "ui.view_history_btn": "查看历史", + "ui.save_btn": "保存", + "ui.load_btn": "加载", + "ui.refresh_btn": "刷新", + "ui.clipspace_btn": "Clipspace", + "ui.clear_btn": "清空", + "ui.load_default_btn": "加载默认配置", + "ui.close_btn": "关闭", + "ui.queue_size": "队列数量: ", + "ui.extra_options": "额外选项", + + "ui.settings.title": "设置", + + "ui.canvas_menu_add_node": "添加节点", + "ui.canvas_menu_add_group": "添加组", + + "ui.node_panel.header.properties": "属性", + "ui.node_panel.header.title": "标题", + "ui.node_panel.header.mode": "模式", + "ui.node_panel.header.color": "颜色", + + "node.title.KSampler": "采样器", + "node.title.KSamplerAdvanced": "采样器 (高级)", + // Loaders + "node.title.CheckpointLoader": "Load Checkpoint (With Config)", + "node.title.CheckpointLoaderSimple": "加载模型", + "node.title.VAELoader": "Load VAE", + "node.title.LoraLoader": "Load LoRA", + "node.title.CLIPLoader": "Load CLIP", + "node.title.ControlNetLoader": "Load ControlNet Model", + "node.title.DiffControlNetLoader": "Load ControlNet Model (diff)", + "node.title.StyleModelLoader": "Load Style Model", + "node.title.CLIPVisionLoader": "Load CLIP Vision", + "node.title.UpscaleModelLoader": "Load Upscale Model", + // Conditioning + "node.title.CLIPVisionEncode": "CLIP Vision Encode", + "node.title.StyleModelApply": "Apply Style Model", + "node.title.CLIPTextEncode": "CLIP Text Encode (Prompt)", + "node.title.CLIPSetLastLayer": "CLIP Set Last Layer", + "node.title.ConditioningCombine": "Conditioning (Combine)", + "node.title.ConditioningAverage ": "Conditioning (Average)", + "node.title.ConditioningConcat": "Conditioning (Concat)", + "node.title.ConditioningSetArea": "Conditioning (Set Area)", + "node.title.ConditioningSetMask": "Conditioning (Set Mask)", + "node.title.ControlNetApply": "Apply ControlNet", + "node.title.ControlNetApplyAdvanced": "Apply ControlNet (Advanced)", + // Latent + "node.title.VAEEncodeForInpaint": "VAE Encode (for Inpainting)", + "node.title.SetLatentNoiseMask": "Set Latent Noise Mask", + "node.title.VAEDecode": "VAE Decode", + "node.title.VAEEncode": "VAE Encode", + "node.title.LatentRotate": "Rotate Latent", + "node.title.LatentFlip": "Flip Latent", + "node.title.LatentCrop": "Crop Latent", + "node.title.EmptyLatentImage": "Empty Latent Image", + "node.title.LatentUpscale": "Upscale Latent", + "node.title.LatentUpscaleBy": "Upscale Latent By", + "node.title.LatentComposite": "Latent Composite", + "node.title.LatentBlend": "Latent Blend", + "LatentFromBatch": "Latent From Batch", + "node.title.RepeatLatentBatch": "Repeat Latent Batch", + // Image + "node.title.SaveImage": "Save Image", + "node.title.PreviewImage": "Preview Image", + "node.title.LoadImage": "Load Image", + "node.title.LoadImageMask": "Load Image (as Mask)", + "node.title.ImageScale": "Upscale Image", + "node.title.ImageScaleBy": "Upscale Image By", + "node.title.ImageUpscaleWithModel": "Upscale Image (using Model)", + "node.title.ImageInvert": "Invert Image", + "node.title.ImagePadForOutpaint": "Pad Image for Outpainting", + // _for_testing + "node.title.VAEDecodeTiled": "VAE Decode (Tiled)", + "node.title.VAEEncodeTiled": "VAE Encode (Tiled)", + + "node.input.SaveImage.filename_prefix": "文件名前缀", + "node.input.SaveImage.images": "图片", + + "node.output.CheckpointLoaderSimple.MODEL": "模型", + + "category.conditioning": "可调参数", + "category.loaders": "加载器", + "category.latent": "潜在", + "category.latent/inpaint": "潜在/修复", + "category.latent/batch": "潜在/批量", + "category.image": "图像", + "category.mask": "遮罩", + "category.image/upscaling": "图像/外扩", + "category.sampling": "采样", + "category._for_testing": "测试", + "category.latent/transform": "潜在/转换", + "category.advanced/loaders": "高级/加载器", + "category.conditioning/style_model": "可调参数/风格模型", + "category.conditioning/gligen": "可调参数/gligen", + "category.advanced/loaders/deprecated": "高级/加载器/已弃用", + "category.advanced/conditioning": "高级/可调参数", + "category.image/postprocessing": "图像/后期处理", + "category.advanced/model_merging": "高级/模型合并", + "category.image/preprocessors": "图像/前期处理", + "category.utils": "工具", + + "settings.Comfy.ConfirmClear": "清空工作流需要确认", + "settings.Comfy.PromptFilename": "Prompt for filename when saving workflow", + "settings.Comfy.PreviewFormat": "预览图格式和压缩尺寸, e.g. webp, jpeg, webp;50, etc.", + "settings.Comfy.DisableSliders": "Disable sliders.", + "settings.Comfy.DevMode": "启用开发模式", + "settings.Comfy.ColorPalette": "主题", + "settings.Comfy.EditAttention.Delta": "Ctrl+up/down precision", + "settings.Comfy.InvertMenuScrolling": "反转滚动", + "settings.Comfy.LinkRenderMode": "链接渲染模式", + "settings.Comfy.NodeSuggestions.number": "Number of nodes suggestions", + "settings.Comfy.SnapToGrid.GridSize": "单元格尺寸", + "settings.Comfy.Logging.Enabled": "记录日志", + "settings.Comfy.MenuPosition": "保存菜单位置", + "settings.Comfy.ColorPalette.export": "导出", + "settings.Comfy.ColorPalette.import": "导入", + "settings.Comfy.ColorPalette.template": "模版", + "settings.Comfy.ColorPalette.delete": "删除", + } +} \ No newline at end of file diff --git a/web/index.html b/web/index.html index 71067d993..c3620a134 100644 --- a/web/index.html +++ b/web/index.html @@ -6,6 +6,8 @@ + +