"use client"; import { createContext, useContext, useEffect, useMemo, useState } from "react"; export type Language = "en" | "zh-CN" | "zh-TW" | "ja"; type Dictionary = typeof en; export type TranslationKey = keyof Dictionary; const STORAGE_KEY = "popiart-node-language"; export const LANGUAGE_OPTIONS: { value: Language; label: string }[] = [ { value: "en", label: "English" }, { value: "zh-CN", label: "简体中文" }, { value: "zh-TW", label: "繁體中文" }, { value: "ja", label: "日本語" }, ]; const en = { "language.label": "Language", "brand.name": "popiart-node", "common.back": "Back", "common.next": "Next", "common.cancel": "Cancel", "common.close": "Close", "common.save": "Save", "common.create": "Create", "common.browse": "Browse", "common.change": "Change", "common.clear": "Clear", "common.select": "Select", "common.selectModel": "Select Model", "common.skip": "Skip", "common.show": "Show", "common.hide": "Hide", "common.override": "Override", "common.configuredViaEnv": "Configured via .env", "common.recommended": "Recommended", "common.optional": "Optional", "common.required": "Required", "common.download": "Download", "common.remove": "Remove", "common.disconnect": "Disconnect", "common.play": "Play", "common.pause": "Pause", "common.set": "Set", "common.previous": "Previous", "common.nextItem": "Next", "common.processing": "Processing...", "error.providerOverloaded": "{model}: provider is temporarily overloaded. Please retry in a moment or switch models.", "node.optionalTitle": "This input is optional - empty inputs will be skipped", "node.markOptionalTitle": "Mark as optional - empty inputs will skip this branch", "header.openWelcome": "Open welcome screen", "header.untitled": "Untitled", "header.saving": "Saving...", "header.savedAt": "Saved {time}", "header.notSaved": "Not saved", "header.saveProject": "Save project", "header.configureSaveLocation": "Configure save location", "header.openProject": "Open project", "header.openProjectFolder": "Open Project Folder", "header.projectSettings": "Project settings", "header.revertAIChanges": "Revert AI Changes", "header.revertAIChangesTitle": "Restore workflow from before AI changes", "header.revertConfirm": "Are you sure? This will restore your previous workflow.", "header.shortcuts": "Keyboard shortcuts (?)", "header.support": "Support", "header.madeBy": "Made by Willie", "header.commentsTitle": "{unviewed} unviewed comments ({total} total)", "header.openFolderFailed": "Failed to open project folder: {error}", "header.openFolderFailedRetry": "Failed to open project folder. Please try again.", "header.saveFailedRetry": "Failed to save project. Please try again.", "quickstart.description": "A node based workflow editor for generative AI pipelines. Connect nodes to build pipelines that transform and generate images, video, audio and 3D assets.", "quickstart.docs": "Docs", "quickstart.discord": "Discord", "quickstart.waitlist": "NB Pro Waitlist", "quickstart.newProject": "New project", "quickstart.newProjectDesc": "Start a new workflow", "quickstart.loadWorkflow": "Load workflow", "quickstart.loadWorkflowDesc": "Open existing file", "quickstart.templates": "Templates", "quickstart.templatesDesc": "Pre-built workflows", "quickstart.promptWorkflow": "Prompt a workflow", "quickstart.promptWorkflowDesc": "Get Gemini to build it", "quickstart.beta": "Beta", "quickstart.templateExplorerTitle": "Template Explorer", "quickstart.workflowTemplatesTitle": "Workflow Templates", "quickstart.templatesIntro": "Pre-built workflows to help you get started quickly. Select a template to load it into the canvas.", "quickstart.quickStart": "Quick Start", "quickstart.searchTemplates": "Search templates", "quickstart.searchTemplatesPlaceholder": "Search templates...", "quickstart.category": "Category", "quickstart.provider": "Provider", "quickstart.filterAll": "All", "quickstart.categorySimple": "Simple", "quickstart.categoryAdvanced": "Advanced", "quickstart.clearFilters": "Clear filters", "quickstart.clearAllFilters": "Clear all filters", "quickstart.noTemplatesMatch": "No templates match your filters", "quickstart.adjustSearchFilters": "Try adjusting your search or filters", "quickstart.useWorkflow": "Use workflow", "quickstart.loading": "Loading...", "quickstart.nodeCount": "{count} nodes", "quickstart.dismiss": "Dismiss", "quickstart.loadTemplateFailed": "Failed to load template", "quickstart.template.productShot.name": "Product Shot", "quickstart.template.productShot.description": "Place product in a new scene or environment", "quickstart.template.modelProduct.name": "Model + Product", "quickstart.template.modelProduct.description": "Combine model, product, and scene", "quickstart.template.colorVariations.name": "Color Variations", "quickstart.template.colorVariations.description": "Generate product color variants from references", "quickstart.template.backgroundSwap.name": "Background Swap", "quickstart.template.backgroundSwap.description": "Place subject in a new background", "quickstart.template.styleTransfer.name": "Style Transfer", "quickstart.template.styleTransfer.description": "Apply style from one image to another", "quickstart.template.sceneComposite.name": "Scene Composite", "quickstart.template.sceneComposite.description": "Combine elements from multiple scenes", "ftux.welcomeTo": "Welcome to popiart-node", "ftux.stepWelcome": "Welcome", "ftux.stepApiKeys": "API Keys", "ftux.stepModelDefaults": "Model Defaults", "ftux.stepReady": "Ready", "ftux.getStarted": "Get Started", "ftux.skipSetup": "Skip setup?", "ftux.skipSetupDesc": "You can configure API keys and model defaults later in settings.", "ftux.welcomeTitle": "Let's get started.", "ftux.welcomeDesc": "Connect AI models like building blocks to generate images, videos, and more.", "ftux.apiKeysTitle": "API Keys", "ftux.apiKeysDesc": "Add keys here to use AI providers (stored in browser), or save them to your .env file for better security and persistence.", "ftux.getApiKey": "Get {provider} API key", "ftux.getApiKeyTip": "Get API key", "ftux.llmOnlyTip": "Used for LLM nodes only", "ftux.enterKey": "Enter key...", "ftux.modelsTitle": "Choose Your Models", "ftux.modelsDesc": "Pick your default AI models for images and videos. You can change these later.", "ftux.defaultImageModel": "Default Image Model", "ftux.defaultVideoModel": "Default Video Model", "ftux.noneSet": "None set", "ftux.readyTitle": "You're ready!", "ftux.readyDesc": "Want a quick tutorial?", "ftux.startTutorial": "Start tutorial", "ftux.tutorial.welcome": "Let's go over the basics.", "ftux.tutorial.addImage": "Click the Image button to add an image node.", "ftux.tutorial.explainNode": "This is a node. Each node has a specific function.\n\nThis node adds images.", "ftux.tutorial.explainNodeInputs": "Inputs always go in on the left side of the node.", "ftux.tutorial.explainNodeOutputs": "Outputs always come from the right side of the node.", "ftux.tutorial.dragAndDrop": "Now drag from the output handle and drop into empty space.", "ftux.tutorial.selectGenerateImage": "This menu will show all available connections for the node.\n\nSelect 'Generate Image' to add an AI image generation node.", "ftux.tutorial.addPromptNode": "Click the Prompt button to add a prompt node.", "ftux.tutorial.connectPromptToGenerate": "Drag from the Prompt's output handle to the Generate Image's input handle.", "ftux.tutorial.populateContent": "Let me just add some stuff here 🎨", "ftux.tutorial.explainGenerateNode": "This is the Generate Image node. It uses AI to create or modify images based on your prompt and reference image.", "ftux.tutorial.explainRunButton": "Clicking this Run button will run your workflow. You can also press Cmd+Enter (Ctrl+Enter on Windows).", "ftux.tutorial.explainRunOptions": "You can also click the dropdown to run from a specific node, or run only selected nodes.", "ftux.tutorial.runWorkflow": "Now let's run your workflow! Click the Run button to generate your image.", "ftux.tutorial.demonstrateDownstream": "Now let me show you the possibilities... 🎬✨", "ftux.tutorial.demonstrateComplete": "Connect more nodes downstream to build generative pipelines, or just use it as an infinite creative canvas.", "ftux.tutorial.saveProject": "Save your project to keep all your work and generations locally.", "ftux.tutorial.resources": "Check out the resources below for help and inspiration:", "ftux.tutorial.discord": "Join our Discord community", "ftux.tutorial.complete": "You're all set! Happy creating.", "ftux.tutorial.clickToContinue": "Click anywhere to continue", "ftux.tutorial.skip": "Skip tutorial", "toolbar.categoryInput": "Input", "toolbar.categoryText": "Text", "toolbar.categoryGenerate": "Generate", "toolbar.categoryProcess": "Process", "toolbar.categoryRoute": "Route", "toolbar.categoryOutput": "Output", "toolbar.image": "Image", "toolbar.video": "Video", "toolbar.prompt": "Prompt", "toolbar.generate": "Generate", "toolbar.output": "Output", "toolbar.allNodes": "All nodes", "toolbar.allModels": "All models", "toolbar.browseModels": "Browse Models", "toolbar.switchConnectors": "Switch to {style} connectors", "toolbar.curved": "curved", "toolbar.angular": "angular", "toolbar.run": "Run", "toolbar.stop": "Stop", "toolbar.running": "Running...", "toolbar.runningNode": "Running {node}...", "toolbar.runningNodes": "Running {count} nodes...", "toolbar.nodesCount": "{count} nodes", "toolbar.runOptions": "Run options", "toolbar.runEntire": "Run entire workflow", "toolbar.runFromSelected": "Run from selected node", "toolbar.runSelectedOnly": "Run selected node only", "toolbar.runSelectedNodes": "Run selected nodes", "toolbar.runSelectedNodesCount": "Run {count} selected nodes", "toolbar.selectSingleNode": "Select a single node first", "toolbar.selectOneOrMoreNodes": "Select one or more nodes first", "node.imageInput": "Image Input", "node.audioInput": "Audio Input", "node.videoInput": "Video Input", "node.glbViewer": "3D Viewer", "node.prompt": "Prompt", "node.promptConstructor": "Prompt Constructor", "node.array": "Array", "node.generateImage": "Generate Image", "node.generateVideo": "Generate Video", "node.generate3d": "Generate 3D", "node.generateAudio": "Generate Audio", "node.llmGenerate": "LLM Generate", "node.annotation": "Annotate", "annotation.tool.select": "Select", "annotation.tool.rectangle": "Rect", "annotation.tool.circle": "Circle", "annotation.tool.arrow": "Arrow", "annotation.tool.draw": "Draw", "annotation.tool.text": "Text", "annotation.undo": "Undo", "annotation.redo": "Redo", "annotation.clear": "Clear", "annotation.cancel": "Cancel", "annotation.done": "Done", "annotation.color": "Color", "annotation.size": "Size", "annotation.fill": "Fill", "node.splitGrid": "Split Grid", "node.videoStitch": "Video Stitch", "node.videoTrim": "Video Trim", "node.easeCurve": "Ease Curve", "node.frameGrab": "Frame Grab", "node.imageCompare": "Image Compare", "imageCompare.connectTwo": "Connect 2 images to compare", "imageCompare.connectAnother": "Connect another image to compare", "imageCompare.imageAConnected": "Image A connected", "imageCompare.imageBConnected": "Image B connected", "imageCompare.imageAAlt": "Image A", "imageCompare.imageBAlt": "Image B", "upload.imageUnsupported": "Unsupported format. Use PNG, JPG, or WebP.", "upload.imageTooLarge": "Image too large. Maximum size is 10MB.", "upload.videoUnsupported": "Unsupported format. Use MP4, WebM, or QuickTime video files.", "upload.videoTooLarge": "Video file too large. Maximum size is 200MB.", "upload.audioUnsupported": "Unsupported format. Use MP3, WAV, OGG, AAC, or other audio formats.", "upload.audioTooLarge": "Audio file too large. Maximum size is 50MB.", "imageInput.uploadedAlt": "Uploaded image", "imageInput.download": "Download image", "imageInput.remove": "Remove image", "videoInput.upload": "Upload video file", "videoInput.dropVideo": "Drop video or click", "videoInput.download": "Download video", "videoInput.remove": "Remove video", "audioInput.upload": "Upload audio file", "audioInput.dropAudio": "Drop audio or click", "audioInput.download": "Download audio", "audioInput.remove": "Remove audio", "audioInput.clear": "Clear audio", "audioInput.loadingWaveform": "Loading waveform...", "generateAudio.fallbackUsed": "Fallback used", "generateAudio.fallbackUsedTitle": "Primary failed: {error}\nUsed fallback: {model}", "generateAudio.generating": "Generating audio...", "annotation.noImage": "No image available. Connect an image or load one manually.", "annotation.annotatedAlt": "Annotated image", "annotation.downloadImage": "Download image", "annotation.removeImage": "Remove image", "annotation.editCount": "Edit ({count})", "annotation.addAnnotations": "Add annotations", "annotation.dropClickConnect": "Drop, click, or connect", "array.split": "Split", "array.delimiter": "Delimiter", "array.newline": "Newline", "array.regexAdvanced": "Regex (Advanced)", "array.batch": "Batch", "array.batchModeTitle": "Batch mode: all items sent to one downstream node", "array.enableBatchMode": "Enable batch mode", "array.autoRouteToPrompts": "Auto-route to Prompts", "array.by": "By", "array.advanced": "Advanced", "array.trim": "Trim", "array.removeEmpty": "Remove empty", "array.parsedItems": "Parsed Items ({count})", "array.noItemsParsed": "No items parsed", "array.selectedForNextConnection": "Selected for next connection (click to unselect)", "array.selectForNextConnection": "Click to select for next connection", "array.batchFooter": "Batch: all items sent to downstream node", "array.nextWireUsesItem": "Next wire uses item {index}", "array.noSelection": "No selection: wires advance in order from item 1", "videoCommon.encoderUnsupported": "Your browser doesn't support video encoding.", "videoCommon.encoderHelp": "Doesn't seem right? Message Willie on Discord.", "videoCommon.checkingEncoder": "Checking encoder...", "videoCommon.processingPercent": "Processing... {progress}%", "videoTrim.videoIn": "Video In", "videoTrim.videoOut": "Video Out", "videoTrim.connectVideo": "Connect a video to trim", "videoTrim.source": "Source", "videoTrim.trimmed": "Trimmed", "videoTrim.clearTrimmedVideo": "Clear trimmed video", "videoTrim.start": "Start", "videoTrim.end": "End", "videoTrim.duration": "Duration", "videoTrim.trimStartTime": "Trim start time", "videoTrim.trimEndTime": "Trim end time", "videoTrim.setStartToCurrent": "Set start to current playback time", "videoTrim.setEndToCurrent": "Set end to current playback time", "videoTrim.trim": "Trim", "videoStitch.videoInput": "Video {index}", "videoStitch.audioInput": "Audio", "videoStitch.output": "Output", "videoStitch.connectVideos": "Connect videos to stitch", "videoStitch.clipAlt": "Clip {id}", "videoStitch.clearVideo": "Clear video", "videoStitch.loop": "Loop", "videoStitch.stitch": "Stitch", "multiAngle.editorTitle": "Multi-Angle Editor", "multiAngle.imageEditorTitle": "Image Multi-Angle Editor", "multiAngle.imageTitle": "Image Multi-Angle", "multiAngle.closeEditor": "Close multi-angle editor", "multiAngle.generate": "Generate multi-angle", "multiAngle.noImageToast": "No usable image found. Cannot generate multi-angle image.", "multiAngle.sightControl": "Multi-angle sight control", "multiAngle.noImage": "No image", "multiAngle.horizontal": "Horizontal orbit", "multiAngle.vertical": "Vertical pitch", "multiAngle.zoom": "Shot scale", "multiAngle.prompt": "Prompt", "multiAngle.enableCustomPrompt": "Enable custom prompt", "multiAngle.promptDialog": "Multi-angle prompt", "multiAngle.promptInput": "Multi-angle prompt input", "multiAngle.promptPlaceholder": "Enter prompt...", "multiAngle.reset": "Reset parameters", "multiAngle.resetAria": "Reset multi-angle parameters", "multiAngle.adjustVerticalUp": "Adjust vertical pitch up", "multiAngle.adjustVerticalDown": "Adjust vertical pitch down", "multiAngle.adjustHorizontalLeft": "Adjust horizontal orbit left", "multiAngle.adjustHorizontalRight": "Adjust horizontal orbit right", "multiAngle.preset.custom": "Custom", "multiAngle.preset.fisheye": "Fisheye", "multiAngle.preset.tilt": "Tilt", "multiAngle.preset.frontOverhead": "Front overhead", "multiAngle.preset.frontLow": "Front low angle", "multiAngle.preset.panoramicOverhead": "Panoramic overhead", "multiAngle.preset.back": "Back view", "multiAngle.zoom.wide": "Wide", "multiAngle.zoom.medium": "Medium", "multiAngle.zoom.close": "Close-up", "workflow.splitGrid.noImage": "No image available to split. Generate or load an image first.", "workflow.splitGrid.detectFailed": "Could not detect grid in image.", "workflow.splitGrid.failed": "Failed to split image grid: {error}", "workflow.generatedSuccess": "Workflow generated successfully", "workflow.generatedFailed": "Failed to generate workflow", "workflow.generatedFailedRetry": "Failed to generate workflow. Please try again.", "workflow.appliedEdits": "Applied {count} edit(s)", "chat.title": "Canvas Assistant", "chat.beta": "Beta", "chat.clear": "Clear chat", "chat.close": "Close chat", "chat.dismiss": "Dismiss", "chat.emptyTitle": "Ask about this canvas or ask me to prepare edits.", "chat.diagnoseSelected": "Diagnose selected", "chat.makeVariants": "Make variants", "chat.promptDiagnose": "Diagnose the selected nodes and suggest the smallest useful fix.", "chat.promptVariants": "Prepare edits to create four visual variants from the selected image or generate node.", "chat.proposalReady": "Proposal ready", "chat.candidateReady": "Candidate workflow ready to apply.", "chat.runReady": "Run action ready to apply.", "chat.candidateWorkflow": "Candidate workflow", "chat.applyWorkflow": "Apply workflow", "chat.operationPreview": "Operation preview", "chat.applyEdits": "Apply edits", "chat.runPreview": "Run preview", "chat.runNow": "Run now", "chat.focusedNodes": "Focused on {count} selected node(s)", "chat.runSelected": "Run selected", "chat.runAffected": "Run affected ({count})", "chat.placeholder": "Type a message...", "chat.building": "Building...", "chat.buildWorkflow": "Build Workflow", "chat.open": "Assistant", "chat.noSelection": "Select one or more nodes first.", "workflow.invalidWorkflowFile": "Invalid workflow file format", "workflow.parseWorkflowFileFailed": "Failed to parse workflow file", "splitGridNode.sourceGridAlt": "Source grid", "splitGridNode.connectImage": "Connect image", "splitGridNode.gridSummary": "{rows}x{cols} grid ({count} images)", "splitGridNode.generateSetsCreated": "{count} generate sets created", "splitGridNode.notConfigured": "Not configured - click Settings", "splitGridNode.configureFirst": "Configure node first", "splitGridNode.connectImageFirst": "Connect an image first", "splitGridNode.splitGrid": "Split grid", "splitGridNode.split": "Split", "node.router": "Router", "node.switch": "Switch", "node.conditionalSwitch": "Conditional Switch", "node.output": "Output", "node.outputGallery": "Output Gallery", "output.downloadCurrent": "Download current {type}", "output.downloadAll": "Download all outputs", "node.settings": "Settings", "node.runToGenerate": "Run to generate", "node.selectModel": "Select model...", "node.primary": "Primary", "node.text": "Text", "node.image": "Image", "node.notUsedByModel": "Not used by this model", "node.generationFailed": "Generation failed", "node.videoGenerationFailed": "Video generation failed", "node.loadingParameters": "Loading parameters...", "node.noParameters": "No parameters available", "node.default": "Default", "node.model": "Model", "node.size": "Size", "node.quality": "Quality", "node.voice": "Voice", "node.sound": "Sound", "node.duration": "Duration", "node.seconds": "{count}s", "node.aspectRatio": "Aspect Ratio", "node.resolution": "Resolution", "node.googleSearch": "Google Search", "node.imageSearch": "Image Search", "node.provider": "Provider", "node.temperature": "Temperature: {value}", "node.maxTokens": "Max Tokens: {value}", "node.generic": "Node", "splitGridSettings.title": "Split Grid Settings", "splitGridSettings.gridLayout": "Grid Layout", "splitGridSettings.gridSummary": "Grid will be split into {rows}x{cols} = {count} images", "splitGridSettings.defaultPrompt": "Default Prompt", "splitGridSettings.promptPlaceholder": "Enter prompt that will be applied to all generated images...", "splitGridSettings.promptHelp": "Each prompt node can be edited individually after creation", "splitGridSettings.generateNodeSettings": "Generate Node Settings", "splitGridSettings.createGenerateSets": "Create {count} Generate Sets", "imageInput.upload": "Upload image", "imageInput.dropImage": "Drop image", "dropOverlay.workflow": "Drop to load workflow", "dropOverlay.node": "Drop to create node", "dropOverlay.audio": "Drop audio to create node", "dropOverlay.image": "Drop image to create node", "dropOverlay.splittingImageGrid": "Splitting image grid...", "connectionMenu.addNode": "Add {type} node", "connectionMenu.type.image": "image", "connectionMenu.type.text": "text", "connectionMenu.type.audio": "audio", "connectionMenu.type.video": "video", "connectionMenu.type.3d": "3D", "connectionMenu.type.easeCurve": "settings", "connectionMenu.splitGridNode": "Split Grid Node", "connectionMenu.splitGridNow": "Split Grid Now", "connectionMenu.multiAngleImage": "Image Multi-Angle", "connectionMenu.navigate": "navigate", "connectionMenu.select": "select", "prompt.placeholder": "Describe what to generate...", "prompt.connectedPlaceholder": "Text from connected node (editable)...", "prompt.optionalPlaceholder": "Optional prompt (leave empty to skip)...", "prompt.addVariable": "Add variable", "prompt.setVariableName": "Set Variable Name", "prompt.variableHelp": "Use this prompt as a variable in PromptConstructor nodes", "prompt.variableName": "Variable name", "prompt.variablePlaceholder": "e.g. color, style, subject", "prompt.preview": "Preview: {value}", "composer.promptProvidedByUpstream": "Prompt is provided by an upstream text node.", "composer.videoStitchClipCount": "{count} video clips", "composer.videoStitchAudio": "Audio connected", "composer.videoStitchNoAudio": "No audio", "composer.videoStitchInputs": "Video inputs", "composer.videoStitchInputHint": "Reorder clips on the node", "composer.videoStitchNeedTwo": "Connect at least 2 video clips to stitch.", "composer.videoStitchClip": "Clip {index}", "composer.videoStitchLoop": "Loop", "composer.videoStitchOutputReady": "Output ready", "composer.videoStitchNoOutput": "No output yet", "composer.videoStitchReady": "Ready to stitch current node", "composer.videoStitchRun": "Stitch current video node", "composer.easeCurveVideoConnected": "Video connected", "composer.easeCurveNoVideo": "Connect a video input to apply ease curve.", "composer.easeCurveInherited": "Inherited settings", "composer.easeCurveLocal": "Local settings", "composer.easeCurveSettings": "Curve settings", "composer.easeCurvePreset": "Preset", "composer.easeCurveCustom": "Custom bezier", "composer.easeCurveHandles": "Bezier handles", "composer.easeCurveInput": "Input", "composer.easeCurveDuration": "Output duration", "composer.easeCurveOutputReady": "Output ready", "composer.easeCurveNoOutput": "No output yet", "composer.easeCurveReady": "Ready to apply current curve", "composer.easeCurveRun": "Apply current ease curve node", "composer.selectModel": "Select model", "composer.chooseModelTitle": "Choose generation model", "composer.chooseImageModel": "Choose image model", "composer.chooseVideoModel": "Choose video model", "composer.chooseAudioModel": "Choose audio model", "composer.regenerateImageNode": "Regenerate current image node", "composer.regenerateVideoNode": "Regenerate current video node", "composer.regenerateAudioNode": "Regenerate current audio node", "composer.imageNode": "Image node", "composer.videoNode": "Video node", "composer.audioNode": "Audio node", "composer.imageCount": "Image count", "composer.imageCountOption": "{count} image(s)", "composer.newGeneration": "New generation", "composer.selectedNodes": "{count} nodes selected", "composer.currentNode": "Current node", "composer.createAndGenerate": "Create and generate", "composer.dragFromPort": "Drag from a node port to create the next step", "composer.multiSelectNoSingleGenerate": "Multi-select does not support single-node generation yet", "composer.retryCurrentNode": "Retry current node", "composer.generate": "Generate", "composer.describeContent": "Describe what you want to generate", "composer.mainPlaceholder": "Describe what you want to generate, press / for commands, @ to reference assets", "composer.uploadReferenceImage": "Upload reference image", "composer.expand": "Expand composer", "composer.collapse": "Collapse composer", "composer.console": "Console", "composer.style": "Style", "composer.mark": "Mark", "composer.focus": "Focus", "composer.addReferenceImage": "Add reference image", "composer.referenceFromUpstream": "Reference images come from upstream connections", "composer.reference": "Reference", "composer.referenceImage": "Reference image {index}", "composer.removeReferenceImage": "Remove reference image {index}", "composer.commands": "Commands", "composer.referenceMaterials": "Reference assets", "composer.commandCharacter": "Character image", "composer.commandCharacterValue": "Generate a character image with consistent styling and clear composition.", "composer.commandTurnaround": "Turnaround sheet", "composer.commandTurnaroundValue": "Generate a character turnaround sheet with front, side, and back views.", "composer.commandVideoShot": "Video shot", "composer.commandVideoShotValue": "Turn the current image into a short video shot with natural motion.", "composer.currentReference": "Current reference asset", "composer.canvasAssets": "Canvas assets", "composer.multiSelectUnsupported": "{count} nodes selected. Batch editing is not supported yet.", "composer.unsupportedNodeHint": "Create the next step by dragging from a node port. The composer only edits the selected generation node.", "composer.videoSchemaHint": "Video parameters follow the selected model schema", "composer.translate": "Translate", "composer.settings": "Settings", "composer.selectModelTitle": "Select model: {model}", "shortcuts.title": "Keyboard Shortcuts", "shortcuts.general": "General", "shortcuts.addNodes": "Add Nodes", "shortcuts.layout": "Layout (select 2+ nodes first)", "shortcuts.canvas": "Canvas", "shortcuts.runWorkflow": "Run workflow", "shortcuts.copyNodes": "Copy selected nodes", "shortcuts.paste": "Paste nodes / image / text", "shortcuts.undo": "Undo", "shortcuts.redo": "Redo", "shortcuts.showShortcuts": "Show keyboard shortcuts", "shortcuts.addPrompt": "Add Prompt node", "shortcuts.addImage": "Add Image Input node", "shortcuts.addGenerateImage": "Add Generate Image node", "shortcuts.addGenerateVideo": "Add Generate Video node", "shortcuts.addLLM": "Add LLM Text node", "shortcuts.addAnnotation": "Add Annotation node", "shortcuts.addAudio": "Add Audio node", "shortcuts.addVideoInput": "Add Video Input node", "shortcuts.addArray": "Add Array node", "shortcuts.stackVertical": "Stack selected vertically", "shortcuts.stackHorizontal": "Stack selected horizontally", "shortcuts.arrangeGrid": "Arrange selected as grid", "shortcuts.zoom": "Zoom in / out", "shortcuts.pan": "Pan (macOS)", "shortcuts.delete": "Delete selected nodes", "project.newProject": "New Project", "project.settings": "Project Settings", "project.tabProject": "Project", "project.tabProviders": "Providers", "project.tabNodeDefaults": "Node Defaults", "project.tabCanvas": "Canvas", "project.name": "Project Name", "project.directory": "Project Directory", "project.localFolderPlaceholder": "Choose a local folder on this device", "project.directoryHelp": "Workflow files and images will be saved here. Subfolders for inputs and generations will be auto-created.", "project.embedImages": "Embed images as base64", "project.embedImagesDesc": "Embeds all images in workflow, larger workflow files. Can hit memory limits on very large workflows.", "project.inlineSettings": "Show model settings on nodes", "project.inlineSettingsDesc": "Show model parameters inside generation nodes instead of the side panel", "project.envHelp": "Add API keys via .env.local for better security. Keys added here override .env and are stored in your browser.", "project.newapiwgDesc": "Popi unified model gateway", "project.baseUrl": "Base URL", "project.systemImageDefault": "System default (Popi Models)", "project.noneSetFirstUse": "None set (select on first use)", "project.defaultLLM": "Default LLM Settings", "project.systemLLMDefault": "Using system defaults (Popi Models Doubao Seed 2.0 Lite)", "project.provider": "Provider", "project.model": "Model", "project.temp": "Temp: {value}", "project.tokens": "Tokens: {value}", "project.executionSettings": "Execution Settings", "project.maxParallel": "Max Parallel Calls: {count}", "project.executionHelp": "Maximum number of nodes to execute in parallel during workflow execution. Higher values may improve speed but increase API rate limit risk.", "project.defaultsHelp": "These defaults are applied when creating nodes via keyboard shortcuts (Shift+G, Shift+L, etc).", "project.canvasHelp": "Configure how you navigate and interact with the canvas.", "project.canvasAssistant": "Canvas Assistant", "project.canvasAssistantShort": "Assistant", "project.panMode": "Pan Mode", "project.panSpace": "Hold Space and drag to pan", "project.panMiddle": "Click and drag with middle mouse button", "project.panAlways": "Pan without holding any keys", "project.panSpaceLabel": "Space + Drag", "project.panMiddleLabel": "Middle Mouse", "project.panAlwaysLabel": "Always On", "project.zoomMode": "Zoom Mode", "project.zoomAlt": "Hold Alt and scroll to zoom", "project.zoomCtrl": "Hold Ctrl/Cmd and scroll to zoom", "project.zoomScroll": "Scroll to zoom without modifier keys", "project.zoomAltLabel": "Alt + Scroll", "project.zoomCtrlLabel": "Ctrl + Scroll", "project.zoomScrollLabel": "Scroll", "project.selectionMode": "Selection Mode", "project.selectClick": "Click to select nodes", "project.selectAlt": "Hold Alt and drag to select", "project.selectShift": "Hold Shift and drag to select", "project.selectClickLabel": "Click", "project.selectAltLabel": "Alt + Drag", "project.selectShiftLabel": "Shift + Drag", "project.validating": "Validating...", "project.errorOpenDir": "Failed to open directory picker", "project.errorOpenDirWithReason": "Failed to open directory picker: {error}", "project.errorNameRequired": "Project name is required", "project.errorDirectoryRequired": "Project directory is required", "project.errorChooseLocalFolder": "Choose a local folder from this browser so the project is saved on this device.", "project.errorAbsolutePath": "Project directory must be an absolute path (starting with /, a drive letter, or a UNC path)", "project.errorNotDirectory": "Project path is not a directory", "project.errorValidateDir": "Failed to validate directory: {error}", "modelSearch.search": "Search models...", "modelSearch.allProviders": "All Providers", "modelSearch.all": "All", "modelSearch.allTypes": "All Types", "modelSearch.image": "Image", "modelSearch.video": "Video", "modelSearch.audio": "Audio", "modelSearch.refresh": "Refresh models & schemas", "modelSearch.loading": "Loading models...", "modelSearch.tryAgain": "Try Again", "modelSearch.removeFallback": "Remove fallback", "modelSearch.clearSelection": "Clear current selection", "modelSearch.noModels": "No models found", "modelSearch.adjustFilters": "Try adjusting your search or filters", "modelSearch.recent": "Recently Used", "promptWorkflow.title": "Prompt a Workflow", "promptWorkflow.describe": "Describe your workflow", "promptWorkflow.placeholder": "e.g., Create product photography with consistent lighting and style from reference images...", "promptWorkflow.help": "Describe what you want your workflow to accomplish. Be specific about inputs, outputs, and any transformations.", "promptWorkflow.note": "Note: This feature currently only works with Gemini models.", "promptWorkflow.generating": "Generating...", "promptWorkflow.generate": "Generate Workflow", "promptWorkflow.dismiss": "Dismiss", "promptWorkflow.validation": "Please describe your workflow (at least 3 characters)", "promptWorkflow.failed": "Failed to generate workflow", "workflowBrowser.noWorkflows": "No workflows found", "workflowBrowser.noWorkflowsDesc": "This folder doesn't contain any workflow projects", "workflowBrowser.title": "Your Workflows", "workflowBrowser.chooseFolderDesc": "Choose the folder that contains your workflow projects. You can change this later.", "workflowBrowser.chooseFolder": "Choose folder", "workflowBrowser.projectCount": "{count} projects", "workflowBrowser.openFromDirectory": "Open from directory", "workflowBrowser.changeFolder": "Change folder", "workflowBrowser.justNow": "just now", "workflowBrowser.minutesAgo": "{count}m ago", "workflowBrowser.hoursAgo": "{count}h ago", "workflowBrowser.daysAgo": "{count}d ago", "workflowBrowser.monthsAgo": "{count}mo ago", "workflowBrowser.errorNoWorkflows": "No workflows found in this folder", "workflowBrowser.errorList": "Failed to list workflows", "workflowBrowser.errorFetch": "Failed to fetch workflows", "multiSelect.stackHorizontal": "Stack horizontally (H)", "multiSelect.stackVertical": "Stack vertically (V)", "multiSelect.arrangeGrid": "Arrange as grid (G)", "multiSelect.removeGroup": "Remove from group", "multiSelect.createGroup": "Create group", "multiSelect.downloadZip": "Download images as ZIP", "cost.viewDetails": "View cost details", }; const zhCN: Dictionary = { ...en, "language.label": "语言", "common.back": "返回", "common.next": "下一步", "common.cancel": "取消", "common.close": "关闭", "common.save": "保存", "common.create": "创建", "common.browse": "浏览", "common.change": "更改", "common.clear": "清除", "common.select": "选择", "common.selectModel": "选择模型", "common.skip": "跳过", "common.show": "显示", "common.hide": "隐藏", "common.override": "覆盖", "common.configuredViaEnv": "已通过 .env 配置", "common.recommended": "推荐", "common.optional": "可选", "common.required": "必填", "common.download": "下载", "common.remove": "移除", "common.disconnect": "断开连接", "common.play": "播放", "common.pause": "暂停", "common.set": "设置", "common.previous": "上一个", "common.nextItem": "下一个", "common.processing": "处理中...", "error.providerOverloaded": "{model}:服务商暂时过载。请稍后重试,或切换到其他模型。", "node.optionalTitle": "此输入为可选,空输入会被跳过", "node.markOptionalTitle": "标记为可选,空输入会跳过这个分支", "header.openWelcome": "打开欢迎页", "header.untitled": "未命名", "header.saving": "保存中...", "header.savedAt": "已保存 {time}", "header.notSaved": "未保存", "header.saveProject": "保存项目", "header.configureSaveLocation": "配置保存位置", "header.openProject": "打开项目", "header.openProjectFolder": "打开项目文件夹", "header.projectSettings": "项目设置", "header.revertAIChanges": "还原 AI 改动", "header.revertAIChangesTitle": "恢复到 AI 改动前的工作流", "header.revertConfirm": "确定吗?这会恢复到之前的工作流。", "header.shortcuts": "快捷键 (?)", "header.support": "支持", "header.commentsTitle": "{unviewed} 条未读评论(共 {total} 条)", "header.openFolderFailed": "打开项目文件夹失败:{error}", "header.openFolderFailedRetry": "打开项目文件夹失败,请重试。", "header.saveFailedRetry": "保存项目失败,请重试。", "quickstart.description": "一个面向生成式 AI 流水线的节点式工作流编辑器。连接节点即可构建生成与转换图片、视频、音频和 3D 资产的流程。", "quickstart.docs": "文档", "quickstart.waitlist": "NB Pro 候补名单", "quickstart.newProject": "新建项目", "quickstart.newProjectDesc": "开始新的工作流", "quickstart.loadWorkflow": "加载工作流", "quickstart.loadWorkflowDesc": "打开已有文件", "quickstart.templates": "模板", "quickstart.templatesDesc": "预置工作流", "quickstart.promptWorkflow": "用提示生成工作流", "quickstart.promptWorkflowDesc": "让 Gemini 帮你构建", "quickstart.beta": "测试版", "quickstart.templateExplorerTitle": "模板浏览器", "quickstart.workflowTemplatesTitle": "工作流模板", "quickstart.templatesIntro": "使用预置工作流快速开始。选择一个模板即可加载到画布。", "quickstart.quickStart": "快速开始", "quickstart.searchTemplates": "搜索模板", "quickstart.searchTemplatesPlaceholder": "搜索模板...", "quickstart.category": "分类", "quickstart.provider": "服务商", "quickstart.filterAll": "全部", "quickstart.categorySimple": "简单", "quickstart.categoryAdvanced": "高级", "quickstart.clearFilters": "清除筛选", "quickstart.clearAllFilters": "清除全部筛选", "quickstart.noTemplatesMatch": "没有匹配的模板", "quickstart.adjustSearchFilters": "尝试调整搜索或筛选条件", "quickstart.useWorkflow": "使用工作流", "quickstart.loading": "加载中...", "quickstart.nodeCount": "{count} 个节点", "quickstart.dismiss": "关闭", "quickstart.loadTemplateFailed": "加载模板失败", "quickstart.template.productShot.name": "产品图", "quickstart.template.productShot.description": "将产品放入新的场景或环境", "quickstart.template.modelProduct.name": "模特 + 产品", "quickstart.template.modelProduct.description": "组合模特、产品和场景", "quickstart.template.colorVariations.name": "颜色变体", "quickstart.template.colorVariations.description": "基于参考图生成产品配色变体", "quickstart.template.backgroundSwap.name": "替换背景", "quickstart.template.backgroundSwap.description": "将主体放入新的背景", "quickstart.template.styleTransfer.name": "风格迁移", "quickstart.template.styleTransfer.description": "将一张图的风格应用到另一张图", "quickstart.template.sceneComposite.name": "场景合成", "quickstart.template.sceneComposite.description": "组合多个场景中的元素", "ftux.welcomeTo": "欢迎使用 popiart-node", "ftux.stepWelcome": "欢迎", "ftux.stepApiKeys": "API 密钥", "ftux.stepModelDefaults": "模型默认值", "ftux.stepReady": "就绪", "ftux.getStarted": "开始使用", "ftux.skipSetup": "跳过设置?", "ftux.skipSetupDesc": "稍后可在设置中配置 API 密钥和模型默认值。", "ftux.welcomeTitle": "开始吧。", "ftux.welcomeDesc": "像搭积木一样连接 AI 模型,生成图片、视频等内容。", "ftux.apiKeysTitle": "API 密钥", "ftux.apiKeysDesc": "在这里添加密钥以使用 AI 服务商(存储在浏览器),也可以写入 .env 文件以获得更好的安全性和持久性。", "ftux.getApiKey": "获取 {provider} API 密钥", "ftux.getApiKeyTip": "获取 API 密钥", "ftux.llmOnlyTip": "仅用于 LLM 节点", "ftux.enterKey": "输入密钥...", "ftux.modelsTitle": "选择你的模型", "ftux.modelsDesc": "选择图片和视频的默认 AI 模型,之后可以随时更改。", "ftux.defaultImageModel": "默认图片模型", "ftux.defaultVideoModel": "默认视频模型", "ftux.noneSet": "未设置", "ftux.readyTitle": "准备好了!", "ftux.readyDesc": "要快速看一遍教程吗?", "ftux.startTutorial": "开始教程", "ftux.tutorial.welcome": "我们先快速了解基础操作。", "ftux.tutorial.addImage": "点击“图片”按钮,添加一个图片节点。", "ftux.tutorial.explainNode": "这是一个节点。每个节点都有特定功能。\n\n这个节点用于添加图片。", "ftux.tutorial.explainNodeInputs": "输入端口始终在节点左侧。", "ftux.tutorial.explainNodeOutputs": "输出端口始终在节点右侧。", "ftux.tutorial.dragAndDrop": "现在从输出端口拖拽,并释放到画布空白处。", "ftux.tutorial.selectGenerateImage": "这个菜单会显示该节点可连接的所有节点。\n\n选择“生成图片”,添加一个 AI 图片生成节点。", "ftux.tutorial.addPromptNode": "点击“提示词”按钮,添加一个提示词节点。", "ftux.tutorial.connectPromptToGenerate": "从提示词节点的输出端口拖到生成图片节点的输入端口。", "ftux.tutorial.populateContent": "我来帮你填充一些示例内容 🎨", "ftux.tutorial.explainGenerateNode": "这是生成图片节点。它会根据提示词和参考图,用 AI 创建或修改图片。", "ftux.tutorial.explainRunButton": "点击这个“运行”按钮会执行工作流。你也可以按 Cmd+Enter(Windows 上为 Ctrl+Enter)。", "ftux.tutorial.explainRunOptions": "你也可以点击下拉菜单,从指定节点开始运行,或只运行选中的节点。", "ftux.tutorial.runWorkflow": "现在运行你的工作流!点击“运行”按钮生成图片。", "ftux.tutorial.demonstrateDownstream": "现在看看还能继续做什么... 🎬✨", "ftux.tutorial.demonstrateComplete": "继续向下游连接更多节点来构建生成式流水线,也可以把它当作无限创意画布使用。", "ftux.tutorial.saveProject": "保存项目后,你的工作和生成结果都会保存在本地。", "ftux.tutorial.resources": "下面这些资源可以提供帮助和灵感:", "ftux.tutorial.discord": "加入我们的 Discord 社区", "ftux.tutorial.complete": "全部设置好了!开始创作吧。", "ftux.tutorial.clickToContinue": "点击任意位置继续", "ftux.tutorial.skip": "跳过教程", "toolbar.categoryInput": "输入", "toolbar.categoryText": "文本", "toolbar.categoryGenerate": "生成", "toolbar.categoryProcess": "处理", "toolbar.categoryRoute": "路由", "toolbar.categoryOutput": "输出", "toolbar.image": "图片", "toolbar.video": "视频", "toolbar.prompt": "提示词", "toolbar.generate": "生成", "toolbar.output": "输出", "toolbar.allNodes": "所有节点", "toolbar.allModels": "所有模型", "toolbar.browseModels": "浏览模型", "toolbar.switchConnectors": "切换为{style}连线", "toolbar.curved": "曲线", "toolbar.angular": "折线", "toolbar.run": "运行", "toolbar.stop": "停止", "toolbar.running": "运行中...", "toolbar.runningNode": "正在运行 {node}...", "toolbar.runningNodes": "正在运行 {count} 个节点...", "toolbar.nodesCount": "{count} 个节点", "toolbar.runOptions": "运行选项", "toolbar.runEntire": "运行整个工作流", "toolbar.runFromSelected": "从选中节点开始运行", "toolbar.runSelectedOnly": "仅运行选中节点", "toolbar.runSelectedNodes": "运行选中节点", "toolbar.runSelectedNodesCount": "运行 {count} 个选中节点", "toolbar.selectSingleNode": "请先选择一个节点", "toolbar.selectOneOrMoreNodes": "请先选择一个或多个节点", "node.imageInput": "图片输入", "node.audioInput": "音频输入", "node.videoInput": "视频输入", "node.glbViewer": "3D 查看器", "node.prompt": "提示词", "node.promptConstructor": "提示词构造器", "node.array": "数组", "node.generateImage": "生成图片", "node.generateVideo": "生成视频", "node.generate3d": "生成 3D", "node.generateAudio": "生成音频", "node.llmGenerate": "LLM 生成", "node.annotation": "标注", "annotation.tool.select": "选择", "annotation.tool.rectangle": "矩形", "annotation.tool.circle": "圆形", "annotation.tool.arrow": "箭头", "annotation.tool.draw": "画笔", "annotation.tool.text": "文字", "annotation.undo": "撤销", "annotation.redo": "重做", "annotation.clear": "清空", "annotation.cancel": "取消", "annotation.done": "完成", "annotation.color": "颜色", "annotation.size": "大小", "annotation.fill": "填充", "node.splitGrid": "拆分网格", "node.videoStitch": "视频拼接", "node.videoTrim": "视频裁剪", "node.easeCurve": "缓动曲线", "node.frameGrab": "抓取帧", "node.imageCompare": "图片对比", "imageCompare.connectTwo": "连接 2 张图片进行对比", "imageCompare.connectAnother": "再连接一张图片进行对比", "imageCompare.imageAConnected": "图片 A 已连接", "imageCompare.imageBConnected": "图片 B 已连接", "imageCompare.imageAAlt": "图片 A", "imageCompare.imageBAlt": "图片 B", "upload.imageUnsupported": "格式不支持。请使用 PNG、JPG 或 WebP。", "upload.imageTooLarge": "图片过大。最大支持 10MB。", "upload.videoUnsupported": "格式不支持。请使用 MP4、WebM 或 QuickTime 视频文件。", "upload.videoTooLarge": "视频文件过大。最大支持 200MB。", "upload.audioUnsupported": "格式不支持。请使用 MP3、WAV、OGG、AAC 或其他音频格式。", "upload.audioTooLarge": "音频文件过大。最大支持 50MB。", "imageInput.uploadedAlt": "已上传图片", "imageInput.download": "下载图片", "imageInput.remove": "移除图片", "videoInput.upload": "上传视频文件", "videoInput.dropVideo": "拖入视频或点击", "videoInput.download": "下载视频", "videoInput.remove": "移除视频", "audioInput.upload": "上传音频文件", "audioInput.dropAudio": "拖入音频或点击", "audioInput.download": "下载音频", "audioInput.remove": "移除音频", "audioInput.clear": "清除音频", "audioInput.loadingWaveform": "正在加载波形...", "generateAudio.fallbackUsed": "已使用备用模型", "generateAudio.fallbackUsedTitle": "主模型失败:{error}\n已使用备用模型:{model}", "generateAudio.generating": "正在生成音频...", "annotation.noImage": "没有可用图片。请连接图片或手动加载一张。", "annotation.annotatedAlt": "已标注图片", "annotation.downloadImage": "下载图片", "annotation.removeImage": "移除图片", "annotation.editCount": "编辑({count})", "annotation.addAnnotations": "添加标注", "annotation.dropClickConnect": "拖入、点击或连接", "array.split": "拆分", "array.delimiter": "分隔符", "array.newline": "换行", "array.regexAdvanced": "正则(高级)", "array.batch": "批量", "array.batchModeTitle": "批量模式:所有条目发送到同一个下游节点", "array.enableBatchMode": "启用批量模式", "array.autoRouteToPrompts": "自动路由到提示词", "array.by": "按", "array.advanced": "高级", "array.trim": "去除空白", "array.removeEmpty": "移除空项", "array.parsedItems": "解析条目({count})", "array.noItemsParsed": "尚未解析出条目", "array.selectedForNextConnection": "已选为下一条连接输出(点击取消)", "array.selectForNextConnection": "点击选择为下一条连接输出", "array.batchFooter": "批量:所有条目发送到下游节点", "array.nextWireUsesItem": "下一条连线使用第 {index} 条", "array.noSelection": "未选择:连线会从第 1 条开始依次使用", "videoCommon.encoderUnsupported": "当前浏览器不支持视频编码。", "videoCommon.encoderHelp": "看起来不对?请在 Discord 联系 Willie。", "videoCommon.checkingEncoder": "正在检查编码器...", "videoCommon.processingPercent": "处理中... {progress}%", "videoTrim.videoIn": "视频输入", "videoTrim.videoOut": "视频输出", "videoTrim.connectVideo": "连接一个视频进行裁剪", "videoTrim.source": "源视频", "videoTrim.trimmed": "已裁剪", "videoTrim.clearTrimmedVideo": "清除裁剪后视频", "videoTrim.start": "开始", "videoTrim.end": "结束", "videoTrim.duration": "时长", "videoTrim.trimStartTime": "裁剪开始时间", "videoTrim.trimEndTime": "裁剪结束时间", "videoTrim.setStartToCurrent": "将开始时间设为当前播放时间", "videoTrim.setEndToCurrent": "将结束时间设为当前播放时间", "videoTrim.trim": "裁剪", "videoStitch.videoInput": "视频 {index}", "videoStitch.audioInput": "音频", "videoStitch.output": "输出", "videoStitch.connectVideos": "连接视频进行拼接", "videoStitch.clipAlt": "片段 {id}", "videoStitch.clearVideo": "清除视频", "videoStitch.loop": "循环", "videoStitch.stitch": "拼接", "multiAngle.editorTitle": "多角度编辑器", "multiAngle.imageEditorTitle": "图片多角度编辑器", "multiAngle.imageTitle": "图片多角度", "multiAngle.closeEditor": "关闭多角度编辑器", "multiAngle.generate": "生成多角度", "multiAngle.noImageToast": "未找到可用图片,无法生成多角度图片", "multiAngle.sightControl": "多角度视线控制", "multiAngle.noImage": "无图片", "multiAngle.horizontal": "水平环绕", "multiAngle.vertical": "垂直俯仰", "multiAngle.zoom": "景别缩放", "multiAngle.prompt": "提示词", "multiAngle.enableCustomPrompt": "开启自定义提示词", "multiAngle.promptDialog": "多角度提示词", "multiAngle.promptInput": "多角度提示词输入", "multiAngle.promptPlaceholder": "输入提示词...", "multiAngle.reset": "重置参数", "multiAngle.resetAria": "重置多角度参数", "multiAngle.adjustVerticalUp": "向上调整垂直俯仰", "multiAngle.adjustVerticalDown": "向下调整垂直俯仰", "multiAngle.adjustHorizontalLeft": "向左调整水平环绕", "multiAngle.adjustHorizontalRight": "向右调整水平环绕", "multiAngle.preset.custom": "自定义", "multiAngle.preset.fisheye": "鱼眼视角", "multiAngle.preset.tilt": "倾斜视角", "multiAngle.preset.frontOverhead": "正面俯拍", "multiAngle.preset.frontLow": "正面仰拍", "multiAngle.preset.panoramicOverhead": "全景俯拍", "multiAngle.preset.back": "背面视角", "multiAngle.zoom.wide": "全景", "multiAngle.zoom.medium": "中景", "multiAngle.zoom.close": "特写", "workflow.splitGrid.noImage": "没有可拆分的图片。请先生成或加载一张图片。", "workflow.splitGrid.detectFailed": "无法识别图片网格。", "workflow.splitGrid.failed": "拆分图片网格失败:{error}", "workflow.generatedSuccess": "工作流生成成功", "workflow.generatedFailed": "生成工作流失败", "workflow.generatedFailedRetry": "生成工作流失败,请重试。", "workflow.appliedEdits": "已应用 {count} 个编辑", "chat.title": "画布助手", "chat.beta": "测试版", "chat.clear": "清空对话", "chat.close": "关闭对话", "chat.dismiss": "关闭", "chat.emptyTitle": "可以询问当前画布,也可以让我准备修改。", "chat.diagnoseSelected": "诊断选中节点", "chat.makeVariants": "生成变体", "chat.promptDiagnose": "诊断选中的节点,并给出最小可用修复建议。", "chat.promptVariants": "准备一组编辑:基于选中的图片或生成节点创建四个视觉变体。", "chat.proposalReady": "修改方案已准备", "chat.candidateReady": "候选工作流已准备好应用。", "chat.runReady": "运行操作已准备好应用。", "chat.candidateWorkflow": "候选工作流", "chat.applyWorkflow": "应用工作流", "chat.operationPreview": "操作预览", "chat.applyEdits": "应用编辑", "chat.runPreview": "运行预览", "chat.runNow": "立即运行", "chat.focusedNodes": "聚焦 {count} 个选中节点", "chat.runSelected": "运行选中", "chat.runAffected": "运行影响范围({count})", "chat.placeholder": "输入消息...", "chat.building": "正在构建...", "chat.buildWorkflow": "构建工作流", "chat.open": "助手", "chat.noSelection": "请先选择一个或多个节点。", "workflow.invalidWorkflowFile": "工作流文件格式无效", "workflow.parseWorkflowFileFailed": "解析工作流文件失败", "splitGridNode.sourceGridAlt": "源网格", "splitGridNode.connectImage": "连接图片", "splitGridNode.gridSummary": "{rows}x{cols} 网格({count} 张图片)", "splitGridNode.generateSetsCreated": "已创建 {count} 组生成节点", "splitGridNode.notConfigured": "未配置 - 点击设置", "splitGridNode.configureFirst": "请先配置节点", "splitGridNode.connectImageFirst": "请先连接图片", "splitGridNode.splitGrid": "拆分网格", "splitGridNode.split": "拆分", "node.router": "路由器", "node.switch": "开关", "node.conditionalSwitch": "条件开关", "node.output": "输出", "node.outputGallery": "输出画廊", "output.downloadCurrent": "下载当前{type}", "output.downloadAll": "下载全部输出", "node.settings": "设置", "node.runToGenerate": "运行以生成", "node.selectModel": "选择模型...", "node.primary": "主模型", "node.text": "文本", "node.image": "图片", "node.notUsedByModel": "此模型不使用", "node.generationFailed": "生成失败", "node.videoGenerationFailed": "视频生成失败", "node.loadingParameters": "正在加载参数...", "node.noParameters": "无可用参数", "node.default": "默认", "node.model": "模型", "node.size": "尺寸", "node.quality": "质量", "node.voice": "声音", "node.sound": "声音", "node.duration": "时长", "node.seconds": "{count}秒", "node.aspectRatio": "宽高比", "node.resolution": "分辨率", "node.googleSearch": "Google 搜索", "node.imageSearch": "图片搜索", "node.provider": "服务商", "node.temperature": "温度:{value}", "node.maxTokens": "最大 Token:{value}", "node.generic": "节点", "splitGridSettings.title": "拆分网格设置", "splitGridSettings.gridLayout": "网格布局", "splitGridSettings.gridSummary": "网格将拆分为 {rows}x{cols} = {count} 张图片", "splitGridSettings.defaultPrompt": "默认提示词", "splitGridSettings.promptPlaceholder": "输入将应用到所有生成图片的提示词...", "splitGridSettings.promptHelp": "创建后,每个提示词节点都可以单独编辑", "splitGridSettings.generateNodeSettings": "生成节点设置", "splitGridSettings.createGenerateSets": "创建 {count} 组生成节点", "imageInput.upload": "上传图片", "imageInput.dropImage": "拖入图片", "dropOverlay.workflow": "拖入以加载工作流", "dropOverlay.node": "拖入以创建节点", "dropOverlay.audio": "拖入音频以创建节点", "dropOverlay.image": "拖入图片以创建节点", "dropOverlay.splittingImageGrid": "正在拆分图片网格...", "connectionMenu.addNode": "添加 {type} 节点", "connectionMenu.type.image": "图片", "connectionMenu.type.text": "文本", "connectionMenu.type.audio": "音频", "connectionMenu.type.video": "视频", "connectionMenu.type.3d": "3D", "connectionMenu.type.easeCurve": "设置", "connectionMenu.splitGridNode": "拆分网格节点", "connectionMenu.splitGridNow": "立即拆分网格", "connectionMenu.multiAngleImage": "图片多角度", "connectionMenu.navigate": "导航", "connectionMenu.select": "选择", "prompt.placeholder": "描述你想生成的内容...", "prompt.connectedPlaceholder": "来自连接节点的文本(可编辑)...", "prompt.optionalPlaceholder": "可选提示词(留空则跳过)...", "prompt.addVariable": "添加变量", "prompt.setVariableName": "设置变量名", "prompt.variableHelp": "将此提示词作为 PromptConstructor 节点中的变量使用", "prompt.variableName": "变量名", "prompt.variablePlaceholder": "例如 color、style、subject", "prompt.preview": "预览:{value}", "composer.promptProvidedByUpstream": "提示词由上游文本节点提供。", "composer.videoStitchClipCount": "{count} 个视频片段", "composer.videoStitchAudio": "已连接音频", "composer.videoStitchNoAudio": "无音频", "composer.videoStitchInputs": "视频输入", "composer.videoStitchInputHint": "在节点上调整片段顺序", "composer.videoStitchNeedTwo": "至少连接 2 个视频片段才能拼接。", "composer.videoStitchClip": "片段 {index}", "composer.videoStitchLoop": "循环", "composer.videoStitchOutputReady": "输出已就绪", "composer.videoStitchNoOutput": "尚未输出", "composer.videoStitchReady": "当前节点可拼接", "composer.videoStitchRun": "拼接当前视频节点", "composer.easeCurveVideoConnected": "已连接视频", "composer.easeCurveNoVideo": "连接一个视频输入后可应用缓动曲线。", "composer.easeCurveInherited": "继承设置", "composer.easeCurveLocal": "本地设置", "composer.easeCurveSettings": "曲线设置", "composer.easeCurvePreset": "预设", "composer.easeCurveCustom": "自定义贝塞尔", "composer.easeCurveHandles": "贝塞尔控制点", "composer.easeCurveInput": "输入", "composer.easeCurveDuration": "输出时长", "composer.easeCurveOutputReady": "输出已就绪", "composer.easeCurveNoOutput": "尚未输出", "composer.easeCurveReady": "当前曲线可应用", "composer.easeCurveRun": "应用当前缓动曲线节点", "composer.selectModel": "选择模型", "composer.chooseModelTitle": "选择生成模型", "composer.chooseImageModel": "选择图像模型", "composer.chooseVideoModel": "选择视频模型", "composer.chooseAudioModel": "选择声音模型", "composer.regenerateImageNode": "重新生成当前图片节点", "composer.regenerateVideoNode": "重新生成当前视频节点", "composer.regenerateAudioNode": "重新生成当前音频节点", "composer.imageNode": "图片节点", "composer.videoNode": "视频节点", "composer.audioNode": "声音节点", "composer.imageCount": "生成张数", "composer.imageCountOption": "{count}张", "composer.newGeneration": "新建生成", "composer.selectedNodes": "已选择 {count} 个节点", "composer.currentNode": "当前节点", "composer.createAndGenerate": "创建并生成", "composer.dragFromPort": "从节点端口拖拽以创建下一步", "composer.multiSelectNoSingleGenerate": "多选暂不支持单节点生成", "composer.retryCurrentNode": "重试当前节点", "composer.generate": "生成", "composer.describeContent": "描述你想生成的内容", "composer.mainPlaceholder": "描述你想生成的内容,按 / 呼出指令,@ 引用素材", "composer.uploadReferenceImage": "上传参考图片", "composer.expand": "展开底部栏", "composer.collapse": "收起底部栏", "composer.console": "控制台", "composer.style": "风格", "composer.mark": "标记", "composer.focus": "聚焦", "composer.addReferenceImage": "添加参考图片", "composer.referenceFromUpstream": "参考图片来自上游连接", "composer.reference": "参考", "composer.referenceImage": "参考图片 {index}", "composer.removeReferenceImage": "移除参考图片 {index}", "composer.commands": "指令", "composer.referenceMaterials": "引用素材", "composer.commandCharacter": "生成角色图", "composer.commandCharacterValue": "生成角色图,保持造型统一,画面清晰。", "composer.commandTurnaround": "生成三视图", "composer.commandTurnaroundValue": "生成角色三视图,包含正面、侧面、背面。", "composer.commandVideoShot": "转视频镜头", "composer.commandVideoShotValue": "将当前画面转成短视频镜头,动作自然。", "composer.currentReference": "当前引用素材", "composer.canvasAssets": "画布素材", "composer.multiSelectUnsupported": "已选择 {count} 个节点。当前版本暂不支持批量编辑。", "composer.unsupportedNodeHint": "下一步需要从节点端口拖拽创建,底部框只编辑当前选中的生成节点。", "composer.videoSchemaHint": "视频参数随模型 schema 生效", "composer.translate": "翻译", "composer.settings": "设置", "composer.selectModelTitle": "选择模型:{model}", "shortcuts.title": "快捷键", "shortcuts.general": "通用", "shortcuts.addNodes": "添加节点", "shortcuts.layout": "布局(先选择 2 个以上节点)", "shortcuts.canvas": "画布", "shortcuts.runWorkflow": "运行工作流", "shortcuts.copyNodes": "复制选中节点", "shortcuts.paste": "粘贴节点 / 图片 / 文本", "shortcuts.undo": "撤销", "shortcuts.redo": "重做", "shortcuts.showShortcuts": "显示快捷键", "shortcuts.addPrompt": "添加提示词节点", "shortcuts.addImage": "添加图片输入节点", "shortcuts.addGenerateImage": "添加图片生成节点", "shortcuts.addGenerateVideo": "添加视频生成节点", "shortcuts.addLLM": "添加 LLM 文本节点", "shortcuts.addAnnotation": "添加标注节点", "shortcuts.addAudio": "添加音频节点", "shortcuts.addVideoInput": "添加视频输入节点", "shortcuts.addArray": "添加数组节点", "shortcuts.stackVertical": "垂直排列选中节点", "shortcuts.stackHorizontal": "水平排列选中节点", "shortcuts.arrangeGrid": "将选中节点排成网格", "shortcuts.zoom": "放大 / 缩小", "shortcuts.pan": "平移(macOS)", "shortcuts.delete": "删除选中节点", "project.newProject": "新建项目", "project.settings": "项目设置", "project.tabProject": "项目", "project.tabProviders": "服务商", "project.tabNodeDefaults": "节点默认值", "project.tabCanvas": "画布", "project.name": "项目名称", "project.directory": "项目目录", "project.localFolderPlaceholder": "选择这台设备上的本地文件夹", "project.directoryHelp": "工作流文件和图片会保存在这里,并自动创建 inputs 与 generations 子文件夹。", "project.embedImages": "将图片嵌入为 base64", "project.embedImagesDesc": "把所有图片嵌入工作流文件,文件会变大;超大工作流可能触达内存限制。", "project.inlineSettings": "在节点上显示模型设置", "project.inlineSettingsDesc": "在生成节点内部显示模型参数,而不是侧边面板", "project.envHelp": "建议通过 .env.local 添加 API 密钥以提升安全性;这里添加的密钥会覆盖 .env,并存储在浏览器中。", "project.newapiwgDesc": "Popi 统一模型网关", "project.baseUrl": "Base URL", "project.systemImageDefault": "系统默认(Popi Models)", "project.noneSetFirstUse": "未设置(首次使用时选择)", "project.defaultLLM": "默认 LLM 设置", "project.systemLLMDefault": "使用系统默认值(Popi Models Doubao Seed 2.0 Lite)", "project.provider": "服务商", "project.model": "模型", "project.temp": "温度:{value}", "project.tokens": "Token:{value}", "project.executionSettings": "执行设置", "project.maxParallel": "最大并行调用:{count}", "project.executionHelp": "工作流执行时最多并行运行的节点数量。数值更高可能更快,但也更容易触发 API 限流。", "project.defaultsHelp": "这些默认值会在通过快捷键创建节点时应用(Shift+G、Shift+L 等)。", "project.canvasHelp": "配置画布导航和交互方式。", "project.canvasAssistant": "画布助手", "project.canvasAssistantShort": "助手", "project.panMode": "平移模式", "project.panSpace": "按住 Space 并拖拽平移", "project.panMiddle": "按住鼠标中键并拖拽", "project.panAlways": "无需按键即可平移", "project.panSpaceLabel": "Space + 拖拽", "project.panMiddleLabel": "鼠标中键", "project.panAlwaysLabel": "始终开启", "project.zoomMode": "缩放模式", "project.zoomAlt": "按住 Alt 并滚动缩放", "project.zoomCtrl": "按住 Ctrl/Cmd 并滚动缩放", "project.zoomScroll": "直接滚动缩放", "project.zoomAltLabel": "Alt + 滚动", "project.zoomCtrlLabel": "Ctrl + 滚动", "project.zoomScrollLabel": "滚动", "project.selectionMode": "选择模式", "project.selectClick": "点击选择节点", "project.selectAlt": "按住 Alt 并拖拽选择", "project.selectShift": "按住 Shift 并拖拽选择", "project.selectClickLabel": "点击", "project.selectAltLabel": "Alt + 拖拽", "project.selectShiftLabel": "Shift + 拖拽", "project.validating": "验证中...", "project.errorOpenDir": "打开目录选择器失败", "project.errorOpenDirWithReason": "打开目录选择器失败:{error}", "project.errorNameRequired": "项目名称必填", "project.errorDirectoryRequired": "项目目录必填", "project.errorChooseLocalFolder": "请从浏览器选择本地文件夹,这样项目会保存在当前操作者的设备上。", "project.errorAbsolutePath": "项目目录必须是绝对路径(以 /、盘符或 UNC 路径开头)", "project.errorNotDirectory": "项目路径不是目录", "project.errorValidateDir": "验证目录失败:{error}", "modelSearch.search": "搜索模型...", "modelSearch.allProviders": "所有服务商", "modelSearch.all": "全部", "modelSearch.allTypes": "所有类型", "modelSearch.image": "图片", "modelSearch.video": "视频", "modelSearch.audio": "音频", "modelSearch.refresh": "刷新模型和参数", "modelSearch.loading": "正在加载模型...", "modelSearch.tryAgain": "重试", "modelSearch.removeFallback": "移除备用模型", "modelSearch.clearSelection": "清除当前选择", "modelSearch.noModels": "未找到模型", "modelSearch.adjustFilters": "尝试调整搜索或筛选条件", "modelSearch.recent": "最近使用", "promptWorkflow.title": "用提示生成工作流", "promptWorkflow.describe": "描述你的工作流", "promptWorkflow.placeholder": "例如:基于参考图创建光照和风格一致的产品摄影...", "promptWorkflow.help": "描述你希望工作流完成什么。请具体说明输入、输出和任何转换步骤。", "promptWorkflow.note": "注意:此功能目前仅适用于 Gemini 模型。", "promptWorkflow.generating": "生成中...", "promptWorkflow.generate": "生成工作流", "promptWorkflow.dismiss": "关闭提示", "promptWorkflow.validation": "请描述你的工作流(至少 3 个字符)", "promptWorkflow.failed": "生成工作流失败", "workflowBrowser.noWorkflows": "未找到工作流", "workflowBrowser.noWorkflowsDesc": "此文件夹不包含任何工作流项目", "workflowBrowser.title": "你的工作流", "workflowBrowser.chooseFolderDesc": "选择包含工作流项目的文件夹。你可以稍后再更改。", "workflowBrowser.chooseFolder": "选择文件夹", "workflowBrowser.projectCount": "{count} 个项目", "workflowBrowser.openFromDirectory": "从目录打开", "workflowBrowser.changeFolder": "更改文件夹", "workflowBrowser.justNow": "刚刚", "workflowBrowser.minutesAgo": "{count} 分钟前", "workflowBrowser.hoursAgo": "{count} 小时前", "workflowBrowser.daysAgo": "{count} 天前", "workflowBrowser.monthsAgo": "{count} 个月前", "workflowBrowser.errorNoWorkflows": "此文件夹中未找到工作流", "workflowBrowser.errorList": "列出工作流失败", "workflowBrowser.errorFetch": "获取工作流失败", "multiSelect.stackHorizontal": "水平排列 (H)", "multiSelect.stackVertical": "垂直排列 (V)", "multiSelect.arrangeGrid": "排列为网格 (G)", "multiSelect.removeGroup": "从分组中移除", "multiSelect.createGroup": "创建分组", "multiSelect.downloadZip": "下载图片 ZIP", "cost.viewDetails": "查看费用详情", }; const zhTW: Dictionary = { ...zhCN, "language.label": "語言", "common.back": "返回", "common.next": "下一步", "common.cancel": "取消", "common.close": "關閉", "common.save": "儲存", "common.create": "建立", "workflowBrowser.title": "你的工作流程", "workflowBrowser.chooseFolderDesc": "選擇包含工作流程專案的資料夾。你可以稍後再變更。", "workflowBrowser.chooseFolder": "選擇資料夾", "workflowBrowser.projectCount": "{count} 個專案", "workflowBrowser.openFromDirectory": "從目錄開啟", "workflowBrowser.changeFolder": "變更資料夾", "workflowBrowser.justNow": "剛剛", "workflowBrowser.minutesAgo": "{count} 分鐘前", "workflowBrowser.hoursAgo": "{count} 小時前", "workflowBrowser.daysAgo": "{count} 天前", "workflowBrowser.monthsAgo": "{count} 個月前", "workflowBrowser.errorNoWorkflows": "此資料夾中找不到工作流程", "workflowBrowser.errorList": "列出工作流程失敗", "workflowBrowser.errorFetch": "取得工作流程失敗", "common.browse": "瀏覽", "common.change": "變更", "common.clear": "清除", "common.select": "選擇", "common.selectModel": "選擇模型", "common.skip": "略過", "common.show": "顯示", "common.hide": "隱藏", "common.override": "覆寫", "common.configuredViaEnv": "已透過 .env 設定", "common.recommended": "推薦", "common.optional": "可選", "common.required": "必填", "common.download": "下載", "common.remove": "移除", "common.disconnect": "斷開連接", "common.play": "播放", "common.pause": "暫停", "common.set": "設定", "common.previous": "上一個", "common.nextItem": "下一個", "common.processing": "處理中...", "error.providerOverloaded": "{model}:服務商暫時過載。請稍後重試,或切換到其他模型。", "node.optionalTitle": "此輸入為可選,空輸入會被略過", "node.markOptionalTitle": "標記為可選,空輸入會略過這個分支", "header.openWelcome": "開啟歡迎頁", "header.untitled": "未命名", "header.saving": "儲存中...", "header.savedAt": "已儲存 {time}", "header.notSaved": "未儲存", "header.saveProject": "儲存專案", "header.configureSaveLocation": "設定儲存位置", "header.openProject": "開啟專案", "header.openProjectFolder": "開啟專案資料夾", "header.projectSettings": "專案設定", "header.revertAIChanges": "還原 AI 變更", "header.revertAIChangesTitle": "恢復到 AI 變更前的工作流程", "header.revertConfirm": "確定嗎?這會恢復先前的工作流程。", "header.shortcuts": "鍵盤快捷鍵 (?)", "header.commentsTitle": "{unviewed} 則未讀評論(共 {total} 則)", "quickstart.description": "一個面向生成式 AI 流程的節點式工作流程編輯器。連接節點即可建立生成與轉換圖片、影片、音訊和 3D 資產的流程。", "quickstart.docs": "文件", "quickstart.waitlist": "NB Pro 候補名單", "quickstart.newProject": "新增專案", "quickstart.newProjectDesc": "開始新的工作流程", "quickstart.loadWorkflow": "載入工作流程", "quickstart.loadWorkflowDesc": "開啟既有檔案", "quickstart.templates": "範本", "quickstart.templatesDesc": "預建工作流程", "quickstart.promptWorkflow": "用提示生成工作流程", "quickstart.promptWorkflowDesc": "讓 Gemini 幫你建立", "quickstart.beta": "測試版", "quickstart.templateExplorerTitle": "範本瀏覽器", "quickstart.workflowTemplatesTitle": "工作流程範本", "quickstart.templatesIntro": "使用預建工作流程快速開始。選擇一個範本即可載入畫布。", "quickstart.quickStart": "快速開始", "quickstart.searchTemplates": "搜尋範本", "quickstart.searchTemplatesPlaceholder": "搜尋範本...", "quickstart.category": "分類", "quickstart.provider": "服務商", "quickstart.filterAll": "全部", "quickstart.categorySimple": "簡單", "quickstart.categoryAdvanced": "進階", "quickstart.clearFilters": "清除篩選", "quickstart.clearAllFilters": "清除全部篩選", "quickstart.noTemplatesMatch": "沒有符合條件的範本", "quickstart.adjustSearchFilters": "嘗試調整搜尋或篩選條件", "quickstart.useWorkflow": "使用工作流程", "quickstart.loading": "載入中...", "quickstart.nodeCount": "{count} 個節點", "quickstart.dismiss": "關閉", "quickstart.loadTemplateFailed": "載入範本失敗", "quickstart.template.productShot.name": "產品圖", "quickstart.template.productShot.description": "將產品放入新的場景或環境", "quickstart.template.modelProduct.name": "模特 + 產品", "quickstart.template.modelProduct.description": "組合模特、產品和場景", "quickstart.template.colorVariations.name": "顏色變體", "quickstart.template.colorVariations.description": "基於參考圖生成產品配色變體", "quickstart.template.backgroundSwap.name": "替換背景", "quickstart.template.backgroundSwap.description": "將主體放入新的背景", "quickstart.template.styleTransfer.name": "風格轉換", "quickstart.template.styleTransfer.description": "將一張圖的風格套用到另一張圖", "quickstart.template.sceneComposite.name": "場景合成", "quickstart.template.sceneComposite.description": "組合多個場景中的元素", "ftux.welcomeTo": "歡迎使用 popiart-node", "ftux.stepApiKeys": "API 金鑰", "ftux.stepModelDefaults": "模型預設值", "ftux.stepReady": "就緒", "ftux.getStarted": "開始使用", "ftux.skipSetup": "略過設定?", "ftux.skipSetupDesc": "稍後可在設定中配置 API 金鑰和模型預設值。", "ftux.welcomeTitle": "開始吧。", "ftux.welcomeDesc": "像積木一樣連接 AI 模型,生成圖片、影片等內容。", "ftux.apiKeysDesc": "在這裡新增金鑰以使用 AI 服務商(儲存在瀏覽器),也可以寫入 .env 檔案以獲得更好的安全性與持久性。", "ftux.enterKey": "輸入金鑰...", "ftux.modelsTitle": "選擇你的模型", "ftux.modelsDesc": "選擇圖片和影片的預設 AI 模型,之後可以隨時變更。", "ftux.defaultImageModel": "預設圖片模型", "ftux.defaultVideoModel": "預設影片模型", "ftux.noneSet": "未設定", "ftux.readyTitle": "準備好了!", "ftux.readyDesc": "要快速看一遍教學嗎?", "ftux.startTutorial": "開始教學", "ftux.tutorial.welcome": "我們先快速了解基本操作。", "ftux.tutorial.addImage": "點擊「圖片」按鈕,新增一個圖片節點。", "ftux.tutorial.explainNode": "這是一個節點。每個節點都有特定功能。\n\n這個節點用於新增圖片。", "ftux.tutorial.explainNodeInputs": "輸入端口一律在節點左側。", "ftux.tutorial.explainNodeOutputs": "輸出端口一律在節點右側。", "ftux.tutorial.dragAndDrop": "現在從輸出端口拖曳,並釋放到畫布空白處。", "ftux.tutorial.selectGenerateImage": "這個選單會顯示該節點可連接的所有節點。\n\n選擇「生成圖片」,新增一個 AI 圖片生成節點。", "ftux.tutorial.addPromptNode": "點擊「提示詞」按鈕,新增一個提示詞節點。", "ftux.tutorial.connectPromptToGenerate": "從提示詞節點的輸出端口拖到生成圖片節點的輸入端口。", "ftux.tutorial.populateContent": "我來幫你填入一些範例內容 🎨", "ftux.tutorial.explainGenerateNode": "這是生成圖片節點。它會根據提示詞和參考圖,用 AI 建立或修改圖片。", "ftux.tutorial.explainRunButton": "點擊這個「執行」按鈕會執行工作流程。你也可以按 Cmd+Enter(Windows 上為 Ctrl+Enter)。", "ftux.tutorial.explainRunOptions": "你也可以點擊下拉選單,從指定節點開始執行,或只執行選中的節點。", "ftux.tutorial.runWorkflow": "現在執行你的工作流程!點擊「執行」按鈕生成圖片。", "ftux.tutorial.demonstrateDownstream": "現在看看還能繼續做什麼... 🎬✨", "ftux.tutorial.demonstrateComplete": "繼續向下游連接更多節點來建立生成式流程,也可以把它當作無限創意畫布使用。", "ftux.tutorial.saveProject": "儲存專案後,你的工作和生成結果都會保存在本機。", "ftux.tutorial.resources": "下面這些資源可以提供幫助和靈感:", "ftux.tutorial.discord": "加入我們的 Discord 社群", "ftux.tutorial.complete": "全部設定好了!開始創作吧。", "ftux.tutorial.clickToContinue": "點擊任意位置繼續", "ftux.tutorial.skip": "略過教學", "toolbar.categoryInput": "輸入", "toolbar.categoryText": "文字", "toolbar.categoryGenerate": "生成", "toolbar.categoryProcess": "處理", "toolbar.categoryRoute": "路由", "toolbar.categoryOutput": "輸出", "toolbar.image": "圖片", "toolbar.video": "影片", "toolbar.prompt": "提示詞", "toolbar.allNodes": "所有節點", "toolbar.allModels": "所有模型", "toolbar.browseModels": "瀏覽模型", "toolbar.switchConnectors": "切換為{style}連線", "toolbar.curved": "曲線", "toolbar.angular": "折線", "toolbar.runningNodes": "正在執行 {count} 個節點...", "toolbar.nodesCount": "{count} 個節點", "toolbar.runEntire": "執行整個工作流程", "toolbar.runFromSelected": "從選中節點開始執行", "toolbar.runSelectedOnly": "僅執行選中節點", "toolbar.runSelectedNodes": "執行選中節點", "toolbar.runSelectedNodesCount": "執行 {count} 個選中節點", "node.imageInput": "圖片輸入", "node.audioInput": "音訊輸入", "node.videoInput": "影片輸入", "node.generateImage": "生成圖片", "node.generateVideo": "生成影片", "node.generateAudio": "生成音訊", "node.annotation": "標註", "annotation.tool.select": "選擇", "annotation.tool.rectangle": "矩形", "annotation.tool.circle": "圓形", "annotation.tool.arrow": "箭頭", "annotation.tool.draw": "繪製", "annotation.tool.text": "文字", "annotation.undo": "復原", "annotation.redo": "重做", "annotation.clear": "清除", "annotation.cancel": "取消", "annotation.done": "完成", "annotation.color": "顏色", "annotation.size": "大小", "annotation.fill": "填充", "node.outputGallery": "輸出圖庫", "imageCompare.connectTwo": "連接 2 張圖片進行對比", "imageCompare.connectAnother": "再連接一張圖片進行對比", "imageCompare.imageAConnected": "圖片 A 已連接", "imageCompare.imageBConnected": "圖片 B 已連接", "imageCompare.imageAAlt": "圖片 A", "imageCompare.imageBAlt": "圖片 B", "upload.imageUnsupported": "格式不支援。請使用 PNG、JPG 或 WebP。", "upload.imageTooLarge": "圖片過大。最大支援 10MB。", "upload.videoUnsupported": "格式不支援。請使用 MP4、WebM 或 QuickTime 影片檔。", "upload.videoTooLarge": "影片檔過大。最大支援 200MB。", "upload.audioUnsupported": "格式不支援。請使用 MP3、WAV、OGG、AAC 或其他音訊格式。", "upload.audioTooLarge": "音訊檔過大。最大支援 50MB。", "imageInput.uploadedAlt": "已上傳圖片", "imageInput.download": "下載圖片", "imageInput.remove": "移除圖片", "videoInput.upload": "上傳影片檔", "videoInput.dropVideo": "拖入影片或點擊", "videoInput.download": "下載影片", "videoInput.remove": "移除影片", "audioInput.upload": "上傳音訊檔", "audioInput.dropAudio": "拖入音訊或點擊", "audioInput.download": "下載音訊", "audioInput.remove": "移除音訊", "audioInput.clear": "清除音訊", "audioInput.loadingWaveform": "正在載入波形...", "generateAudio.fallbackUsed": "已使用備用模型", "generateAudio.fallbackUsedTitle": "主模型失敗:{error}\n已使用備用模型:{model}", "generateAudio.generating": "正在生成音訊...", "annotation.noImage": "沒有可用圖片。請連接圖片或手動載入一張。", "annotation.annotatedAlt": "已標註圖片", "annotation.downloadImage": "下載圖片", "annotation.removeImage": "移除圖片", "annotation.editCount": "編輯({count})", "annotation.addAnnotations": "新增標註", "annotation.dropClickConnect": "拖入、點擊或連接", "array.split": "拆分", "array.delimiter": "分隔符號", "array.newline": "換行", "array.regexAdvanced": "正則(進階)", "array.batch": "批次", "array.batchModeTitle": "批次模式:所有項目傳送到同一個下游節點", "array.enableBatchMode": "啟用批次模式", "array.autoRouteToPrompts": "自動路由到提示詞", "array.by": "依", "array.advanced": "進階", "array.trim": "去除空白", "array.removeEmpty": "移除空項", "array.parsedItems": "解析項目({count})", "array.noItemsParsed": "尚未解析出項目", "array.selectedForNextConnection": "已選為下一條連接輸出(點擊取消)", "array.selectForNextConnection": "點擊選擇為下一條連接輸出", "array.batchFooter": "批次:所有項目傳送到下游節點", "array.nextWireUsesItem": "下一條連線使用第 {index} 項", "array.noSelection": "未選擇:連線會從第 1 項開始依序使用", "videoCommon.encoderUnsupported": "目前瀏覽器不支援影片編碼。", "videoCommon.encoderHelp": "看起來不對?請在 Discord 聯絡 Willie。", "videoCommon.checkingEncoder": "正在檢查編碼器...", "videoCommon.processingPercent": "處理中... {progress}%", "videoTrim.videoIn": "影片輸入", "videoTrim.videoOut": "影片輸出", "videoTrim.connectVideo": "連接一個影片進行裁剪", "videoTrim.source": "來源影片", "videoTrim.trimmed": "已裁剪", "videoTrim.clearTrimmedVideo": "清除裁剪後影片", "videoTrim.start": "開始", "videoTrim.end": "結束", "videoTrim.duration": "時長", "videoTrim.trimStartTime": "裁剪開始時間", "videoTrim.trimEndTime": "裁剪結束時間", "videoTrim.setStartToCurrent": "將開始時間設為目前播放時間", "videoTrim.setEndToCurrent": "將結束時間設為目前播放時間", "videoTrim.trim": "裁剪", "videoStitch.videoInput": "影片 {index}", "videoStitch.audioInput": "音訊", "videoStitch.output": "輸出", "videoStitch.connectVideos": "連接影片進行拼接", "videoStitch.clipAlt": "片段 {id}", "videoStitch.clearVideo": "清除影片", "videoStitch.loop": "循環", "videoStitch.stitch": "拼接", "multiAngle.editorTitle": "多角度編輯器", "multiAngle.imageEditorTitle": "圖片多角度編輯器", "multiAngle.imageTitle": "圖片多角度", "multiAngle.closeEditor": "關閉多角度編輯器", "multiAngle.generate": "生成多角度", "multiAngle.noImageToast": "未找到可用圖片,無法生成多角度圖片", "multiAngle.sightControl": "多角度視線控制", "multiAngle.noImage": "無圖片", "multiAngle.horizontal": "水平環繞", "multiAngle.vertical": "垂直俯仰", "multiAngle.zoom": "景別縮放", "multiAngle.prompt": "提示詞", "multiAngle.enableCustomPrompt": "開啟自訂提示詞", "multiAngle.promptDialog": "多角度提示詞", "multiAngle.promptInput": "多角度提示詞輸入", "multiAngle.promptPlaceholder": "輸入提示詞...", "multiAngle.reset": "重置參數", "multiAngle.resetAria": "重置多角度參數", "multiAngle.adjustVerticalUp": "向上調整垂直俯仰", "multiAngle.adjustVerticalDown": "向下調整垂直俯仰", "multiAngle.adjustHorizontalLeft": "向左調整水平環繞", "multiAngle.adjustHorizontalRight": "向右調整水平環繞", "multiAngle.preset.custom": "自訂", "multiAngle.preset.fisheye": "魚眼視角", "multiAngle.preset.tilt": "傾斜視角", "multiAngle.preset.frontOverhead": "正面俯拍", "multiAngle.preset.frontLow": "正面仰拍", "multiAngle.preset.panoramicOverhead": "全景俯拍", "multiAngle.preset.back": "背面視角", "multiAngle.zoom.wide": "全景", "multiAngle.zoom.medium": "中景", "multiAngle.zoom.close": "特寫", "workflow.splitGrid.noImage": "沒有可拆分的圖片。請先生成或載入一張圖片。", "workflow.splitGrid.detectFailed": "無法識別圖片網格。", "workflow.splitGrid.failed": "拆分圖片網格失敗:{error}", "workflow.generatedSuccess": "工作流程生成成功", "workflow.generatedFailed": "生成工作流程失敗", "workflow.generatedFailedRetry": "生成工作流程失敗,請重試。", "workflow.appliedEdits": "已套用 {count} 個編輯", "chat.title": "畫布助手", "chat.beta": "測試版", "chat.clear": "清空對話", "chat.close": "關閉對話", "chat.dismiss": "關閉", "chat.emptyTitle": "可以詢問目前畫布,也可以讓我準備修改。", "chat.diagnoseSelected": "診斷選中節點", "chat.makeVariants": "生成變體", "chat.promptDiagnose": "診斷選中的節點,並給出最小可用修復建議。", "chat.promptVariants": "準備一組編輯:基於選中的圖片或生成節點建立四個視覺變體。", "chat.proposalReady": "修改方案已準備", "chat.candidateReady": "候選工作流程已準備好套用。", "chat.runReady": "執行操作已準備好套用。", "chat.candidateWorkflow": "候選工作流程", "chat.applyWorkflow": "套用工作流程", "chat.operationPreview": "操作預覽", "chat.applyEdits": "套用編輯", "chat.runPreview": "執行預覽", "chat.runNow": "立即執行", "chat.focusedNodes": "聚焦 {count} 個選中節點", "chat.runSelected": "執行選中", "chat.runAffected": "執行影響範圍({count})", "chat.placeholder": "輸入訊息...", "chat.building": "正在建立...", "chat.buildWorkflow": "建立工作流程", "chat.open": "助手", "chat.noSelection": "請先選擇一個或多個節點。", "workflow.invalidWorkflowFile": "工作流程檔案格式無效", "workflow.parseWorkflowFileFailed": "解析工作流程檔案失敗", "splitGridNode.sourceGridAlt": "來源網格", "splitGridNode.connectImage": "連接圖片", "splitGridNode.gridSummary": "{rows}x{cols} 網格({count} 張圖片)", "splitGridNode.generateSetsCreated": "已建立 {count} 組生成節點", "splitGridNode.notConfigured": "未設定 - 點擊設定", "splitGridNode.configureFirst": "請先設定節點", "splitGridNode.connectImageFirst": "請先連接圖片", "splitGridNode.splitGrid": "拆分網格", "splitGridNode.split": "拆分", "output.downloadCurrent": "下載目前{type}", "output.downloadAll": "下載全部輸出", "node.settings": "設定", "node.runToGenerate": "執行以生成", "node.selectModel": "選擇模型...", "node.primary": "主模型", "node.text": "文字", "node.image": "圖片", "node.notUsedByModel": "此模型不使用", "node.generationFailed": "生成失敗", "node.videoGenerationFailed": "影片生成失敗", "node.loadingParameters": "正在載入參數...", "node.noParameters": "無可用參數", "node.default": "預設", "node.model": "模型", "node.size": "尺寸", "node.quality": "品質", "node.voice": "聲音", "node.sound": "聲音", "node.duration": "時長", "node.seconds": "{count}秒", "node.aspectRatio": "寬高比", "node.resolution": "解析度", "node.googleSearch": "Google 搜尋", "node.imageSearch": "圖片搜尋", "node.provider": "服務商", "node.temperature": "溫度:{value}", "node.maxTokens": "最大 Token:{value}", "node.generic": "節點", "splitGridSettings.title": "拆分網格設定", "splitGridSettings.gridLayout": "網格版面", "splitGridSettings.gridSummary": "網格將拆分為 {rows}x{cols} = {count} 張圖片", "splitGridSettings.defaultPrompt": "預設提示詞", "splitGridSettings.promptPlaceholder": "輸入將套用到所有生成圖片的提示詞...", "splitGridSettings.promptHelp": "建立後,每個提示詞節點都可以個別編輯", "splitGridSettings.generateNodeSettings": "生成節點設定", "splitGridSettings.createGenerateSets": "建立 {count} 組生成節點", "imageInput.upload": "上傳圖片", "imageInput.dropImage": "拖入圖片", "dropOverlay.workflow": "拖入以載入工作流程", "dropOverlay.node": "拖入以建立節點", "dropOverlay.audio": "拖入音訊以建立節點", "dropOverlay.image": "拖入圖片以建立節點", "dropOverlay.splittingImageGrid": "正在拆分圖片網格...", "connectionMenu.addNode": "新增 {type} 節點", "connectionMenu.type.image": "圖片", "connectionMenu.type.text": "文字", "connectionMenu.type.audio": "音訊", "connectionMenu.type.video": "影片", "connectionMenu.type.3d": "3D", "connectionMenu.type.easeCurve": "設定", "connectionMenu.splitGridNode": "拆分網格節點", "connectionMenu.splitGridNow": "立即拆分網格", "connectionMenu.multiAngleImage": "圖片多角度", "connectionMenu.navigate": "導覽", "connectionMenu.select": "選擇", "prompt.placeholder": "描述你想生成的內容...", "prompt.connectedPlaceholder": "來自連接節點的文字(可編輯)...", "prompt.optionalPlaceholder": "可選提示詞(留空則略過)...", "prompt.addVariable": "新增變數", "prompt.setVariableName": "設定變數名稱", "prompt.variableHelp": "將此提示詞作為 PromptConstructor 節點中的變數使用", "prompt.variableName": "變數名稱", "prompt.variablePlaceholder": "例如 color、style、subject", "prompt.preview": "預覽:{value}", "composer.promptProvidedByUpstream": "提示詞由上游文字節點提供。", "composer.videoStitchClipCount": "{count} 個影片片段", "composer.videoStitchAudio": "已連接音訊", "composer.videoStitchNoAudio": "無音訊", "composer.videoStitchInputs": "影片輸入", "composer.videoStitchInputHint": "在節點上調整片段順序", "composer.videoStitchNeedTwo": "至少連接 2 個影片片段才能拼接。", "composer.videoStitchClip": "片段 {index}", "composer.videoStitchLoop": "循環", "composer.videoStitchOutputReady": "輸出已就緒", "composer.videoStitchNoOutput": "尚未輸出", "composer.videoStitchReady": "目前節點可拼接", "composer.videoStitchRun": "拼接目前影片節點", "composer.easeCurveVideoConnected": "已連接影片", "composer.easeCurveNoVideo": "連接一個影片輸入後可套用緩動曲線。", "composer.easeCurveInherited": "繼承設定", "composer.easeCurveLocal": "本機設定", "composer.easeCurveSettings": "曲線設定", "composer.easeCurvePreset": "預設", "composer.easeCurveCustom": "自訂貝塞爾", "composer.easeCurveHandles": "貝塞爾控制點", "composer.easeCurveInput": "輸入", "composer.easeCurveDuration": "輸出時長", "composer.easeCurveOutputReady": "輸出已就緒", "composer.easeCurveNoOutput": "尚未輸出", "composer.easeCurveReady": "目前曲線可套用", "composer.easeCurveRun": "套用目前緩動曲線節點", "shortcuts.title": "鍵盤快捷鍵", "shortcuts.layout": "版面(先選擇 2 個以上節點)", "shortcuts.addNodes": "新增節點", "shortcuts.runWorkflow": "執行工作流程", "shortcuts.copyNodes": "複製選中節點", "shortcuts.paste": "貼上節點 / 圖片 / 文字", "shortcuts.undo": "復原", "shortcuts.redo": "重做", "shortcuts.addPrompt": "新增提示詞節點", "shortcuts.addImage": "新增圖片輸入節點", "shortcuts.addGenerateImage": "新增圖片生成節點", "shortcuts.addGenerateVideo": "新增影片生成節點", "shortcuts.addAudio": "新增音訊節點", "shortcuts.addVideoInput": "新增影片輸入節點", "shortcuts.delete": "刪除選中節點", "project.newProject": "新增專案", "project.settings": "專案設定", "project.tabProject": "專案", "project.tabProviders": "服務商", "project.tabNodeDefaults": "節點預設值", "project.name": "專案名稱", "project.directory": "專案目錄", "project.localFolderPlaceholder": "選擇這台裝置上的本機資料夾", "project.directoryHelp": "工作流程檔案和圖片會儲存在這裡,並自動建立 inputs 與 generations 子資料夾。", "project.embedImages": "將圖片嵌入為 base64", "project.inlineSettings": "在節點上顯示模型設定", "project.newapiwgDesc": "Popi 統一模型閘道", "project.baseUrl": "Base URL", "project.defaultLLM": "預設 LLM 設定", "project.systemLLMDefault": "使用系統預設值(Popi Models Doubao Seed 2.0 Lite)", "project.executionSettings": "執行設定", "project.maxParallel": "最大平行呼叫:{count}", "project.canvasHelp": "設定畫布導覽和互動方式。", "project.canvasAssistant": "畫布助手", "project.canvasAssistantShort": "助手", "project.panMode": "平移模式", "project.zoomMode": "縮放模式", "project.selectionMode": "選擇模式", "project.validating": "驗證中...", "project.errorChooseLocalFolder": "請從瀏覽器選擇本機資料夾,這樣專案會儲存在目前操作者的裝置上。", "modelSearch.search": "搜尋模型...", "modelSearch.allProviders": "所有服務商", "modelSearch.all": "全部", "modelSearch.allTypes": "所有類型", "modelSearch.image": "圖片", "modelSearch.video": "影片", "modelSearch.audio": "音訊", "modelSearch.refresh": "重新整理模型和參數", "modelSearch.loading": "正在載入模型...", "modelSearch.tryAgain": "重試", "modelSearch.removeFallback": "移除備用模型", "modelSearch.clearSelection": "清除目前選擇", "modelSearch.noModels": "找不到模型", "modelSearch.adjustFilters": "嘗試調整搜尋或篩選條件", "modelSearch.recent": "最近使用", "promptWorkflow.title": "用提示生成工作流程", "promptWorkflow.describe": "描述你的工作流程", "promptWorkflow.placeholder": "例如:基於參考圖建立光線和風格一致的產品攝影...", "promptWorkflow.help": "描述你希望工作流程完成什麼。請具體說明輸入、輸出和任何轉換步驟。", "promptWorkflow.note": "注意:此功能目前僅適用於 Gemini 模型。", "promptWorkflow.generating": "生成中...", "promptWorkflow.generate": "生成工作流程", "promptWorkflow.dismiss": "關閉提示", "promptWorkflow.validation": "請描述你的工作流程(至少 3 個字元)", "promptWorkflow.failed": "生成工作流程失敗", "workflowBrowser.noWorkflows": "找不到工作流程", "workflowBrowser.noWorkflowsDesc": "此資料夾不包含任何工作流程專案", "multiSelect.stackHorizontal": "水平排列 (H)", "multiSelect.stackVertical": "垂直排列 (V)", "multiSelect.arrangeGrid": "排列為網格 (G)", "multiSelect.removeGroup": "從群組中移除", "multiSelect.createGroup": "建立群組", "multiSelect.downloadZip": "下載圖片 ZIP", "cost.viewDetails": "查看費用詳情", }; const ja: Dictionary = { ...en, "language.label": "言語", "common.back": "戻る", "common.next": "次へ", "common.cancel": "キャンセル", "common.close": "閉じる", "common.save": "保存", "common.create": "作成", "common.browse": "参照", "common.change": "変更", "common.clear": "クリア", "common.select": "選択", "common.selectModel": "モデルを選択", "common.skip": "スキップ", "common.show": "表示", "common.hide": "非表示", "common.override": "上書き", "common.configuredViaEnv": ".env で設定済み", "common.recommended": "推奨", "common.optional": "任意", "common.required": "必須", "common.download": "ダウンロード", "common.remove": "削除", "common.disconnect": "接続解除", "common.play": "再生", "common.pause": "一時停止", "common.set": "設定", "common.previous": "前へ", "common.nextItem": "次へ", "common.processing": "処理中...", "error.providerOverloaded": "{model}: プロバイダーが一時的に混雑しています。少し待って再試行するか、別のモデルに切り替えてください。", "node.optionalTitle": "この入力は任意です。空の入力はスキップされます", "node.markOptionalTitle": "任意に設定します。空の入力はこの分岐をスキップします", "header.openWelcome": "ウェルカム画面を開く", "header.untitled": "無題", "header.saving": "保存中...", "header.savedAt": "{time} に保存済み", "header.notSaved": "未保存", "header.saveProject": "プロジェクトを保存", "header.configureSaveLocation": "保存先を設定", "header.openProject": "プロジェクトを開く", "header.openProjectFolder": "プロジェクトフォルダを開く", "header.projectSettings": "プロジェクト設定", "header.revertAIChanges": "AI の変更を戻す", "header.revertAIChangesTitle": "AI 変更前のワークフローに戻す", "header.revertConfirm": "よろしいですか?以前のワークフローに戻します。", "header.shortcuts": "キーボードショートカット (?)", "header.support": "サポート", "header.commentsTitle": "未読コメント {unviewed} 件(合計 {total} 件)", "quickstart.description": "生成 AI パイプライン向けのノードベースのワークフローエディタです。ノードを接続して、画像、動画、音声、3D アセットを生成・変換するパイプラインを構築できます。", "quickstart.docs": "ドキュメント", "quickstart.waitlist": "NB Pro ウェイトリスト", "quickstart.newProject": "新規プロジェクト", "quickstart.newProjectDesc": "新しいワークフローを開始", "quickstart.loadWorkflow": "ワークフローを読み込み", "quickstart.loadWorkflowDesc": "既存ファイルを開く", "quickstart.templates": "テンプレート", "quickstart.templatesDesc": "事前作成済みワークフロー", "quickstart.promptWorkflow": "プロンプトで作成", "quickstart.promptWorkflowDesc": "Gemini に構築してもらう", "quickstart.beta": "ベータ", "quickstart.templateExplorerTitle": "テンプレート一覧", "quickstart.workflowTemplatesTitle": "ワークフローテンプレート", "quickstart.templatesIntro": "すぐに始められる事前作成済みワークフローです。テンプレートを選ぶとキャンバスに読み込まれます。", "quickstart.quickStart": "クイックスタート", "quickstart.searchTemplates": "テンプレートを検索", "quickstart.searchTemplatesPlaceholder": "テンプレートを検索...", "quickstart.category": "カテゴリ", "quickstart.provider": "プロバイダー", "quickstart.filterAll": "すべて", "quickstart.categorySimple": "シンプル", "quickstart.categoryAdvanced": "高度", "quickstart.clearFilters": "フィルターをクリア", "quickstart.clearAllFilters": "すべてのフィルターをクリア", "quickstart.noTemplatesMatch": "条件に一致するテンプレートがありません", "quickstart.adjustSearchFilters": "検索条件またはフィルターを調整してください", "quickstart.useWorkflow": "ワークフローを使用", "quickstart.loading": "読み込み中...", "quickstart.nodeCount": "{count} ノード", "quickstart.dismiss": "閉じる", "quickstart.loadTemplateFailed": "テンプレートの読み込みに失敗しました", "quickstart.template.productShot.name": "商品撮影", "quickstart.template.productShot.description": "商品を新しいシーンや環境に配置", "quickstart.template.modelProduct.name": "モデル + 商品", "quickstart.template.modelProduct.description": "モデル、商品、シーンを組み合わせる", "quickstart.template.colorVariations.name": "カラーバリエーション", "quickstart.template.colorVariations.description": "参照画像から商品の色違いを生成", "quickstart.template.backgroundSwap.name": "背景差し替え", "quickstart.template.backgroundSwap.description": "被写体を新しい背景に配置", "quickstart.template.styleTransfer.name": "スタイル変換", "quickstart.template.styleTransfer.description": "ある画像のスタイルを別の画像に適用", "quickstart.template.sceneComposite.name": "シーン合成", "quickstart.template.sceneComposite.description": "複数のシーンの要素を組み合わせる", "ftux.welcomeTo": "popiart-node へようこそ", "ftux.stepWelcome": "ようこそ", "ftux.stepApiKeys": "API キー", "ftux.stepModelDefaults": "モデル既定値", "ftux.stepReady": "準備完了", "ftux.getStarted": "開始", "ftux.skipSetup": "セットアップをスキップしますか?", "ftux.skipSetupDesc": "API キーとモデル既定値は後で設定から変更できます。", "ftux.welcomeTitle": "始めましょう。", "ftux.welcomeDesc": "AI モデルをブロックのように接続して、画像や動画などを生成します。", "ftux.apiKeysTitle": "API キー", "ftux.apiKeysDesc": "AI プロバイダーを使うためのキーをここに追加します(ブラウザに保存)。より安全に保持するには .env ファイルに保存してください。", "ftux.getApiKey": "{provider} の API キーを取得", "ftux.getApiKeyTip": "API キーを取得", "ftux.llmOnlyTip": "LLM ノードのみで使用", "ftux.enterKey": "キーを入力...", "ftux.modelsTitle": "モデルを選択", "ftux.modelsDesc": "画像と動画の既定 AI モデルを選びます。後から変更できます。", "ftux.defaultImageModel": "既定の画像モデル", "ftux.defaultVideoModel": "既定の動画モデル", "ftux.noneSet": "未設定", "ftux.readyTitle": "準備できました!", "ftux.readyDesc": "クイックチュートリアルを見ますか?", "ftux.startTutorial": "チュートリアルを開始", "ftux.tutorial.welcome": "まず基本操作を見ていきましょう。", "ftux.tutorial.addImage": "「画像」ボタンをクリックして画像ノードを追加します。", "ftux.tutorial.explainNode": "これはノードです。各ノードには決まった役割があります。\n\nこのノードは画像を追加します。", "ftux.tutorial.explainNodeInputs": "入力端子は常にノードの左側にあります。", "ftux.tutorial.explainNodeOutputs": "出力端子は常にノードの右側にあります。", "ftux.tutorial.dragAndDrop": "出力端子からドラッグして、キャンバスの空いている場所にドロップします。", "ftux.tutorial.selectGenerateImage": "このメニューには、このノードから接続できる項目が表示されます。\n\n「画像生成」を選択して AI 画像生成ノードを追加します。", "ftux.tutorial.addPromptNode": "「プロンプト」ボタンをクリックしてプロンプトノードを追加します。", "ftux.tutorial.connectPromptToGenerate": "プロンプトノードの出力端子から、画像生成ノードの入力端子へドラッグします。", "ftux.tutorial.populateContent": "サンプル内容を少し追加します 🎨", "ftux.tutorial.explainGenerateNode": "これは画像生成ノードです。プロンプトと参照画像をもとに、AI が画像を作成または編集します。", "ftux.tutorial.explainRunButton": "この「実行」ボタンをクリックするとワークフローが実行されます。Cmd+Enter(Windows では Ctrl+Enter)でも実行できます。", "ftux.tutorial.explainRunOptions": "ドロップダウンから、特定のノードから実行したり、選択中のノードだけを実行したりできます。", "ftux.tutorial.runWorkflow": "ワークフローを実行しましょう!「実行」ボタンをクリックして画像を生成します。", "ftux.tutorial.demonstrateDownstream": "次に、広げられる可能性を見てみましょう... 🎬✨", "ftux.tutorial.demonstrateComplete": "下流にさらにノードを接続して生成パイプラインを作ることも、無限のクリエイティブキャンバスとして使うこともできます。", "ftux.tutorial.saveProject": "プロジェクトを保存すると、作業内容と生成結果をローカルに残せます。", "ftux.tutorial.resources": "ヘルプやアイデアには以下のリソースをご覧ください:", "ftux.tutorial.discord": "Discord コミュニティに参加", "ftux.tutorial.complete": "準備完了です!制作を始めましょう。", "ftux.tutorial.clickToContinue": "任意の場所をクリックして続行", "ftux.tutorial.skip": "チュートリアルをスキップ", "toolbar.categoryInput": "入力", "toolbar.categoryText": "テキスト", "toolbar.categoryGenerate": "生成", "toolbar.categoryProcess": "処理", "toolbar.categoryRoute": "ルート", "toolbar.categoryOutput": "出力", "toolbar.image": "画像", "toolbar.video": "動画", "toolbar.prompt": "プロンプト", "toolbar.generate": "生成", "toolbar.output": "出力", "toolbar.allNodes": "すべてのノード", "toolbar.allModels": "すべてのモデル", "toolbar.browseModels": "モデルを参照", "toolbar.switchConnectors": "{style}コネクタに切り替え", "toolbar.curved": "曲線", "toolbar.angular": "直角", "toolbar.run": "実行", "toolbar.stop": "停止", "toolbar.running": "実行中...", "toolbar.runningNode": "{node} を実行中...", "toolbar.runningNodes": "{count} 個のノードを実行中...", "toolbar.nodesCount": "{count} 個のノード", "toolbar.runOptions": "実行オプション", "toolbar.runEntire": "ワークフロー全体を実行", "toolbar.runFromSelected": "選択ノードから実行", "toolbar.runSelectedOnly": "選択ノードのみ実行", "toolbar.runSelectedNodes": "選択ノードを実行", "toolbar.runSelectedNodesCount": "選択した {count} ノードを実行", "toolbar.selectSingleNode": "先に 1 つのノードを選択してください", "toolbar.selectOneOrMoreNodes": "先に 1 つ以上のノードを選択してください", "node.imageInput": "画像入力", "node.audioInput": "音声入力", "node.videoInput": "動画入力", "node.glbViewer": "3D ビューア", "node.prompt": "プロンプト", "node.promptConstructor": "プロンプト構築", "node.array": "配列", "node.generateImage": "画像生成", "node.generateVideo": "動画生成", "node.generate3d": "3D 生成", "node.generateAudio": "音声生成", "node.llmGenerate": "LLM 生成", "node.annotation": "注釈", "annotation.tool.select": "選択", "annotation.tool.rectangle": "矩形", "annotation.tool.circle": "円形", "annotation.tool.arrow": "矢印", "annotation.tool.draw": "描画", "annotation.tool.text": "テキスト", "annotation.undo": "元に戻す", "annotation.redo": "やり直し", "annotation.clear": "クリア", "annotation.cancel": "キャンセル", "annotation.done": "完了", "annotation.color": "色", "annotation.size": "サイズ", "annotation.fill": "塗りつぶし", "node.splitGrid": "グリッド分割", "node.videoStitch": "動画結合", "node.videoTrim": "動画トリム", "node.easeCurve": "イーズ曲線", "node.frameGrab": "フレーム取得", "node.imageCompare": "画像比較", "imageCompare.connectTwo": "比較する画像を 2 枚接続してください", "imageCompare.connectAnother": "比較するもう 1 枚の画像を接続してください", "imageCompare.imageAConnected": "画像 A が接続済み", "imageCompare.imageBConnected": "画像 B が接続済み", "imageCompare.imageAAlt": "画像 A", "imageCompare.imageBAlt": "画像 B", "upload.imageUnsupported": "未対応の形式です。PNG、JPG、WebP を使用してください。", "upload.imageTooLarge": "画像が大きすぎます。最大サイズは 10MB です。", "upload.videoUnsupported": "未対応の形式です。MP4、WebM、QuickTime 動画ファイルを使用してください。", "upload.videoTooLarge": "動画ファイルが大きすぎます。最大サイズは 200MB です。", "upload.audioUnsupported": "未対応の形式です。MP3、WAV、OGG、AAC、またはその他の音声形式を使用してください。", "upload.audioTooLarge": "音声ファイルが大きすぎます。最大サイズは 50MB です。", "imageInput.uploadedAlt": "アップロード済み画像", "imageInput.download": "画像をダウンロード", "imageInput.remove": "画像を削除", "videoInput.upload": "動画ファイルをアップロード", "videoInput.dropVideo": "動画をドロップまたはクリック", "videoInput.download": "動画をダウンロード", "videoInput.remove": "動画を削除", "audioInput.upload": "音声ファイルをアップロード", "audioInput.dropAudio": "音声をドロップまたはクリック", "audioInput.download": "音声をダウンロード", "audioInput.remove": "音声を削除", "audioInput.clear": "音声をクリア", "audioInput.loadingWaveform": "波形を読み込み中...", "generateAudio.fallbackUsed": "フォールバックを使用", "generateAudio.fallbackUsedTitle": "メインが失敗: {error}\n使用したフォールバック: {model}", "generateAudio.generating": "音声を生成中...", "annotation.noImage": "利用可能な画像がありません。画像を接続するか手動で読み込んでください。", "annotation.annotatedAlt": "注釈付き画像", "annotation.downloadImage": "画像をダウンロード", "annotation.removeImage": "画像を削除", "annotation.editCount": "編集({count})", "annotation.addAnnotations": "注釈を追加", "annotation.dropClickConnect": "ドロップ、クリック、または接続", "array.split": "分割", "array.delimiter": "区切り文字", "array.newline": "改行", "array.regexAdvanced": "正規表現(詳細)", "array.batch": "一括", "array.batchModeTitle": "一括モード:すべての項目を 1 つの下流ノードへ送信", "array.enableBatchMode": "一括モードを有効化", "array.autoRouteToPrompts": "プロンプトへ自動ルート", "array.by": "方法", "array.advanced": "詳細", "array.trim": "空白を削除", "array.removeEmpty": "空項目を削除", "array.parsedItems": "解析済み項目({count})", "array.noItemsParsed": "解析済み項目はありません", "array.selectedForNextConnection": "次の接続に選択済み(クリックで解除)", "array.selectForNextConnection": "クリックして次の接続に選択", "array.batchFooter": "一括:すべての項目を下流ノードへ送信", "array.nextWireUsesItem": "次のワイヤーは項目 {index} を使用", "array.noSelection": "未選択:ワイヤーは項目 1 から順に使用", "videoCommon.encoderUnsupported": "このブラウザは動画エンコードに対応していません。", "videoCommon.encoderHelp": "問題がある場合は Discord で Willie に連絡してください。", "videoCommon.checkingEncoder": "エンコーダーを確認中...", "videoCommon.processingPercent": "処理中... {progress}%", "videoTrim.videoIn": "動画入力", "videoTrim.videoOut": "動画出力", "videoTrim.connectVideo": "トリムする動画を接続してください", "videoTrim.source": "元動画", "videoTrim.trimmed": "トリム済み", "videoTrim.clearTrimmedVideo": "トリム済み動画をクリア", "videoTrim.start": "開始", "videoTrim.end": "終了", "videoTrim.duration": "長さ", "videoTrim.trimStartTime": "トリム開始時間", "videoTrim.trimEndTime": "トリム終了時間", "videoTrim.setStartToCurrent": "開始時間を現在の再生位置に設定", "videoTrim.setEndToCurrent": "終了時間を現在の再生位置に設定", "videoTrim.trim": "トリム", "videoStitch.videoInput": "動画 {index}", "videoStitch.audioInput": "音声", "videoStitch.output": "出力", "videoStitch.connectVideos": "結合する動画を接続してください", "videoStitch.clipAlt": "クリップ {id}", "videoStitch.clearVideo": "動画をクリア", "videoStitch.loop": "ループ", "videoStitch.stitch": "結合", "multiAngle.editorTitle": "マルチアングルエディタ", "multiAngle.imageEditorTitle": "画像マルチアングルエディタ", "multiAngle.imageTitle": "画像マルチアングル", "multiAngle.closeEditor": "マルチアングルエディタを閉じる", "multiAngle.generate": "マルチアングルを生成", "multiAngle.noImageToast": "利用可能な画像が見つかりません。マルチアングル画像を生成できません。", "multiAngle.sightControl": "マルチアングル視線コントロール", "multiAngle.noImage": "画像なし", "multiAngle.horizontal": "水平オービット", "multiAngle.vertical": "垂直ピッチ", "multiAngle.zoom": "ショットスケール", "multiAngle.prompt": "プロンプト", "multiAngle.enableCustomPrompt": "カスタムプロンプトを有効化", "multiAngle.promptDialog": "マルチアングルプロンプト", "multiAngle.promptInput": "マルチアングルプロンプト入力", "multiAngle.promptPlaceholder": "プロンプトを入力...", "multiAngle.reset": "パラメータをリセット", "multiAngle.resetAria": "マルチアングルパラメータをリセット", "multiAngle.adjustVerticalUp": "垂直ピッチを上げる", "multiAngle.adjustVerticalDown": "垂直ピッチを下げる", "multiAngle.adjustHorizontalLeft": "水平オービットを左へ調整", "multiAngle.adjustHorizontalRight": "水平オービットを右へ調整", "multiAngle.preset.custom": "カスタム", "multiAngle.preset.fisheye": "魚眼", "multiAngle.preset.tilt": "傾き", "multiAngle.preset.frontOverhead": "正面俯瞰", "multiAngle.preset.frontLow": "正面ローアングル", "multiAngle.preset.panoramicOverhead": "パノラマ俯瞰", "multiAngle.preset.back": "背面", "multiAngle.zoom.wide": "ワイド", "multiAngle.zoom.medium": "ミディアム", "multiAngle.zoom.close": "クローズアップ", "workflow.splitGrid.noImage": "分割できる画像がありません。先に画像を生成または読み込んでください。", "workflow.splitGrid.detectFailed": "画像内のグリッドを検出できませんでした。", "workflow.splitGrid.failed": "画像グリッドの分割に失敗しました: {error}", "workflow.generatedSuccess": "ワークフローを生成しました", "workflow.generatedFailed": "ワークフローの生成に失敗しました", "workflow.generatedFailedRetry": "ワークフローの生成に失敗しました。再試行してください。", "workflow.appliedEdits": "{count} 件の編集を適用しました", "chat.title": "キャンバスアシスタント", "chat.beta": "ベータ", "chat.clear": "チャットをクリア", "chat.close": "チャットを閉じる", "chat.dismiss": "閉じる", "chat.emptyTitle": "このキャンバスについて質問したり、編集案を作成できます。", "chat.diagnoseSelected": "選択を診断", "chat.makeVariants": "バリエーション作成", "chat.promptDiagnose": "選択したノードを診断し、最小限の有用な修正を提案してください。", "chat.promptVariants": "選択した画像または生成ノードから、4つの視覚バリエーションを作る編集案を準備してください。", "chat.proposalReady": "提案を準備しました", "chat.candidateReady": "候補ワークフローを適用できます。", "chat.runReady": "実行アクションを適用できます。", "chat.candidateWorkflow": "候補ワークフロー", "chat.applyWorkflow": "ワークフローを適用", "chat.operationPreview": "操作プレビュー", "chat.applyEdits": "編集を適用", "chat.runPreview": "実行プレビュー", "chat.runNow": "今すぐ実行", "chat.focusedNodes": "選択中の {count} ノードにフォーカス", "chat.runSelected": "選択を実行", "chat.runAffected": "影響範囲を実行({count})", "chat.placeholder": "メッセージを入力...", "chat.building": "構築中...", "chat.buildWorkflow": "ワークフローを構築", "chat.open": "アシスタント", "chat.noSelection": "先に1つ以上のノードを選択してください。", "workflow.invalidWorkflowFile": "ワークフローファイル形式が無効です", "workflow.parseWorkflowFileFailed": "ワークフローファイルの解析に失敗しました", "splitGridNode.sourceGridAlt": "元グリッド", "splitGridNode.connectImage": "画像を接続", "splitGridNode.gridSummary": "{rows}x{cols} グリッド({count} 枚の画像)", "splitGridNode.generateSetsCreated": "{count} 個の生成セットを作成済み", "splitGridNode.notConfigured": "未設定 - 設定をクリック", "splitGridNode.configureFirst": "先にノードを設定してください", "splitGridNode.connectImageFirst": "先に画像を接続してください", "splitGridNode.splitGrid": "グリッドを分割", "splitGridNode.split": "分割", "node.router": "ルーター", "node.switch": "スイッチ", "node.conditionalSwitch": "条件スイッチ", "node.output": "出力", "node.outputGallery": "出力ギャラリー", "output.downloadCurrent": "現在の{type}をダウンロード", "output.downloadAll": "すべての出力をダウンロード", "node.settings": "設定", "node.runToGenerate": "実行して生成", "node.selectModel": "モデルを選択...", "node.primary": "メイン", "node.text": "テキスト", "node.image": "画像", "node.notUsedByModel": "このモデルでは未使用", "node.generationFailed": "生成に失敗しました", "node.videoGenerationFailed": "動画生成に失敗しました", "node.loadingParameters": "パラメータを読み込み中...", "node.noParameters": "利用可能なパラメータはありません", "node.default": "既定", "node.model": "モデル", "node.size": "サイズ", "node.quality": "品質", "node.voice": "音声", "node.sound": "音声", "node.duration": "長さ", "node.seconds": "{count}秒", "node.aspectRatio": "アスペクト比", "node.resolution": "解像度", "node.googleSearch": "Google 検索", "node.imageSearch": "画像検索", "node.provider": "プロバイダー", "node.temperature": "温度:{value}", "node.maxTokens": "最大トークン:{value}", "node.generic": "ノード", "splitGridSettings.title": "グリッド分割設定", "splitGridSettings.gridLayout": "グリッドレイアウト", "splitGridSettings.gridSummary": "グリッドは {rows}x{cols} = {count} 枚の画像に分割されます", "splitGridSettings.defaultPrompt": "既定のプロンプト", "splitGridSettings.promptPlaceholder": "生成されるすべての画像に適用するプロンプトを入力...", "splitGridSettings.promptHelp": "作成後、各プロンプトノードは個別に編集できます", "splitGridSettings.generateNodeSettings": "生成ノード設定", "splitGridSettings.createGenerateSets": "{count} 個の生成セットを作成", "imageInput.upload": "画像をアップロード", "imageInput.dropImage": "画像をドロップ", "dropOverlay.workflow": "ドロップしてワークフローを読み込み", "dropOverlay.node": "ドロップしてノードを作成", "dropOverlay.audio": "音声をドロップしてノードを作成", "dropOverlay.image": "画像をドロップしてノードを作成", "dropOverlay.splittingImageGrid": "画像グリッドを分割中...", "connectionMenu.addNode": "{type} ノードを追加", "connectionMenu.type.image": "画像", "connectionMenu.type.text": "テキスト", "connectionMenu.type.audio": "音声", "connectionMenu.type.video": "動画", "connectionMenu.type.3d": "3D", "connectionMenu.type.easeCurve": "設定", "connectionMenu.splitGridNode": "グリッド分割ノード", "connectionMenu.splitGridNow": "今すぐグリッド分割", "connectionMenu.multiAngleImage": "画像マルチアングル", "connectionMenu.navigate": "移動", "connectionMenu.select": "選択", "prompt.placeholder": "生成したい内容を入力...", "prompt.connectedPlaceholder": "接続ノードからのテキスト(編集可)...", "prompt.optionalPlaceholder": "任意のプロンプト(空ならスキップ)...", "prompt.addVariable": "変数を追加", "prompt.setVariableName": "変数名を設定", "prompt.variableHelp": "このプロンプトを PromptConstructor ノードの変数として使用します", "prompt.variableName": "変数名", "prompt.variablePlaceholder": "例: color, style, subject", "prompt.preview": "プレビュー:{value}", "composer.promptProvidedByUpstream": "プロンプトは上流のテキストノードから提供されています。", "composer.videoStitchClipCount": "{count} 本の動画クリップ", "composer.videoStitchAudio": "音声接続済み", "composer.videoStitchNoAudio": "音声なし", "composer.videoStitchInputs": "動画入力", "composer.videoStitchInputHint": "クリップ順序はノード上で調整", "composer.videoStitchNeedTwo": "結合には動画クリップを 2 本以上接続してください。", "composer.videoStitchClip": "クリップ {index}", "composer.videoStitchLoop": "ループ", "composer.videoStitchOutputReady": "出力準備完了", "composer.videoStitchNoOutput": "出力はまだありません", "composer.videoStitchReady": "現在のノードを結合できます", "composer.videoStitchRun": "現在の動画ノードを結合", "composer.easeCurveVideoConnected": "動画接続済み", "composer.easeCurveNoVideo": "緩動曲線を適用するには動画入力を接続してください。", "composer.easeCurveInherited": "継承設定", "composer.easeCurveLocal": "ローカル設定", "composer.easeCurveSettings": "曲線設定", "composer.easeCurvePreset": "プリセット", "composer.easeCurveCustom": "カスタムベジェ", "composer.easeCurveHandles": "ベジェ制御点", "composer.easeCurveInput": "入力", "composer.easeCurveDuration": "出力時間", "composer.easeCurveOutputReady": "出力準備完了", "composer.easeCurveNoOutput": "出力はまだありません", "composer.easeCurveReady": "現在の曲線を適用できます", "composer.easeCurveRun": "現在の緩動曲線ノードを適用", "shortcuts.title": "キーボードショートカット", "shortcuts.general": "一般", "shortcuts.addNodes": "ノード追加", "shortcuts.layout": "レイアウト(先に 2 つ以上のノードを選択)", "shortcuts.canvas": "キャンバス", "shortcuts.runWorkflow": "ワークフローを実行", "shortcuts.copyNodes": "選択ノードをコピー", "shortcuts.paste": "ノード / 画像 / テキストを貼り付け", "shortcuts.undo": "元に戻す", "shortcuts.redo": "やり直し", "shortcuts.showShortcuts": "ショートカットを表示", "shortcuts.addPrompt": "プロンプトノードを追加", "shortcuts.addImage": "画像入力ノードを追加", "shortcuts.addGenerateImage": "画像生成ノードを追加", "shortcuts.addGenerateVideo": "動画生成ノードを追加", "shortcuts.addLLM": "LLM テキストノードを追加", "shortcuts.addAnnotation": "注釈ノードを追加", "shortcuts.addAudio": "音声ノードを追加", "shortcuts.addVideoInput": "動画入力ノードを追加", "shortcuts.addArray": "配列ノードを追加", "shortcuts.stackVertical": "選択ノードを縦に並べる", "shortcuts.stackHorizontal": "選択ノードを横に並べる", "shortcuts.arrangeGrid": "選択ノードをグリッド配置", "shortcuts.zoom": "ズームイン / アウト", "shortcuts.pan": "パン(macOS)", "shortcuts.delete": "選択ノードを削除", "project.newProject": "新規プロジェクト", "project.settings": "プロジェクト設定", "project.tabProject": "プロジェクト", "project.tabProviders": "プロバイダー", "project.tabNodeDefaults": "ノード既定値", "project.tabCanvas": "キャンバス", "project.name": "プロジェクト名", "project.directory": "プロジェクトディレクトリ", "project.localFolderPlaceholder": "このデバイス上のローカルフォルダを選択", "project.directoryHelp": "ワークフローファイルと画像はここに保存されます。inputs と generations のサブフォルダは自動作成されます。", "project.embedImages": "画像を base64 として埋め込む", "project.embedImagesDesc": "すべての画像をワークフローに埋め込みます。ファイルは大きくなり、非常に大きなワークフローではメモリ制限に達する場合があります。", "project.inlineSettings": "ノード上にモデル設定を表示", "project.inlineSettingsDesc": "生成ノード内にモデルパラメータを表示し、サイドパネルを使いません", "project.envHelp": ".env.local に API キーを追加するとより安全です。ここで追加したキーは .env を上書きし、ブラウザに保存されます。", "project.newapiwgDesc": "Popi 統合モデルゲートウェイ", "project.baseUrl": "Base URL", "project.systemImageDefault": "システム既定(Popi Models)", "project.noneSetFirstUse": "未設定(初回使用時に選択)", "project.defaultLLM": "既定の LLM 設定", "project.systemLLMDefault": "システム既定値を使用(Popi Models Doubao Seed 2.0 Lite)", "project.provider": "プロバイダー", "project.model": "モデル", "project.temp": "温度: {value}", "project.tokens": "トークン: {value}", "project.executionSettings": "実行設定", "project.maxParallel": "最大並列呼び出し: {count}", "project.executionHelp": "ワークフロー実行時に並列実行するノード数の上限です。値を上げると速くなる場合がありますが、API レート制限のリスクも上がります。", "project.defaultsHelp": "これらの既定値はキーボードショートカット(Shift+G、Shift+L など)でノードを作成するときに適用されます。", "project.canvasHelp": "キャンバスの移動と操作方法を設定します。", "project.canvasAssistant": "キャンバスアシスタント", "project.canvasAssistantShort": "アシスタント", "project.panMode": "パンモード", "project.panSpace": "Space を押しながらドラッグしてパン", "project.panMiddle": "マウス中ボタンでクリックしてドラッグ", "project.panAlways": "キーを押さずにパン", "project.panSpaceLabel": "Space + ドラッグ", "project.panMiddleLabel": "中ボタン", "project.panAlwaysLabel": "常時オン", "project.zoomMode": "ズームモード", "project.zoomAlt": "Alt を押しながらスクロールでズーム", "project.zoomCtrl": "Ctrl/Cmd を押しながらスクロールでズーム", "project.zoomScroll": "修飾キーなしでスクロールズーム", "project.zoomAltLabel": "Alt + スクロール", "project.zoomCtrlLabel": "Ctrl + スクロール", "project.zoomScrollLabel": "スクロール", "project.selectionMode": "選択モード", "project.selectClick": "クリックしてノードを選択", "project.selectAlt": "Alt を押しながらドラッグして選択", "project.selectShift": "Shift を押しながらドラッグして選択", "project.selectClickLabel": "クリック", "project.selectAltLabel": "Alt + ドラッグ", "project.selectShiftLabel": "Shift + ドラッグ", "project.validating": "検証中...", "project.errorOpenDir": "ディレクトリ選択を開けませんでした", "project.errorOpenDirWithReason": "ディレクトリ選択を開けませんでした: {error}", "project.errorNameRequired": "プロジェクト名は必須です", "project.errorDirectoryRequired": "プロジェクトディレクトリは必須です", "project.errorChooseLocalFolder": "このデバイスに保存するため、ブラウザからローカルフォルダを選択してください。", "project.errorAbsolutePath": "プロジェクトディレクトリは絶対パスである必要があります(/、ドライブ文字、UNC パスで始まる形式)", "project.errorNotDirectory": "プロジェクトパスはディレクトリではありません", "project.errorValidateDir": "ディレクトリ検証に失敗しました: {error}", "modelSearch.search": "モデルを検索...", "modelSearch.allProviders": "すべてのプロバイダー", "modelSearch.all": "すべて", "modelSearch.allTypes": "すべての種類", "modelSearch.image": "画像", "modelSearch.video": "動画", "modelSearch.audio": "音声", "modelSearch.refresh": "モデルとスキーマを更新", "modelSearch.loading": "モデルを読み込み中...", "modelSearch.tryAgain": "再試行", "modelSearch.removeFallback": "フォールバックを削除", "modelSearch.clearSelection": "現在の選択をクリア", "modelSearch.noModels": "モデルが見つかりません", "modelSearch.adjustFilters": "検索条件またはフィルターを調整してください", "modelSearch.recent": "最近使用", "promptWorkflow.title": "プロンプトでワークフロー作成", "promptWorkflow.describe": "ワークフローを説明", "promptWorkflow.placeholder": "例: 参考画像から一貫した照明とスタイルの商品写真を作成...", "promptWorkflow.help": "ワークフローで実現したいことを説明してください。入力、出力、変換内容を具体的に書くと効果的です。", "promptWorkflow.note": "注: この機能は現在 Gemini モデルでのみ動作します。", "promptWorkflow.generating": "生成中...", "promptWorkflow.generate": "ワークフローを生成", "promptWorkflow.dismiss": "閉じる", "promptWorkflow.validation": "ワークフローを説明してください(3 文字以上)", "promptWorkflow.failed": "ワークフローの生成に失敗しました", "workflowBrowser.noWorkflows": "ワークフローが見つかりません", "workflowBrowser.noWorkflowsDesc": "このフォルダにはワークフロープロジェクトがありません", "workflowBrowser.title": "ワークフロー", "workflowBrowser.chooseFolderDesc": "ワークフロープロジェクトを含むフォルダを選択します。後で変更できます。", "workflowBrowser.chooseFolder": "フォルダを選択", "workflowBrowser.projectCount": "{count} 件のプロジェクト", "workflowBrowser.openFromDirectory": "ディレクトリから開く", "workflowBrowser.changeFolder": "フォルダを変更", "workflowBrowser.justNow": "たった今", "workflowBrowser.minutesAgo": "{count} 分前", "workflowBrowser.hoursAgo": "{count} 時間前", "workflowBrowser.daysAgo": "{count} 日前", "workflowBrowser.monthsAgo": "{count} か月前", "workflowBrowser.errorNoWorkflows": "このフォルダにワークフローが見つかりません", "workflowBrowser.errorList": "ワークフロー一覧の取得に失敗しました", "workflowBrowser.errorFetch": "ワークフローの取得に失敗しました", "multiSelect.stackHorizontal": "横に並べる (H)", "multiSelect.stackVertical": "縦に並べる (V)", "multiSelect.arrangeGrid": "グリッド配置 (G)", "multiSelect.removeGroup": "グループから削除", "multiSelect.createGroup": "グループを作成", "multiSelect.downloadZip": "画像を ZIP でダウンロード", "cost.viewDetails": "コスト詳細を表示", }; const dictionaries: Record = { en, "zh-CN": zhCN, "zh-TW": zhTW, ja, }; function detectLanguage(): Language { if (typeof navigator === "undefined") return "en"; const language = navigator.language.toLowerCase(); if (language.startsWith("ja")) return "ja"; if (language.includes("tw") || language.includes("hk") || language.includes("hant")) return "zh-TW"; if (language.startsWith("zh")) return "zh-CN"; return "en"; } function interpolate(text: string, values?: Record) { if (!values) return text; return text.replace(/\{(\w+)\}/g, (_, key) => String(values[key] ?? `{${key}}`)); } interface I18nContextValue { language: Language; setLanguage: (language: Language) => void; t: (key: TranslationKey, values?: Record) => string; } const I18nContext = createContext(null); export function I18nProvider({ children }: { children: React.ReactNode }) { const [language, setLanguageState] = useState("en"); useEffect(() => { const stored = window.localStorage.getItem(STORAGE_KEY) as Language | null; setLanguageState(stored && stored in dictionaries ? stored : detectLanguage()); }, []); useEffect(() => { document.documentElement.lang = language; window.localStorage.setItem(STORAGE_KEY, language); }, [language]); const value = useMemo(() => ({ language, setLanguage: setLanguageState, t: (key, values) => interpolate(dictionaries[language][key] ?? en[key], values), }), [language]); return {children}; } export function useI18n() { const context = useContext(I18nContext); return context ?? { language: "en", setLanguage: () => {}, t: (key, values) => interpolate(en[key], values), }; }