diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index d038208c580..580b2179f94 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -224,6 +224,7 @@ "discordLabel": "Discord", "dontAskMeAgain": "Don't ask me again", "dontShowMeThese": "Don't show me these", + "editName": "Edit name", "editor": "Editor", "error": "Error", "error_withCount_one": "{{count}} error", @@ -231,50 +232,67 @@ "model_withCount_one": "{{count}} model", "model_withCount_other": "{{count}} models", "file": "File", + "fitView": "Fit View", "folder": "Folder", "format": "format", "githubLabel": "Github", "goTo": "Go to", "hotkeysLabel": "Hotkeys", - "loadingImage": "Loading Image", - "loadingModel": "Loading Model", + "hex": "Hex", "imageFailedToLoad": "Unable to Load Image", "img2img": "Image To Image", "inpaint": "inpaint", "input": "Input", "installed": "Installed", + "json": "JSON", "languagePickerLabel": "Language", "linear": "Linear", "load": "Load", "loading": "Loading", + "loadingImage": "Loading Image", + "loadingModel": "Loading Model", "localSystem": "Local System", + "minimize": "Minimize", + "next": "Next", + "noMatchingItems": "No matching items", + "notifications": "Notifications", "learnMore": "Learn More", "modelManager": "Model Manager", "noMatches": "No matches", "noOptions": "No options", "nodes": "Workflows", "notInstalled": "Not $t(common.installed)", + "openSlider": "Open slider", "openInNewTab": "Open in New Tab", "openInViewer": "Open in Viewer", "orderBy": "Order By", "outpaint": "outpaint", "outputs": "Outputs", "postprocessing": "Post Processing", + "previous": "Previous", "random": "Random", + "removeFromCollection": "Remove from Collection", "reportBugLabel": "Report Bug", + "resetView": "Reset View", "safetensors": "Safetensors", "save": "Save", "saveAs": "Save As", "saveChanges": "Save Changes", + "saveToAssets": "Save to Assets", + "settings": "Settings", "settingsLabel": "Settings", "simple": "Simple", "somethingWentWrong": "Something went wrong", "statusDisconnected": "Disconnected", "template": "Template", + "toggleRgbHex": "Toggle RGB/HEX", "toResolve": "To resolve", "txt2img": "Text To Image", "unknown": "Unknown", + "unpin": "Unpin", "upload": "Upload", + "zoomIn": "Zoom In", + "zoomOut": "Zoom Out", "updated": "Updated", "created": "Created", "prevPage": "Previous Page", @@ -344,13 +362,19 @@ "discard": "Discard", "noPromptHistory": "No prompt history recorded.", "noMatchingPrompts": "No matching prompts in history.", - "toSwitchBetweenPrompts": "to switch between prompts." + "toSwitchBetweenPrompts": "to switch between prompts.", + "promptHistory": "Prompt History", + "clearHistory": "Clear History", + "usePrompt": "Use prompt", + "searchPrompts": "Search..." }, "queue": { "queue": "Queue", "queueFront": "Add to Front of Queue", "queueBack": "Add to Queue", + "queueActionsMenu": "Queue Actions Menu", "queueEmpty": "Queue Empty", + "queueItem": "Queue Item", "enqueueing": "Queueing Batch", "resume": "Resume", "resumeTooltip": "Resume Processor", @@ -493,7 +517,10 @@ "imagesSettings": "Gallery Images Settings", "jump": "Jump", "loading": "Loading", + "loadingGallery": "Loading gallery...", + "loadingMetadata": "Loading metadata...", "newestFirst": "Newest First", + "noImagesFound": "No images found", "oldestFirst": "Oldest First", "sortDirection": "Sort Direction", "showStarredImagesFirst": "Show Starred Images First", @@ -505,6 +532,8 @@ "unableToLoad": "Unable to load Gallery", "deleteSelection": "Delete Selection", "downloadSelection": "Download Selection", + "bulkDownloadReady": "Download ready", + "clickToDownload": "Click here to download", "bulkDownloadRequested": "Preparing Download", "bulkDownloadRequestedDesc": "Your download request is being prepared. This may take a few moments.", "bulkDownloadRequestFailed": "Problem Preparing Download", @@ -936,7 +965,8 @@ } }, "lora": { - "weight": "Weight" + "weight": "Weight", + "removeLoRA": "Remove LoRA" }, "metadata": { "allPrompts": "All Prompts", @@ -983,6 +1013,14 @@ "modelManager": { "active": "active", "actions": "Bulk Actions", + "deleteModelsConfirm": "Are you sure you want to delete {{count}} model(s)? This action cannot be undone.", + "deleteWarning": "Models in your Invoke models directory will be permanently deleted from disk.", + "modelsDeleted": "Successfully deleted {{count}} model(s)", + "modelsDeleteFailed": "Failed to delete models", + "someModelsFailedToDelete": "{{count}} model(s) could not be deleted", + "modelsDeletedPartial": "Partially completed", + "someModelsDeleted": "{{deleted}} deleted, {{failed}} failed", + "modelsDeleteError": "Error deleting models", "pause": "Pause", "pauseAll": "Pause All", "pauseAllTooltip": "Pause all active downloads", @@ -1331,6 +1369,7 @@ "noWorkflows": "No Workflows", "noMatchingWorkflows": "No Matching Workflows", "noWorkflow": "No Workflow", + "noWorkflowToSave": "No workflow to save", "unableToUpdateNode": "Node update failed: node {{node}} of type {{type}} (may require deleting and recreating)", "mismatchedVersion": "Invalid node: node {{node}} of type {{type}} has mismatched version (try updating?)", "missingTemplate": "Invalid node: node {{node}} of type {{type}} missing template (not installed?)", @@ -1354,6 +1393,7 @@ "nodeOpacity": "Node Opacity", "nodeVersion": "Node Version", "noOutputRecorded": "No outputs recorded", + "nodeData": "Node Data", "notes": "Notes", "description": "Description", "notesDescription": "Add notes about your workflow", @@ -1603,6 +1643,7 @@ "perPromptDesc": "Use a different seed for each image" }, "loading": "Generating Dynamic Prompts...", + "problemGeneratingPrompts": "Problem generating prompts", "promptsToGenerate": "Prompts to Generate" }, "sdxl": { @@ -2479,6 +2520,8 @@ "disableAutoNegative": "Disable Auto Negative", "deletePrompt": "Delete Prompt", "deleteReferenceImage": "Delete Reference Image", + "disableReferenceImage": "Disable Reference Image", + "enableReferenceImage": "Enable Reference Image", "showHUD": "Show HUD", "rectangle": "Rectangle", "maskFill": "Mask Fill", @@ -2499,6 +2542,7 @@ "controlLayer": "Control Layer", "inpaintMask": "Inpaint Mask", "invertMask": "Invert Mask", + "invertRegion": "Invert Region", "regionalGuidance": "Regional Guidance", "referenceImageRegional": "Reference Image (Regional)", "referenceImageGlobal": "Reference Image (Global)", @@ -2506,7 +2550,10 @@ "asRasterLayerResize": "As $t(controlLayers.rasterLayer) (Resize)", "asControlLayer": "As $t(controlLayers.controlLayer)", "asControlLayerResize": "As $t(controlLayers.controlLayer) (Resize)", + "invalidReferenceImage": "Invalid Reference Image:", "referenceImage": "Reference Image", + "removeImageFromCollection": "Remove Image from Collection", + "selectRefImage": "Select Ref Image", "maxRefImages": "Max Ref Images", "useAsReferenceImage": "Use as Reference Image", "regionalReferenceImage": "Regional Reference Image", @@ -2527,7 +2574,11 @@ "alignLeft": "Align Left", "alignCenter": "Align Center", "alignRight": "Align Right", - "px": "px" + "px": "px", + "lineHeight": "Spacing", + "lineHeightDense": "Dense", + "lineHeightNormal": "Normal", + "lineHeightSpacious": "Spacious" }, "newCanvasFromImage": "New Canvas from Image", "newImg2ImgCanvasFromImage": "New Img2Img from Image", @@ -2674,7 +2725,8 @@ "crosshatch": "Crosshatch", "vertical": "Vertical", "horizontal": "Horizontal", - "diagonal": "Diagonal" + "diagonal": "Diagonal", + "switchColors": "Switch FG/BG (X)" }, "gradient": { "linear": "Linear", @@ -2938,8 +2990,11 @@ }, "autoSwitch": { "off": "Off", + "doNotAutoSwitch": "Do not auto-switch", "switchOnStart": "On Start", - "switchOnFinish": "On Finish" + "switchOnStartDesc": "Switch on start", + "switchOnFinish": "On Finish", + "switchOnFinishDesc": "Switch on finish" } }, "upscaling": { @@ -3158,9 +3213,21 @@ "watchRecentReleaseVideos": "Watch Recent Release Videos", "watchUiUpdatesOverview": "Watch UI Updates Overview" }, + "cropper": { + "cropImage": "Crop Image", + "aspectRatio": "Aspect Ratio", + "free": "Free", + "mouseWheelZoom": "Mouse wheel: Zoom", + "spaceDragPan": "Space + Drag: Pan", + "dragCropBoxToAdjust": "Drag crop box or handles to adjust" + }, "supportVideos": { "supportVideos": "Support Videos", "gettingStarted": "Getting Started", + "gettingStartedPlaylist": "Getting Started playlist", + "studioSessionsPlaylist": "Studio Sessions playlist", + "discord": "Discord", + "github": "GitHub", "watch": "Watch", "studioSessionsDesc": "Join our to participate in the live sessions and ask questions. Sessions are uploaded to the playlist the following week.", "videos": { diff --git a/invokeai/frontend/web/src/common/components/ColorPicker/RgbaColorPicker.tsx b/invokeai/frontend/web/src/common/components/ColorPicker/RgbaColorPicker.tsx index 6bcf546fd34..38fcb2696ef 100644 --- a/invokeai/frontend/web/src/common/components/ColorPicker/RgbaColorPicker.tsx +++ b/invokeai/frontend/web/src/common/components/ColorPicker/RgbaColorPicker.tsx @@ -85,7 +85,7 @@ const RgbaColorPicker = (props: Props) => { h={10} whiteSpace="nowrap" onClick={onToggleMode} - aria-label="Toggle RGB/HEX" + aria-label={t('common.toggleRgbHex')} > RGB @@ -144,12 +144,12 @@ const RgbaColorPicker = (props: Props) => { h={10} whiteSpace="nowrap" onClick={onToggleMode} - aria-label="Toggle RGB/HEX" + aria-label={t('common.toggleRgbHex')} > HEX - {t('common.hex', { defaultValue: 'Hex' })} + {t('common.hex')} diff --git a/invokeai/frontend/web/src/common/hooks/useImageUploadButton.tsx b/invokeai/frontend/web/src/common/hooks/useImageUploadButton.tsx index 445f58c9a66..fc173de979f 100644 --- a/invokeai/frontend/web/src/common/hooks/useImageUploadButton.tsx +++ b/invokeai/frontend/web/src/common/hooks/useImageUploadButton.tsx @@ -187,11 +187,12 @@ export const UploadImageIconButton = memo( onUpload?: (imageDTO: ImageDTO) => void; isError?: boolean; } & SetOptional) => { + const { t } = useTranslation(); const uploadApi = useImageUploadButton({ isDisabled, allowMultiple: false, onUpload }); return ( <> { + const { t } = useTranslation(); const { children, isDisabled = false, onUpload, isError = false, ...rest } = props; const uploadApi = useImageUploadButton({ isDisabled, allowMultiple: false, onUpload }); return ( <> {tab === 'canvas' && ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImagePreview.tsx b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImagePreview.tsx index 84c1b2fc37b..b910f3f1399 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImagePreview.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImagePreview.tsx @@ -13,6 +13,7 @@ import { import { isIPAdapterConfig } from 'features/controlLayers/store/types'; import { getGlobalReferenceImageWarnings } from 'features/controlLayers/store/validators'; import { memo, useCallback, useEffect, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { PiExclamationMarkBold, PiEyeSlashBold, PiImageBold } from 'react-icons/pi'; import { useImageDTOFromCroppableImage } from 'services/api/endpoints/images'; @@ -64,6 +65,7 @@ const getImageSxWithWeight = (weight: number): SystemStyleObject => { }; export const RefImagePreview = memo(() => { + const { t } = useTranslation(); const dispatch = useAppDispatch(); const id = useRefImageIdContext(); const entity = useRefImageEntity(id); @@ -105,7 +107,7 @@ export const RefImagePreview = memo(() => { if (!entity.config.image) { return ( - Invalid Reference Image: + {t('controlLayers.invalidReferenceImage')} {warnings.map((tKey) => ( {upperFirst(t(tKey))} diff --git a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaAutoSwitchButtons.tsx b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaAutoSwitchButtons.tsx index f9fc483eea5..eca468fe3fd 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaAutoSwitchButtons.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaAutoSwitchButtons.tsx @@ -7,9 +7,11 @@ import { settingsStagingAreaAutoSwitchChanged, } from 'features/controlLayers/store/canvasSettingsSlice'; import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; import { PiCaretLineRightBold, PiCaretRightBold, PiMoonBold } from 'react-icons/pi'; export const StagingAreaAutoSwitchButtons = memo(() => { + const { t } = useTranslation(); const canvasManager = useCanvasManager(); const shouldShowStagedImage = useStore(canvasManager.stagingArea.$shouldShowStagedImage); @@ -29,24 +31,24 @@ export const StagingAreaAutoSwitchButtons = memo(() => { return ( <> } colorScheme={autoSwitch === 'off' ? 'invokeBlue' : 'base'} onClick={onClickOff} isDisabled={!shouldShowStagedImage} /> } colorScheme={autoSwitch === 'switch_on_start' ? 'invokeBlue' : 'base'} onClick={onClickSwitchOnStart} isDisabled={!shouldShowStagedImage} /> } colorScheme={autoSwitch === 'switch_on_finish' ? 'invokeBlue' : 'base'} onClick={onClickSwitchOnFinished} diff --git a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarMenu.tsx b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarMenu.tsx index ce32c823aa5..42b92d3db94 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarMenu.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarMenu.tsx @@ -3,16 +3,18 @@ import { useStore } from '@nanostores/react'; import { StagingAreaToolbarNewLayerFromImageMenuItems } from 'features/controlLayers/components/StagingArea/StagingAreaToolbarMenuNewLayerFromImage'; import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { PiDotsThreeVerticalBold } from 'react-icons/pi'; export const StagingAreaToolbarMenu = memo(() => { + const { t } = useTranslation(); const canvasManager = useCanvasManager(); const shouldShowStagedImage = useStore(canvasManager.stagingArea.$shouldShowStagedImage); return ( } colorScheme="invokeBlue" diff --git a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarMenuNewLayerFromImage.tsx b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarMenuNewLayerFromImage.tsx index 6b1b4a11150..d263620bc7b 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarMenuNewLayerFromImage.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarMenuNewLayerFromImage.tsx @@ -96,7 +96,7 @@ export const StagingAreaToolbarNewLayerFromImageMenuItems = memo(() => { }, [selectedItemImageDTO, store, toastSentToCanvas]); return ( - + } onClickCapture={onClickNewInpaintMaskFromImage} diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Text/TextToolOptions.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Text/TextToolOptions.tsx index 5dce61de4da..e2c6af2359d 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Text/TextToolOptions.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Text/TextToolOptions.tsx @@ -94,7 +94,7 @@ const FontSelect = () => { return ( - {t('controlLayers.text.font', { defaultValue: 'Font' })} + {t('controlLayers.text.font')} { return ( - {t('controlLayers.text.size', { defaultValue: 'Size' })} + {t('controlLayers.text.size')} - + @@ -207,7 +207,7 @@ const FontSizeControl = () => { } size="sm" variant="link" @@ -249,9 +249,9 @@ const LineHeightSelect = () => { const lineHeight = useAppSelector(selectTextLineHeight); const lineHeightOptions = useMemo( () => [ - { value: '0.75', label: t('controlLayers.text.lineHeightDense', { defaultValue: 'Dense' }) }, - { value: '1.0', label: t('controlLayers.text.lineHeightNormal', { defaultValue: 'Normal' }) }, - { value: '1.25', label: t('controlLayers.text.lineHeightSpacious', { defaultValue: 'Spacious' }) }, + { value: '0.75', label: t('controlLayers.text.lineHeightDense') }, + { value: '1.0', label: t('controlLayers.text.lineHeightNormal') }, + { value: '1.25', label: t('controlLayers.text.lineHeightSpacious') }, ], [t] ); @@ -270,9 +270,9 @@ const LineHeightSelect = () => { return ( - {t('controlLayers.text.lineHeight', { defaultValue: 'Spacing' })} + {t('controlLayers.text.lineHeight')} - + { return ( - + } size="sm" /> - + } size="sm" /> - + } size="sm" /> - + } @@ -350,27 +350,27 @@ const AlignmentControls = () => { return ( - + } size="sm" /> - + } size="sm" /> - + } diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/PinnedFillColorPickerOverlay.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/PinnedFillColorPickerOverlay.tsx index 38cf2d81b21..17cb34343ee 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/PinnedFillColorPickerOverlay.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/PinnedFillColorPickerOverlay.tsx @@ -69,16 +69,16 @@ export const PinnedFillColorPickerOverlay = memo(() => { } /> { // clicking selects the gradient tool; mode switching is handled in the top toolbar const handleClick = useCallback(() => selectGradient(), [selectGradient]); - const gradientLabel = t('controlLayers.tool.gradient', { defaultValue: 'Gradient' }); + const gradientLabel = t('controlLayers.tool.gradient'); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolGradientClipToggle.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolGradientClipToggle.tsx index a89ef6a470b..ca8b138ec40 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolGradientClipToggle.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolGradientClipToggle.tsx @@ -17,7 +17,7 @@ export const ToolGradientClipToggle = memo(() => { dispatch(settingsGradientClipToggled()); }, [dispatch]); - const label = t('controlLayers.gradient.clip', { defaultValue: 'Clip Gradient' }); + const label = t('controlLayers.gradient.clip'); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolGradientModeToggle.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolGradientModeToggle.tsx index 03b18c466ee..9056f7c5649 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolGradientModeToggle.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolGradientModeToggle.tsx @@ -15,18 +15,18 @@ export const ToolGradientModeToggle = memo(() => { return ( - + } colorScheme={gradientType === 'linear' ? 'invokeBlue' : 'base'} variant="solid" onClick={onLinearClick} /> - + } colorScheme={gradientType === 'radial' ? 'invokeBlue' : 'base'} variant="solid" diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolTextButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolTextButton.tsx index f1cabbc7954..29b87535f63 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolTextButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolTextButton.tsx @@ -10,9 +10,9 @@ export const ToolTextButton = memo(() => { const selectText = useSelectTool('text'); return ( - + } colorScheme={isSelected ? 'invokeBlue' : 'base'} variant="solid" diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolWidthPicker.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolWidthPicker.tsx index c6c1cb16def..98a7fb29c58 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolWidthPicker.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolWidthPicker.tsx @@ -25,6 +25,7 @@ import { import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import type { FocusEvent, KeyboardEvent, PointerEvent } from 'react'; import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { PiCaretDownBold } from 'react-icons/pi'; import { useToolIsSelected } from './hooks'; @@ -105,6 +106,7 @@ const DropDownToolWidthPickerComponent = memo( onPointerUpCapture, onBlur, }: ToolWidthPickerComponentProps) => { + const { t } = useTranslation(); const onChangeNumberInput = useCallback( (valueAsString: string, valueAsNumber: number) => { onChangeInput(valueAsNumber); @@ -136,7 +138,7 @@ const DropDownToolWidthPickerComponent = memo( } size="sm" variant="link" diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarScale.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarScale.tsx index 85dfccbf82d..ad793b2250c 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarScale.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarScale.tsx @@ -20,6 +20,7 @@ import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerP import { snapToNearest } from 'features/controlLayers/konva/util'; import type { KeyboardEvent } from 'react'; import { memo, useCallback, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { PiCaretDownBold, PiMagnifyingGlassMinusBold, PiMagnifyingGlassPlusBold } from 'react-icons/pi'; function formatPct(v: number | string) { @@ -77,6 +78,7 @@ const inputFieldSx = { } satisfies SystemStyleObject; export const CanvasToolbarScale = memo(() => { + const { t } = useTranslation(); const canvasManager = useCanvasManager(); const scale = useStore(canvasManager.stage.$scale); const [localScale, setLocalScale] = useState(scale * 100); @@ -143,7 +145,7 @@ export const CanvasToolbarScale = memo(() => { } size="sm" variant="link" @@ -182,6 +184,7 @@ CanvasToolbarScale.displayName = 'CanvasToolbarScale'; const SCALE_SNAPS = [0.1, 0.15, 0.2, 0.25, 0.5, 0.75, 1, 1.5, 2, 2.5, 5, 7.5, 10, 15, 20]; const ZoomOutButton = memo(() => { + const { t } = useTranslation(); const canvasManager = useCanvasManager(); const scale = useStore(canvasManager.stage.$scale); const onClick = useCallback(() => { @@ -197,7 +200,7 @@ const ZoomOutButton = memo(() => { } - aria-label="Zoom out" + aria-label={t('common.zoomOut')} variant="link" alignSelf="stretch" isDisabled={scale <= canvasManager.stage.config.MIN_SCALE} @@ -207,6 +210,7 @@ const ZoomOutButton = memo(() => { ZoomOutButton.displayName = 'ZoomOutButton'; const ZoomInButton = memo(() => { + const { t } = useTranslation(); const canvasManager = useCanvasManager(); const scale = useStore(canvasManager.stage.$scale); const onClick = useCallback(() => { @@ -219,7 +223,7 @@ const ZoomInButton = memo(() => { } - aria-label="Zoom out" + aria-label={t('common.zoomIn')} variant="link" alignSelf="stretch" isDisabled={scale >= canvasManager.stage.config.MAX_SCALE} diff --git a/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityHeaderWarnings.tsx b/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityHeaderWarnings.tsx index 78c768b6693..2e524eddf36 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityHeaderWarnings.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityHeaderWarnings.tsx @@ -74,7 +74,7 @@ export const CanvasEntityHeaderWarnings = memo(() => { size="sm" variant="link" alignSelf="stretch" - aria-label="warnings" + aria-label={t('common.warnings')} tooltip={} icon={} colorScheme="warning" diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasObject/CanvasObjectImage.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasObject/CanvasObjectImage.ts index 0aab41ee7e3..5cf6c814c36 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasObject/CanvasObjectImage.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasObject/CanvasObjectImage.ts @@ -95,7 +95,7 @@ export class CanvasObjectImage extends CanvasModuleBase { fontFamily: '"Inter Variable", sans-serif', fontSize: width / 16, fontStyle: '600', - text: t('common.loadingImage', 'Loading Image'), + text: t('common.loadingImage'), listening: false, perfectDrawEnabled: false, }), @@ -116,23 +116,20 @@ export class CanvasObjectImage extends CanvasModuleBase { if (!this.konva.image) { this.konva.placeholder.group.visible(false); - this.konva.placeholder.text.text(t('common.loadingImage', 'Loading Image')); + this.konva.placeholder.text.text(t('common.loadingImage')); } const imageDTO = await getImageDTOSafe(imageName); if (imageDTO === null) { // ImageDTO not found (or network error) - this.onFailedToLoadImage(t('controlLayers.unableToFindImage', 'Unable to find image')); + this.onFailedToLoadImage(t('controlLayers.errors.unableToFindImage')); return; } const imageElementResult = await withResultAsync(() => loadImage(imageDTO.image_url)); if (imageElementResult.isErr()) { // Image loading failed (e.g. the URL to the "physical" image is invalid) - this.onFailedToLoadImage( - t('controlLayers.unableToLoadImage', 'Unable to load image'), - parseify(imageElementResult.error) - ); + this.onFailedToLoadImage(t('controlLayers.errors.unableToLoadImage'), parseify(imageElementResult.error)); return; } @@ -149,16 +146,13 @@ export class CanvasObjectImage extends CanvasModuleBase { if (!this.konva.image) { this.konva.placeholder.group.visible(false); - this.konva.placeholder.text.text(t('common.loadingImage', 'Loading Image')); + this.konva.placeholder.text.text(t('common.loadingImage')); } const imageElementResult = await withResultAsync(() => loadImage(dataURL)); if (imageElementResult.isErr()) { // Image loading failed (e.g. the URL to the "physical" image is invalid) - this.onFailedToLoadImage( - t('controlLayers.unableToLoadImage', 'Unable to load image'), - parseify(imageElementResult.error) - ); + this.onFailedToLoadImage(t('controlLayers.errors.unableToLoadImage'), parseify(imageElementResult.error)); return; } diff --git a/invokeai/frontend/web/src/features/cropper/components/CropImageEditor.tsx b/invokeai/frontend/web/src/features/cropper/components/CropImageEditor.tsx index 0790608041b..e01115a2a46 100644 --- a/invokeai/frontend/web/src/features/cropper/components/CropImageEditor.tsx +++ b/invokeai/frontend/web/src/features/cropper/components/CropImageEditor.tsx @@ -16,6 +16,7 @@ import type { CropBox } from 'features/cropper/lib/editor'; import { cropImageModalApi, type CropImageModalState } from 'features/cropper/store'; import { selectAutoAddBoardId } from 'features/gallery/store/gallerySelectors'; import React, { memo, useCallback, useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { useUploadImageMutation } from 'services/api/endpoints/images'; import { objectEntries } from 'tsafe'; @@ -39,6 +40,7 @@ const getAspectRatioString = (ratio: number | null): AspectRatioID => { }; export const CropImageEditor = memo(({ editor, onApplyCrop, onReady }: Props) => { + const { t } = useTranslation(); const containerRef = useRef(null); const [zoom, setZoom] = useState(100); const [cropBox, setCropBox] = useState(null); @@ -154,9 +156,9 @@ export const CropImageEditor = memo(({ editor, onApplyCrop, onReady }: Props) => - Aspect Ratio: + {t('cropper.aspectRatio')}: { onClick={onClickClearHistory} isDisabled={positivePromptHistory.length === 0} > - Clear History + {t('prompt.clearHistory')} @@ -131,6 +132,7 @@ const PromptHistoryContent = memo(() => { PromptHistoryContent.displayName = 'PromptHistoryContent'; const PromptItem = memo(({ prompt }: { prompt: string }) => { + const { t } = useTranslation(); const dispatch = useAppDispatch(); const shiftKey = useShiftModifier(); @@ -148,7 +150,7 @@ const PromptItem = memo(({ prompt }: { prompt: string }) => { } onClick={onClickUse} /> @@ -157,7 +159,7 @@ const PromptItem = memo(({ prompt }: { prompt: string }) => { } onClick={onClickDelete} colorScheme="error" diff --git a/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx b/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx index 1c0f04d4fed..140ea7e1e6f 100644 --- a/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx +++ b/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx @@ -34,7 +34,13 @@ export const QueueActionsMenuButton = memo(() => { return ( <> - } /> + } + /> {(tab === 'canvas' || tab === 'generate') && ( diff --git a/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemDetail.tsx b/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemDetail.tsx index 47a062792aa..ccba0f56b15 100644 --- a/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemDetail.tsx +++ b/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemDetail.tsx @@ -137,7 +137,7 @@ const QueueItemComponent = ({ queueItem: queueItemDTO }: Props) => { {queueItem ? ( get(data, 'session.graph') }]} /> diff --git a/invokeai/frontend/web/src/features/system/components/VideosModal/VideosModal.tsx b/invokeai/frontend/web/src/features/system/components/VideosModal/VideosModal.tsx index 818f531820e..d4572cfa5e3 100644 --- a/invokeai/frontend/web/src/features/system/components/VideosModal/VideosModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/VideosModal/VideosModal.tsx @@ -25,29 +25,34 @@ import { Trans, useTranslation } from 'react-i18next'; export const [useVideosModal] = buildUseDisclosure(false); const GettingStartedPlaylistLink = () => { + const { t } = useTranslation(); return ( ); }; const StudioSessionsPlaylistLink = () => { + const { t } = useTranslation(); return ( ); }; const DiscordLink = () => { - return ; + const { t } = useTranslation(); + return ( + + ); }; const components = { diff --git a/invokeai/frontend/web/src/features/ui/components/Notifications.tsx b/invokeai/frontend/web/src/features/ui/components/Notifications.tsx index e1d32429af4..281e8540555 100644 --- a/invokeai/frontend/web/src/features/ui/components/Notifications.tsx +++ b/invokeai/frontend/web/src/features/ui/components/Notifications.tsx @@ -40,7 +40,7 @@ export const Notifications = () => { } boxSize={8} diff --git a/invokeai/frontend/web/src/features/ui/layouts/LaunchpadAddStyleReference.tsx b/invokeai/frontend/web/src/features/ui/layouts/LaunchpadAddStyleReference.tsx index c3746c875f6..3648d62a063 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/LaunchpadAddStyleReference.tsx +++ b/invokeai/frontend/web/src/features/ui/layouts/LaunchpadAddStyleReference.tsx @@ -45,7 +45,11 @@ export const LaunchpadAddStyleReference = memo((props: { extraAction?: () => voi - + ); }); diff --git a/invokeai/frontend/web/src/features/ui/layouts/LaunchpadEditImageButton.tsx b/invokeai/frontend/web/src/features/ui/layouts/LaunchpadEditImageButton.tsx index 9bdf044aa43..69e0afc89d7 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/LaunchpadEditImageButton.tsx +++ b/invokeai/frontend/web/src/features/ui/layouts/LaunchpadEditImageButton.tsx @@ -43,7 +43,7 @@ export const LaunchpadEditImageButton = memo((props: { extraAction?: () => void diff --git a/invokeai/frontend/web/src/features/ui/layouts/LaunchpadUseALayoutImageButton.tsx b/invokeai/frontend/web/src/features/ui/layouts/LaunchpadUseALayoutImageButton.tsx index 71af2634600..ba849dd51bb 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/LaunchpadUseALayoutImageButton.tsx +++ b/invokeai/frontend/web/src/features/ui/layouts/LaunchpadUseALayoutImageButton.tsx @@ -44,7 +44,7 @@ export const LaunchpadUseALayoutImageButton = memo((props: { extraAction?: () => diff --git a/invokeai/frontend/web/src/features/workflowLibrary/components/SaveWorkflowAsDialog.tsx b/invokeai/frontend/web/src/features/workflowLibrary/components/SaveWorkflowAsDialog.tsx index 72ca9c309b3..6dab1e3f04d 100644 --- a/invokeai/frontend/web/src/features/workflowLibrary/components/SaveWorkflowAsDialog.tsx +++ b/invokeai/frontend/web/src/features/workflowLibrary/components/SaveWorkflowAsDialog.tsx @@ -146,7 +146,7 @@ Content.displayName = 'Content'; const NoWorkflowToSaveContent = memo(() => { return ( - + ); }); diff --git a/invokeai/frontend/web/src/services/events/onModelInstallError.tsx b/invokeai/frontend/web/src/services/events/onModelInstallError.tsx index 24c31c4a296..d4c7109b709 100644 --- a/invokeai/frontend/web/src/services/events/onModelInstallError.tsx +++ b/invokeai/frontend/web/src/services/events/onModelInstallError.tsx @@ -194,8 +194,24 @@ const HFUnauthorizedToastDescription = () => { }; export const DiscordLink = () => { - return ; + const { t: tFunc } = useTranslation(); + return ( + + ); }; export const GitHubIssuesLink = () => { - return ; + const { t: tFunc } = useTranslation(); + return ( + + ); }; diff --git a/invokeai/frontend/web/src/services/events/setEventListeners.tsx b/invokeai/frontend/web/src/services/events/setEventListeners.tsx index 59a9ff2afcc..2e0ff2251eb 100644 --- a/invokeai/frontend/web/src/services/events/setEventListeners.tsx +++ b/invokeai/frontend/web/src/services/events/setEventListeners.tsx @@ -860,15 +860,9 @@ export const setEventListeners = ({ socket, store, setIsConnected }: SetEventLis toast({ id: bulk_download_item_name, - title: t('gallery.bulkDownloadReady', 'Download ready'), + title: t('gallery.bulkDownloadReady'), status: 'success', - description: ( - - ), + description: , duration: null, }); });