From 3920d5c90d4a5f16cf576438bd2fef131ffdf0cd Mon Sep 17 00:00:00 2001 From: mickr777 Date: Wed, 13 Sep 2023 21:15:36 +1000 Subject: [PATCH] Missed Translations --- invokeai/frontend/web/public/locales/en.json | 129 +++++++++++++- .../web/src/features/nodes/types/constants.ts | 161 +++++++++--------- .../web/src/features/nodes/types/types.ts | 25 ++- .../src/features/nodes/util/buildWorkflow.ts | 5 +- .../getMetadataAndWorkflowFromImageBlob.ts | 5 +- .../util/graphBuilders/buildCanvasGraph.ts | 7 +- .../buildCanvasImageToImageGraph.ts | 5 +- .../graphBuilders/buildCanvasInpaintGraph.ts | 5 +- .../graphBuilders/buildCanvasOutpaintGraph.ts | 5 +- .../buildCanvasSDXLImageToImageGraph.ts | 5 +- .../buildCanvasSDXLInpaintGraph.ts | 5 +- .../buildCanvasSDXLOutpaintGraph.ts | 5 +- .../buildCanvasSDXLTextToImageGraph.ts | 5 +- .../buildCanvasTextToImageGraph.ts | 5 +- .../buildLinearImageToImageGraph.ts | 9 +- .../buildLinearSDXLImageToImageGraph.ts | 9 +- .../buildLinearSDXLTextToImageGraph.ts | 5 +- .../buildLinearTextToImageGraph.ts | 5 +- .../src/features/nodes/util/parseSchema.ts | 26 +-- .../features/nodes/util/validateWorkflow.ts | 47 +++-- 20 files changed, 323 insertions(+), 150 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index c1983c6a53..7faa10a889 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -619,56 +619,175 @@ "addNodeToolTip": "Add Node (Shift+A, Space)", "animatedEdges": "Animated Edges", "animatedEdgesHelp": "Animate selected edges and edges connected to selected nodes", + "boolean": "Booleans", + "booleanCollection": "Boolean Collection", + "booleanCollectionDescription": "A collection of booleans.", + "booleanDescription": "Booleans are true or false.", + "booleanPolymorphic": "Boolean Polymorphic", + "booleanPolymorphicDescription": "A collection of booleans.", "cannotConnectInputToInput": "Cannot connect input to input", "cannotConnectOutputToOutput": "Cannot connect output to output", "cannotConnectToSelf": "Cannot connect to self", + "clipField": "Clip", + "clipFieldDescription": "Tokenizer and text_encoder submodels.", + "collection": "Collection", + "collectionDescription": "TODO", + "collectionItem": "Collection Item", + "collectionItemDescription": "TODO", "colorCodeEdges": "Color-Code Edges", "colorCodeEdgesHelp": "Color-code edges according to their connected fields", + "colorCollectionDescription": "A collection of colors.", + "colorField": "Color", + "colorFieldDescription": "A RGBA color.", + "colorPolymorphic": "Color Polymorphic", + "colorPolymorphicDescription": "A collection of colors.", + "conditioningCollection": "Conditioning Collection", + "conditioningCollectionDescription": "Conditioning may be passed between nodes.", + "conditioningField": "Conditioning", + "conditioningFieldDescription": "Conditioning may be passed between nodes.", + "conditioningPolymorphic": "Conditioning Polymorphic", + "conditioningPolymorphicDescription": "Conditioning may be passed between nodes.", "connectionWouldCreateCycle": "Connection would create a cycle", + "controlCollection": "Control Collection", + "controlCollectionDescription": "Control info passed between nodes.", + "controlField": "Control", + "controlFieldDescription": "Control info passed between nodes.", "currentImage": "Current Image", "currentImageDescription": "Displays the current image in the Node Editor", + "denoiseMaskField": "Denoise Mask", + "denoiseMaskFieldDescription": "Denoise Mask may be passed between nodes", + "doesNotExist": "does not exist", "downloadWorkflow": "Download Workflow JSON", + "edge": "Edge", + "enum": "Enum", + "enumDescription": "Enums are values that may be one of a number of options.", + "executionStateCompleted": "Completed", + "executionStateError": "Error", + "executionStateInProgress": "In Progress", "fieldTypesMustMatch": "Field types must match", "fitViewportNodes": "Fit View", + "float": "Float", + "floatCollection": "Float Collection", + "floatCollectionDescription": "A collection of floats.", + "floatDescription": "Floats are numbers with a decimal point.", + "floatPolymorphic": "Float Polymorphic", + "floatPolymorphicDescription": "A collection of floats.", "fullyContainNodes": "Fully Contain Nodes to Select", "fullyContainNodesHelp": "Nodes must be fully inside the selection box to be selected", "hideGraphNodes": "Hide Graph Overlay", "hideLegendNodes": "Hide Field Type Legend", "hideMinimapnodes": "Hide MiniMap", + "imageCollection": "Image Collection", + "imageCollectionDescription": "A collection of images.", + "imageField": "Image", + "imageFieldDescription": "Images may be passed between nodes.", + "imagePolymorphic": "Image Polymorphic", + "imagePolymorphicDescription": "A collection of images.", + "inputFields": "Input Feilds", "inputMayOnlyHaveOneConnection": "Input may only have one connection", + "inputNode": "Input Node", + "integer": "Integer", + "integerCollection": "Integer Collection", + "integerCollectionDescription": "A collection of integers.", + "integerDescription": "Integers are whole numbers, without a decimal point.", + "integerPolymorphic": "Integer Polymorphic", + "integerPolymorphicDescription": "A collection of integers.", + "invalidOutputSchema": "Invalid output schema", + "latentsCollection": "Latents Collection", + "latentsCollectionDescription": "Latents may be passed between nodes.", + "latentsField": "Latents", + "latentsFieldDescription": "Latents may be passed between nodes.", + "latentsPolymorphic": "Latents Polymorphic", + "latentsPolymorphicDescription": "Latents may be passed between nodes.", "loadingNodes": "Loading Nodes...", "loadWorkflow": "Load Workflow", + "loRAModelField": "LoRA", + "loRAModelFieldDescription": "TODO", + "mainModelField": "Model", + "mainModelFieldDescription": "TODO", + "maybeIncompatible": "May be Incompatible With Installed", + "mismatchedVersion": "Has Mismatched Version", + "missingCanvaInitImage": "Missing canvas init image", + "missingCanvaInitMaskImages": "Missing canvas init and mask images", + "missingTemplate": "Missing Template", "noConnectionData": "No connection data", "noConnectionInProgress": "No connection in progress", + "node": "Node", "nodeOutputs": "Node Outputs", "nodeSearch": "Search for nodes", "nodeTemplate": "Node Template", + "nodeType": "Node Type", "noFieldsLinearview": "No fields added to Linear View", "noFieldType": "No field type", + "noImageFoundState": "No initial image found in state", "noMatchingNodes": "No matching nodes", + "noModelFoundState": "No model found in state", "noNodeSelected": "No node selected", "noOpacity": "Node Opacity", "noOutputRecorded": "No outputs recorded", + "noOutputSchemaName": "No output schema name found in ref object", "notes": "Notes", "notesDescription": "Add notes about your workflow", + "oNNXModelField": "ONNX Model", + "oNNXModelFieldDescription": "ONNX model field.", + "outputFields": "Output Feilds", + "outputNode": "Output node", + "outputSchemaNotFound": "Output schema not found", "pickOne": "Pick One", + "problemReadingMetadata": "Problem reading metadata from image", + "problemReadingWorkflow": "Problem reading workflow from image", "problemSettingTitle": "Problem Setting Title", "reloadNodeTemplates": "Reload Node Templates", "removeLinearView": "Remove from Linear View", "resetWorkflow": "Reset Workflow", "resetWorkflowDesc": "Are you sure you want to reset this workflow?", "resetWorkflowDesc2": "Resetting the workflow will clear all nodes, edges and workflow details.", + "scheduler": "Scheduler", + "schedulerDescription": "TODO", + "sDXLMainModelField": "SDXL Model", + "sDXLMainModelFieldDescription": "SDXL model field.", + "sDXLRefinerModelField": "Refiner Model", + "sDXLRefinerModelFieldDescription": "TODO", "showGraphNodes": "Show Graph Overlay", "showLegendNodes": "Show Field Type Legend", "showMinimapnodes": "Show MiniMap", + "skipped": "Skipped", + "skippedReservedInput": "Skipped reserved input field", + "skippedReservedOutput": "Skipped reserved output field", + "skippingInputNoTemplate": "Skipping input field with no template", + "skippingReservedFieldType": "Skipping reserved field type", + "skippingUnknownInputType": "Skipping unknown input field type", + "skippingUnknownOutputType": "Skipping unknown output field type", "snapToGrid": "Snap to Grid", "snapToGridHelp": "Snap nodes to grid when moved", + "sourceNode": "Source node", + "string": "String", + "stringCollection": "String Collection", + "stringCollectionDescription": "A collection of strings.", + "stringDescription": "Strings are text.", + "stringPolymorphic": "String Polymorphic", + "stringPolymorphicDescription": "A collection of strings.", "unableToLoadWorkflow": "Unable to Validate Workflow", + "unableToParseEdge": "Unable to parse edge", + "unableToParseNode": "Unable to parse node", "unableToValidateWorkflow": "Unable to Validate Workflow", + "uNetField": "UNet", + "uNetFieldDescription": "UNet submodel.", + "unhandledInputProperty": "Unhandled input property", + "unhandledOutputProperty": "Unhandled output property", "unknownField": "Unknown Field", + "unknownNode": "Unknown Node", + "unknownTemplate": "Unknown Template", "unkownInvocation": "Unknown Invocation type", + "updateApp": "Update App", + "vaeField": "Vae", + "vaeFieldDescription": "Vae submodel.", + "vaeModelField": "VAE", + "vaeModelFieldDescription": "TODO", "validateConnections": "Validate Connections and Graph", "validateConnectionsHelp": "Prevent invalid connections from being made, and invalid graphs from being invoked", + "version": "Version", + "versionUnknown": " Version Unknown", "workflow": "Workflow", "workflowAuthor": "Author", "workflowContact": "Contact", @@ -680,15 +799,7 @@ "workflowValidation": "Workflow Validation Error", "workflowVersion": "Version", "zoomInNodes": "Zoom In", - "zoomOutNodes": "Zoom Out", - "executionStateError": "Error", - "executionStateCompleted": "Completed", - "executionStateInProgress": "In Progress", - "versionUnknown": " Version Unknown", - "unknownNode": "Unknown Node", - "version": "Version", - "updateApp": "Update App", - "unknownTemplate": "Unknown Template" + "zoomOutNodes": "Zoom Out" }, "parameters": { "aspectRatio": "Ratio", diff --git a/invokeai/frontend/web/src/features/nodes/types/constants.ts b/invokeai/frontend/web/src/features/nodes/types/constants.ts index a12c1fbddc..11b74cd002 100644 --- a/invokeai/frontend/web/src/features/nodes/types/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/types/constants.ts @@ -1,4 +1,5 @@ import { FieldType, FieldUIConfig } from './types'; +import i18n from 'i18next'; export const HANDLE_TOOLTIP_OPEN_DELAY = 500; export const COLOR_TOKEN_VALUE = 500; @@ -102,73 +103,73 @@ export const isPolymorphicItemType = ( export const FIELDS: Record = { boolean: { color: 'green.500', - description: 'Booleans are true or false.', - title: 'Boolean', + description: i18n.t('nodes.booleanDescription'), + title: i18n.t('nodes.boolean'), }, BooleanCollection: { color: 'green.500', - description: 'A collection of booleans.', - title: 'Boolean Collection', + description: i18n.t('nodes.booleanCollectionDescription'), + title: i18n.t('nodes.booleanCollection'), }, BooleanPolymorphic: { color: 'green.500', - description: 'A collection of booleans.', - title: 'Boolean Polymorphic', + description: i18n.t('nodes.booleanPolymorphicDescription'), + title: i18n.t('nodes.booleanPolymorphic'), }, ClipField: { color: 'green.500', - description: 'Tokenizer and text_encoder submodels.', - title: 'Clip', + description: i18n.t('nodes.clipFieldDescription'), + title: i18n.t('nodes.clipField'), }, Collection: { color: 'base.500', - description: 'TODO', - title: 'Collection', + description: i18n.t('nodes.collectionDescription'), + title: i18n.t('nodes.collection'), }, CollectionItem: { color: 'base.500', - description: 'TODO', - title: 'Collection Item', + description: i18n.t('nodes.collectionItemDescription'), + title: i18n.t('nodes.collectionItem'), }, ColorCollection: { color: 'pink.300', - description: 'A collection of colors.', - title: 'Color Collection', + description: i18n.t('nodes.colorCollectionDescription'), + title: i18n.t('nodes.colorCollection'), }, ColorField: { color: 'pink.300', - description: 'A RGBA color.', - title: 'Color', + description: i18n.t('nodes.colorFieldDescription'), + title: i18n.t('nodes.colorField'), }, ColorPolymorphic: { color: 'pink.300', - description: 'A collection of colors.', - title: 'Color Polymorphic', + description: i18n.t('nodes.colorPolymorphicDescription'), + title: i18n.t('nodes.colorPolymorphic'), }, ConditioningCollection: { color: 'cyan.500', - description: 'Conditioning may be passed between nodes.', - title: 'Conditioning Collection', + description: i18n.t('nodes.conditioningCollectionDescription'), + title: i18n.t('nodes.conditioningCollection'), }, ConditioningField: { color: 'cyan.500', - description: 'Conditioning may be passed between nodes.', - title: 'Conditioning', + description: i18n.t('nodes.conditioningFieldDescription'), + title: i18n.t('nodes.conditioningField'), }, ConditioningPolymorphic: { color: 'cyan.500', - description: 'Conditioning may be passed between nodes.', - title: 'Conditioning Polymorphic', + description: i18n.t('nodes.conditioningPolymorphicDescription'), + title: i18n.t('nodes.conditioningPolymorphic'), }, ControlCollection: { color: 'teal.500', - description: 'Control info passed between nodes.', - title: 'Control Collection', + description: i18n.t('nodes.controlCollectionDescription'), + title: i18n.t('nodes.controlCollection'), }, ControlField: { color: 'teal.500', - description: 'Control info passed between nodes.', - title: 'Control', + description: i18n.t('nodes.controlFieldDescription'), + title: i18n.t('nodes.controlField'), }, ControlNetModelField: { color: 'teal.500', @@ -182,132 +183,132 @@ export const FIELDS: Record = { }, DenoiseMaskField: { color: 'blue.300', - description: 'Denoise Mask may be passed between nodes', - title: 'Denoise Mask', + description: i18n.t('nodes.denoiseMaskFieldDescription'), + title: i18n.t('nodes.denoiseMaskField'), }, enum: { color: 'blue.500', - description: 'Enums are values that may be one of a number of options.', - title: 'Enum', + description: i18n.t('nodes.enumDescription'), + title: i18n.t('nodes.enum'), }, float: { color: 'orange.500', - description: 'Floats are numbers with a decimal point.', - title: 'Float', + description: i18n.t('nodes.floatDescription'), + title: i18n.t('nodes.float'), }, FloatCollection: { color: 'orange.500', - description: 'A collection of floats.', - title: 'Float Collection', + description: i18n.t('nodes.floatCollectionDescription'), + title: i18n.t('nodes.floatCollection'), }, FloatPolymorphic: { color: 'orange.500', - description: 'A collection of floats.', - title: 'Float Polymorphic', + description: i18n.t('nodes.floatPolymorphicDescription'), + title: i18n.t('nodes.floatPolymorphic'), }, ImageCollection: { color: 'purple.500', - description: 'A collection of images.', - title: 'Image Collection', + description: i18n.t('nodes.imageCollectionDescription'), + title: i18n.t('nodes.imageCollection'), }, ImageField: { color: 'purple.500', - description: 'Images may be passed between nodes.', - title: 'Image', + description: i18n.t('nodes.imageFieldDescription'), + title: i18n.t('nodes.imageField'), }, ImagePolymorphic: { color: 'purple.500', - description: 'A collection of images.', - title: 'Image Polymorphic', + description: i18n.t('nodes.imagePolymorphicDescription'), + title: i18n.t('nodes.imagePolymorphic'), }, integer: { color: 'red.500', - description: 'Integers are whole numbers, without a decimal point.', - title: 'Integer', + description: i18n.t('nodes.integerDescription'), + title: i18n.t('nodes.integer'), }, IntegerCollection: { color: 'red.500', - description: 'A collection of integers.', - title: 'Integer Collection', + description: i18n.t('nodes.integerCollectionDescription'), + title: i18n.t('nodes.integerCollection'), }, IntegerPolymorphic: { color: 'red.500', - description: 'A collection of integers.', - title: 'Integer Polymorphic', + description: i18n.t('nodes.integerPolymorphicDescription'), + title: i18n.t('nodes.integerPolymorphic'), }, LatentsCollection: { color: 'pink.500', - description: 'Latents may be passed between nodes.', - title: 'Latents Collection', + description: i18n.t('nodes.latentsCollectionDescription'), + title: i18n.t('nodes.latentsCollection'), }, LatentsField: { color: 'pink.500', - description: 'Latents may be passed between nodes.', - title: 'Latents', + description: i18n.t('nodes.latentsFieldDescription'), + title: i18n.t('nodes.latentsField'), }, LatentsPolymorphic: { color: 'pink.500', - description: 'Latents may be passed between nodes.', - title: 'Latents Polymorphic', + description: i18n.t('nodes.latentsPolymorphicDescription'), + title: i18n.t('nodes.latentsPolymorphic'), }, LoRAModelField: { color: 'teal.500', - description: 'TODO', - title: 'LoRA', + description: i18n.t('nodes.loRAModelFieldDescription'), + title: i18n.t('nodes.loRAModelField'), }, MainModelField: { color: 'teal.500', - description: 'TODO', - title: 'Model', + description: i18n.t('nodes.mainModelFieldDescription'), + title: i18n.t('nodes.mainModelField'), }, ONNXModelField: { color: 'teal.500', - description: 'ONNX model field.', - title: 'ONNX Model', + description: i18n.t('nodes.oNNXModelFieldDescription'), + title: i18n.t('nodes.oNNXModelField'), }, Scheduler: { color: 'base.500', - description: 'TODO', - title: 'Scheduler', + description: i18n.t('nodes.schedulerDescription'), + title: i18n.t('nodes.scheduler'), }, SDXLMainModelField: { color: 'teal.500', - description: 'SDXL model field.', - title: 'SDXL Model', + description: i18n.t('nodes.sDXLMainModelFieldDescription'), + title: i18n.t('nodes.sDXLMainModelField'), }, SDXLRefinerModelField: { color: 'teal.500', - description: 'TODO', - title: 'Refiner Model', + description: i18n.t('nodes.sDXLRefinerModelFieldDescription'), + title: i18n.t('nodes.sDXLRefinerModelField'), }, string: { color: 'yellow.500', - description: 'Strings are text.', - title: 'String', + description: i18n.t('nodes.stringDescription'), + title: i18n.t('nodes.string'), }, StringCollection: { color: 'yellow.500', - description: 'A collection of strings.', - title: 'String Collection', + description: i18n.t('nodes.stringCollectionDescription'), + title: i18n.t('nodes.stringCollection'), }, StringPolymorphic: { color: 'yellow.500', - description: 'A collection of strings.', - title: 'String Polymorphic', + description: i18n.t('nodes.stringPolymorphicDescription'), + title: i18n.t('nodes.stringPolymorphic'), }, UNetField: { color: 'red.500', - description: 'UNet submodel.', - title: 'UNet', + description: i18n.t('nodes.uNetFieldDescription'), + title: i18n.t('nodes.uNetField'), }, VaeField: { color: 'blue.500', - description: 'Vae submodel.', - title: 'Vae', + description: i18n.t('nodes.vaeFieldDescription'), + title: i18n.t('nodes.vaeField'), }, VaeModelField: { color: 'teal.500', - description: 'TODO', - title: 'VAE', + description: i18n.t('nodes.vaeModelFieldDescription'), + title: i18n.t('nodes.vaeModelField'), }, }; diff --git a/invokeai/frontend/web/src/features/nodes/types/types.ts b/invokeai/frontend/web/src/features/nodes/types/types.ts index b1ad6a7b96..a4b71457f7 100644 --- a/invokeai/frontend/web/src/features/nodes/types/types.ts +++ b/invokeai/frontend/web/src/features/nodes/types/types.ts @@ -20,6 +20,7 @@ import { import { O } from 'ts-toolbelt'; import { JsonObject } from 'type-fest'; import { z } from 'zod'; +import i18n from 'i18next'; export type NonNullableGraph = O.Required; @@ -1258,23 +1259,35 @@ export const zValidatedWorkflow = zWorkflow.transform((workflow) => { const targetNode = keyedNodes[edge.target]; const issues: string[] = []; if (!sourceNode) { - issues.push(`Output node ${edge.source} does not exist`); + issues.push( + `${i18n.t('nodes.outputNode')} ${edge.source} ${i18n.t( + 'nodes.doesNotExist' + )}` + ); } else if ( edge.type === 'default' && !(edge.sourceHandle in sourceNode.data.outputs) ) { issues.push( - `Output field "${edge.source}.${edge.sourceHandle}" does not exist` + `${i18n.t('nodes.outputField')}"${edge.source}.${ + edge.sourceHandle + }" ${i18n.t('nodes.doesNotExist')}` ); } if (!targetNode) { - issues.push(`Input node ${edge.target} does not exist`); + issues.push( + `${i18n.t('nodes.inputNode')} ${edge.target} ${i18n.t( + 'nodes.doesNotExist' + )}` + ); } else if ( edge.type === 'default' && !(edge.targetHandle in targetNode.data.inputs) ) { issues.push( - `Input field "${edge.target}.${edge.targetHandle}" does not exist` + `${i18n.t('nodes.inputField')} "${edge.target}.${ + edge.targetHandle + }" ${i18n.t('nodes.doesNotExist')}` ); } if (issues.length) { @@ -1282,7 +1295,9 @@ export const zValidatedWorkflow = zWorkflow.transform((workflow) => { const src = edge.type === 'default' ? edge.sourceHandle : edge.source; const tgt = edge.type === 'default' ? edge.targetHandle : edge.target; warnings.push({ - message: `Edge "${src} -> ${tgt}" skipped`, + message: `${i18n.t('nodes.edge')} "${src} -> ${tgt}" ${i18n.t( + 'nodes.skipped' + )}`, issues, data: edge, }); diff --git a/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts b/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts index b0ade42a9f..43ee75b735 100644 --- a/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts +++ b/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts @@ -3,6 +3,7 @@ import { NodesState } from '../store/types'; import { Workflow, zWorkflowEdge, zWorkflowNode } from '../types/types'; import { fromZodError } from 'zod-validation-error'; import { parseify } from 'common/util/serialize'; +import i18n from 'i18next'; export const buildWorkflow = (nodesState: NodesState): Workflow => { const { workflow: workflowMeta, nodes, edges } = nodesState; @@ -20,7 +21,7 @@ export const buildWorkflow = (nodesState: NodesState): Workflow => { const result = zWorkflowNode.safeParse(node); if (!result.success) { const { message } = fromZodError(result.error, { - prefix: 'Unable to parse node', + prefix: i18n.t('nodes.unableToParseNode'), }); logger('nodes').warn({ node: parseify(node) }, message); return; @@ -32,7 +33,7 @@ export const buildWorkflow = (nodesState: NodesState): Workflow => { const result = zWorkflowEdge.safeParse(edge); if (!result.success) { const { message } = fromZodError(result.error, { - prefix: 'Unable to parse edge', + prefix: i18n.t('nodes.unableToParseEdge'), }); logger('nodes').warn({ edge: parseify(edge) }, message); return; diff --git a/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts b/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts index b46a701757..6f850e7d29 100644 --- a/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts +++ b/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts @@ -7,6 +7,7 @@ import { zWorkflow, } from 'features/nodes/types/types'; import { get } from 'lodash-es'; +import i18n from 'i18next'; export const getMetadataAndWorkflowFromImageBlob = async ( image: Blob @@ -23,7 +24,7 @@ export const getMetadataAndWorkflowFromImageBlob = async ( } else { logger('system').error( { error: parseify(metadataResult.error) }, - 'Problem reading metadata from image' + i18n.t('nodes.problemReadingMetadata') ); } } @@ -36,7 +37,7 @@ export const getMetadataAndWorkflowFromImageBlob = async ( } else { logger('system').error( { error: parseify(workflowResult.error) }, - 'Problem reading workflow from image' + i18n.t('nodes.problemReadingWorkflow') ); } } diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts index d268a3990d..bfed5f417a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts @@ -9,6 +9,7 @@ import { buildCanvasSDXLInpaintGraph } from './buildCanvasSDXLInpaintGraph'; import { buildCanvasSDXLOutpaintGraph } from './buildCanvasSDXLOutpaintGraph'; import { buildCanvasSDXLTextToImageGraph } from './buildCanvasSDXLTextToImageGraph'; import { buildCanvasTextToImageGraph } from './buildCanvasTextToImageGraph'; +import i18n from 'i18next'; export const buildCanvasGraph = ( state: RootState, @@ -29,7 +30,7 @@ export const buildCanvasGraph = ( } } else if (generationMode === 'img2img') { if (!canvasInitImage) { - throw new Error('Missing canvas init image'); + throw new Error(i18n.t('nodes.missingCanvaInitImage')); } if ( state.generation.model && @@ -41,7 +42,7 @@ export const buildCanvasGraph = ( } } else if (generationMode === 'inpaint') { if (!canvasInitImage || !canvasMaskImage) { - throw new Error('Missing canvas init and mask images'); + throw new Error(i18n.t('nodes.missingCanvaInitMaskImages')); } if ( state.generation.model && @@ -57,7 +58,7 @@ export const buildCanvasGraph = ( } } else { if (!canvasInitImage) { - throw new Error('Missing canvas init image'); + throw new Error(i18n.t('nodes.missingCanvaInitImage')); } if ( state.generation.model && diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts index e750b40220..b27ffe7149 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts @@ -25,6 +25,7 @@ import { POSITIVE_CONDITIONING, SEAMLESS, } from './constants'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Image to Image graph. @@ -66,8 +67,8 @@ export const buildCanvasImageToImageGraph = ( ); if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } let modelLoaderNodeId = MAIN_MODEL_LOADER; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts index 58a7726410..3a0db8c55a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts @@ -44,6 +44,7 @@ import { RANGE_OF_SIZE, SEAMLESS, } from './constants'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Inpaint graph. @@ -79,8 +80,8 @@ export const buildCanvasInpaintGraph = ( } = state.generation; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noImageFoundState')); + throw new Error(i18n.t('nodes.noImageFoundState')); } // The bounding box determines width and height, not the width and height params diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts index 71d3492bdc..2222fcbfe8 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts @@ -46,6 +46,7 @@ import { RANGE_OF_SIZE, SEAMLESS, } from './constants'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Outpaint graph. @@ -83,8 +84,8 @@ export const buildCanvasOutpaintGraph = ( } = state.generation; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noImageFoundState')); + throw new Error(i18n.t('nodes.noImageFoundState')); } // The bounding box determines width and height, not the width and height params diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts index 2a677a8775..6beb4c725c 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts @@ -27,6 +27,7 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Image to Image graph. @@ -74,8 +75,8 @@ export const buildCanvasSDXLImageToImageGraph = ( ); if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } // Model Loader ID diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts index baa1c0155f..6b63ec4e44 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts @@ -46,6 +46,7 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Inpaint graph. @@ -86,8 +87,8 @@ export const buildCanvasSDXLInpaintGraph = ( } = state.sdxl; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } // The bounding box determines width and height, not the width and height params diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts index 3f8fffb70a..c1105c0ecd 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts @@ -48,6 +48,7 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Outpaint graph. @@ -90,8 +91,8 @@ export const buildCanvasSDXLOutpaintGraph = ( } = state.sdxl; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } // The bounding box determines width and height, not the width and height params diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts index 6d787987ef..07f9b8f573 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts @@ -29,6 +29,7 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Text to Image graph. @@ -71,8 +72,8 @@ export const buildCanvasSDXLTextToImageGraph = ( state.sdxl; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } const use_cpu = shouldUseNoiseSettings diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts index 094a7b02cc..ae06a27a3e 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts @@ -27,6 +27,7 @@ import { POSITIVE_CONDITIONING, SEAMLESS, } from './constants'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Text to Image graph. @@ -66,8 +67,8 @@ export const buildCanvasTextToImageGraph = ( ); if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } const use_cpu = shouldUseNoiseSettings diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts index dc9a34c67e..b032e6d9f7 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts @@ -27,6 +27,7 @@ import { RESIZE, SEAMLESS, } from './constants'; +import i18n from 'i18next'; /** * Builds the Image to Image tab graph. @@ -75,13 +76,13 @@ export const buildLinearImageToImageGraph = ( */ if (!initialImage) { - log.error('No initial image found in state'); - throw new Error('No initial image found in state'); + log.error(i18n.t('nodes.noImageFoundState')); + throw new Error(i18n.t('nodes.noImageFoundState')); } if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } const fp32 = vaePrecision === 'fp32'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts index 757a3976bb..7dd4aaf301 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts @@ -29,6 +29,7 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; +import i18n from 'i18next'; /** * Builds the Image to Image tab graph. @@ -75,13 +76,13 @@ export const buildLinearSDXLImageToImageGraph = ( */ if (!initialImage) { - log.error('No initial image found in state'); - throw new Error('No initial image found in state'); + log.error(i18n.t('nodes.noImageFoundState')); + throw new Error(i18n.t('nodes.noImageFoundState')); } if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } const fp32 = vaePrecision === 'fp32'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts index 9590e77f89..86ea08b41c 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts @@ -23,6 +23,7 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; +import i18n from 'i18next'; export const buildLinearSDXLTextToImageGraph = ( state: RootState @@ -58,8 +59,8 @@ export const buildLinearSDXLTextToImageGraph = ( : initialGenerationState.shouldUseCpuNoise; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } const fp32 = vaePrecision === 'fp32'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts index 5c534fff21..6ca16b0ae0 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts @@ -26,6 +26,7 @@ import { SEAMLESS, TEXT_TO_IMAGE_GRAPH, } from './constants'; +import i18n from 'i18next'; export const buildLinearTextToImageGraph = ( state: RootState @@ -53,8 +54,8 @@ export const buildLinearTextToImageGraph = ( : initialGenerationState.shouldUseCpuNoise; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } const fp32 = vaePrecision === 'fp32'; diff --git a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts index 8615a12c46..55ca593827 100644 --- a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts @@ -15,6 +15,7 @@ import { isInvocationSchemaObject, } from '../types/types'; import { buildInputFieldTemplate, getFieldType } from './fieldTemplateBuilders'; +import i18n from 'i18next'; const RESERVED_INPUT_FIELD_NAMES = ['id', 'type', 'metadata']; const RESERVED_OUTPUT_FIELD_NAMES = ['type']; @@ -97,7 +98,7 @@ export const parseSchema = ( if (isReservedInputField(type, propertyName)) { logger('nodes').trace( { node: type, fieldName: propertyName, field: parseify(property) }, - 'Skipped reserved input field' + i18n.t('nodes.skippedReservedInput') ); return inputsAccumulator; } @@ -105,7 +106,7 @@ export const parseSchema = ( if (!isInvocationFieldSchema(property)) { logger('nodes').warn( { node: type, propertyName, property: parseify(property) }, - 'Unhandled input property' + i18n.t('nodes.unhandledInputProperty') ); return inputsAccumulator; } @@ -120,7 +121,7 @@ export const parseSchema = ( fieldType, field: parseify(property), }, - 'Skipping unknown input field type' + i18n.t('nodes.skippingUnknownInputType') ); return inputsAccumulator; } @@ -133,7 +134,7 @@ export const parseSchema = ( fieldType, field: parseify(property), }, - 'Skipping reserved field type' + i18n.t('nodes.skippingReservedFieldType') ); return inputsAccumulator; } @@ -153,7 +154,7 @@ export const parseSchema = ( fieldType, field: parseify(property), }, - 'Skipping input field with no template' + i18n.t('nodes.skippingInputNoTemplate') ); return inputsAccumulator; } @@ -169,21 +170,24 @@ export const parseSchema = ( if (!outputSchemaName) { logger('nodes').warn( { outputRefObject: parseify(schema.output) }, - 'No output schema name found in ref object' + i18n.t('nodes.noOutputSchemaName') ); return invocationsAccumulator; } const outputSchema = openAPI.components?.schemas?.[outputSchemaName]; if (!outputSchema) { - logger('nodes').warn({ outputSchemaName }, 'Output schema not found'); + logger('nodes').warn( + { outputSchemaName }, + i18n.t('nodes.outputSchemaNotFound') + ); return invocationsAccumulator; } if (!isInvocationOutputSchemaObject(outputSchema)) { logger('nodes').error( { outputSchema: parseify(outputSchema) }, - 'Invalid output schema' + i18n.t('nodes.invalidOutputSchema') ); return invocationsAccumulator; } @@ -196,7 +200,7 @@ export const parseSchema = ( if (!isAllowedOutputField(type, propertyName)) { logger('nodes').trace( { type, propertyName, property: parseify(property) }, - 'Skipped reserved output field' + i18n.t('nodes.skippedReservedOutput') ); return outputsAccumulator; } @@ -204,7 +208,7 @@ export const parseSchema = ( if (!isInvocationFieldSchema(property)) { logger('nodes').warn( { type, propertyName, property: parseify(property) }, - 'Unhandled output property' + i18n.t('nodes.unhandledOutputProperty') ); return outputsAccumulator; } @@ -214,7 +218,7 @@ export const parseSchema = ( if (!isFieldType(fieldType)) { logger('nodes').warn( { fieldName: propertyName, fieldType, field: parseify(property) }, - 'Skipping unknown output field type' + i18n.t('nodes.skippingUnknownOutputType') ); return outputsAccumulator; } diff --git a/invokeai/frontend/web/src/features/nodes/util/validateWorkflow.ts b/invokeai/frontend/web/src/features/nodes/util/validateWorkflow.ts index a3085d516b..14b90fc731 100644 --- a/invokeai/frontend/web/src/features/nodes/util/validateWorkflow.ts +++ b/invokeai/frontend/web/src/features/nodes/util/validateWorkflow.ts @@ -7,6 +7,7 @@ import { isWorkflowInvocationNode, } from '../types/types'; import { parseify } from 'common/util/serialize'; +import i18n from 'i18next'; export const validateWorkflow = ( workflow: Workflow, @@ -25,8 +26,14 @@ export const validateWorkflow = ( const nodeTemplate = nodeTemplates[node.data.type]; if (!nodeTemplate) { errors.push({ - message: `Node "${node.data.type}" skipped`, - issues: [`Node type "${node.data.type}" does not exist`], + message: `${i18n.t('nodes.node')} "${node.data.type}" ${i18n.t( + 'nodes.skipped' + )}`, + issues: [ + `${i18n.t('nodes.nodeType')}"${node.data.type}" ${i18n.t( + 'nodes.doesNotExist' + )}`, + ], data: node, }); return; @@ -38,9 +45,13 @@ export const validateWorkflow = ( compareVersions(nodeTemplate.version, node.data.version) !== 0 ) { errors.push({ - message: `Node "${node.data.type}" has mismatched version`, + message: `${i18n.t('nodes.node')} "${node.data.type}" ${i18n.t( + 'nodes.mismatchedVersion' + )}`, issues: [ - `Node "${node.data.type}" v${node.data.version} may be incompatible with installed v${nodeTemplate.version}`, + `${i18n.t('nodes.node')} "${node.data.type}" v${ + node.data.version + } ${i18n.t('nodes.maybeIncompatible')} v${nodeTemplate.version}`, ], data: { node, nodeTemplate: parseify(nodeTemplate) }, }); @@ -52,33 +63,49 @@ export const validateWorkflow = ( const targetNode = keyedNodes[edge.target]; const issues: string[] = []; if (!sourceNode) { - issues.push(`Output node ${edge.source} does not exist`); + issues.push( + `${i18n.t('nodes.outputNode')} ${edge.source} ${i18n.t( + 'nodes.doesNotExist' + )}` + ); } else if ( edge.type === 'default' && !(edge.sourceHandle in sourceNode.data.outputs) ) { issues.push( - `Output field "${edge.source}.${edge.sourceHandle}" does not exist` + `${i18n.t('nodes.outputNodes')} "${edge.source}.${ + edge.sourceHandle + }" ${i18n.t('nodes.doesNotExist')}` ); } if (!targetNode) { - issues.push(`Input node ${edge.target} does not exist`); + issues.push( + `${i18n.t('nodes.inputNode')} ${edge.target} ${i18n.t( + 'nodes.doesNotExist' + )}` + ); } else if ( edge.type === 'default' && !(edge.targetHandle in targetNode.data.inputs) ) { issues.push( - `Input field "${edge.target}.${edge.targetHandle}" does not exist` + `${i18n.t('nodes.inputFeilds')} "${edge.target}.${ + edge.targetHandle + }" ${i18n.t('nodes.doesNotExist')}` ); } if (!nodeTemplates[sourceNode?.data.type ?? '__UNKNOWN_NODE_TYPE__']) { issues.push( - `Source node "${edge.source}" missing template "${sourceNode?.data.type}"` + `${i18n.t('nodes.sourceNode')} "${edge.source}" ${i18n.t( + 'nodes.missingTemplate' + )} "${sourceNode?.data.type}"` ); } if (!nodeTemplates[targetNode?.data.type ?? '__UNKNOWN_NODE_TYPE__']) { issues.push( - `Source node "${edge.target}" missing template "${targetNode?.data.type}"` + `${i18n.t('nodes.sourceNode')}"${edge.target}" ${i18n.t( + 'nodes.missingTemplate' + )} "${targetNode?.data.type}"` ); } if (issues.length) {