Files
aigc-home/calliope-web/src/lib/i18n/en.ts
T

2102 lines
99 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export const en = {
// --- Common ---
'common.add': 'Add',
'common.cancel': 'Cancel',
'common.cancelButton': 'Cancel',
'common.delete': 'Delete',
'common.description': 'Description',
'common.edit': 'Edit',
'common.failed': 'Failed',
'common.generating': 'Generating',
'common.loading': 'Loading',
'common.missing': 'Missing',
'common.name': 'Name',
'common.pending': 'Pending',
'common.queued': 'Queued',
'common.ready': 'Ready',
'common.rename': 'Rename',
'common.retry': 'Retry',
'common.running': 'Running',
'common.save': 'Save',
'common.saved': 'Saved',
'common.saveFailed': 'Save failed',
'common.saving': 'Saving',
'common.send': 'Send',
'common.stop': 'Stop',
'common.title': 'Title',
'common.language': 'Language',
// --- App shell / nav ---
'nav.canvas': 'AI Canvas',
'nav.library': 'Asset Library',
'nav.projects': 'Projects',
'nav.buildScene': 'Build Scene',
'nav.settings': 'Settings',
'nav.agents': 'Agents',
'nav.models': 'Models',
'nav.home': 'Home',
'nav.primary': 'Primary',
'nav.projectStages': 'Project stages',
'nav.backProjects': 'Back to projects',
'nav.story': 'Story',
'nav.assets': 'Assets',
'nav.script': 'Script',
'nav.video': 'Video',
'nav.countActive': '{count} active',
'nav.eyebrow': 'Calliope',
'nav.unsaved': 'Unsaved changes',
'nav.llm': 'LLMs',
'nav.llmBlurb': 'Configure the language models used by the agent.',
'nav.comfy': 'ComfyUI',
'nav.comfyBlurb': 'Where ComfyUI runs.',
'nav.workflows': 'Workflows',
'nav.workflowsBlurb': 'Upload and register ComfyUI workflows for generation.',
'nav.agent': 'Agent model',
'nav.agentBlurb': 'Model used for story drafting and agent tasks.',
'nav.skills': 'Skills',
'nav.skillsBlurb': 'Agent skills available in this project.',
'nav.queue': 'Job queue',
'nav.queueBlurb': 'Concurrency and timeouts for generation jobs.',
'nav.storage': 'System Paths',
'nav.storageBlurb': 'Where files live, and where the agent may work.',
// --- Toast ---
'toast.dismiss': 'Dismiss',
'toast.undo': 'Undo',
'toast.uploadFailed': 'Upload failed',
// --- Modal ---
'modal.dialog': 'Dialog',
'modal.closeDialog': 'Close dialog',
// --- Projects page ---
'projects.new': 'New Project',
'projects.title': 'Projects',
'projects.subtitle': 'Your local story-to-video workspace. Pick up where you left off.',
'projects.newReel': 'New reel',
'projects.close': 'Close',
'projects.titleField': 'Title',
'projects.titlePlaceholder': 'Moonlit Harbor',
'projects.ideaField': 'Story idea',
'projects.ideaPlaceholder':
'A lighthouse keeper finds a glowing bottle that shows memories of sailors lost at sea…',
'projects.ideaHint': 'Optional — you can refine this later on the Story stage.',
'projects.genre': 'Genre',
'projects.tone': 'Tone',
'projects.duration': 'Target duration',
'projects.durationHint': 'Guides beat and scene counts on the Story stage.',
'projects.cancel': 'Cancel',
'projects.create': 'Create project',
'projects.searchPlaceholder': 'Search projects…',
'projects.searchLabel': 'Search projects',
'projects.filterBy': 'Filter by status',
'projects.filterAll': 'All',
'projects.filterProgress': 'In Progress',
'projects.filterCompleted': 'Completed',
'projects.filterDraft': 'Drafts',
'projects.loading': 'Loading projects',
'projects.loadError': "Couldn't load projects",
'projects.loadErrorBody': 'The backend did not respond.',
'projects.emptyTitle': 'No projects yet',
'projects.emptyBody':
'Calliope turns a story idea into characters, shots and finished video — all on your machine.',
'projects.firstProject': 'Create your first project',
'projects.noMatchSearch': 'No projects match “{q}”',
'projects.noMatchFilter': 'No projects match the current filter',
'projects.noMatchBody': 'Try a different search or clear the filters.',
'projects.clearFilters': 'Clear filters',
'projects.newCard': 'Create New Project',
'projects.newCardSub': 'Start with a story idea',
'projects.created': 'Project “{title}” created',
'projects.createFailed': 'Could not create project',
// --- Project form options (values stored in English) ---
'genres.adventure': 'Adventure / Mystery',
'genres.drama': 'Drama',
'genres.scifi': 'Sci-Fi',
'genres.fantasy': 'Fantasy',
'genres.horror': 'Horror',
'genres.romance': 'Romance',
'genres.thriller': 'Thriller',
'tones.cinematic': 'Cinematic, atmospheric',
'tones.dark': 'Dark, tense',
'tones.whimsical': 'Whimsical, warm',
'tones.gritty': 'Gritty, realistic',
'tones.epic': 'Epic, sweeping',
'durations.30': '30 seconds',
'durations.1m': '1 minute',
'durations.2m': '2 minutes',
'durations.5m': '5 minutes',
'durations.10m': '10 minutes',
// --- Project card ---
'projectCard.actions': 'Project actions',
'projectCard.assets': 'Assets',
'projectCard.changeCover': 'Change cover',
'projectCard.characters': 'Characters',
'projectCard.deleted': 'Project deleted',
'projectCard.deleteFailed': 'Could not delete project',
'projectCard.deleteMessage': 'This will permanently delete the project and its assets. This cannot be undone.',
'projectCard.deleteTitle': 'Delete project',
'projectCard.menuLabel': 'Project menu',
'projectCard.noIdea': 'No story idea yet',
'projectCard.open': 'Open project',
'projectCard.renamedTo': 'Renamed to “{title}”',
'projectCard.renameFailed': 'Could not rename project',
'projectCard.renameTitle': 'Rename project',
'projectCard.scenes': 'Scenes',
'projectCard.status.in_progress': 'In Progress',
'projectCard.status.completed': 'Completed',
'projectCard.status.draft': 'Draft',
'projectCard.timeJustNow': 'just now',
'projectCard.timeM': '{n}m ago',
'projectCard.timeH': '{n}h ago',
'projectCard.timeD': '{n}d ago',
'projectCard.timeMo': '{n}mo ago',
'projectCard.timeY': '{n}y ago',
// --- Project detail page ---
'project.backToProjects': 'Back to projects',
'project.notFound': 'Project not found',
'project.invalidIdBody': '“{id}” isn’t a valid project id — the link may be broken or the project was deleted.',
'project.openVideoStage': 'Open the Video stage',
'project.runningQueued': '{running} running · {queued} queued',
'project.queueIdle': 'Queue idle',
// --- API errors ---
'api.unknownError': 'Something went wrong',
'api.networkError': 'Cannot reach the workbench backend — check that it is running and retry',
'api.httpError': 'Request failed (HTTP {status}): {detail}',
'playground.openFailed': 'Failed to open playground',
'playground.opening': 'Opening playground…',
'agents.opening': 'Opening agent…',
'agents.openFailed': 'Failed to open agent',
// --- ActivityPanel ---
'activity.title': 'Activity',
'activity.agentLog': 'Agent log',
'activity.agentWorking': 'Agent working…',
'activity.assetReady': 'Asset ready',
'activity.busyCount': '{n} busy',
'activity.connecting': 'Connecting',
'activity.reconnecting': 'Reconnecting',
'activity.quiet': 'Idle',
'activity.quietHint': 'No background jobs',
'activity.show': 'Show',
'activity.hide': 'Hide',
'activity.done': 'Done',
'activity.failed': 'Failed',
'activity.files': 'Files',
'activity.filesSaved': '{n} files saved',
'activity.finished': 'Finished',
'activity.jobDeleted': 'Job deleted',
'activity.outputSaved': 'Output saved',
'activity.queue': 'Queue',
'activity.queueIdle': 'Queue idle',
'activity.queueStats': '{active} active · {queued} queued',
'activity.queued': 'Queued',
'activity.removed': 'Removed',
'activity.running': 'Running',
'activity.storylineDrafted': 'Storyline drafted',
'activity.storyReady': 'Story ready',
'activity.working': 'Working…',
// --- SafeMedia ---
'safeMedia.noMedia': 'No media',
// --- ImageLightbox ---
'lightbox.clickToFit': 'Click to fit',
'lightbox.clickToZoom': 'Click to zoom',
'lightbox.closeEsc': 'Press Esc to close',
'lightbox.closeHint': 'Close',
'lightbox.closePreview': 'Close preview',
'lightbox.download': 'Download',
'lightbox.downloadMedia': 'Download media',
'lightbox.fitToScreen': 'Fit to screen',
'lightbox.imagePreview': 'Image preview',
'lightbox.imageUnavailable': 'Image unavailable',
'lightbox.next': 'Next',
'lightbox.prev': 'Previous',
'lightbox.openOriginal': 'Open original',
'lightbox.videoPreview': 'Video preview',
'lightbox.videoUnavailable': 'Video unavailable',
'lightbox.zoom100': '100%',
'lastFrame.export': 'Export last frame',
'lastFrame.exporting': 'Exporting last frame…',
'lastFrame.hint': 'Save the final frame as a full-size PNG, e.g. as a first-frame reference',
'lastFrame.fileTag': 'last-frame',
'lastFrame.done': 'Exported last frame {name} ({size})',
'lastFrame.errTimeout': 'The video took too long to load. Try again later.',
'lastFrame.errNotFound': 'The video file is missing or was removed.',
'lastFrame.errForbidden': 'You do not have permission to read this video.',
'lastFrame.errNetwork': 'Reading the video failed (network error). Check the connection and retry.',
'lastFrame.errDecode': 'The video is damaged; its ending cannot be decoded.',
'lastFrame.errUnsupported': 'This browser cannot play the video format, or the file is damaged.',
'lastFrame.errCrossOrigin':
'The video comes from another site that blocks reading its frames (cross-origin). Download the video first.',
'lastFrame.errNoPicture': 'This file has no video picture.',
'lastFrame.errUnseekable':
'Cannot reach the end of the video (unknown length, or the source does not allow seeking); no frame exported.',
'lastFrame.errBlack': 'The last second of the video is black; no frame exported.',
'lastFrame.errEmpty': 'The browser could not decode the ending. Retry, or use desktop Chrome / Edge.',
'lastFrame.errUnknown': 'Exporting the last frame failed: {msg}',
// --- Artifact / canvas nodes ---
'artifact.artifactLabel': 'Artifact',
'artifact.fileMissing': 'File missing',
'artifact.imageUnavailable': 'Image unavailable',
'artifact.playInViewer': 'Play in viewer',
'artifact.playVideo': 'Play video',
'artifact.videoUnavailable': 'Video unavailable',
'artifact.viewImage': 'View image',
'canvas.emptyHint': 'Ask the agent on the right to create characters, scenes, or to generate an image or video — outputs land here as cards.',
'canvas.loadFailed': 'Could not load this canvas',
'canvas.tidy': 'Tidy layout',
'canvas.tidyTitle': 'Re-arrange all cards into clean columns and grids',
'canvas.savePosFailed': 'Could not save position',
'canvas.openThatFailed': 'Could not open that canvas',
'canvas.sessionCreateFailed': 'Could not create session',
'canvas.sessionDeleteFailed': 'Could not delete session',
'canvas.renameFailed': 'Rename failed',
'canvas.suggestFilm': 'Create a new film',
'canvas.suggestStory': 'Draft a storyline',
'canvas.emptyBoard': 'Empty board',
'canvas.noChatSelected': 'No chat selected',
'canvas.failed': 'failed',
'canvas.generating': 'generating…',
'canvas.noMedia': 'no media',
'canvas.openPreview': 'Open large preview',
'canvas.running': 'running',
'canvas.openFailed': 'Failed to open board',
'canvas.opening': 'Opening board…',
'canvas.invalidId': 'Invalid canvas id',
'canvas.confirmDeleteChat': 'Delete this chat and its message history?',
'canvas.sessionDeleted': 'Session deleted',
'canvas.chatUnlinked': 'Chat unlinked — moved to Sandbox',
'canvas.unlinkFailed': 'Unlink failed',
'canvas.unlinkButton': 'Unlink',
'canvas.resizePanel': 'Resize chat panel (drag or arrow keys), currently {width} pixels',
'canvas.sendFailed': 'Failed to send',
'canvas.runCancelled': 'Run cancelled',
'canvas.cancelFailed': 'Cancel failed',
'canvas.tidied': 'Tidied {count} cards into columns',
'canvas.tidyFailed': 'Tidy failed',
'canvas.rename': 'Rename canvas',
'canvas.waitFinish': 'Wait for the run to finish',
'canvas.unlinkFrom': 'Unlink this chat from {title}',
'canvas.noChatYet': 'No chat on this canvas yet',
'canvas.collapseChat': 'Collapse chat',
'canvas.expandChat': 'Expand chat',
'canvas.deleteBlocked': 'Project assets and running jobs can’t be deleted here — replace them from Project Assets',
'canvas.deleteFailed': 'Could not delete {count} card(s)',
'canvas.deletedWithFile': 'Deleted {count} card(s) and file(s) from the Asset Library',
'canvas.deletedCardOnly': 'Removed {count} card(s) — file kept (project data)',
'canvas.deletedMixed': 'Deleted {files} file(s), kept {kept} (project data)',
'global.somethingWentWrong': 'Something went wrong.',
// --- Memory ---
'memory.title': 'Memory',
'memory.lead': 'Persisted facts the agent remembers across sessions.',
'memory.empty': 'Nothing saved yet',
'memory.loading': 'Loading memory',
'memory.placeholder': 'Add a fact the agent should remember…',
'memory.saveFailed': 'Could not save memory',
'memory.saved': 'Saved',
'memory.deleteFailed': 'Could not delete',
'memory.forget': 'Forget',
'memory.chooseProject': 'Project',
'memory.kindConvention': 'Convention',
'memory.kindCorrection': 'Correction',
'memory.kindPreference': 'Preference',
'memory.groupGlobal': 'Global',
'memory.groupProject': 'Project',
'memory.scopeGlobal': 'All projects',
'memory.scopeProject': 'This project',
'memory.sourceAgent': 'Agent',
'memory.sourceYou': 'You',
'memory.usedCount': 'Used {n} times',
// --- Skills ---
'skills.title': 'Skills',
'skills.lead': 'Agent skills available in this project.',
'skills.close': 'Close',
'skills.copied': 'Copied',
'skills.copy': 'Copy path',
'skills.copyPath': 'Path copied to clipboard',
'skills.copyPathBtn': 'Copy',
'skills.couldNotRead': 'Could not read skill',
'skills.filesIn': 'Files in this skill',
'skills.hideFiles': 'Hide files',
'skills.showFiles': 'Show files',
'skills.howto1': 'Skills add reusable abilities to the agent.',
'skills.howto2': 'Reference a skill with @name in the composer.',
'skills.howto3': 'The agent loads it on demand.',
'skills.howto4': 'Add skills by placing folders under .agents/skills.',
'skills.howtoTitle': 'How skills work',
'skills.loadingFile': 'Loading file…',
'skills.noFiles': 'No files',
'skills.noSkills': 'No skills available',
'skills.note': 'Note',
'skills.refresh': 'Refresh',
'skills.refreshed': 'Skills refreshed',
'skills.truncated': 'Preview truncated',
// --- Reasoning ---
'reasoning.title': 'Reasoning',
'reasoning.thinking': 'Thinking…',
'reasoning.show': 'Show reasoning',
// --- Agent chat/composer ---
'agentChat.approveRender': 'Approve render',
'agentChat.approveReplace': 'Approve replace',
'agentChat.emptyHint': 'The agent is ready. Ask it to draft storylines, edit assets, or build scenes.',
'agentChat.emptyTitle': 'Start a conversation',
'agentChat.loading': 'Loading conversation',
'agentChat.pickOption': 'Pick an option',
'agentChat.working': 'Agent is working…',
'agent.task.story': 'Draft Storyline',
'agent.task.script': 'Regenerate Script',
'agentComposer.aria': 'Message composer',
'agentComposer.attach': 'Attach file',
'agentComposer.attachLimit': 'Attachment limit reached',
'agentComposer.attachments': 'Attachments',
'agentComposer.mentionLock': 'Locked to this project',
'agentComposer.message': 'Message',
'agentComposer.placeholder': 'Ask the agent or @mention a skill…',
'agentComposer.remove': 'Remove attachment',
'agentComposer.sendTitle': 'Send message',
'agentComposer.stopTitle': 'Stop agent',
'agentComposer.working': 'Sending…',
'agentComposer.steer': 'Steer',
'agentComposer.steerTitle': 'Send a course correction while the agent works',
'agentComposer.steerPlaceholder': 'Steer the agent while it works…',
'agentChat.steering': 'Steering',
'agentPlan.planner': 'Plan',
'agentPlan.skipped': 'Skipped',
'agentTool.args': 'Arguments',
'agentTool.done': 'Done',
'agentTool.failed': 'Failed',
'agentTool.result': 'Result',
'agentTool.running': 'Running…',
'mentionMenu.noSkill': 'No matching skill',
'mentionMenu.noWorkflow': 'No matching workflow',
'mentionMenu.skills': 'Skills',
'mentionMenu.workflows': 'Workflows',
// --- Agent session sidebar ---
'sessionSidebar.collapse': 'Collapse sidebar',
'sessionSidebar.expand': 'Expand sidebar',
'sessionSidebar.deleteSession': 'Delete session',
'sessionSidebar.newProjectChat': 'New project chat',
'sessionSidebar.newSandbox': 'New sandbox',
'sessionSidebar.newSandboxButton': 'New sandbox session',
'sessionSidebar.noSessions': 'No sessions yet',
'sessionSidebar.open': 'Open session',
'sessionSidebar.projectFallback': 'Project chat',
'sessionSidebar.sandbox': 'Sandbox',
// --- Story stage ---
'story.stageTitle': 'Story',
'story.ideaTitle': 'Story idea',
'story.ideaPlaceholder': 'Describe the story you want to tell…',
'story.targetLength': 'Target length',
'story.lengthsHint': 'How long should the finished video feel?',
'story.lengthHint': 'Guides beat and scene counts.',
'story.draftStoryline': 'Draft storyline',
'story.draftPromptTitle': 'Draft prompt',
'story.promptExplain': 'The finished brief the agent uses to structure the story.',
'story.showPrompt': 'Show prompt',
'story.hidePrompt': 'Hide prompt',
'story.promptCollapsedHint': 'Edit the draft prompt before generating beats.',
'story.addBeat': 'Add beat',
'story.addBeatManual': 'Add beat manually',
'story.addBeatFailed': 'Could not add beat',
'story.beatAdded': 'Beat added',
'story.beatDeleted': 'Beat deleted',
'story.beatSaved': 'Beat saved',
'story.deleteBeat': 'Delete beat',
'story.deleteBeatFailed': 'Could not delete beat',
'story.beats': 'Beats',
'story.editBeatTitle': 'Edit beat',
'story.editCharTitle': 'Edit character',
'story.editLocTitle': 'Edit location',
'story.editItemTitle': 'Edit item',
'story.fieldAge': 'Age',
'story.fieldAppearance': 'Appearance',
'story.fieldConsistency': 'Consistency',
'story.fieldDescription': 'Description',
'story.fieldName': 'Name',
'story.fieldPersonality': 'Personality',
'story.fieldRole': 'Role',
'story.fieldTitle': 'Heading',
'story.noBeats': 'No beats yet',
'story.noBeatsBody': 'Add beats manually or let the agent draft a storyline.',
'story.continueAssets': 'Continue to assets',
'story.confirmDeleteBeatMsg': 'This beat will be permanently deleted. Continue?',
'story.confirmDeleteBeatTitle': 'Delete beat?',
'story.confirmExampleMsg': 'This replaces your current story idea with the example.',
'story.confirmExampleTitle': 'Load example?',
'story.exampleLoaded': 'Example loaded',
'story.extracted': 'Extracted from story',
'story.charTag': 'CHARACTER',
'story.envTag': 'LOCATION',
'story.itemTag': 'ITEM',
'story.beatsTitle': 'Story beats',
'story.characterSaved': 'Character saved',
'story.locationSaved': 'Location saved',
'story.itemSaved': 'Item saved',
'story.openAssets': 'Open assets',
'story.loadExample': 'Load example',
'story.saveBeatFailed': 'Could not save beat',
'story.saveCharacterFailed': 'Could not save character',
'story.saveItemFailed': 'Could not save item',
'story.saveLocationFailed': 'Could not save location',
'story.saveSettingsFailed': 'Could not save settings',
'story.settingsTitle': 'Story settings',
'story.llmBanner': 'The story stage uses the active LLM to draft and refine beats.',
'story.newBeat': 'New beat {n}',
// --- Assets stage ---
'assets.title': 'Assets',
'assets.lead': 'Characters, locations and items generated for your story.',
'assets.tabCharacters': 'Characters',
'assets.tabEnvironments': 'Locations',
'assets.tabItems': 'Items',
'assets.tabAria': 'Asset type tabs',
'assets.kind.character': 'Character',
'assets.kind.environment': 'Location',
'assets.kind.item': 'Item',
'assets.charSheets': 'Character sheets',
'assets.envRefs': 'Location references',
'assets.itemRefs': 'Item references',
'assets.charSheetPlaceholder': 'Reference sheet',
'assets.optionEnvironment': 'Location reference',
'assets.optionItem': 'Item reference',
'assets.optionSheet': 'Character sheet',
'assets.generateImage': 'Generate image',
'assets.generateSheet': 'Generate sheet',
'assets.replaceImage': 'Replace image',
'assets.regenImage': 'Regenerate image',
'assets.regenSheet': 'Regenerate sheet',
'assets.regenImageFor': 'Regenerate image for “{name}”',
'assets.regenSheetFor': 'Regenerate sheet for “{name}”',
'assets.generating': 'Generating…',
'assets.generatingEllipsis': 'Generating',
'assets.queuing': 'Queuing…',
'assets.generateMissing': 'Generate missing',
'assets.generateMissingTitle': 'Generate missing assets',
'assets.editPrompt': 'Edit prompt',
'assets.savePrompt': 'Save prompt',
'assets.resetSheetTemplate': 'Reset sheet template',
'assets.resetEnvTemplate': 'Reset location template',
'assets.resetItemTemplate': 'Reset item template',
'assets.noCharsTitle': 'No characters yet',
'assets.noCharsBody': 'Characters appear here once the story defines them.',
'assets.noEnvsTitle': 'No locations yet',
'assets.noEnvsBody': 'Locations appear here once the story defines them.',
'assets.noItemsTitle': 'No items yet',
'assets.noItemsBody': 'Items appear here once the story defines them.',
'assets.confirmDeleteTitle': 'Delete asset',
'assets.confirmDeleteLabel': 'Delete',
'assets.confirmDeleteBody': 'This asset and its generated images will be deleted. Continue?',
'assets.confirmDeleteFallback': 'Delete this asset?',
'assets.deleteCharacter': 'Delete character',
'assets.deleteEnvironment': 'Delete location',
'assets.deleteItem': 'Delete item',
'assets.deleteFor': 'Delete “{name}”',
'assets.description': 'Description',
'assets.appearance': 'Appearance',
'assets.personality': 'Personality',
'assets.cover': 'Cover',
'assets.removeCover': 'Remove cover',
'assets.removeCoverChar': 'Remove character cover',
'assets.removeCoverRef': 'Remove reference cover',
'assets.setCover': 'Set as cover',
'assets.setCoverChar': 'Set as character cover',
'assets.setCoverRef': 'Set as reference cover',
'assets.refPlaceholder': 'Reference',
'assets.sentToComfy': 'Sent to ComfyUI',
'assets.uploadImage': 'Upload image',
'assets.viewCharFull': 'View character full',
'assets.viewRefFull': 'View reference full',
'assets.viewFull': 'View full size',
'assets.charSheetAlt': 'Character sheet for {name}',
'assets.goToStory': 'Go to Story',
'assets.genSettings': 'Generation settings',
'assets.toast.addImageFailed': 'Could not add image',
'assets.toast.chooseImage': 'Choose an image',
'assets.toast.coverFail': 'Could not set cover',
'assets.toast.coverRemoved': 'Cover removed',
'assets.toast.coverUpdated': 'Cover updated',
'assets.toast.deleted': 'Asset deleted',
'assets.toast.deleteFailed': 'Could not delete asset',
'assets.toast.imageAdded': 'Image added',
'assets.toast.jobRequeued': 'Requested again',
'assets.toast.nothingMissing': 'Nothing is missing',
'assets.toast.notImage': 'That file is not an image',
'assets.toast.queued': 'Image queued',
'assets.toast.queuedMany': '{n} images queued',
'assets.toast.queuedOne': 'Image queued',
'assets.toast.retryFailed': 'Could not retry',
'assets.toast.savedPrompt': 'Prompt saved',
'assets.toast.savePromptFailed': 'Could not save prompt',
'assets.wf.sheet': 'Character sheet workflow',
'assets.wf.environment': 'Location reference workflow',
'assets.wf.item': 'Item reference workflow',
'assets.wf.selectSheet': 'Select a sheet workflow',
'assets.wf.selectEnv': 'Select a location workflow',
'assets.wf.selectItem': 'Select an item workflow',
'assets.wf.needWorkflow': 'Set up a workflow on the Settings page first.',
'assets.wf.missingInputs': 'This workflow is missing required inputs.',
'assets.wf.none': 'No workflow selected',
'assets.wf.noPromptPre': 'This workflow has no prompt input.',
'assets.wf.noPromptPost': 'Add a prompt field to use it here.',
'assets.noWorkflowPre': 'Generation needs a workflow.',
'assets.noWorkflowPost': 'Configure one in Settings.',
'assets.noWorkflowLink': 'Open Settings',
// --- Build scene ---
'buildScene.title': 'Build Scene',
'buildScene.builderBadge': '3D Builder',
'buildScene.preparing': 'Preparing scene…',
'buildScene.stillLoading': 'Scene still loading…',
'buildScene.expandChat': 'Expand chat',
'buildScene.collapseChat': 'Collapse chat',
'buildScene.videoExported': 'Video exported',
'buildScene.legacyNeedsViewport': 'Viewport not ready for export',
'buildScene.videoExportFailed': 'Video export failed',
'buildScene.captureSaved': 'Capture saved',
'buildScene.createSceneFailed': 'Could not create scene',
'buildScene.deleteSceneFailed': 'Could not delete scene',
'buildScene.sendFailed': 'Could not send message',
'buildScene.runCancelled': 'Run cancelled',
'buildScene.cancelFailed': 'Could not cancel',
'buildScene.openCompositionFailed': 'Could not open composition',
'buildScene.uploadSizeFail': 'File too large',
// --- Script stage ---
'script.actionField': 'Action',
'script.actionPlaceholder': 'What happens in this scene…',
'script.dialogField': 'Dialogue',
'script.dialogPlaceholder': 'Who says what…',
'script.headingField': 'Heading',
'script.headingPlaceholder': 'INT. HARBOR — NIGHT',
'script.sceneNumber': 'Scene {n}',
'script.edit': 'Edit scene',
'script.editScene': 'Edit scene',
'script.editSceneNumbered': 'Edit scene {n}',
'script.durationField': 'Duration',
'script.addScene': 'Add scene',
'script.deleteSceneTitle': 'Delete scene',
'script.deleteSceneMessage': 'This scene and its shots will be deleted. Continue?',
'script.delete': 'Delete scene',
'script.loadingScenes': 'Loading scenes',
'script.noScenesTitle': 'No scenes yet',
'script.noScenesBody': 'Break your story into scenes to start filming.',
'script.regenerate': 'Regenerate script',
'script.break': 'Break into shots',
'script.breakTitle': 'Break scene into shots',
'script.rebreak': 'Rebreak shots',
'script.rebreakTitle': 'Rebreak shots for this scene',
'script.breakAllIntoShots': 'Break all into shots',
'script.breakAllTitle': 'Break every scene into shots',
'script.chainOn': 'Chain clips',
'script.chainOff': 'Unchain clips',
'script.chainTitle': 'Toggle clip chaining',
'script.save': 'Save',
'script.untitledScene': 'Untitled scene',
'script.untitledShot': 'Untitled shot',
'script.justAdded': 'Added',
'script.rendering': 'Rendering…',
'script.renderedCount': '{n} clips rendered',
'script.clipDone': 'Clip done',
'script.noActionYet': 'No action written yet',
'script.shotClipSingular': '1 clip',
'script.shotClipPlural': '{n} clips',
'script.moveSceneUp': 'Move scene up',
'script.moveSceneDown': 'Move scene down',
'script.deleteShotAria': 'Delete shot',
'script.deleteShotTitle': 'Delete shot',
'script.status.rendering': 'Rendering',
'script.status.renderFailed': 'Failed',
'script.status.clipReady': 'Ready',
'script.status.noClip': 'No clip',
'script.toast.addSceneFail': 'Could not add scene',
'script.toast.boardExpanded': 'Scene opened on the board',
'script.toast.breakAllConfirm': 'Break all scenes into shots?',
'script.toast.breakAllFail': 'Could not break scenes',
'script.toast.breakFail': 'Could not break scene',
'script.toast.breakIntoShots': 'Scene broken into shots',
'script.toast.deleteClipFail': 'Could not delete clip',
'script.toast.deleted': 'Scene deleted',
'script.toast.deletedShot': 'Shot deleted',
'script.toast.deleteFailed': 'Could not delete',
'script.toast.saveSceneFail': 'Could not save scene',
'script.toast.sceneAdded': 'Scene added',
'script.toast.sceneSaved': 'Scene saved',
'script.toast.updateSceneFail': 'Could not update scene',
// --- Script drawer ---
'scriptDrawer.script': 'Script',
'scriptDrawer.heading': 'Heading',
'scriptDrawer.action': 'Action',
'scriptDrawer.dialog': 'Dialogue',
'scriptDrawer.characters': 'Characters',
'scriptDrawer.noAction': 'No action written',
'scriptDrawer.noDialog': 'No dialogue',
'scriptDrawer.regionAria': 'Script region',
'scriptDrawer.untitled': 'Untitled',
'scriptDrawer.untitledScene': 'Untitled scene',
// --- Queue stage ---
'queue.sceneLabel': 'Scene',
'queue.clipLabel': 'Clip #{n}',
'queue.jobLabel': 'Job #{n}',
'queue.scene': 'Scene {n}',
'queue.sceneRef': 'Scene reference',
'queue.clipRef': 'Clip reference',
'queue.clipQueued': 'Clip queued',
'queue.clipsDoneSummary': '{done}/{total} clips done',
'queue.clipsMissing': 'Some shots have no clip yet',
'queue.clipRenderUpdated': 'Clip render updated',
'queue.clipsChanged': 'Clips changed',
'queue.blockoutLabel': 'Blockout',
'queue.blockoutSuffix': 'blockout',
'queue.blockoutClipSuffix': 'blockout clip',
'queue.uploadSuffix': 'upload',
'queue.generateAllTitle': 'Generate all clips',
'queue.generateMissing': 'Generate missing',
'queue.regenerateAll': 'Regenerate all',
'queue.queueingProgress': 'Queued {n}/{total} jobs',
'queue.queued': 'Queued',
'queue.queuedInSequence': 'Will run in sequence',
'queue.pauseQueue': 'Pause queue',
'queue.resumeQueue': 'Resume queue',
'queue.paused': 'Queue paused',
'queue.pausedText': 'New jobs wait until you resume.',
'queue.resumeNow': 'Resume now',
'queue.editTab': 'Scenes',
'queue.filmTab': 'Film',
'queue.filmViewAria': 'Film view',
'queue.viewAria': 'Queue view',
'queue.emptyHeader': 'Nothing queued yet',
'queue.noTimeline': 'No timeline yet',
'queue.noTimelineBody': 'Generate clips first, then export the film.',
'queue.savedDrafts': 'Drafts saved here',
'queue.exportFilm': 'Export film',
'queue.downloadFilm': 'Download film',
'queue.exporting': 'Exporting…',
'queue.exportingTitle': 'Exporting film',
'queue.exportingSub': 'Combining {n} clips into a single video.',
'queue.exportQueued': 'Export queued',
'queue.exportedAgo': 'Exported {ago}',
'queue.exportFailed': 'Export failed',
'queue.retryExport': 'Retry export',
'queue.exportUnavailable': 'Export not available yet',
'queue.notExported': 'Not exported',
'queue.notExportedTitle': 'No export yet',
'queue.slateSub': '{clips} clips · {time} · 0.5s crossfades · loudness matched',
'queue.staleBanner': 'Clips changed since export',
'queue.exportDisabledTitle': 'Add at least one clip to export',
'queue.chainDisabledReason': 'Select a scene or clip first',
'queue.editInTimeline': 'Edit in timeline',
'queue.inThisFilm': 'In this film',
'queue.filmMeta': '{scenes} scenes · {clips} clips · {duration}',
'queue.reexport': 'Re-export',
// --- Job / job drawer ---
'job.title': 'Job',
'job.status.generating': 'Generating',
'job.status.generatingPulse': 'Generating',
'job.status.queued': 'Queued',
'job.status.running': 'Running',
'job.status.done': 'Done',
'job.status.failed': 'Failed',
'job.cancelJob': 'Cancel job',
'job.cancelFailed': 'Could not cancel job',
'job.cancelled': 'Cancelled',
'job.requeued': 'Requeued',
'job.retryJob': 'Retry job',
'job.retryFailed': 'Could not retry job',
'job.exportFilm': 'Export film',
'jobDrawer.title': 'Job details',
'jobDrawer.historyAria': 'Job history',
'jobDrawer.noJobs': 'No jobs yet',
'jobDrawer.noPrompt': 'No prompt for this job',
'jobDrawer.output': 'Output',
'jobDrawer.prompt': 'Prompt',
'jobDrawer.references': 'References',
'jobDrawer.characterRef': 'Character reference',
'jobDrawer.locationRef': 'Location reference',
'jobDrawer.audioInput': 'Audio input',
'jobDrawer.videoInput': 'Video input',
'jobDrawer.refImage': 'Reference image',
'jobDrawer.currentClip': 'Current clip',
'jobDrawer.otherInputs': 'Other inputs',
'jobDrawer.copy': 'Copy',
'jobDrawer.copied': 'Copied',
'jobDrawer.copySettings': 'Copy settings',
'jobDrawer.applying': 'Applying…',
'jobDrawer.applyToScene': 'Apply to scene',
'jobDrawer.h3Hint': 'The selection above was used for this job.',
// --- Filmstrip ---
'filmstrip.title': 'Filmstrip',
'filmstrip.clipTitle': '{scene} · shot {shot} · {time}',
'filmstrip.scene': 'Scene',
'filmstrip.sceneClips': '{n} clips',
'filmstrip.prev': 'Previous clip',
'filmstrip.next': 'Next clip',
// --- Clip monitor / clip source ---
'clipMonitor.untitled': 'Untitled clip',
'clipMonitor.id': 'Clip ID',
'clipMonitor.sceneId': 'Scene ID',
'clipMonitor.generating': 'Generating…',
'clipMonitor.generationFailed': 'Generation failed',
'clipMonitor.queued': 'Queued',
'clipMonitor.noRenderHint': 'This clip has no render yet.',
'clipMonitor.downloadClip': 'Download clip',
'clipMonitor.videoUnavailable': 'Video unavailable',
'clipMonitor.showDetails': 'Show details',
'clipMonitor.hideDetails': 'Hide details',
'clipSource.title': 'Clip source',
'clipSource.projectClips': 'Project clips',
'clipSource.noClips': 'No clips available',
'clipSource.autoName': 'Auto',
'clipSource.autoDesc': 'Auto label',
'clipSource.uploadName': 'Upload',
'clipSource.uploadDesc': 'Upload a file',
// --- Video edit workspace ---
'videoEdit.clipId': 'Clip ID',
'videoEdit.sceneId': 'Scene ID',
'videoEdit.generateLabel': 'Generate',
'videoEdit.videoSource': 'Video source',
'videoEdit.noVideoInputWf': 'This workflow has no video input',
'videoEdit.noWf': 'No workflow selected',
'videoEdit.wfLink': 'Configure workflows in Settings',
'videoEdit.enableWfPre': 'Render with the active workflow?',
'videoEdit.enableWfPost': 'It determines output format.',
'videoEdit.assetHint': 'Pick the generation target',
'videoEdit.continueHint': 'Continue with the selected workflow',
'videoEdit.viewPrompt': 'View prompt',
'videoEdit.dockAria': 'Clip generation inputs',
// --- Shot brief ---
'shotBrief.copyTitle': 'Copy shot description',
'shotBrief.copied': 'Copied',
'shotBrief.copy': 'Copy',
'shotBrief.collapse': 'Collapse shot brief',
'shotBrief.expand': 'Expand shot brief',
'shotBrief.noDesc': 'No shot description — this clip inherited the scene defaults.',
'shotBrief.notePre': 'This clip has no per-shot description yet — the text above is the full scene action. Use',
'shotBrief.breakIntoShots': 'Break into shots',
'shotBrief.notePost': 'in the Script stage to split it into coverage.',
'shotBrief.dialogKey': 'Dialog in this shot',
'shotBrief.characters': 'Characters',
// --- Prompt preview modal ---
'promptPreview.title': 'Prompt preview',
'promptPreview.generate': 'Generate',
'promptPreview.regenerate': 'Regenerate',
'promptPreview.resolving': 'Resolving prompt…',
'promptPreview.saveDraft': 'Save draft',
'promptPreview.draftSaved': 'Draft saved',
'promptPreview.promptEmpty': 'Nothing to preview yet',
'promptPreview.noClip': 'No clip',
'promptPreview.noClipSelected': 'No clip selected',
'promptPreview.untitled': 'Untitled',
'promptPreview.failedHint': 'Prompt resolution failed — showing a fallback instead.',
'promptPreview.staleHint': 'Resolution is stale — resend to get the current prompt.',
'promptPreview.fromDraftHint': 'Based on your draft, not the current workflow.',
'promptPreview.proseHint': 'Editable prose prompt — changes stay local.',
'promptPreview.h3Hint': 'Prompt built from the selection above.',
'promptPreview.criticTitle': 'Continuity check',
'promptPreview.h3Rewrite': 'Rewritten',
'promptPreview.editorAria': 'Prompt editor',
'promptPreview.defaultWorkflow': 'default',
'promptPreview.sceneMeta': 'Scene #{index} · {heading}',
'promptPreview.shotMeta': 'Shot {label} · {heading}',
// --- Workflows (wf) ---
'wf.title': 'Workflows',
'wf.lead': 'Upload and register ComfyUI workflows for generation.',
'wf.loadingWorkflows': 'Loading workflows',
'wf.noWorkflows': 'No workflows registered',
'wf.noWorkflowsHint': 'Drop a workflow JSON below to get started.',
'wf.detectedInputs': 'Detected inputs',
'wf.detectedOutputs': 'Detected outputs',
'wf.inputs': 'Inputs',
'wf.outputs': 'Outputs',
'wf.inputsCount': '{n} inputs',
'wf.outputsCount': '{n} outputs',
'wf.kind': 'Type',
'wf.kindImage': 'Image',
'wf.kindVideo': 'Video',
'wf.enable': 'Enable',
'wf.disable': 'Disable',
'wf.disabled': 'Disabled',
'wf.stateEnabled': 'Enabled',
'wf.stateDisabled': 'Disabled',
'wf.enabledState': 'Enabled',
'wf.hideIo': 'Hide inputs/outputs',
'wf.viewIo': 'Show inputs/outputs',
'wf.dropHint': 'Drop workflow JSON here',
'wf.dropSub': 'or click to browse',
'wf.namePlaceholder': 'Workflow name',
'wf.descPlaceholder': 'Short description (optional)',
'wf.invalidJson': 'This file is not valid workflow JSON',
'wf.jsonLocked': 'Frozen by an active job',
'wf.jsonPreview': 'Workflow JSON',
'wf.reanalyze': 'Re-analyze',
'wf.saveToLibrary': 'Save to library',
'wf.savedWorkflows': 'Saved workflows',
'wf.savedToLibrary': 'Saved to library',
'wf.saveFailed': 'Could not save workflow',
'wf.updateFailed': 'Could not update workflow',
'wf.updated': 'Workflow updated',
'wf.deleted': 'Workflow deleted',
'wf.deleteFailed': 'Could not delete workflow',
'wf.deleteTitle': 'Delete workflow',
'wf.deleteMessage': 'This workflow and its saved JSON will be deleted.',
'wf.analyzeRegister': 'Analyze & register',
'wf.countImage': '{n} images',
'wf.countVideo': '{n} videos',
'wf.countSaved': '{n} saved',
'wf.profileH3': 'Use case',
'wf.profileProse': 'This workflow generates {kind} from a {target}.',
'wf.promptFormat': 'Prompt format',
'wf.noInputs': 'No inputs detected',
'wf.noInputsCached': 'No inputs',
'wf.noOutputs': 'No outputs detected',
'wf.noOutputsCached': 'No outputs',
// --- Comfy dynamic form (cdf) ---
'cdf.browse': 'Browse',
'cdf.chooseAsset': 'Choose asset',
'cdf.clear': 'Clear',
'cdf.clearAria': 'Clear field',
'cdf.dropPre': 'Drop a file',
'cdf.localPath': 'Local path',
'cdf.noAssets': 'No assets yet',
'cdf.noInputs': 'No configurable inputs',
'cdf.orChooseAsset': 'or choose an asset',
'cdf.required': 'required',
'cdf.requiredMsg': 'This field is required',
'cdf.selectedPreviewAlt': 'Selected preview',
'cdf.uploadedPreviewAlt': 'Uploaded preview',
'cdf.uploadFailed': 'Upload failed',
'cdf.uploading': 'Uploading…',
// --- Omni composer ---
'omni.advanced': 'Advanced',
'omni.assetType': 'Asset type',
'omni.choose': 'Choose',
'omni.chooseReference': 'Choose reference',
'omni.clearSlot': 'Clear slot',
'omni.decrease': 'Decrease',
'omni.increase': 'Increase',
'omni.duration': 'Duration',
'omni.resolution': 'Resolution',
'omni.seed': 'Seed',
'omni.emptyCharacters': 'No characters yet',
'omni.emptyLocations': 'No locations yet',
'omni.emptyItems': 'No items yet',
'omni.emptyShots': 'No shots yet',
'omni.emptyClips': 'No clips yet',
'omni.emptyUploads': 'No uploads yet',
'omni.emptyUploadsNew': 'No uploads yet',
'omni.generate': 'Generate',
'omni.generateAria': 'Generate',
'omni.negativeAria': 'Negative prompt',
'omni.negativePlaceholder': 'Negative prompt…',
'omni.negativeToggle': 'Negative prompt',
'omni.noMatches': 'No matches',
'omni.noPromptRole': 'This workflow has no prompt input',
'omni.promptAria': 'Prompt',
'omni.promptPlaceholder': 'Describe the image…',
'omni.queuing': 'Queuing…',
'omni.removeSlot': 'Remove',
'omni.required': 'Required',
'omni.roleAudio': 'Audio',
'omni.roleCharacter': 'Character',
'omni.roleLocation': 'Location',
'omni.roleVideo': 'Video',
'omni.searchAssets': 'Search assets',
'omni.searchIn': 'Search in',
'omni.thisList': 'this list',
'omni.uploadNew': 'Upload new',
// --- Attach to project dialog ---
'attach.panelAria': 'Attach to project',
'attach.title': 'Attach to project',
'attach.addToProject': 'Add to project',
'attach.noScenes': 'No scenes yet',
'attach.noCharacters': 'No characters yet',
'attach.noLocations': 'No locations yet',
'attach.pickProject': 'Pick a project',
'attach.selectProject': 'Select project',
'attach.selectScene': 'Select scene',
'attach.selectCharacter': 'Select character',
'attach.selectLocation': 'Select location',
'attach.pickCharacter': 'Pick a character',
'attach.pickLocation': 'Pick a location',
'attach.pickScene': 'Pick a scene',
'attach.projectField': 'Project',
'attach.sceneField': 'Scene',
'attach.characterField': 'Character',
'attach.locationField': 'Location',
'attach.nameField': 'Name',
'attach.asCharacterSheet': 'as character sheet',
'attach.asItem': 'as item',
'attach.asLocation': 'as location',
'attach.addAs': 'Add as',
'attach.addBtn': 'Add',
'attach.added': 'Attached',
'attach.addedTo': 'Added to “{title}”',
'attach.failed': 'Could not attach',
'attach.dismiss': 'Dismiss',
'attach.viewInProject': 'View in project',
'attach.newItem': 'New item',
'attach.newItemHint': 'Create an item from this media.',
'attach.newItemPlaceholder': 'Item name',
'attach.projectFallback': 'Untitled project',
'attach.scene': 'Scene',
// --- Asset Library ---
'library.selectAll': 'Select all',
'library.deselectAll': 'Deselect all',
'library.itemCount': '{count} item(s)',
'library.loadError': 'Failed to load the library',
'library.subtitle': 'Generated assets in one place — preview, filter and remove images and videos not tied to a project',
'library.deleteSelected': 'Delete ({count})',
'library.addToProject': 'Add to Project',
'library.filterLabel': 'Filter by kind',
'library.filterAll': 'All',
'library.filterImage': 'Images',
'library.filterVideo': 'Videos',
'library.loadMore': 'Load more ({count} remaining)',
'library.loadingMore': 'Loading…',
'library.confirmDelete': 'Delete {count} selected file(s) from the Asset Library? This cannot be undone.',
'library.deleted': 'Deleted {count} file(s)',
'library.deletedPartial': '{kept} file(s) kept — still referenced by project data',
'library.deleteFailed': 'Could not delete',
'library.emptyTitle': 'Nothing in the Asset Library',
'library.emptyBody': 'Images and videos that are not linked to a project land here — upload on a canvas or generate in a sandbox chat.',
'library.emptyFilterTitle': 'No {kind} in the library',
'library.emptyFilterBody': 'Nothing matches this filter yet — try All or generate something new.',
// --- Settings ---
'settings.pageSub': 'Generation queue, agent runtime and storage paths · LLMs, ComfyUI connections and Skills live on their own pages',
'settings.secQueue': 'Queue & generation',
'settings.secQueueBlurb': 'Concurrency, retries, polling and dry run',
'settings.secAgent': 'Agent runtime',
'settings.secAgentBlurb': 'Steps, context, prompt hardening and shell',
'settings.secStorage': 'Storage paths',
'settings.secStorageBlurb': 'Data, assets and agent workspace folders',
'settings.elsewhere': 'Managed elsewhere',
'settings.linkModelsBlurb': 'LLMs and default model per agent',
'settings.linkConnectionsBlurb': 'Addresses, connection tests and workflow library',
'settings.linkAgentsBlurb': 'Skills and standalone chats for the five agents',
'settings.dryRunTitle': 'Dry-run mode',
'settings.dryRunHint': 'When on, ComfyUI is not called and jobs return placeholder images / videos so you can walk the flow; turn off for real generation.',
'settings.agentRunSection': 'Agent runtime',
'settings.agentRunLead': 'Caps tool-call steps per run and how much history is carried along.',
'settings.rangeHint': 'Range {min}–{max}',
'settings.loadFailed': 'Could not load settings — check that the workbench server is running',
'skillName.character-consistency': 'Character consistency',
'skillName.h3-video-prompt-enhancer': 'H3 video prompt enhancer',
'skillName.scene-to-video': 'Scene to video',
'skillName.shot-composer-blockout': 'Shot blockout',
'settings.loading': 'Loading settings',
'settings.allSaved': 'All changes saved',
'settings.unsaved': 'Unsaved changes',
'settings.saveChanges': 'Save changes',
'settings.discard': 'Discard',
'settings.saved': 'Saved',
'settings.saveFailed': 'Could not save settings',
'settings.savedDryRun': 'Dry run saved',
'settings.current': 'Current',
'settings.useThis': 'Use this',
'settings.useActiveLlm': 'Currently active',
'settings.llmSection': 'LLMs',
'settings.llmLead': 'Configure the language models used by the agent.',
'settings.addLlm': 'Add LLM',
'settings.addAtLeastOneLlm': 'Add at least one LLM.',
'settings.llmNamePlaceholder': 'My LLM',
'settings.llmDefaultName': 'Generic model',
'settings.newLlmDefault': 'New LLM',
'settings.model': 'Model',
'settings.baseUrl': 'Base URL',
'settings.apiKey': 'API key',
'settings.apiKeyOptional': 'Optional',
'settings.apiKeyHint': 'Some providers accept no key.',
'settings.apiKeySaved': 'Key saved',
'settings.requiredName': 'Name is required',
'settings.requiredModel': 'Model is required',
'settings.requiredBaseUrl': 'Base URL is required',
'settings.invalidValue': 'Invalid value',
'settings.invalidField': 'Invalid',
'settings.remove': 'Remove',
'settings.removeLlmTitle': 'Remove LLM',
'settings.name': 'Name',
'settings.active': 'Active',
'settings.testLlm': 'Test connection',
'settings.llmTestOk': 'Connected ({ms} ms)',
'settings.llmTestFail': 'Connection failed: {detail}',
'settings.llmTestAuth': 'API key rejected ({detail})',
'settings.llmTestTimeout': 'No response within 15 s',
'settings.llmTestConnect': 'Could not reach the server ({detail})',
'settings.agentModelsSection': 'Agent model',
'settings.agentModelsLead': 'Model used for story drafting and agent tasks.',
'settings.agentMaxStepsField': 'Max steps',
'settings.agentMaxStepsHint': 'Cap on tool calls per agent run.',
'settings.queueSection': 'Job queue',
'settings.queueLead': 'Concurrency and timeouts for generation jobs and agent tool calls.',
'settings.concurrencyField': 'Concurrent jobs',
'settings.pollIntervalField': 'Poll interval (sec)',
'settings.pollTimeoutField': 'Job timeout (s)',
'settings.pollTimeoutHint': 'How long a ComfyUI job or one agent tool call may run. 0 waits until it finishes.',
'settings.maxRetriesField': 'Max retries',
'settings.maxError': 'Too high',
'settings.minError': 'Too low',
'settings.notNumber': 'Must be a number',
'settings.comfySection': 'ComfyUI',
'settings.comfyLead': 'Where ComfyUI runs.',
'settings.comfyHint': 'Must be reachable from this machine.',
'settings.comfyMultiHint': 'ComfyUI addresses now support multiple connections (local / LAN / cloud), bindable per imported workflow.',
'settings.comfyGoto': 'Manage in “ComfyUI Connections” →',
'settings.storageSection': 'System Paths',
'settings.storageLead': 'Where files live on disk, and where the agent may work.',
'settings.storageCalloutStrong': 'Changing data directory',
'settings.storageCalloutBody': 'moves assets. Existing paths keep working until set here.',
'settings.dataDir': 'Data directory',
'settings.assetsDir': 'Assets directory',
'settings.workspaceDir': 'Agent workspace',
'settings.workspaceDirHint':
'Sandbox folder the AI agent’s shell may work in (run_command). Leave empty to use DATA_DIR/workspace. The agent cannot touch anything outside it.',
'settings.shellSection': 'Agent shell',
'settings.shellLead': 'Let the agent run installed command-line tools in its workspace.',
'settings.shellCalloutStrong': 'Opt-in only:',
'settings.shellCalloutBody':
'commands run on this machine, sandboxed to the agent workspace. Sensitive files (config, database, credentials) are always denied; anything not read-only asks you first.',
'settings.shellLabel': 'Enable agent shell (run_command)',
'settings.shellHint':
'Off by default. When on, the agent may run inspection commands (ffprobe) freely and mutating commands only after you approve a scope="shell" question card.',
'settings.historyBudgetSection': 'Context history budget',
'settings.historyBudgetLead':
'Caps how much conversation history each agent request replays, so long sessions never overflow the model’s context window.',
'settings.historyBudgetField': 'History budget (characters)',
'settings.historyBudgetHint':
'≈4 characters per token. Oldest whole turns drop first; presets below are good starting points.',
'settings.historyBudgetSmall': 'Small · 60k',
'settings.historyBudgetMedium': 'Medium · 120k',
'settings.historyBudgetLarge': 'Large · 400k',
'settings.hardeningSection': 'Prompt hardening',
'settings.hardeningLead': 'Rules prepended to generation prompts.',
'settings.hardeningHint': 'Used to enforce negative constraints or style guardrails.',
'settings.hardeningPlaceholder': 'No violence, no gore, no explicit content.',
'settings.hardeningRulesLabel': 'Hardening rules',
'settings.hardeningCalloutStrong': 'Hardening applies',
'settings.hardeningCalloutBody': 'to every prompt sent through the pipeline.',
'settings.leaveTitle': 'Leave without saving?',
'settings.leaveMessage': 'You have unsaved changes that will be lost.',
'settings.leaveConfirm': 'Leave',
'settings.dryRunLabel': 'Validate only (dry run)',
// --- Shot editor ---
'shot.scene': 'Scene',
'shot.hint': 'Add objects, arrange the shot, then capture.',
'shot.addObject': 'Add object',
'shot.clearScene': 'Clear scene',
'shot.visibility': 'Toggle visibility',
'shot.lock': 'Toggle lock',
'shot.emptyScene': 'Scene is empty',
'shot.objName.male': 'Male',
'shot.objName.female': 'Female',
'shot.objName.child': 'Child',
'shot.objName.cube': 'Cube',
'shot.objName.plane': 'Plane',
'shot.objName.cylinder': 'Cylinder',
'shot.objName.sphere': 'Sphere',
'shot.objName.capsule': 'Capsule',
'shot.objName.cone': 'Cone',
'shot.objName.torus': 'Torus',
'shot.objName.camera': 'Camera',
'shot.selectObject': 'Select object',
'shot.selectObjectPose': 'Select object and pose it',
'shot.fov': 'Field of view',
'shot.transform': 'Transform',
'shot.pose': 'Pose',
'shot.shotSection': 'Shot',
'shot.shotSize': 'Shot size',
'shot.angle': 'Camera angle',
'shot.elevation': 'Elevation',
'shot.composition': 'Composition',
'shot.center': 'Center',
'shot.captureRef': 'Reference capture',
'shot.railExpand': 'Expand session rail',
'shot.railCollapse': 'Collapse session rail',
'shot.railOpen': 'Open {title}',
'shot.railNoScenes': 'No scenes yet',
'shot.railDeleteScene': 'Delete scene',
'shot.newScene': 'New scene',
'shot.captures': '{count} captures',
'shot.videoBadge': 'Video',
'shot.captureAlt': 'Scene capture',
'shot.noCaptures': 'No captures yet',
'shot.timelinePlay': 'Play',
'shot.timelinePause': 'Pause',
'shot.timelinePlayhead': 'Playhead',
'shot.camKeyframe': 'Camera at {time}s',
'shot.objKeyframe': '{name} at {time}s',
'shot.keyframeCamAdd': 'Add camera keyframe',
'shot.keyframeCamRemove': 'Remove camera keyframe',
'shot.keyframeObjAdd': 'Add keyframe for {name}',
'shot.keyframeObjDelete': 'Delete keyframe',
'shot.keyframeObjSelectFirst': 'Select an object first',
'shot.exportHint': 'Need scene objects or at least 2 camera keyframes (captures not required).',
'shot.exportHintNeedBeats': 'Add scene objects or ≥2 camera keyframes to export. Captures are not required.',
'shot.exportTitle': 'Export timeline',
'shot.exportImage': 'Export image',
'shot.exportVideo': 'Export video',
'shot.viewportTools': 'Tools',
'shot.toolSelect': 'Select',
'shot.toolSelectTitle': 'Select tool',
'shot.toolMove': 'Move',
'shot.toolMoveTitle': 'Move tool',
'shot.toolRotate': 'Rotate',
'shot.toolRotateTitle': 'Rotate tool',
'shot.toolScale': 'Scale',
'shot.toolScaleTitle': 'Scale tool',
'shot.toolPose': 'Pose',
'shot.toolPoseTitle': 'Pose tool',
'shot.toolPoseDisabled': 'Select an object to pose it',
'shot.undoTitle': 'Undo',
'shot.redoTitle': 'Redo',
'shot.gridTitle': 'Toggle grid',
'shot.grid': 'Grid',
'shot.compositionTitle': 'Toggle composition guides',
'shot.captureTitle': 'Capture frame',
'shot.capture': 'Capture',
'shot.errBlob': 'Could not read the captured frame',
'shot.errRecorder': 'Could not start recorder',
'shot.errNoData': 'No scene data to export',
// Models settings page (spec-v2 §9)
'models.title': 'Models',
'models.subtitle': 'Add custom LLMs for your agents · phase 1 covers LLMs only; image / video models come later',
'models.statusCount': '{n} models · {m} available',
'models.add': 'Add model',
'models.tabLlm': 'Language models',
'models.tabImage': 'Image models',
'models.tabVideo': 'Video models',
'models.comingSoon': 'Coming later',
'models.empty': 'No models yet — click "Add model" in the top right to connect your first LLM',
'models.typeLocal': 'Local',
'models.typeLan': 'LAN',
'models.typeCloud': 'Cloud',
'models.defaultBadge': 'Agent default',
'models.setDefault': 'Set as default',
'models.defaultSetToast': 'Set as agent default model',
'models.test': 'Test connection',
'models.testing': 'Testing…',
'models.edit': 'Edit',
'models.delete': 'Delete',
'models.statusUntested': 'Not tested',
'models.statusConnected': 'Connected',
'models.statusFailed': 'Connection failed',
'models.latency': '{ms}ms latency',
'models.agentsUsing': 'used by {n} agents',
'models.lastTestAt': 'last test {time}',
'models.consecutiveFails': '{n} consecutive failures',
'models.cloudPaused': 'Cloud calls paused',
'models.formTitleAdd': 'Add model',
'models.formTitleEdit': 'Edit model',
'models.formClose': 'Close',
'models.fName': 'Name',
'models.fNamePh': 'Name this model, e.g. DeepSeek official',
'models.fApiType': 'API type',
'models.apiOpenai': 'OpenAI-compatible',
'models.apiAnthropic': 'Anthropic',
'models.apiOther': 'Other',
'models.apiTypeHelp': 'Phase 1 supports OpenAI-compatible APIs only; other protocols arrive with image / video models',
'models.fBaseUrl': 'Base URL',
'models.baseUrlHelp': 'Include protocol and port, e.g. http://192.168.200.18:11434/v1',
'models.fModel': 'Model name',
'models.modelHelp': 'Use the model ID from your provider',
'models.fApiKey': 'API key',
'models.keyNoEcho': 'never echoed',
'models.keyHelp': 'Stored on this server only; the full key is never shown in the UI',
'models.keyKeepHint': 'Key saved — leave empty to keep it',
'models.fTimeout': 'Timeout',
'models.timeoutSec': '{n}s',
'models.testOk': '✓ Test passed · {ms}ms · {model} available',
'models.testFail': '✕ Test failed · {reason}',
'models.needTest': 'Save unlocks after a passing test',
'models.testBtn': 'Test connection',
'models.save': 'Save model',
'models.errName': 'Please name this model',
'models.errUrl': 'Invalid URL — it needs protocol and path, e.g. https://api.deepseek.com/v1',
'models.errModel': 'Please enter the model name from your provider',
'models.errKey': 'Please enter the API key',
'models.failTimeout': 'Timed out ({sec}s, no response): the server cannot reach this address — check the address, port and firewall',
'models.failAuth': 'Authentication failed (401): check that the API key is correct and not expired; with aggregators, confirm the model is enabled for your account',
'models.failNotFound': 'Reachable but model not found (404): check the model name spelling',
'models.failNotOpenai': 'Reachable but not recognized as an OpenAI-compatible API — make sure the path ends with /v1',
'models.failConnect': 'The server cannot connect to this address — check the address and port',
'models.failHttp': 'Test failed (HTTP {status})',
'models.delTitle': 'Delete model',
'models.delConfirmUsed': '{n} agents use this model; after deletion they fall back to the agent default. Delete?',
'models.delConfirmFree': 'Delete this model? This cannot be undone.',
'models.delDefaultHint': 'This is the agent default — pick another default first',
'models.agentsTitle': 'Agent default models',
'models.agentsHint': 'Changes apply to new sessions · per-agent overrides live on the Agents page',
'models.agentDefault': 'Agent default',
'models.agentStory': 'Screenplay',
'models.agentStyle': 'Visual design',
'models.agentScript': 'Storyboards',
'models.agentAssets': 'Asset library',
'models.agentVideo': 'Shot lists',
'models.unavailable': '(unavailable)',
'models.noticeStrong': 'Connectivity is measured from the workbench server:',
'models.noticeBody': 'a URL opening in your browser does not mean the server running this workbench can reach it; connection tests and chat requests are made by the server. API keys are stored on the server only and never echoed in the UI.',
'models.saved': 'Model saved',
'models.deleted': 'Model deleted',
'models.assignSaved': 'Agent models updated',
'models.saveFailed': 'Save failed: {detail}',
'models.loading': 'Loading…',
'models.loadFailed': 'Failed to load settings',
'models.idleFormHint': 'Pick "Edit" on a card, or click "Add model" above',
// --- A shell + projects overview (HEL-608) ---
'shell.brand': 'Film Atelier',
'shell.brandMark': 'F',
'shell.brandHome': 'Back to project overview',
'shell.navAria': 'Primary',
'shell.navProjects': 'Projects',
'shell.navWorkbench': 'Workbench',
'shell.navImage': 'Image Gen',
'shell.navVideo': 'Video Gen',
'shell.navTasks': 'Jobs',
'shell.navAgents': 'Agents',
'shell.navConnections': 'ComfyUI Connections',
'shell.navModels': 'Models',
'shell.navLibrary': 'Asset Library',
'shell.navSettings': 'Settings',
'shell.comfy_ok': '{name} connected',
'shell.comfy_fail': '{name} unreachable',
'shell.comfy_testing': 'Testing {name}…',
'shell.comfyUnset': 'ComfyUI · not configured',
'shell.scopeHint': 'Switch project',
'shell.scopeAll': 'All projects',
'shell.scopeAllList': 'All projects list',
'shell.scopeRecent': 'Recent projects',
'shell.scopeLoadFailed': 'Could not load projects',
'shell.scopeEmpty': 'No projects yet — create one',
'shell.scopeStage': '{n}/5 confirmed',
'shell.queueRunning': '{n} generating',
'shell.queueQueued': '{n} queued',
'shell.queueIdle': 'Queue idle',
'shell.queueActive': '{n} active',
'shell.trayTitle': 'Job tray',
'shell.trayRecent': 'Recent jobs · click to see all jobs',
'shell.trayEmpty': 'No generation jobs yet',
'shell.trayAll': 'View all jobs',
'shell.searchTitle': 'Search pages and projects',
'shell.searchPlaceholder': 'Search pages, projects',
'shell.searchShortcut': 'Search (Ctrl/⌘ + K)',
'shell.searchEmpty': 'No page or project matches “{q}”',
'shell.searchGroupPages': 'Pages',
'shell.searchGroupProjects': 'Projects · open the workbench',
'shell.searchHintMove': 'select',
'shell.searchHintOpen': 'open',
'shell.searchHintClose': 'close',
'shell.reduceMotion': 'Reduce motion',
'shell.reduceHint': 'Turn off movement, scaling and glow animations; keep only short fades',
'shell.reduceSystem': 'Following the system “Reduce motion” setting',
'shell.tabAria': 'Primary (narrow screens)',
'shell.tabProjects': 'Projects',
'shell.tabCreate': 'Create',
'shell.tabGenerate': 'Generate',
'shell.tabMore': 'More',
'shell.morePages': 'More pages',
'shell.moreTools': 'Tools',
'home.title': 'Projects overview',
'home.subtitle': 'Manage your projects — start from an idea or a ready-made script.',
'home.projectCount': '{n} projects · {m} in progress',
'home.startIdea': 'Start from an idea',
'home.importScript': 'Import a script',
'home.entryIdeaTitle': 'Start from an idea',
'home.entryIdeaBody': 'Describe an idea once; the agents take it through story, boards and clips step by step.',
'home.entryScriptTitle': 'Import a script',
'home.entryScriptBody': 'Already have a script? Paste it in, create the project, and let the script agent break it into ordered scenes.',
'home.ideaPlaceholder': 'A rainy little harbor where the lighthouse keeper finds…',
'home.scriptField': 'Full script',
'home.scriptPlaceholder': 'Paste the complete script here…',
'home.scriptHint': 'After creating, the Agents page opens and the script agent turns the pasted script into ordered scenes.',
'home.errTitle': 'Please give the project a title',
'home.errScript': 'Please paste the full script',
'home.myProjects': 'My projects',
'home.myProjectsHint': 'Click a project to continue working',
'home.emptyProjects': 'No projects yet. Use “Start from an idea” or “Import a script” above to create the first one.',
'home.noIdea': 'No idea description yet',
'home.statScenes': '{n} scenes',
'home.statCharacters': '{n} characters',
'home.statAssets': 'assets {ready}/{total}',
'home.statusDraft': 'Draft',
'home.statusProgress': 'In progress',
'home.statusDone': 'Completed',
'home.tasksTitle': 'Jobs',
'home.activeJobs': '{n} active',
'home.emptyJobs': 'No generation jobs yet',
'home.emptyJobsSub': 'Jobs started from a project or the workbench will show up here.',
'home.tasksNote': 'Full generation history and filters live in the Jobs page (nav → 生成任务).',
'home.kindImage': 'image',
'home.kindVideo': 'video',
'home.kindExport': 'film',
'home.jobDone': 'done',
'home.jobRunning': 'running',
'home.jobQueued': 'queued',
'home.jobFailed': 'failed',
'home.jobRequeued': 'Job requeued',
'home.jobRetryFailed': 'Could not requeue the job',
'home.jobProject': 'Project #{id}',
// --- ComfyUI connections page (a6, HEL-611) ---
'conn.title': 'ComfyUI Connections',
'conn.subtitle': 'Register local, LAN or cloud ComfyUI API addresses · connectivity is probed by the server running this workbench',
'conn.statusCount': '{n} connections · {m} passing',
'conn.add': 'Add connection',
'conn.loading': 'Loading connections…',
'conn.loadFailed': 'Failed to load connections',
'conn.empty': 'No ComfyUI connections yet — add your first address with “Add connection”.',
'conn.targetsTitle': 'Where jobs run',
'conn.targetImage': 'Standalone image',
'conn.targetVideo': 'Standalone video',
'conn.targetFlow': 'Workbench jobs',
'conn.targetChange': 'Change',
'conn.targetMixed': '{n} connections',
'conn.targetNote': 'Jobs follow each workflow’s binding; unbound workflows use the default connection. Change bindings in the workflow library — the image / video pages can also switch before generating.',
'conn.defaultBadge': 'Default',
'conn.test': 'Test connection',
'conn.testing': 'Testing…',
'conn.edit': 'Edit',
'conn.delete': 'Delete',
'conn.setDefault': 'Set as default',
'conn.delDefaultHint': 'The default connection cannot be deleted; set another default first',
'conn.delTitle': 'Delete connection',
'conn.delConfirmUsed': 'Workflows bound to this connection will fall back to the default. Existing job snapshots are kept. Delete “{name}”?',
'conn.delConfirmFree': 'Delete connection “{name}”?',
'conn.statusUntested': 'Untested',
'conn.statusConnected': 'Test passed',
'conn.statusFailed': 'Test failed',
'conn.latency': '{ms} ms latency',
'conn.version': 'version {v}',
'conn.lastTestAt': 'last tested {time}',
'conn.boundWorkflows': '{n} workflows bound',
'conn.tokenSaved': 'Token saved — leave blank to keep it',
'conn.saved': 'Connection saved',
'conn.deleted': 'Connection deleted',
'conn.saveFailed': 'Save failed: {detail}',
'conn.defaultSetToast': 'Set as default connection',
'conn.formTitleAdd': 'Add ComfyUI connection',
'conn.formTitleEdit': 'Edit ComfyUI connection',
'conn.formClose': 'Close',
'conn.fName': 'Name',
'conn.fNamePh': 'e.g. Local ComfyUI / render box',
'conn.fBaseUrl': 'API address',
'conn.fBaseUrlPh': 'http://192.168.200.18:8188',
'conn.baseUrlHelp': 'HTTP API address of ComfyUI (default port 8188); same format for local, LAN and cloud.',
'conn.fAuth': 'Authentication',
'conn.authNone': 'None',
'conn.authBearer': 'Bearer token',
'conn.authHeader': 'Custom header',
'conn.authHelp': 'Only needed when the endpoint sits behind auth (reverse proxy key, etc.).',
'conn.fToken': 'Access token',
'conn.fHeaderName': 'Header name',
'conn.fHeaderNamePh': 'X-Api-Key',
'conn.keyNoEcho': 'stored server-side only, never echoed',
'conn.keyHelp': 'The token lives in the workbench server config file and never reaches the browser.',
'conn.fNotes': 'Notes',
'conn.fNotesPh': 'optional: what this box runs, VRAM…',
'conn.errName': 'Name is required',
'conn.errUrl': 'Address must be a valid http:// or https:// URL',
'conn.errHeaderName': 'Custom header needs a header name',
'conn.testOk': '✓ Test passed · {ms} ms · ComfyUI {v}',
'conn.testFail': '✕ {reason}',
'conn.needTest': 'Pass the test before saving',
'conn.testBtn': 'Test',
'conn.save': 'Save',
'conn.noticeStrong': 'The server decides connectivity: ',
'conn.noticeBody': 'an address opening in your browser does not mean generation works; both tests and generation requests are made by the server running this workbench. Tokens stay server-side.',
'conn.wfTitle': 'Workflow library',
'conn.wfHint': 'Import ComfyUI API-format JSON, classify as image / video, bind to a connection',
'conn.wfEmpty': 'No workflows imported yet. In ComfyUI enable developer mode, export as “API format” JSON, then paste it here.',
'conn.wfCount': '{n} workflows · {m} image · {k} video',
'conn.wfKindImage': 'Image',
'conn.wfKindVideo': 'Video',
'conn.wfConnection': 'Bound connection',
'conn.wfConnectionActive': 'Follows the default connection',
'conn.wfParams': '{n} fillable parameters',
'conn.wfImport': 'Import workflow',
'conn.wfImporting': 'Importing…',
'conn.wfNodes': '{n} nodes',
'conn.wfImportedN': 'Workflow imported — {n} fillable parameters detected',
'conn.wfImportedNoParams': 'Workflow imported, but no fillable parameters were detected: it will run with its built-in settings',
'conn.wfImportFailed': 'Import failed: {detail}',
'conn.wfImportTitle': 'Import ComfyUI workflow (API-format JSON)',
'conn.wfImportHint': 'Paste or pick a file; name is required, the kind decides whether it shows in the image or video window.',
'conn.wfJsonInvalid': 'Not valid API-format JSON (expected an object of node id to class_type)',
'conn.wfJsonPh': 'Paste the ComfyUI API-format JSON here, or pick a file',
'conn.wfDeleted': 'Workflow deleted',
'conn.wfImportedBroken': 'Imported, but the workflow file is incomplete and must be re-exported before generating: {detail}',
'conn.wfBrokenBadge': 'Incomplete file — cannot generate',
// --- Five usages & import confirmation (HEL-636) ---
'usage.text2image': 'Text → Image',
'usage.image2image': 'Image → Image',
'usage.text2video': 'Text → Video',
'usage.image2video': 'Image → Video',
'usage.ref2video': 'Reference → Video',
'usage.pending': 'Usage pending',
'wfRole.image': 'Input image',
'wfRole.first_frame': 'First frame',
'wfRole.last_frame': 'Last frame',
'wfRole.reference_image': 'Reference',
'wfRole.mask': 'Mask',
'conn.wfImportAction': 'Import workflow',
'conn.wfConfirmTitle': 'Confirm detection',
'conn.wfStepAnalyze': 'Paste & analyze',
'conn.wfStepConfirm': 'Confirm & save',
'conn.wfChooseFile': 'Choose file',
'conn.wfAnalyze': 'Analyze',
'conn.wfAnalyzing': 'Analyzing…',
'conn.wfConfirmHint': 'Review the evidence, output nodes and image slots; correct the usage or slot roles before saving.',
'conn.wfUsageLabel': 'Usage',
'conn.wfUsageAuto': 'Auto-detected: {usage}',
'conn.wfUsageNeedPick': 'Pick manually',
'conn.wfPickUsage': 'Choose a usage first',
'conn.wfSlotsLabel': 'Image slots',
'conn.wfSlotsHint': 'Roles are inferred from wiring; override them (input image / first / last frame / reference / mask) and the manual choice sticks.',
'conn.wfBack': 'Back',
'conn.wfConfirmSave': 'Confirm & save',
'conn.wfImportedWithUsage': 'Saved as “{usage}” with {n} fillable parameters',
'conn.wfPendingCount': '{n} pending',
'conn.wfConfirmed': 'Usage confirmed: {usage} — the workflow can generate now',
'conn.wfSourceUser': 'Usage set manually; re-analysis will not overwrite it',
'conn.wfSourceAuto': 'Usage auto-detected',
'conn.wfDisabledBadge': 'Disabled',
'conn.wfConfirmAria': 'Confirm workflow usage',
'conn.wfOutputLabel': 'Output nodes',
'conn.wfOutputNeedPick': 'Unrecognized custom output nodes — designate them',
'conn.wfOutputHint': 'Check the nodes that actually produce results and pick each one’s media type; generation harvests images/videos only from these nodes.',
'conn.wfOutputPick': 'Check at least one output node',
'conn.wfOutputKindAria': 'Output node media type',
'conn.wfOutputPendingBadge': 'Outputs unset',
'conn.wfOutputNeedMap': 'This workflow has unrecognized output nodes; designate them and their media type to enable it',
'conn.wfOutputApply': 'Save output mapping',
'conn.wfMapCancel': 'Cancel',
'conn.wfOutputApplied': 'Output mapping saved: node {nodes}',
'conn.wfOutputCleared': 'Output mapping cleared — the workflow is pending again',
'conn.missingMaterial': 'A dedicated Qwen Image 2.1 workflow JSON is not in the repo yet: export it from ComfyUI and import it here — the generic import path is ready.',
// --- Standalone image / video generation (a3/a4, HEL-612) ---
'studio.image.title': 'Image',
'studio.image.subtitle': 'Generate images with imported workflows · shares connections & queue with ComfyUI Connections',
'studio.video.title': 'Video',
'studio.video.subtitle': 'Generate videos with imported workflows · shares connections & queue with ComfyUI Connections',
'studio.genParams': 'Parameters',
'studio.modeTextToImage': 'Text to image',
'studio.modeTextToVideo': 'Text to video',
'studio.video.resultsTitle': 'Preview',
'studio.image.historyTitle': 'Image history',
'studio.video.historyTitle': 'Video history',
'studio.historyCount': '{n} total',
'studio.doneAt': 'Done at {time}',
'studio.kindImageText': 'image',
'studio.kindVideoText': 'video',
'studio.loading': 'Loading…',
'studio.connLabel': 'Connection',
'studio.connQueue': 'Queue {n}',
'studio.connUntested': 'Checking…',
'studio.connOk': 'Connected · {ms} ms',
'studio.connFail': 'Unreachable',
'studio.connManage': 'Manage connections',
'studio.wfLabel': 'Workflow',
'studio.wfParams': '{n} fillable params',
'studio.wfBindTo': 'Bound to {name}',
'studio.wfFollowActive': 'Follows the default connection',
'studio.promptLabel': 'Positive prompt',
'studio.promptPh': 'Describe the shot: subject, setting, light, style…',
'studio.negLabel': 'Negative prompt',
'studio.seedLabel': 'Seed',
'studio.sizeLabel': 'Size',
'studio.batchLabel': 'Batch',
'studio.durationLabel': 'Duration (s)',
'studio.fpsLabel': 'Frame rate',
'studio.stepsLabel': 'Steps',
'studio.cfgLabel': 'CFG',
'studio.paramsTitle': 'Workflow params',
'studio.chars': '{n} chars',
'studio.insertStyle': 'Insert style words',
'studio.styleSoon': 'Skill word library arrives with the Agents feature',
'studio.generateN': 'Generate · {n} images',
'studio.generate': 'Generate',
'studio.submitting': 'Submitting…',
'studio.etaHint': 'Actual time depends on the target connection and workflow',
'studio.errNoConn': 'Select a generation connection first',
'studio.errConnDown': "This connection is unavailable (last test failed at {time}) — switch to another or fix it in ComfyUI Connections",
'studio.errPrompt': 'Please fill in the prompt',
'studio.errPromptLong': 'Prompt exceeds 2000 characters — please trim it',
'studio.errRefImage': 'Image-to-image needs a reference image',
'studio.errFirstLast': 'First/last-frame video needs both the first and the last frame',
'studio.errUpload': 'Please upload {label}',
'studio.errFill': 'Please fill in {label}',
'studio.slotRef': 'Reference image',
'studio.slotRefN': 'Reference {n}',
'studio.slotMask': 'Mask',
'studio.slotFirst': 'First frame',
'studio.slotLast': 'Last frame',
'studio.slotOptional': 'Optional',
'studio.slotRefVideo': 'Reference video',
'studio.slotAudio': 'Reference audio',
'studio.slotPick': 'Click or drop a file',
'studio.slotFromResults': 'Pick from image results',
'studio.taskCurrent': 'Current task',
'studio.taskQueued': 'Queued',
'studio.taskRunning': 'Generating',
'studio.taskCancel': 'Cancel task',
'studio.queuedBehind': '{n} task(s) ahead',
'studio.stepsShort': 'Steps {v}',
'studio.usedShort': 'Elapsed {v}',
'studio.etaShort': 'ETA {v}',
'studio.targetShort': 'Target {name}',
'studio.renderFrames': 'Frame {done}/{total}',
'studio.noActiveTask': 'No active task · set the parameters on the left and press Generate',
'studio.resultsTitle': 'Recent results',
'studio.selectHint': 'Selected',
'studio.sendToImg2Img': 'Send to img2img',
'studio.zoom': 'Zoom',
'studio.download': 'Download',
'studio.downloadMp4': 'Download MP4',
'studio.copyPrompt': 'Copy prompt',
'studio.copiedToast': 'Copied — paste it into image/video generation',
'studio.sentToImg2ImgToast': 'Filled in as the reference image — check the params and generate',
'studio.noImg2ImgWf': 'No image workflow declares a reference-image input yet — import an img2img workflow in ComfyUI Connections first',
'studio.videoRefStrip': 'First / last frame reference',
'studio.historyEmptyImage': 'No image generations yet — set the parameters on the left and press Generate',
'studio.historyEmptyVideo': 'No video generations yet — set the parameters on the left and press Generate',
'studio.jobName': 'Task #{id}',
'studio.retryLink': 'Retry',
'studio.retryQueuedToast': 'Task re-queued',
'studio.retryFailedToast': 'Re-queue failed: {detail}',
'studio.errNoWorkflow': 'Choose a workflow first',
'studio.errBlocked': 'Cannot submit: {reason}',
'studio.queuedToast': 'Submitted to “{name}”, queued',
'studio.submitFailedToast': 'Submit failed: {detail}',
'studio.jobFailedToast': 'Generation failed: {detail}',
'studio.wfNoParamsNote': 'This workflow has no fillable parameters and will run with its built-in prompt and settings. To fill them here, tag node titles with (Input:prompt) etc. in ComfyUI and re-import.',
'studio.wfAutoParamsNote': 'No (Input:…) title tags found — {n} parameters were detected from node types; blank fields keep the workflow values.',
'studio.promptNotDeclared': 'This workflow has no prompt node — nothing to fill',
'studio.modeImageEdit': 'Image edit',
'studio.modeImageToVideo': 'Image to video',
'studio.modeRefToVideo': 'Reference to video',
'studio.slotInput': 'Input image',
'studio.slotHintOne': 'Required · 1 image',
'studio.slotEmptyInput': 'Click or drop the input image',
'studio.slotEmptyFirst': 'Click or drop the first frame',
'studio.slotEmptySub': 'PNG / JPG / WebP · ≤ 20MB each',
'studio.slotFromResultsShort': 'From results',
'studio.errImageFormat': '"{name}" is not supported — use PNG / JPG / WebP; this file will not be used',
'studio.errImageSize': '"{name}" is larger than 20MB — compress it and upload again',
'studio.errNeedInputImage': 'Image edit needs an input image',
'studio.errNeedFirstFrame': 'Image to video needs a first frame',
'studio.errNeedRef': 'Reference to video needs at least 1 reference image',
'studio.errRefMax': 'At most {max} reference images: {n} selected, these {k} were not added',
'studio.refHint': 'Required · 1–{max} · {n} selected',
'studio.refAdd': 'Add reference image',
'studio.refAddSub': '{n} more · max {max}',
'studio.refReplace': 'Replace',
'studio.refRemove': 'Remove reference {n}',
'studio.refRejectedShort': 'Not added',
'studio.refFull': 'Limit of {max} reached — remove one to add another',
'studio.refStrip': 'Reference images ({n} used)',
'studio.resolutionLabel': 'Output resolution',
'studio.resolutionHint': 'About {v}×{v} px, keeps the input aspect; 0 = original size',
'studio.wfBrokenTitle': 'This workflow file is incomplete — ComfyUI cannot run it, generation is blocked',
'studio.wfBrokenHint': 'Re-export the API-format JSON from a ComfyUI that has the custom nodes installed, then import it again under ComfyUI connections.',
'studio.errWfBroken': 'Workflow file is incomplete — re-export it before generating',
'studio.cancelToast': 'Cancel requested',
'studio.deleteBtn': 'Delete',
'studio.delTitle': 'Delete task record',
'studio.delConfirm': 'Deleting also removes this job’s result files; the history cannot be restored. Delete?',
'studio.delTitleJob': 'Delete job “{name}”',
'studio.delConfirmMulti': 'This job produced {n} results. Deleting removes the whole job record and all {n} result files; this cannot be undone. Delete?',
'studio.deleteFailedToast': 'Delete failed: {detail}',
'studio.deletedTakeNoFilesToast': 'Deleted “{name}”',
'studio.deletedTakeToast': 'Deleted “{name}” together with its result files',
'studio.deletedToast': 'Job deleted together with its result files',
'studio.wfDeletedTag': 'Workflow deleted',
'studio.wfEmptyTitle': 'No {kind} workflows yet',
'studio.wfEmptyBody': "Enable ComfyUI's developer mode, export the workflow as API JSON, then import it on the ComfyUI Connections page as {kind}.",
'studio.wfEmptyGo': 'Import in ComfyUI Connections',
'studio.missingQwen': 'Dedicated Qwen Image 2.1 (t2i / img2img / mask) JSONs are still missing — the generic import path is ready; export from ComfyUI and import.',
'studio.missingFirstLast': 'The dedicated MiniMax H3 first/last-frame JSON is still missing — the bundled t2v / reference-to-video examples can be imported meanwhile.',
'studio.pickerTitle': 'Pick an image result',
'studio.pickerEmpty': 'No image results available yet',
'studio.pickerPick': 'Use',
'studio.uploadFailedToast': 'Upload failed: {detail}',
'studio.playAria': 'Play',
'studio.pauseAria': 'Pause',
'studio.fullscreenAria': 'Fullscreen',
// --- Generation tasks page (HEL-612) ---
'tasks.title': 'Generation tasks',
'tasks.subtitle': 'All image / video tasks — standalone windows and the creation flow',
'tasks.filterAll': 'All',
'tasks.filterImage': 'Images',
'tasks.filterFailed': 'Failed',
'tasks.filterActive': 'Active',
'tasks.filterVideo': 'Videos',
'tasks.count': '{n} tasks · {m} active',
'tasks.empty': 'No generation tasks yet. Submit the first one in Image or Video.',
'tasks.emptyFiltered': 'No tasks match the current filter.',
'tasks.goGenerate': 'Open Image',
'tasks.sourceStudioImage': 'Standalone image',
'tasks.sourceStudioVideo': 'Standalone video',
'tasks.sourcePlayground': 'Playground',
'tasks.sourceFlow': 'Creation flow',
'tasks.sourceOther': 'Generation',
'tasks.queued': 'Queued',
'tasks.running': 'Running',
'tasks.done': 'Done',
'tasks.failed': 'Failed',
'tasks.retry': 'Retry',
'tasks.cancel': 'Cancel',
'tasks.delete': 'Delete',
'tasks.download': 'Download',
'tasks.delTitle': 'Delete task',
'tasks.delConfirm': 'The result files will be removed together with the task. Delete it?',
'tasks.searchPh': 'Search tasks…',
'tasks.outputs': '{n} outputs',
'agentsPage.title': 'Agents',
'agentsPage.subtitle': 'Chat independently with the five creation agents; define and assign Skills',
'agentsPage.statusChip': '{n} Skills · {m} enabled',
'agentsPage.agentsTitle': 'Five agents',
'agentsPage.skillLib': 'Skill library',
'agentsPage.skillLibCount': '{n}',
'agentsPage.installedTitle': '{name} · installed Skills',
'agentsPage.installedCount': '{n} · {m} on',
'agentsPage.newSkill': 'New Skill',
'agentsPage.skillLibEmpty': 'No Skills yet — create one with “New Skill” above.',
'agentsPage.skillsCount': '{n} Skills',
'agentsPage.replying': 'Replying…',
'agentsPage.idle': 'Idle',
'agentsPage.assigned': 'assigned {n}',
'agentsPage.edit': 'Edit',
'agentsPage.toggleSkill': 'Enable or disable Skill',
'agentsPage.independentNote': 'Independent chat · not part of the creation flow',
'agentsPage.model': 'Model',
'agentsPage.modelDefault': 'Agent default',
'agentsPage.newSessionLabel': 'New chat',
'agentsPage.newSession': 'New chat',
'agentsPage.clear': 'Clear',
'agentsPage.export': 'Export',
'agentsPage.skillManage': 'Skill manager',
'agentsPage.composerPlaceholder': 'Keep chatting, or paste a script fragment… (Enter to send, Shift+Enter for newline)',
'agentsPage.send': 'Send',
'agentsPage.clearTitle': 'Clear chat',
'agentsPage.clearConfirm': 'History cannot be recovered after clearing. Clear the chat with the {name} agent?',
'agentsPage.skillErrName': 'Please give the Skill a name',
'agentsPage.skillErrAssign': 'Assign it to at least one Agent, otherwise it never takes effect',
'agentsPage.skillLoadFailed': 'Failed to read Skill content',
'agentsPage.skillSaved': 'Skill saved',
'agentsPage.skillSaveFailed': 'Save failed: {detail}',
'agentsPage.skillEnabled': 'Skill enabled',
'agentsPage.skillDisabled': 'Skill disabled — new replies will not use it',
'agentsPage.skillDeleted': 'Skill deleted',
'agentsPage.skillRestored': 'Rolled back to a previous version',
'agentsPage.skillTypeTemplate': 'Prompt template',
'agentsPage.skillTypeKnowledge': 'Reference knowledge',
'agentsPage.skillTypeRules': 'Process rules',
'agentsPage.versions': 'Version history',
'agentsPage.versionsEmpty': 'No versions yet — every save snapshots the old one.',
'agentsPage.restore': 'Restore',
'agentsPage.close': 'Close',
'agentsPage.editSkill': 'Edit Skill',
'agentsPage.skillName': 'Name',
'agentsPage.skillNamePh': 'e.g. cyberpunk-style-kit',
'agentsPage.skillType': 'Type',
'agentsPage.skillDesc': 'Description',
'agentsPage.skillDescPh': 'When should the agent use this Skill (shown in its skill list)',
'agentsPage.skillContent': 'Content',
'agentsPage.skillContentPh': 'Markdown supported: prompt templates, references, or process rules…',
'agentsPage.skillContentHint': 'Markdown supported; saving auto-bumps the version and archives the old one.',
'agentsPage.assignTo': 'Assign to',
'agentsPage.saveNext': 'Save v{v}+1',
'agentsPage.save': 'Save',
'agentsPage.disable': 'Disable',
'agentsPage.enable': 'Enable',
'agentsPage.delete': 'Delete',
'agentsPage.delSkillTitle': 'Delete Skill',
'agentsPage.delSkillConfirm': 'Deletion is irreversible; the {n} assigned agents lose it too. Delete it?',
'agentsPage.skillIdleHint': 'Pick “Edit” from the Skill library, or click “New Skill”',
'agentsPage.sugScript1': 'Turn an idea into a three-act outline',
'agentsPage.sugScript1P': 'I have an idea: a convenience-store clerk notices the same customer at the same minute every night. Please write a three-act short-film outline.',
'agentsPage.sugScript2': 'Polish an existing script',
'agentsPage.sugScript2P': 'I will paste an existing script — read it first, then point out three improvements to dialogue and pacing.',
'agentsPage.sugStyle1': 'Propose style directions',
'agentsPage.sugStyle1P': 'A neon-lit rainy urban romance short — give me three distinct visual style directions, each with English image-prompt keyword sets.',
'agentsPage.sugStyle2': 'Cinematic-realism keywords',
'agentsPage.sugStyle2P': 'Compile a ready-to-use set of cinematic-realism style prompts (positive + negative), English with Chinese notes.',
'agentsPage.sugBoard1': 'Break the script into a storyboard',
'agentsPage.sugBoard1P': 'Break this script into a shot list: shot number, size, camera move, frame content, dialogue cue, suggested duration.',
'agentsPage.sugBoard2': 'Storyboard a climax',
'agentsPage.sugBoard2P': 'A thirty-second chase climax — give one storyboard pass with clear rhythm changes.',
'agentsPage.sugAssets1': 'Character sheet prompts',
'agentsPage.sugAssets1P': 'The protagonist is a 17-year-old night-owl girl detective — write a consistent character-sheet prompt set (front / side / full body).',
'agentsPage.sugAssets2': 'Asset checklist',
'agentsPage.sugAssets2P': 'Based on the rainy convenience-store scene, list scene and prop asset prompts.',
'agentsPage.sugShot1': 'One video prompt',
'agentsPage.sugShot1P': 'A push-in shot at the store entrance, neon sign to glass door — write one directly usable video-model prompt.',
'agentsPage.sugShot2': 'First/last-frame shots',
'agentsPage.sugShot2P': 'Show how to write a first/last-frame video prompt: how to describe first frame, last frame, camera move, and duration.',
'workbench.title': 'Creation Workbench',
'workbench.subtitle': 'Script → style → storyboard → assets → shot list, five agents in relay',
'workbench.pickerSubtitle': 'Pick a project to continue its five-stage flow',
'workbench.pickerEmpty': 'No projects yet',
'workbench.pickerEmptyBody': 'Go back to the overview and start from an idea or import a script.',
'workbench.pickerGoHome': 'Open overview',
'workbench.pickerFootHint': 'You can also enter the workbench from the overview\'s 从创意开始 / 导入剧本 entries.',
'workbench.stageProgress': 'Five-stage progress',
'workbench.activeJobs': '{n} jobs running',
'workbench.stage.script': 'Script',
'workbench.stage.style': 'Visual Style',
'workbench.stage.storyboard': 'Storyboard',
'workbench.stage.assets': 'Assets',
'workbench.stage.shot': 'Shot List',
'workbench.lockedStep': 'Unlocks after 「{stage}」 is confirmed',
'workbench.state.todo': 'Not started',
'workbench.state.running': 'Generating',
'workbench.state.draft': 'Awaiting confirm',
'workbench.state.confirmed': 'Confirmed',
'workbench.state.edited': 'Edited',
'workbench.copied': 'Copied — paste it into image/video generation',
'workbench.copyFailed': 'Copy failed, please copy manually',
'workbench.copy': 'Copy',
'workbench.charCount': '{n} chars',
'workbench.runStage': 'Generate with {agent}',
'workbench.runDone': '{agent} finished the draft — please review and confirm',
'workbench.runFailed': 'Generation failed, please retry',
'workbench.runningHint': '{agent} is writing this stage…',
'workbench.confirmNext': 'Confirm & continue',
'workbench.confirmLast': 'Confirm stage',
'workbench.confirmed': '「{agent}」 stage confirmed',
'workbench.confirmFailed': 'Confirm failed, please retry',
'workbench.restore': 'Restore confirmed',
'workbench.restored': 'Restored to the last confirmed version',
'workbench.restoreFailed': 'Restore failed, please retry',
'workbench.draftNotice': 'This is an unconfirmed draft — the next agent only sees it after you confirm.',
'workbench.draftSaved': 'Draft saved — still needs confirmation',
'workbench.saveFailed': 'Save failed, please retry',
'workbench.saveDraft': 'Save draft',
'workbench.cancelEdit': 'Cancel',
'workbench.editDraft': 'Edit',
'workbench.regenerate': 'Regenerate',
'workbench.regenerateHint': 'Ask the agent to redo this stage (the confirmed version is kept and restorable)',
'workbench.instructionPh': 'Extra instructions (optional), e.g. more cinematic, casual dialogue…',
'workbench.jobSubmitted': 'Generation queued — results return to this project',
'workbench.jobSubmitFailed': 'Failed to submit the job',
'workbench.jobRequeued': 'Job re-queued',
'workbench.retryJob': 'Retry',
'workbench.cancelJob': 'Cancel job',
'workbench.openOutput': 'Open result',
'workbench.jobRunningPct': '{n}%',
'workbench.jobRunning': 'Running',
'workbench.jobQueued': 'Queued',
'workbench.jobDone': 'Done',
'workbench.jobFailed': 'Failed',
'workbench.generating': 'Generating…',
'workbench.progressChip': 'Stage {n}/5',
'workbench.backHome': 'Overview',
'workbench.loadFailed': 'Failed to load the workbench.',
'workbench.retryLoad': 'Retry',
'workbench.agentSkills': '{n} skills',
'workbench.chatWithAgent': 'Chat solo',
'workbench.tasksTitle': 'Stage jobs',
'workbench.tasksAll': 'All jobs',
'workbench.tasksEmpty': 'No generation jobs yet. Send prompts from the assets or shot-list stage.',
'workbench.flowTitle': 'Five-stage progress',
'workbench.script.todoTitle': 'Start from the script: hand your idea to the Script agent',
'workbench.script.todoIdea': 'Your idea:',
'workbench.script.generate': 'Draft the script',
'workbench.script.importBtn': 'Import existing script',
'workbench.script.writeManually': 'Write manually',
'workbench.script.importPlaceholder': 'Paste an existing script here… Importing skips script drafting and continues from visual style.',
'workbench.script.importHint': 'The imported script becomes the confirmed baseline of this stage.',
'workbench.script.importConfirm': 'Import & skip drafting',
'workbench.script.importDone': 'Script imported — continue from visual style',
'workbench.script.importFailed': 'Import failed, please check the text and retry',
'workbench.script.editorHint': 'Edit the script text directly; confirmation is still required after saving.',
'workbench.script.copyLabel': 'Full script',
'workbench.style.todoTitle': 'Define the visual style for the script',
'workbench.style.todoBody': 'The Visual Style agent proposes several distinct directions, each with copy-ready image prompts.',
'workbench.style.generate': 'Propose style directions',
'workbench.style.namePh': 'Direction name, e.g. Neon Cyber',
'workbench.style.descPh': 'Description (palette / lighting / texture)',
'workbench.style.promptPh': 'English image keywords, comma separated',
'workbench.style.negativePh': 'Negative prompt (optional, English)',
'workbench.style.negativeLabel': 'Negative prompt',
'workbench.style.remove': 'Remove direction',
'workbench.style.add': 'Add direction',
'workbench.style.chosen': 'Selected',
'workbench.style.chooseHint': 'When confirming this stage, your selected style is handed to later stages.',
'workbench.style.promptLabel': 'Style prompt',
'workbench.board.scene': 'Scene',
'workbench.board.size': 'Shot size',
'workbench.board.camera': 'Camera',
'workbench.board.duration': 'Sec',
'workbench.board.desc': 'Description',
'workbench.board.dialog': 'Dialog/SFX',
'workbench.board.descPh': 'What this shot shows',
'workbench.board.dialogPh': 'Dialog or SFX cue (optional)',
'workbench.board.remove': 'Remove shot',
'workbench.board.add': 'Add shot',
'workbench.board.todoTitle': 'Break the script into a shot-by-shot storyboard',
'workbench.board.todoBody': 'The Storyboard agent produces shot numbers, sizes, camera moves, framing and durations.',
'workbench.board.generate': 'Draft the storyboard',
'workbench.board.summary': '{n} shots · ~{sec}s',
'workbench.asset.kindCharacter': 'Character',
'workbench.asset.kindLocation': 'Location',
'workbench.asset.kindProp': 'Prop',
'workbench.asset.namePh': 'Asset name',
'workbench.asset.descPh': 'Description (appearance, usage)',
'workbench.asset.promptPh': 'Full English image prompt',
'workbench.asset.promptLabel': 'Image prompt',
'workbench.asset.remove': 'Remove asset',
'workbench.asset.add': 'Add asset',
'workbench.asset.todoTitle': 'Build the asset list with image prompts',
'workbench.asset.todoBody': 'The Assets agent combines script, style and storyboard into copy-ready prompts for characters/locations/props.',
'workbench.asset.generate': 'Draft the asset list',
'workbench.asset.generateImage': 'Generate image',
'workbench.asset.generateHint': 'Generate with the connected ComfyUI workflow; results return to this project',
'workbench.asset.summary': '{n} assets',
'workbench.vshot.noPh': 'Shot no., e.g. S1',
'workbench.vshot.descPh': 'Description of the shot',
'workbench.vshot.promptPh': 'Full video-model prompt (English)',
'workbench.vshot.promptLabel': 'Video prompt',
'workbench.vshot.remove': 'Remove shot',
'workbench.vshot.add': 'Add shot',
'workbench.vshot.todoTitle': 'Produce the shot-by-shot video script',
'workbench.vshot.todoBody': 'The Shot List agent turns the storyboard into prompts ready for video models.',
'workbench.vshot.generate': 'Draft the shot list',
'workbench.vshot.generateVideo': 'Generate shot video',
'workbench.vshot.generateHint': 'Generate with the connected ComfyUI video workflow; results return to this project',
'workbench.vshot.summary': '{n} shots',
'home.errScriptShort': 'The script looks too short — check the paste is complete (min 30 characters)',
'home.stageProgress': 'Five-stage progress',
'tasks.sourceWorkbench': 'Creation flow',
'jobst.idSuffix': ' · ComfyUI prompt ID {id}',
'jobst.done': 'Done',
'jobst.doneDetail': 'ComfyUI finished and the results are saved',
'jobst.dryRun': 'Placeholder',
'jobst.dryRunDetail': 'Placeholder only: Dry-run is on, ComfyUI was not called',
'jobst.noOutput': 'No output',
'jobst.noOutputDetail': 'The job ended without any result file — not a finished generation',
'jobst.missing': 'Files missing',
'jobst.missingDetail': 'The task succeeded, but its result files are no longer on the server',
'jobst.queued': 'Queued',
'jobst.queuedDetail': 'Waiting in the workbench queue to be sent to ComfyUI',
'jobst.connecting': 'Connecting',
'jobst.connectingDetail': 'Connecting to ComfyUI and uploading inputs',
'jobst.comfyQueued': 'Accepted',
'jobst.comfyQueuedDetail': 'ComfyUI accepted the job and queued it',
'jobst.comfyQueuedAhead': 'ComfyUI accepted the job — {n} ahead in its queue',
'jobst.comfyRunning': 'Running',
'jobst.comfyRunningDetail': 'ComfyUI is running the job',
'jobst.saving': 'Saving',
'jobst.savingDetail': 'ComfyUI returned results, downloading them',
'jobst.failed': 'Failed',
'jobst.cancelled': 'Cancelled',
'studio.ratioLabel': 'Aspect ratio',
'studio.megapixelsLabel': 'Megapixels',
'studio.outputSize': 'Output {w} × {h}',
'studio.denoiseLabel': 'Denoise',
'studio.errNumber': '“{label}” must be a number',
'studio.errInteger': '“{label}” must be a whole number',
'studio.errMin': '“{label}” must be at least {v}',
'studio.errMax': '“{label}” must be at most {v}',
'studio.errOption': '“{label}” is not one of the workflow\'s options',
'studio.reuseParams': 'Reuse settings',
'studio.reusedToast': 'Settings from this job are filled in — adjust and generate again',
'studio.reuseMissingWf': 'The workflow this job used no longer exists',
'studio.doneToast': 'Done: {n} file(s) (ComfyUI prompt ID {id})',
'studio.dryRunToast': 'Placeholder only: Dry-run is on, ComfyUI was not called',
'studio.dryRunNote': 'Dry-run is on: Generate only writes placeholder files and never calls ComfyUI. Turn it off in Settings.',
// --- HEL-643: workflow import check / real test / media groups ---
'studio.errVideoFormat': '"{name}" is not a supported video format — use MP4 / WebM / MOV',
'studio.errAudioFormat': '"{name}" is not a supported audio format — use MP3 / WAV / M4A',
'studio.errMediaSize': '"{name}" exceeds the size limit — compress it first',
'studio.errNeedRefMedia': '"{label}" needs at least {n} clips',
'studio.refHintMedia': 'Required · 1–{max} clips · {n} selected',
'studio.refAddMedia': 'Add {kind}',
'studio.refAddSubMedia': '{n} more · max {max}',
'studio.refRemoveMedia': 'Remove {kind} {n}',
'studio.refFullMedia': 'Limit of {max} clips reached — remove one to add another',
'wfMedia.h3Limits': 'MiniMax H3 Ref2VA official limits: up to 9 reference images, 3 reference videos and 3 reference audios; each clip 2–15s with video/audio totals ≤15s each; audio cannot be the only reference; at most 12 reference files in total.',
'wfMedia.h3TotalOver': '{n} reference files selected — above the official cap of 12; generation may fail',
'wfMedia.h3AudioAlone': 'Audio cannot be the only reference — add at least one reference image or video',
'conn.wfCheckTitle': 'Connection compatibility check',
'conn.wfCheckEndpoint': 'Target: {name}',
'conn.wfCheckBtn': 'Re-check',
'conn.wfChecking': 'Checking…',
'conn.wfCheckOk': 'This connection has the nodes and models this workflow needs',
'conn.wfCheckProblems': '{n} missing node(s)/model(s) found',
'conn.wfCheckUnreachable': 'Cannot verify (ComfyUI unreachable) — saving stays possible; re-check after fixing the connection',
'conn.wfCheckSaveHint': 'You can still save the draft (it is not marked generatable); install the missing pieces and re-check.',
'conn.wfTestBtn': 'Test',
'conn.wfLastTest': 'Last test',
'conn.wfTestPassed': '{time} passed ({n} files)',
'conn.wfTestRunning': '{time} running',
'conn.wfTestFailed': '{time} failed',
'wft.title': 'Test workflow',
'wft.connection': 'Target connection',
'wft.costNote': 'A test submits one real job to the selected ComfyUI and uses its VRAM and queue time.',
'wft.submit': 'Start test',
'wft.confirmTitle': 'Confirm a real run',
'wft.confirmBody': 'One real job will be submitted to "{endpoint}" ({n} jobs in queue). The test only passes when at least one downloadable output of the right media type comes back.',
'wft.running': 'Testing…',
'wft.cancel': 'Cancel test',
'wft.passed': 'Test passed: {n} file(s) produced',
'wft.passedShort': 'Passed ({n} files)',
'wft.failed': 'Test failed',
'wft.failedShort': 'Failed',
'wft.cancelledShort': 'Cancelled',
'wft.reusedToast': 'A test is already running for this workflow — attached to it',
'wft.history': 'Test records ({n})',
'wft.clear': 'Clear test records',
'wft.cleared': 'Test records cleared',
'wft.never': 'Never tested',
'wft.download': 'Download',
'wft.errRequired': 'Please fill in "{label}"',
'wft.errListMin': '"{label}" needs at least {n} {unit}',
'tasks.testBadge': 'Test',
'tasks.sourceWorkflowTest': 'Workflow test',
// --- 生成台 (HEL-653) ---
'cdf.orig': 'Original {v}',
'desk.title': 'Generate',
'desk.advanced': 'Advanced · {n} · untouched ones keep the workflow values',
'desk.chipResolution': 'Resolution {v}',
'desk.chipSeconds': '{v}s',
'desk.chipSeed': 'Seed {v}',
'desk.closeInspector': 'Close inspector',
'desk.countActive': '{n} running',
'desk.countTakes': '{n} takes',
'desk.ctxAsset': '{kind} “{name}”',
'desk.ctxShot': 'Shot {no}',
'desk.ctxBack': 'Back to {stage}',
'desk.ctxDismiss': 'Dismiss source note',
'desk.ctxFrom': 'From “{project}”',
'desk.ctxNoBackfill': 'Results stay in the desk feed and are not filled back into {stage}',
'desk.dayDate': '{m}/{d}',
'desk.download': 'Download',
'desk.dropNoSlot': '{n} file(s) have no slot: this workflow has no input of that kind',
'desk.dryRun': 'Dry run',
'desk.durMin': '{m}m {s}s',
'desk.durSec': '{s}s',
'desk.elapsed': 'Time',
'desk.emptyFailed': 'No failed takes',
'desk.emptyFeed': 'No takes yet. Write a prompt below and press Generate.',
'desk.filterAria': 'Filter takes',
'desk.filterAll': 'All',
'desk.filterImage': 'Images',
'desk.filterVideo': 'Videos',
'desk.filterFailed': 'Failed',
'desk.generate': 'Generate',
'desk.genHint': 'Generate (Ctrl/⌘ + Enter)',
'desk.inputs': 'Inputs',
'desk.inspector': 'Inspector',
'desk.keyClose': 'Close',
'desk.keyInspector': 'Show / hide',
'desk.keySelect': 'Select',
'desk.keyUse': 'Use',
'desk.kvCreated': 'Submitted',
'desk.kvName': 'Name',
'desk.kvPromptId': 'ComfyUI prompt id',
'desk.kvUsage': 'Usage',
'desk.loadEarlier': 'Show {n} earlier takes',
'desk.missingSub': 'Redo with the same params, or remove this take',
'desk.missingTitle': 'The result files are no longer on the server',
'desk.needWorkflow': 'Missing: workflow',
'desk.noConn': 'Not connected',
'desk.noPromptInput': 'This workflow takes no prompt; it runs with its own values.',
'desk.notGenerated': 'Not generated',
'desk.noWorkflows': 'No image or video workflow is ready yet',
'desk.openInDesk': 'Tune in desk',
'desk.openInDeskHint': 'Open the desk with this prompt and pick the workflow and params yourself; results stay in the desk feed',
'desk.openInspector': 'Inspector',
'desk.origValue': 'Workflow value',
'desk.outputN': 'Result {n}',
'desk.outputs': 'All results',
'desk.paramError': 'Invalid parameter: {msg}',
'desk.paramsAll': 'All params',
'desk.paramsChanged': 'Params · {n} changed',
'desk.paramsCommon': 'Common params',
'desk.pickTake': 'Pick a take in the feed to see its result',
'desk.pickWorkflow': 'Choose workflow',
'desk.promptOnly': 'Prompt only',
'desk.promptPh': 'Describe the shot… (Ctrl/⌘ + Enter to generate, / to focus)',
'desk.restoreAll': 'Restore all workflow values',
'desk.redo': 'Redo with same params',
'desk.removeRecord': 'Remove record',
'desk.restoreOrig': 'Restore original',
'desk.reuse': 'Reuse',
'desk.reuseToComposer': 'Reuse in composer',
'desk.seedRandom': 'Random',
'desk.sendToSlot': 'Send to image slot',
'desk.sent': 'Submitted',
'desk.sentToSlotToast': 'Sent to the current workflow’s image slot',
'desk.slotOne': '{label} ×1',
'desk.slotRange': '{label} {min}–{max}',
'desk.specSize': 'Size',
'desk.stillNeed': 'Missing: {what}',
'desk.tabParams': 'Params',
'desk.tabResult': 'Result',
'desk.today': 'Today',
'desk.took': 'Took {d}',
'desk.wfBroken': 'Unavailable',
'desk.wfCurrent': 'current',
'desk.wfDefaultConn': 'Default connection',
'desk.wfImport': 'Import / manage workflows',
'desk.wfLastFailed': 'Last run failed',
'desk.wfNoMatch': 'No matching workflow',
'desk.wfOk': 'Ready',
'desk.wfSearchPh': 'Search workflows or a usage: image to video, reference…',
'desk.wfTesting': 'Test running',
'desk.wfUntested': 'Not tested',
'desk.workflow': 'Workflow',
'desk.yesterday': 'Yesterday',
'wfd.stepParse': 'Parse JSON',
'wfd.stepNodes': 'Identify nodes',
'wfd.stepModels': 'Verify models',
'wfd.stepSlots': 'Build input slots',
'wfd.noOutput': 'The workflow has no output node — cannot import',
'wfd.nodesAutoOk': 'Usage auto-detected: {usage}',
'wfd.nodesUserOk': 'Usage confirmed: {usage}',
'wfd.modelsOk': '"{name}" has all required nodes and models',
'wfd.slotsOk': '{n} input slot(s) built ({m} media)',
'wfd.checksAria': 'Import check results',
'wfd.showDetails': 'Show error details',
'wfd.hideDetails': 'Hide error details',
'wfd.unreachableSuggest': 'Being unverifiable does not block saving; re-check after fixing the connection.',
'wfd.nodesPickSuggest': 'Pick the usage and finish the output mapping below before saving.',
'wfd.showRaw': 'View raw JSON',
'wfd.hideRaw': 'Hide raw JSON',
};
export type Dict = typeof en;