export default {
    meta: {
        title: "Infinite Canvas",
        description: "An infinite canvas creation tool",
    },
    theme: { toggle: "Toggle theme" },
    common: {
        cancel: "Cancel",
        save: "Save",
        edit: "Edit",
        done: "Done",
        delete: "Delete",
        copy: "Copy",
        copied: "Copied",
        details: "Details",
        addToAssets: "Add to My Assets",
        addedToAssets: "Added to My Assets",
        copyPrompt: "Copy prompt",
        promptCopied: "Prompt copied",
        created: "Created: {{date}}",
        updated: "Updated: {{date}}",
        all: "All",
        view: "View",
        download: "Download",
        upload: "Upload",
        requestCanceled: "Request canceled",
        durationMinutes: "{{minutes}}m {{seconds}}s",
        durationSeconds: "{{seconds}}s",
        imageReadFailed: "Failed to read image",
    },
    settingsPanels: {
        common: { auto: "Auto", low: "Low", medium: "Medium", high: "High", xhigh: "Extra high" },
        image: { title: "Image settings", quality: "Quality", size: "Size", align16: "Align to multiples of 16", align16Hint: "Round dimensions up to the next multiple of 16 after input", aspectRatio: "Aspect ratio", transparent: "Transparent background", transparentHint: "Generate an image without a background when supported by the model", count: "Image count", images: "{{count}} images" },
        video: { title: "Video settings", quality: "Quality", size: "Size", seconds: "Seconds", resolution: "Resolution", ratio: "Aspect ratio", duration: "Duration", smart: "Smart", output: "Output", generateAudio: "Generate audio", watermark: "Add watermark", adaptive: "Adaptive", sizes: { landscape: "Landscape", portrait: "Portrait", square: "Square", widescreen: "Widescreen", tall: "Tall", auto: "Auto" }, ratios: { landscape: "Landscape", portrait: "Portrait", square: "Square", standardLandscape: "Standard landscape", standardPortrait: "Standard portrait", cinematic: "Cinematic", adaptive: "Adaptive" } },
        audio: { title: "Audio settings", voice: "Voice", format: "Format", speed: "Speed", instructions: "Voice instructions", instructionsPlaceholder: "For example: natural, warm, and suitable for narration." },
        text: { title: "Text settings", reasoning: "Reasoning effort", count: "Generation count" },
        model: { select: "Select model", assign: "Assign a model for {{capability}} in the provider settings", noMatch: "No matching {{capability}} models", addFirst: "Add a provider and models in Settings first", capabilities: { image: "image generation", video: "video", text: "text", audio: "audio" } },
    },
    generation: { pending: ["Creating image", "Almost there", "Just a little longer", "Refining details"] },
    imageReferences: { label: "Image {{index}}", separator: ", ", promptPrefix: "Reference image labels: {{labels}}. Use these labels to interpret image references in the prompt.\n\n{{prompt}}" },
    modelPlugin: {
        pollTimeout: "Plugin polling timed out. Check the request script or try again later.", executionFailed: "Model request script failed: {{message}}", noImages: "The model request script did not return any images",
        variables: { prompt: "User prompt with the system prompt already included", images: "Reference images as a data URL array, available for image editing and image-to-video", messages: "Conversation message array including the system message", params: "Generation parameters: image {size,quality,count}, video {seconds,size,resolution,ratio,generateAudio,watermark}, audio {voice,format,speed,instructions}", model: "Model name without the provider prefix", baseUrl: "Provider endpoint as entered, without appending /v1", apiKey: "Provider API key; add it to request headers yourself", systemPrompt: "Original system prompt", reasoningEffort: "Text reasoning effort; auto lets the script decide whether to send it", http: "Convenience client: http.post(path, body, {headers,params,responseType}), http.get(path, opts), and http.url(path). Authorization: Bearer apiKey is included by default and can be overridden. Relative paths append /v1 to baseUrl.", request: "Raw request({ method, url, headers, params, data, responseType }) with no default headers. Add authentication yourself. Relative URLs are joined to baseUrl without /v1.", poll: "poll(request, extract, {intervalMs,timeoutMs}) continues until extract returns a truthy value", sleep: "Delay with sleep(ms)", signal: "Cancellation signal that can be passed to http/request", onDelta: "Push streaming text with onDelta(text) for text models" },
        returns: { image: "Text-to-image and image editing use different APIs; distinguish them by whether images is empty. Return an image URL or data URL, an array of them, or [{ dataUrl }] / [{ url }] / [{ b64_json }].", video: "Poll inside the script and return { url }, { blob }, or a video URL string.", audio: "Return a Blob, base64/data URL string, or { b64_json } / { data } / { url }.", text: "Push streaming output with onDelta(text), then return the complete text string." },
        templates: { openai: "OpenAI format", gemini: "Gemini format", imageOpenai: "Image generation and editing use different endpoints; distinguish them by whether images is empty.", availableImage: "Available: prompt, images(dataURL[]), params{size,quality,count}, model, baseUrl, apiKey", textToImage: "Text to image: /images/generations (JSON)", imageToImage: "Image editing: /images/edits (multipart/form-data with reference images uploaded as files)", formDataHeader: "Do not set Content-Type manually; let the browser add the boundary", imageGemini: "Gemini image generation and editing both use generateContent, with references in parts.inline_data.", availableImageGemini: "Available: prompt, images(dataURL[]), model, baseUrl, apiKey", videoOpenai: "Video with polling handled inside the script. Available: prompt, images(dataURL[]), params{seconds,size,resolution,ratio}", videoGemini: "Gemini (Veo) video: submit with predictLongRunning and poll the operation for the video URI.", availableVideoGemini: "Available: prompt, images(dataURL[]), params, model, baseUrl, apiKey", geminiNoVideoUri: "Gemini did not return a video URI", audioOpenai: "Audio TTS. Available: prompt, params{voice,format,speed,instructions}, model", audioGemini: "Gemini TTS: generateContent with AUDIO modality, returning base64 PCM in inlineData.data.", availableAudioGemini: "Available: prompt, params{voice}, model, baseUrl, apiKey", geminiNoAudio: "Gemini did not return audio", textOpenai: "Text chat using the OpenAI Responses API. Available: messages([{role,content}]), systemPrompt, model, reasoningEffort", textGemini: "Gemini text: generateContent with the system message in systemInstruction.", availableTextGemini: "Available: messages([{role,content}]), systemPrompt, model, baseUrl, apiKey" },
    },
    apiErrors: { requestFailed: "Request failed", requestCanceled: "Request canceled", baseUrlRequired: "Configure the Base URL first", apiKeyRequired: "Configure the API key first", authenticationFailed: "Authentication failed. Check the API key, plan permissions, and model permissions.", rateLimited: "The request was rate-limited or the quota is insufficient. Try again later.", notFound: "The endpoint was not found (404). Check the Base URL and selected model.", badGateway: "Gateway error (502). The API service is temporarily unavailable.", serviceBusy: "Service unavailable (503). Try again later.", httpFailed: "Request failed (HTTP {{status}}). Check the Base URL and API key.", htmlError: "The service returned an HTML error page ({{preview}})", audioModelRequired: "Configure an audio model first", audioGenerationFailed: "Audio generation failed", scriptNoAudio: "The model request script did not return audio", geminiAudioUnsupported: "The Gemini API format does not support audio generation. Use an OpenAI-format provider.", invalidImageSizeFormat: "Unsupported image size. Use auto, 9:16, or 1024x1024.", positiveImageRatio: "The image ratio must use positive numbers, such as 9:16.", imageRatioLimit: "The image aspect ratio cannot exceed 3:1. Adjust the dimensions.", positiveImageDimensions: "Image dimensions must be positive integers, such as 1024x1024.", imageDimensionStep: "Image width and height must be multiples of 16.", imageEdgeLimit: "The longest image edge cannot exceed 3840px.", imagePixelLimit: "The total image pixel count must be between 655360 and 8294400.", unknownImageResponse: "The API returned data in an unknown format (fields: {{fields}}). Check model or API compatibility.", noImageReturned: "The API did not return an image. The prompt may have triggered safety review or the model may not support this operation.", geminiRejected: "Gemini rejected the request: {{reason}}", geminiNoImage: "The Gemini API did not return an image", geminiMaskUnsupported: "The Gemini API format does not support mask editing", maskModelUnsupported: "This model does not support mask editing. Use another provider.", noContent: "No content returned", modelReadFailed: "Failed to load models", videoTimeout: "{{provider}}video generation timed out. Try again later.", pluginVideoExpired: "The plugin video task has expired. Generate it again.", scriptNoVideo: "The model request script did not return a video", noPlayableVideo: "The video API did not return a playable video", noVideoTaskId: "The video API did not return a task ID", videoTaskCreateFailed: "Failed to create video task", videoGenerationFailed: "Video generation failed", videoTaskQueryFailed: "Failed to query video task", videoPromptRequired: "Enter a video prompt or connect a reference image, video, or audio asset", referenceImageReadFailed: "Failed to read the reference image. Choose another image or upload it again.", invalidReferenceVideo: "A reference video must be a public URL, asset ID, or locally saved video", invalidReferenceAudio: "Reference audio must be a public URL, asset ID, or locally saved audio file", videoModelRequired: "Configure a video model first", geminiVideoUnsupported: "The Gemini API format does not support video generation. Use an OpenAI-format provider.", noVideoTask: "The API did not return a video task", videoDownloadFailed: "Failed to download video", localAssetReadFailed: "Failed to read local asset" },
    prompts: {
        title: "Prompt Center",
        library: "Prompt Library",
        total: "{{count}} prompts",
        category: "Category",
        tags: "Tags",
        search: "Search titles, content, or tags",
        searchTitle: "Search by title",
        loadFailed: "Failed to load prompts",
        sourceMissing: "Prompt source not found",
        use: "Use this prompt",
        empty: "No matching prompts found",
        loading: "Loading...",
        loadMore: "Scroll down to load more",
        end: "You've reached the end",
    },
    assets: {
        title: "My Assets",
        description: "Save frequently used text and images, then find them quickly by type, title, or tag.",
        search: "Search titles, content, tags, or sources",
        type: "Type",
        export: "Export assets",
        import: "Import assets",
        add: "Add asset",
        edit: "Edit asset",
        empty: "No assets found",
        manual: "Added manually",
        selectImage: "Select an image file",
        updated: "Asset updated",
        saved: "Asset saved",
        textCopied: "Text copied",
        noneToExport: "No assets to export",
        imported: "Imported {{count}} assets",
        importFailed: "Import failed. Select a valid asset package.",
        deleted: "Asset deleted",
        packageName: "my-assets.zip",
        kinds: { text: "Text", image: "Image", video: "Video" },
        fields: {
            title: "Title",
            titleRequired: "Enter a title",
            titlePlaceholder: "Give the asset an easy-to-find name",
            coverUrl: "Cover URL",
            coverPlaceholder: "Paste an image URL or upload a local cover",
            tags: "Tags",
            tagsPlaceholder: "Type a tag and press Enter",
            source: "Source",
            sourcePlaceholder: "Added manually / Canvas / Prompt Library",
            note: "Note",
            optional: "Optional",
            textContent: "Text content",
            textRequired: "Enter text content",
            textPlaceholder: "Save prompts, copy, reference descriptions, and other text assets",
            imageContent: "Image content",
        },
        selectImageFile: "Select image file",
        noImageSelected: "No image selected",
        preview: "Preview",
        noCover: "No cover",
        untitled: "Untitled asset",
        noTags: "No tags",
        untagged: "Untagged",
        unknownSource: "Source not specified",
        details: "Asset details",
        deleteTitle: "Delete asset",
        deleteConfirm: "Delete “{{name}}”? It will be removed from My Assets.",
        copyText: "Copy text",
        downloadImage: "Download image",
        downloadVideo: "Download video",
    },
    notFound: {
        title: "Page not found",
        description: "There is no page at this address. It may have moved or been merged into another section.",
        home: "Back to home",
    },
    workbench: {
        logs: "Generation history",
        settings: "Settings",
        prompt: "Prompt",
        viewPrompts: "Browse prompts",
        viewAssets: "Browse My Assets",
        clipboard: "Clipboard",
        upload: "Upload",
        adjust: "Adjust",
        generate: "Generate",
        results: "Results",
        waiting: "Waiting {{time}}",
        model: "Model",
        generating: "Generating",
        success: "Succeeded",
        failed: "Generation failed",
        retry: "Retry",
        new: "New",
        selectAll: "Select all",
        noLogs: "No generation history",
        deleteLogs: "Delete generation history",
        deleteLogsConfirm: "Delete the selected {{count}} generation records?",
        successCount: "{{count}} succeeded",
        failCount: "{{count}} failed",
        itemCount: "{{count}} images",
        untitled: "Untitled",
        configFirst: "Complete the configuration first",
        generationFailed: "Generation failed",
        retrySuccess: "Retry succeeded",
    },
    imageWorkbench: {
        title: "Image Studio",
        promptPlaceholder: "Describe the subject, style, composition, lighting, and intended use",
        references: "Reference images",
        removeReference: "Remove reference image",
        dropReferences: "Drop to add reference images",
        noReferences: "No reference images. Drag images here to add them.",
        clipboardEmpty: "No readable images found on the clipboard",
        clipboardAdded: "Added {{count}} reference images",
        promptRequired: "Enter an image prompt",
        configIncomplete: "Image generation configuration is incomplete",
        invalidParams: "Invalid image generation parameters",
        busy: "The Image Studio is already running a task",
        generated: "Images generated",
        addedReference: "Added to reference images",
        resultTitle: "Generated image {{count}}",
        source: "Image Studio",
        unsupportedAsset: "Image Studio only supports text and image assets",
        missingResult: "The API returned no image",
        empty: "No images generated yet",
        resultAlt: "Generated image {{count}}",
        addReference: "Add as reference",
    },
    videoWorkbench: {
        title: "Video Studio",
        promptPlaceholder: "Describe camera movement, subject action, atmosphere, and visual style",
        references: "Reference images",
        videoReferences: "Reference videos",
        audioReferences: "Reference audio",
        removeImage: "Remove reference image",
        removeVideo: "Remove reference video",
        removeAudio: "Remove reference audio",
        dropReferences: "Drop to upload reference assets",
        noImages: "No reference images. Drag in up to 9 files.",
        noVideos: "No reference videos. Drag in up to 3 files.",
        noAudio: "No reference audio. Drag in up to 3 MP3/WAV files, each under 15 MB.",
        unsupportedFiles: "Unsupported reference assets were ignored. Use images, MP4/MOV video, or MP3/WAV audio.",
        imageTooLarge: "Reference images over 30 MB were ignored",
        videoTooLarge: "Reference videos over 200 MB were ignored",
        audioTooLarge: "Reference audio over 15 MB was ignored",
        audioDurationInvalid: "Reference audio outside the duration limits was ignored: 2–15 seconds each, 15 seconds total.",
        clipboardEmpty: "No readable images found on the clipboard",
        clipboardAdded: "Added {{count}} reference images",
        promptRequired: "Enter a video prompt",
        referenceError: "{{error}}. {{hint}}",
        invalidParams: "Invalid video generation parameters",
        busy: "The Video Studio is already running a task",
        generated: "Video generated",
        timeout: "Video generation timed out. Try again later.",
        resultTitle: "Generated video",
        source: "Video Studio",
        empty: "No video generated yet",
    },
    canvas: {
        defaultTitle: "Infinite Canvas {{count}}",
        library: "Canvas library",
        title: "Infinite Canvas",
        imported: "Imported {{count}} canvases",
        importFailed: "Import failed. Select a valid canvas package.",
        opening: "Opening canvas...",
        loading: "Loading canvases...",
        exportSelected: "Export selected",
        deleteSelected: "Delete selected",
        deleteAll: "Delete all",
        import: "Import canvas",
        create: "New canvas",
        empty: "No canvases yet",
        emptyDescription: "Create a canvas to save its nodes, connections, and appearance independently.",
        collapsePanel: "Collapse panel",
        expandPanel: "Expand panel",
        home: "Home",
        docs: "Documentation",
        projects: "My Canvases",
        deleteCurrent: "Delete current canvas",
        importAsset: "Import asset",
        exportCurrent: "Export current canvas",
        undo: "Undo",
        redo: "Redo",
        openMenu: "Open canvas menu",
        renameHint: "Double-click to rename the canvas",
        shortcuts: "Keyboard shortcuts",
        miniMapOpen: "Open minimap",
        miniMapClose: "Close minimap",
        resetView: "Reset view",
        zoom: "Zoom canvas",
        agentConnected: "Codex connected",
        agentConnecting: "Codex {{activity}}",
        agentDisconnected: "Codex disconnected",
        connecting: "Connecting",
        openAgent: "Open local Codex panel",
        nodeTypes: { image: "Image", text: "Text", config: "Generation config", video: "Video", audio: "Audio", group: "Group" },
        toolbar: {
            select: "Select", pan: "Move", text: "Text", image: "Image", video: "Video", audio: "Audio", config: "Generation config", group: "Group", extensions: "Extension nodes", upload: "Upload assets", appearance: "Canvas appearance", clear: "Clear canvas",
            themeMode: "Theme", light: "Light", dark: "Dark", gridStyle: "Grid style", dots: "Dots", lines: "Lines", blank: "Blank", imageInfo: "Image info",
        },
        project: {
            untitled: "Untitled canvas", imported: "Imported canvas",
            select: "Select {{name}}", stats: "{{nodes}} nodes · {{connections}} connections", updated: "Updated {{date}}", saveName: "Save name", cancelRename: "Cancel rename", export: "Export", rename: "Rename", delete: "Delete",
            deleteTitle: "Delete canvases?", deleteDescription: "This will delete {{count}} canvases along with their nodes and connections.",
        },
        export: { defaultProjectName: "Infinite Canvas", defaultNodesName: "Canvas elements", item: "Element" },
        createMenu: {
            fromNode: "Generate from this node", close: "Close", text: "Generate text", textDescription: "Scripts, ad copy, and brand content", image: "Generate image", video: "Generate video", audio: "Audio reference", config: "Configuration node", configDescription: "Model, size, count, and input order", select: "Select a node",
        },
        node: {
            node: "Node",
            untitled: "Untitled node", renameHint: "Double-click to rename the node", group: "Group", nodeCount: "{{count}} nodes", generating: "Generating", failed: "Generation failed", retry: "Retry", missingPlugin: "Plugin missing", missingPluginDescription: "The plugin for node type “{{type}}” is not installed or enabled", generateImage: "Generate image from text", generate: "Generate", editText: "Double-click to edit text", emptyImage: "Empty image node", emptyVideo: "Empty video node", emptyAudio: "Empty audio node", audio: "Audio", batchExpanded: "Image group expanded", batchCollapsed: "Image group collapsed", textBatchExpanded: "Text alternatives expanded", textBatchCollapsed: "Text alternatives collapsed", createCopy: "Create copy", setPrimary: "Set as primary", setPrimaryText: "Set as primary",
        },
        videoFrames: { first: "Capture first frame", last: "Capture last frame", current: "Capture current frame", firstTitle: "{{name}} first frame", lastTitle: "{{name}} last frame", currentTitle: "{{name}} current frame", captured: "Image node created", failed: "Could not capture this frame. Try again." },
        sidePanel: {
            canvas: "Canvas", assets: "Assets", prompts: "Prompt Library", resize: "Resize left panel", elements: "Canvas elements", select: "Select", searchNodes: "Search nodes", focusNode: "Focus node", preview: "Large preview", noNodes: "No nodes on this canvas", clearAll: "Clear all", selected: "{{count}} selected", exporting: "Exporting selected elements…", exportName: "canvas-elements-{{count}}", exported: "Exported {{count}} elements", exportFailed: "Export failed. Try again.",
            addingAssets: "Adding assets…", addedAssets: "Added {{count}} assets", mediaOnly: "Only image and video files are supported", addFailed: "Failed to add assets. Try again.", searchAssets: "Search assets", add: "Add", noAssets: "No assets", inserted: "Insert into canvas", removeAssetTitle: "Remove this asset?", remove: "Remove", removeAsset: "Remove asset", assetRemoved: "Asset removed",
            searchPrompts: "Search prompts", noPrompts: "No prompts", promptCopied: "Prompt copied", copyFailed: "Copy failed", loadFailedRetry: "Load failed. Click to retry.", noMatchingPrompts: "No matching prompts", sourceEmpty: "No prompts from this source", viewDetails: "View details",
            filter: { image: "Image", video: "Video", text: "Text", audio: "Audio", config: "Configuration", group: "Group" },
        },
        assetPicker: { title: "Select assets", insert: "Insert", search: "Search assets", empty: "No assets" },
        imageTools: { copyPrompt: "Copy prompt", copyPromptTitle: "Copy the prompt used to generate this image", reversePrompt: "Reverse prompt", reversePromptTitle: "Create text and configuration nodes to infer the prompt", replace: "Replace image", locked: "Lock ratio", free: "Free ratio", lockTitle: "Switch to proportional scaling", freeTitle: "Switch to free resizing", mask: "Local edit", maskTitle: "Paint a mask and edit the selected area", crop: "Crop", cropTitle: "Crop into a new node", split: "Split", splitTitle: "Split the image by rows and columns", upscale: "Upscale", upscaleTitle: "Increase image resolution", superResolve: "Super resolution", superResolveTitle: "AI super resolution", angle: "Multi-angle", angleTitle: "Generate another angle", view: "View image", viewTitle: "View image details", more: "More", configure: "Configure quick tools", customize: "Customize toolbar", showLabels: "Show button labels", description: "Choose the quick tools shown in the image-node toolbar.", preview: "Node preview", imageNode: "Image node", quickTools: "Quick tools" },
        nodeToolbar: { noPrompt: "No prompt to copy", infoTitle: "View node information", info: "Info", removeTitle: "Remove node", retryTitle: "Generate again", saveAsset: "Save asset", downloadAudio: "Download audio", downloadVideo: "Download video", downloadImage: "Download image", editTextTitle: "Edit text", editText: "Edit text", decreaseFont: "Decrease font size", increaseFont: "Increase font size", zoomOut: "Smaller", zoomIn: "Larger", uploadImage: "Upload image", replaceVideo: "Replace video", uploadVideo: "Upload video", replaceAudio: "Replace audio", uploadAudio: "Upload audio", nodeInfo: "Node information", name: "Name", type: "Type", size: "Size", position: "Position", status: "Status", imageGroup: "Image group", imageSize: "Image size" },
        configNode: { title: "Generation config", image: "Image", text: "Text", video: "Video", audio: "Audio", prompt: "Prompt", references: "Reference images", videoReferences: "Reference videos", audioReferences: "Reference audio", items: "{{count}} items", images: "{{count}} images", compose: "Compose prompt", stop: "Stop", generate: "Generate" },
        projectPage: {
            stopTitle: "Stop generation?", stopDescription: "The current request will be interrupted. Completed results will be kept.", stop: "Stop", continue: "Continue generating", configConnection: "Configuration nodes cannot be connected to each other", notFound: "Current canvas not found", exporting: "Exporting current canvas…", exported: "Current canvas exported", clipboardText: "Clipboard text", clipboardImageAdded: "Added image from clipboard", clipboardTextAdded: "Added text from clipboard", noTextToSave: "No text to save", canvasText: "Canvas text", noVideoToSave: "No video to save", canvasVideo: "Canvas video", noImageToSave: "No image to save", canvasImage: "Canvas image", emptyReverse: "The image node is empty, so its prompt cannot be inferred", reverseTitle: "Reverse prompt", reverseConfigTitle: "Reverse prompt configuration", splitTitle: "{{name}} {{row}}-{{column}}", splitSuccess: "Split into {{count}} child nodes", maskResult: "Local edit result", maskFailed: "Local edit failed", generationFailed: "Generation failed", partialFailed: "Some images failed to generate", partialTextFailed: "Some text alternatives failed to generate", allFailed: "All images failed to generate", retryPromptMissing: "No prompt found for retry", referenceMissing: "The reference image is missing, so retry cannot continue", emptyTextImage: "The text node is empty, so an image cannot be generated", untitledCanvas: "Untitled canvas", superResolve: "AI super resolution", notImplemented: "Not implemented yet", imageDetails: "Image details", clearTitle: "Clear canvas?", clear: "Clear", clearDescription: "This will delete every node and connection on the current canvas.", reversePreset: "Infer a prompt suitable for AI image generation from the reference image.\n\nRequirements:\n1. Output only the prompt, with no explanation.\n2. Cover the subject, composition, style, lighting, color, materials, lens, and atmosphere.\n3. Write a complete prompt that can be used directly with an image model.", maskPrompt: "Only modify the transparent masked area and keep everything else unchanged. {{prompt}}", editTextPrompt: "Revise the text according to the instructions.\n\nOriginal:\n{{source}}\n\nInstructions:\n{{prompt}}"
        },
        reverseComposer: "Reference image: @[node:{{imageId}}]\nTask: @[node:{{textId}}]",
        editors: {
            reset: "Reset", zoomOut: "Zoom out", zoomIn: "Zoom in", loading: "Loading", unknown: "Unknown", cancel: "Cancel",
            angleTitle: "AI Multi-angle", angleDescription: "The left side previews direction only; the result is regenerated from the original image", horizontal: "Horizontal angle", pitch: "Pitch angle", distance: "Camera distance", lens: "Wide-angle lens", standard: "Standard", wide: "Wide", aiGenerate: "Generate with AI",
            upscaleTitle: "Upscale image", source: "Source", targetPixels: "Target pixels", maxReached: "The image is already 4K and does not need upscaling", targetReached: "The image already meets the target pixel count", algorithm: "Upscaling algorithm", outputSize: "Output size", upscale: "Generate upscaled image", high: "High-quality interpolation", highDescription: "Best for photos and detailed images", bilinear: "Bilinear", bilinearDescription: "Smooth and fast", nearest: "Nearest neighbor", nearestDescription: "Best for pixel art",
            cropTitle: "Crop image", adjustCrop: "Adjust crop box", cropHint: "Mouse wheel to zoom · middle button or Space + left drag to pan", cropSize: "Crop size {{size}}", ratio: "Ratio {{ratio}}", original: "Original {{width}} x {{height}}", confirmCrop: "Crop", free: "Free", fixed: "Fixed", originalMode: "Original",
            maskTitle: "Local mask edit", maskHint: "Mouse wheel to zoom · middle button or Space + left drag to pan · Alt + left/right drag to resize brush · Ctrl/Cmd+Z to undo · Ctrl/Cmd+Shift+Z to redo", brush: "Brush", erase: "Erase", undoMaskTitle: "Undo mask stroke (Ctrl/Cmd+Z)", undoMask: "Undo mask stroke", redoMaskTitle: "Redo mask stroke (Ctrl/Cmd+Shift+Z)", redoMask: "Redo mask stroke", brushSize: "Brush size", editInstructions: "Edit instructions", maskPlaceholder: "For example: change the selected area to metal while preserving the original lighting", maskPromptRequired: "Enter edit instructions", maskRequired: "Paint the area to edit first", aiEdit: "Edit with AI",
            splitTitle: "Split image", splitDescription: "Create {{count}} image nodes and arrange them in the original grid to the right of the canvas", splitHint: "Mouse wheel to zoom · middle button or Space + left drag to pan · Delete removes the selected line · Ctrl/Cmd+Z to undo · Ctrl/Cmd+Shift+Z to redo", undoSplitTitle: "Undo split adjustment (Ctrl/Cmd+Z)", undoSplit: "Undo split adjustment", redoSplitTitle: "Redo split adjustment (Ctrl/Cmd+Shift+Z)", redoSplit: "Redo split adjustment", rows: "Rows", columns: "Columns", horizontalLine: "Horizontal line", verticalLine: "Vertical line", deleteLine: "Delete line", resetLines: "Reset lines", pieceCount: "Pieces", pieces: "{{count}}", averageSize: "Average size", generateChildren: "Create child nodes",
        },
        plugins: { title: "Node plugins", installedPlugin: "Installed plugin {{name}}", installed: "Installed {{name}}", installFailed: "Installation failed: {{error}}", enabled: "Enabled", disabled: "Disabled", upgradeAvailable: "New version available — click to upgrade", updateFromSource: "Update from source", updated: "Updated", uninstallTitle: "Uninstall this plugin?", uninstall: "Uninstall", newVersion: "A new version is available", officialDescription: "Official plugins from this project's registry", refresh: "Refresh", loadFailed: "Failed to load: {{error}}", loadingOfficial: "Loading official plugins…", noOfficial: "No official plugins", install: "Install", urlPlaceholder: "Enter a plugin JavaScript URL, for example https://.../plugin.js", noThirdParty: "No third-party plugins installed", official: "Official", local: "Local", thirdParty: "Third-party", warning: "Plugin code runs directly on this page and can access local data, including your AI API key. Only install plugins from sources you trust.", aiConfigRequired: "AI configuration is not ready. Configure a model and API key in Settings first.", interactiveTitle: "Interaction mode is active. Click to switch to Move mode and drag the node.", movableTitle: "Move mode is active. Click to switch to Interaction mode and operate the node content.", move: "Move", interact: "Interact" },
        promptPanel: { video: "Describe the video you want to generate", audio: "Describe the audio you want to generate", image: "Describe the image you want to generate", text: "Describe the text you want to generate", editImage: "Describe how you want to change this image", editText: "Describe how you want to revise this text", expandEditor: "Expand editor", editorTitle: "Edit prompt", stopGeneration: "Stop generation", generate: "Generate", stop: "Stop" },
        references: { title: "References", select: "Select references from canvas", uploadImage: "Upload a local reference image", disconnect: "Disconnect reference", empty: "No content", selecting: "Adding references", choose: "Select", selectingHint: "Select references from canvas · ESC to return" },
        composer: { title: "Compose prompt", description: "Use @ to reference connected assets; references are renumbered before sending", placeholder: "Enter a prompt and use @ to reference connected images, text, or groups", imagePreview: "Referenced image preview", resources: { image: "Image {{index}}", video: "Video {{index}}", audio: "Audio {{index}}", text: "Text {{index}}", group: "Group {{index}}" } },
        controls: { ratio: "Ratio", duplicate: "Duplicate", delete: "Delete", images: "{{count}} images", texts: "{{count}} options", generations: "{{count}} runs", reasoning: "Reasoning" },
        generation: { interrupted: "Generation was interrupted by a page refresh. Generate again.", front: "front view", rotateRight: "rotated {{angle}} degrees right", rotateLeft: "rotated {{angle}} degrees left", level: "eye-level view", topDown: "{{angle}}-degree top-down view", lowAngle: "{{angle}}-degree low-angle view", angleLabel: "AI multi-angle: {{horizontal}}, {{pitch}}, camera distance {{distance}}, {{lens}} lens", anglePrompt: "Regenerate a new view of the same subject from the reference image. Preserve the subject, colors, materials, and visual style; do not merely apply perspective distortion. {{angle}}." },
        agentOps: { add_node: "Add node", update_node: "Update node", delete_node: "Delete node", delete_connections: "Delete connections", connect_nodes: "Connect", set_viewport: "Adjust view", select_nodes: "Select nodes", run_generation: "Run generation" },
        pluginErrors: { invalidExport: "The plugin did not export a valid object", missingFields: "The plugin is missing id or nodes", downloadFailed: "Download failed (HTTP {{status}})", registryFailed: "Failed to load the official plugin registry (HTTP {{status}})" },
        shortcut: {
            dragCanvas: "Drag canvas",
            pan: "Pan view",
            toggleTool: "Temporarily switch Select / Move",
            wheel: "Mouse wheel",
            zoom: "Zoom canvas",
            zoomSlider: "Zoom slider",
            preciseZoom: "Adjust zoom precisely",
            boxSelect: "Select multiple nodes",
            addSelection: "Add nodes to selection",
            selectAll: "Select all nodes",
            copyPaste: "Copy/paste nodes or paste clipboard text/images",
            copyPasteNodes: "Copy/paste nodes",
            delete: "Delete selection",
            escape: "Clear selection and close overlays",
            dropMedia: "Drop images/videos/audio",
            upload: "Upload to canvas",
            drag: "Drag",
            click: "Click",
        },
    },
    navigation: {
        canvas: "My Canvases",
        image: "Image Studio",
        video: "Video Studio",
        prompts: "Prompt Library",
        assets: "My Assets",
        config: "Settings",
    },
    topNav: {
        openMenu: "Open navigation menu",
        menu: "Navigation menu",
        navigation: "Navigation",
        openAgent: "Open Agent",
        closeAgent: "Close Agent",
        plugins: "Node plugins",
        docs: "Documentation",
        switchLanguage: "Switch to {{language}}",
        shortcuts: "Keyboard shortcuts",
        lightTheme: "Switch to light theme",
        darkTheme: "Switch to dark theme",
    },
    home: {
        promptError: "Failed to load prompts",
        description: "Generate, connect, and reshape <content>images, text, and graphics</content> in <canvas>Infinite Canvas</canvas>, turning one-off generations into a continuous creative process.",
        start: "Get started",
        openCanvas: "Open canvas",
        showcaseTitle: "Keep every great result",
        showcaseDescription: "Save reliable prompts, visual references, and generated images so your next creation starts from proven ideas.",
        viewPrompts: "View prompt library",
    },
    version: {
        viewUpdates: "View release updates",
        title: "Release updates",
        currentVersion: "Current version",
        latestVersion: "Latest version",
        checking: "Checking...",
        checkUpdates: "Check for updates",
        unreleased: "Unreleased",
        latest: "Latest",
        current: "Current",
        readFailed: "Failed to read version",
        changelogFailed: "Failed to read changelog",
        updated: "Latest version information loaded",
        updateFailed: "Failed to load the latest version information",
        types: { added: "Added", fixed: "Fixed", changed: "Changed", optimized: "Optimized", docs: "Docs" },
    },
    config: {
        title: "Settings & Preferences",
        invalidFile: "The settings file format is invalid",
        description: "Providers, model selection, sync, and local storage",
        modalDescription: "Providers, default models, sync, and local storage",
        tabs: {
            channels: "Providers",
            preferences: "Preferences",
            promptSources: "Prompt sources",
            localStorage: "Local storage",
        },
        localStorage: {
            title: "IndexedDB storage usage",
            description: "View browser data saved by Infinite Canvas, grouped by object store.",
            indexedDbUsage: "IndexedDB usage",
            siteUsage: "Total site usage",
            quota: "Available quota",
            contentEstimate: "Estimated from stored content",
            siteUsageHint: "Includes IndexedDB and other site data",
            quotaHint: "Allocated dynamically by the browser",
            quotaProgress: "Site quota usage",
            mainDatabase: "Infinite Canvas data",
            records: "{{count}} records",
            refresh: "Refresh usage",
            readFailed: "Failed to read local storage",
            stores: { appState: "App state", images: "Image files", media: "Audio and video files", imageLogs: "Image history", videoLogs: "Video history", agentMessages: "Agent messages", promptCache: "Prompt cache" },
        },
        promptSources: {
            add: "Add source",
            deleteTitle: "Delete “{{name}}”?",
            deleteDescription: "The source configuration will be removed. Items already saved to My Assets are unaffected.",
            refreshed: "Updated {{count}} prompts from “{{name}}”",
            refreshFailedCached: "Update failed; the previous cache was kept",
            refreshPartial: "Update complete: {{success}} succeeded and {{failed}} failed. Failed sources kept their previous cache.",
            refreshAllSuccess: "Updated {{sources}} sources with {{total}} prompts",
            refreshFailed: "Update failed",
            builtIn: "Built-in",
            itemCount: "{{count}} prompts",
            failed: "Failed",
            healthy: "Healthy",
            unsynced: "Not synced",
            lastSuccess: "Last successful {{time}}",
            neverFetched: "Not fetched yet",
            view: "View content",
            refresh: "Fetch now",
            edit: "Edit source",
            schedule: "Scheduled fetch",
            interval: "Fetch interval",
            refreshAll: "Fetch all now",
            lastFetched: "Last fetched {{time}}",
            neverScheduled: "No scheduled fetch yet",
            scheduleDescription: "When enabled, all active sources are fetched on this interval while the page is open.",
            intervals: {
                disabled: "Disabled",
                minutes30: "Every 30 minutes",
                hour1: "Every hour",
                hours6: "Every 6 hours",
                hours24: "Every 24 hours",
            },
            editor: {
                addTitle: "Add prompt source",
                editTitle: "Edit prompt source",
                nameRequired: "Enter a source name",
                invalidUrl: "Enter a valid JSON URL",
                invalidHomepage: "Enter a valid homepage URL",
                name: "Source name",
                namePlaceholder: "Used for categories and labels",
                homepage: "Source homepage (optional)",
                enabled: "Enable source",
                jsonFormat: "JSON format",
            },
            content: {
                loadFailed: "Failed to fetch prompts",
                title: "{{name}} · Prompt content",
                count: "{{count}} prompts",
                refresh: "Update now",
                empty: "No prompts",
                cover: "Cover",
                titleColumn: "Title",
                tags: "Tags",
                actions: "Actions",
            },
            runtime: { requestFailed: "Request failed ({{status}})", urlRequired: "JSON URL is required", fetchFailed: "Failed to fetch “{{name}}”: {{error}}", noPrompts: "No valid prompts were parsed from “{{name}}”", invalidRoot: "Invalid “{{name}}” format: the root value must be an array" },
        },
        fileSecurity: "The JSON file contains API keys and WebDAV credentials. Keep it secure.",
        import: "Import settings",
        export: "Export settings",
        imported: "Settings and preferences imported",
        importedDirectConfig: "Local direct connection settings imported",
        importFailed: "Failed to read the settings file",
        saved: "Settings saved",
        savedContinue: "Settings saved. Continue with your previous request.",
        channels: {
            description: "Choose a protocol for each provider, fetch its models, assign capabilities, and optionally customize request scripts.",
            add: "Add provider",
            unnamed: "Unnamed provider",
            numberedName: "Provider {{count}}",
            modelCount: "{{count}} models",
            missingUrl: "API endpoint not set",
            keepOne: "Keep at least one provider",
            defaultName: "Default provider",
            newName: "New provider",
            indexedName: "Provider {{index}}",
        },
        preferences: {
            interface: "Interface",
            language: "Display language",
            languageDescription: "Change the language used by the interface and components.",
            defaultModels: "Default models",
            defaultImageModel: "Default image model",
            defaultVideoModel: "Default video model",
            defaultTextModel: "Default text model",
            defaultAudioModel: "Default audio model",
            generation: "Generation preferences",
            canvasImageCount: "Default canvas image count",
            canvasImageCountDescription: "Used by new canvas image and configuration nodes. Individual nodes can override it.",
            audioVoice: "Default audio voice",
            audioFormat: "Default audio format",
            audioSpeed: "Default audio speed",
            audioInstructions: "Default audio instructions",
            audioInstructionsPlaceholder: "For example: natural, warm, and suitable for narration.",
            systemPrompt: "System prompt",
            systemPromptPlaceholder: "For example: You are a visual director specializing in cinematic, photorealistic imagery.",
        },
        channelEditor: {
            title: "Edit provider",
            name: "Provider name",
            protocol: "Protocol",
            baseUrl: "API endpoint",
            models: "Provider models",
            modelDescription: "{{count}} selected; assign a capability to each model and optionally customize its request script.",
            selectModels: "Select models",
            scriptReady: "Script set",
            script: "Request script",
            empty: "Select models to fetch or manually add models.",
            capabilities: {
                image: "Image",
                video: "Video",
                text: "Text",
                audio: "Audio",
            },
        },
        modelSelect: {
            missingConfig: "Enter an API endpoint and API key first",
            fetched: "Fetched {{count}} models",
            fetchFailed: "Failed to fetch models",
            title: "Select provider models",
            selected: "{{selected}} / {{total}} selected",
            confirm: "Confirm",
            search: "Search models",
            modelName: "Enter a model name",
            add: "Add model",
            fetch: "Fetch model list",
            description: "If the provider does not expose an OpenAI /models endpoint, add model names manually here.",
            fetchedTab: "Fetched models ({{count}})",
            existingTab: "Selected models ({{count}})",
            visibleSelected: "{{selected}} / {{total}} selected in this list",
            selectVisible: "Select this list",
            clearVisible: "Clear this list",
            fetchedEmpty: "Fetch models from the provider or add a model name manually.",
            existingEmpty: "No models selected.",
        },
        scriptEditor: {
            description: "The script is an async function body. Use the variables below and return the result; leave it empty to use the default request.",
            insertTemplate: "Insert {{name}} template",
            restoreDefault: "Restore default request",
            returnRequirements: "Return requirements",
            variables: "Available variables",
            insert: "Click to insert",
            placeholder: "// Leave empty to use the default request; insert a template to view an example.",
        },
        webdav: {
            title: "WebDAV sync",
            description: "Sync canvases, assets, generation history, and local media files. AI API keys are excluded; the browser connects directly to WebDAV.",
            lastSynced: "Last synced {{time}}",
            neverSynced: "Not synced yet",
            url: "WebDAV URL",
            directory: "Remote directory",
            directoryDescription: "Business directories are created here, each containing {{manifest}} and files/",
            username: "Username",
            password: "Password / app password",
            test: "Test connection",
            syncing: "Syncing",
            syncNow: "Sync now",
            missingUrl: "Enter a WebDAV URL first",
            available: "WebDAV connection is available",
            testFailed: "WebDAV connection test failed",
            preparing: "Preparing to sync",
            failed: "WebDAV sync failed",
            completed: "Sync complete: {{projects}} canvases, {{assets}} assets, {{records}} records, and {{files}} files ({{bytes}}) uploaded",
            domains: {
                canvas: "Canvases",
                assets: "My Assets",
                imageWorkbench: "Image Studio",
                videoWorkbench: "Video Studio",
            },
            stages: {
                waiting: "Waiting",
                localWaiting: "Waiting for local data",
                syncComplete: "Sync complete",
                remoteManifest: "Reading remote manifest",
                localData: "Reading local data",
                downloadMedia: "Downloading missing media",
                writeMerge: "Writing merged local data",
                uploadMedia: "Uploading new media",
                mediaReady: "Media is up to date",
                mediaSkipped: "No media to upload",
                checkMissingMedia: "Checking for missing media",
                downloadMediaFile: "Downloading media",
                checkLocalMedia: "Checking local media",
                uploadMediaFile: "Uploading media {{size}}",
                uploadManifest: "Uploading manifest {{size}}",
                complete: "Complete",
            },
            errors: { testFailed: "WebDAV connection test failed", downloadFailed: "Failed to read the WebDAV sync file", downloadTimeout: "Timed out while reading the WebDAV sync file", emptyUpload: "The upload file is empty; upload canceled", uploadFailed: "Failed to upload the WebDAV sync file", directoryFailed: "Failed to create the remote WebDAV directory", requestTimeout: "The WebDAV request timed out. Check the network or remote service.", connectionFailed: "Could not connect to WebDAV. Check the address, HTTPS certificate, CORS, and network.", urlRequired: "Enter a WebDAV URL first", authenticationFailed: "WebDAV authentication failed. Check the username, password, or app password.", pathMissing: "The WebDAV path does not exist. Check the address and remote directory.", responseFailed: "{{fallback}}: {{status}}{{detail}}", syncFailed: "Sync failed", invalidManifest: "The {{domain}} sync manifest does not belong to this app" },
        },
        protocols: {
        },
    },
    agent: {
        status: { failed: "Connection failed", connected: "Connected", connecting: "Connecting", disconnected: "Disconnected" },
        state: { ready: "Ready", connectionRequired: "Enter the Local URL and Connect token", invalidUrl: "The Local URL is invalid", offline: "Offline", skillReadFailed: "Failed to read Skill", skillParseFailed: "Failed to parse Skill", requestFailed: "Local Agent request failed" },
        siteTools: { canvasList: "Canvas list", generationStatus: "Generation task status", imageConfig: "Image configuration", imageGenerate: "Generate in Image Studio", videoConfig: "Video configuration", videoGenerate: "Generate in Video Studio", promptSearch: "Search prompts", assetList: "Asset list", assetAdd: "Add asset", unknownTool: "Unknown tool: {{name}}", canvasLoading: "The canvas is still loading. Try again shortly.", canvasHint: "Use site_navigate to open /canvas/{id}", assetsLoading: "Assets are still loading. Try again shortly.", assetTitleRequired: "Provide the asset title", textContentRequired: "content is required when kind=text", imageUrlRequired: "imageUrl is required when kind=image", imageReadFailed: "Could not read the image. Use a data URL or a cross-origin accessible image URL.", assetKindUnsupported: "assets_add supports only kind=text or kind=image", imageGenerationStarted: "Opened Image Studio and started generation. Use generation_get_status to query the task.", imageConfigApplied: "Opened Image Studio and applied the parameters without starting generation.", videoGenerationStarted: "Opened Video Studio and started generation. Use generation_get_status to query the task.", videoConfigApplied: "Opened Video Studio and applied the parameters without starting generation." },
        connect: { pluginTitle: "Option 1: Use the Codex plugin", pluginText: "Install the Infinite Canvas plugin in the Codex app and launch the canvas through it. The plugin starts the local Agent and supplies the connection details automatically.", directTitle: "Option 2: Run the Agent directly", directText: "Without the Codex plugin, run the command below in a terminal, then return here to connect or enter the Local URL and Connect token manually.", commandCopied: "Command copied", pluginReminder: "Codex plugin note", pluginReminderText: "The tool list enters the Codex context and consumes additional tokens only after installing the Codex plugin or adding MCP manually. Running npx -y @basketikun/canvas-agent alone does not install MCP.", removePlugin: "Remove plugin", removeMcp: "Remove manual MCP", copyCommand: "Copy command", title: "Connect local Agent", description: "Choose the connection method that fits your workflow.", webConnection: "Web connection", autoDiscover: "The Local URL and Connect token are discovered automatically by default. Enter them manually only if discovery fails.", disconnect: "Disconnect", connect: "Connect", localAddress: "Local address", urlPlaceholder: "For example http://127.0.0.1:17371", token: "Connection token", tokenPlaceholder: "Discover automatically or enter the Connect token" },
        history: { workspace: "Workspace", defaultWorkspace: "Default canvas directory", selected: "{{count}} selected", count: "{{count}} conversations", empty: "No history", deleteCount: "Delete {{count}}", refresh: "Refresh", newThread: "New chat", selectThread: "Select {{name}}", untitled: "Untitled conversation", current: "Current", noWorkspaceThreads: "No conversations in this workspace yet", connectHint: "Connect the local Agent to view conversation history" },
        skills: { selectLocal: "Select local Skill", search: "Search Skills", loading: "Loading Skills…", noMatch: "No matching enabled Skills", none: "No Skills available", select: "Select Skill", connectHint: "Connect the Agent to use Skills" },
        skillManager: {
            codexBusy: "Codex is running. Finish the current task before extracting a Skill.", noConversation: "This conversation has no completed content to extract", noCanvas: "There is no canvas on this page to extract", connecting: "This page is still connecting to the Agent. Try again shortly.", syncFailed: "Failed to sync the current canvas. Check the Agent connection and try again.", noDraft: "No Skill draft was generated", draftCreated: "Draft generated. Review it on the Skills tab before creating it.", draftFailed: "Failed to generate Skill draft", contentMissing: "Skill content was not returned", readFailed: "Failed to read Skill", defaultPromptMention: "The default prompt must include ${{name}}", created: "Skill created", updated: "Skill updated", saveFailed: "Failed to save Skill", deleteTitle: "Delete {{name}}", deleteDescription: "The local files cannot be recovered after deletion. Continue?", delete: "Delete", deleted: "Skill deleted", deleteFailed: "Failed to delete Skill", statusFailed: "Failed to update Skill status",
            fromConversation: "Generate draft from this conversation", availableAfterRun: "Available when Codex finishes running", conversationDescription: "Extract reusable workflows from this conversation", noCompletedContent: "This conversation has no completed content", startConversation: "Start a conversation first", fromCanvas: "Generate draft from this canvas", canvasDescription: "Extract nodes and generation workflows from this page", canvasUnavailable: "There is no available canvas on this page", blankCreate: "Create from scratch", blankDescription: "Start with an empty form", localSkills: "Local Skills", localDescription: "Installed locally and run directly by Codex", reload: "Reload", reloadSkill: "Reload Skills", createSkill: "Create Skill", filterBySource: "Filter Skills by source", scopes: { all: "All sources", repo: "Project", user: "Personal", system: "System", admin: "Admin" }, loadErrors: "{{count}} Skills could not be loaded", externalReadonly: "External Skills can only be used or enabled and disabled", noDescription: "No description", enabled: "Enabled", disabled: "Disabled", selected: "Selected", use: "Use", editNamed: "Edit {{name}}", deleteNamed: "Delete {{name}}", connectToView: "Connect the Agent to view Skills", noMatch: "No matching Skills", none: "No local Skills yet", connectDescription: "Installed local Skills will load after connection", tryAnotherFilter: "Try another keyword or source", createOrInstall: "Create one, or install one locally and refresh", saveChanges: "Save changes", saveLocation: "Save to the local Agent workspace", basicInfo: "Basic information",
            identifier: "Skill identifier", identifierExtra: "Used as the folder name and for $skill-name invocation.", identifierRequired: "Enter a Skill identifier", identifierMax: "The Skill identifier cannot exceed 64 characters", identifierPattern: "Use lowercase letters, numbers, and hyphens only; hyphens cannot repeat or appear at either end", identifierPlaceholder: "For example, product-grid", displayName: "Display name", displayNameMax: "The display name cannot exceed 64 characters", displayNamePlaceholder: "For example, Product grid generator", whenToUse: "When to use", whenToUseExtra: "Describe the Skill's capabilities and use cases so Codex can decide when to invoke it.", whenToUseRequired: "Describe when to use this Skill", whenToUseMax: "The use-case description cannot exceed 1,024 characters", noAngleBrackets: "The use-case description cannot contain angle brackets", whenToUsePlaceholder: "For example: Use when planning and generating a set of product images from product information", instructions: "Instructions", instructionsExtra: "Describe the steps, constraints, and output requirements in execution order.", instructionsRequired: "Enter the instructions", instructionsPlaceholder: "Describe execution steps, required checks, and the final output", advanced: "Advanced settings", shortDescription: "Card summary", shortDescriptionExtra: "Use 25–64 characters for easy scanning.", shortDescriptionMin: "The card summary must contain at least 25 characters", shortDescriptionMax: "The card summary cannot exceed 64 characters", shortDescriptionPlaceholder: "Optional; shown in the list", defaultPrompt: "Default prompt", defaultPromptExtra: "Must include the exact $skill-name, such as $product-grid.", defaultPromptMax: "The default prompt cannot exceed 1,024 characters", defaultPromptPlaceholder: "Optional; prefilled when the Skill is selected",
        },
        composer: { removeImage: "Remove image", removeSkill: "Remove Skill", uploadImage: "Upload image", stop: "Stop", send: "Send", model: "Model: {{model}}", selectModel: "Select a Codex model. Current: {{model}}", reasoning: "Reasoning effort: {{effort}}", selectReasoning: "Select reasoning effort. Current: {{effort}}", permissionLabel: "Permissions: {{mode}}", selectPermission: "Select Codex permission mode. Current: {{mode}}", effort: { minimal: "Minimal", low: "Low", medium: "Medium", high: "High", xhigh: "Extra high", max: "Maximum", ultra: "Ultra" }, permission: { request: "Ask for approval", requestDescription: "Always ask before editing outside the workspace or accessing the network", automatic: "Automatic review", automaticDescription: "Codex reviews risky actions and asks only when needed", full: "Full access", fullShort: "Full access", fullDescription: "Unrestricted access to the network and local files" }, tools: { label: "Tool confirmation: {{mode}}", manual: "Manual", manualDescription: "Ask before the Agent writes to the canvas", automatic: "Automatic", automaticDescription: "Let the Agent perform canvas writes automatically", select: "Select tool confirmation mode. Current: {{mode}}" }, mentions: { selectSkill: "Select a Skill", selectResource: "Reference canvas assets", loadingSkills: "Loading Skills…", noSkills: "No enabled Skills match", noResources: "No matching canvas assets", previewUnavailable: "This asset cannot be previewed", referenceLabel: "Referenced {{kind}}: {{title}}", resourceMissing: "Canvas asset “{{title}}” no longer exists", imageReadFailed: "Could not read canvas image “{{title}}”", kind: { image: "Image", video: "Video", audio: "Audio", text: "Text" } } },
        panel: { connectionSettings: "Connection settings · {{status}}", connectionSettingsLabel: "Connection settings. Current status: {{status}}", chat: "Chat", history: "History", skills: "Skills", logs: "Logs", collapse: "Collapse chat", collapseLabel: "Collapse Agent panel", resize: "Resize right panel", content: "Agent content", mcpInitializing: "MCP is initializing. You can send messages when it is ready.", initFailed: "Codex conversation initialization failed. Start or resume a conversation.", placeholder: "Ask Codex, type / for Skills, or @ to reference canvas assets" },
        chat: { latestMessages: "View latest messages", latestCall: "Latest call", input: "Input", cached: "Cached", output: "Output" },
        logs: { copied: "Logs copied", selectedManual: "Logs selected; copy them manually", copyFailed: "Copy failed. Switch to raw JSON and copy manually.", title: "Runtime logs", diagnostics: "Diagnostics", rawJson: "Raw JSON", messages: "{{count}} messages", tool: "Tool: {{tool}}", noPendingTool: "No pending tool", all: "All {{count}}", errors: "Errors {{count}}", warnings: "Warnings {{count}}", info: "Info {{count}}", list: "Diagnostics log list", noFiltered: "No logs match this filter", empty: "No event logs", new: "{{count}} new logs", newLabel: "{{count}} new logs. View latest logs.", latest: "View latest logs", fullData: "Full diagnostics · {{count}} entries", copyAll: "Copy all logs", copyLastError: "Copy latest error", lastErrorCopied: "Latest error copied", clear: "Clear logs", repeated: "Repeated {{count}} times", details: "Details", skillLoading: "Skill loading", plugin: "Plugin", terminal: "Terminal", conversationStorage: "Conversation storage" },
        message: { close: "Close", copied: "Copied", copyCode: "Copy code", copyLink: "Copy link", externalWarning: "You are about to open an external link. Make sure you trust it.", openExternal: "Open external link?", continueOpen: "Open", revealed: "Revealed in file manager", openLocalFailed: "Could not open the local file", openLocal: "Open local file?", localDescription: "This path will be revealed in your local file manager and will not be opened in the browser.", externalDescription: "You are about to open an external link. Make sure you trust it.", pathCopied: "Path copied", linkCopied: "Link copied", copyPath: "Copy path", showInFolder: "Show in file manager", toolCall: "Tool call", awaitingConfirmation: "Awaiting confirmation", reject: "Reject", approve: "Approve", networkApproval: "Network access request", fileApproval: "File edit request", permissionApproval: "Extended permission request", commandApproval: "Command execution request", decline: "Decline", allowOnce: "Allow once", allowSession: "Allow for session", thinking: "Thinking", commandsRunning: "Running {{count}} commands", commandRunning: "Running command", commandsCompleted: "Ran {{count}} commands{{failed}}", commandsFailed: " · {{count}} failed", failed: "Failed", running: "In progress", completed: "Completed", command: "Command", slowResponse: "The response is taking longer, but the task is still running. You can keep waiting or use the stop button beside the input to end this turn.", waitingSeconds: "Waited {{seconds}} seconds", waitingMinutes: "Waited {{minutes}}m {{seconds}}s", files: "Files", errorInfo: "Error", output: "Output", viewLarge: "View full image", attachmentPreview: "Image attachment preview", noEffect: "No effect", canceled: "Canceled", recorded: "Recorded", stopped: "Stopped", finished: "Finished", pending: "Pending" },
        events: { analyzing: "Analyzing the task…", reasoning: "Reasoning summary", plan: "Execution plan", commandFailed: "Command failed", commandCompleted: "Command completed", executeCommand: "Run command", editFiles: "Edit files", searchWeb: "Search the web", viewImage: "View image", imageViewed: "Image viewed", viewingImage: "Viewing image", imageGeneration: "Generate image", imageFailed: "Image generation failed", imageCompleted: "Image generation completed", generatingImage: "Generating image…", compactContext: "Compact context", contextCompacted: "Conversation context compacted; continuing the task", compactingContext: "Compacting conversation context…", collaboration: "Collaborate", collaborationFailed: "Collaboration task failed", collaborationCompleted: "Collaboration task completed", collaborating: "Working with collaborators…", progress: "Task progress", progressCount: "{{completed}}/{{total}} completed", planning: "Preparing execution steps…", executingCommand: "Running command…", workingDirectory: "Working directory", exitStatus: "Exit status", duration: "Duration", seconds: "{{value}} seconds", filesCompleted: "File changes completed", preparingFiles: "Preparing file changes…", fileCompleted: "{{action}} completed: {{path}}", editingFile: "{{action}} in progress: {{path}}", filesEdited: "Edited {{count}} files: {{names}}{{more}}", editingFiles: "Editing {{count}} files: {{names}}{{more}}", andMore: " and more", openPage: "Open page: {{url}}", findInPage: "Find “{{pattern}}” on page", content: "content", search: "Search: {{query}}", relatedInfo: "related information", keyword: "Keyword", webpage: "Web page", add: "Add", delete: "Delete", edit: "Edit", diagnostics: "Infinite Canvas Agent diagnostics", address: "Address: {{endpoint}}", connection: "Connection: {{connection}} · Status: {{status}}", online: "Online", connecting: "Connecting", disabled: "Disabled", messageTool: "Messages: {{messages}} · Tool: {{tool}}", none: "None", noLogs: "No event logs", threadCreated: "Conversation created", turnStarted: "Processing started", progressUpdated: "Task progress updated", turnFailed: "Processing failed", turnStopped: "Processing stopped", turnCompleted: "Processing completed", toolCalled: "Tool called", toolFailed: "Tool failed", toolCompleted: "Tool completed", replyReceived: "Reply received", completed: "Completed", modelBusy: "Model temporarily busy", modelBusyDescription: "The selected model is receiving too many requests. Try again later or switch models.", taskFailed: "Task failed", taskFailedDescription: "Codex could not complete this task. Try again later." },
        eventExtra: { toolNamed: "Call tool: {{name}}", toolOperation: "Tool operation", targetPage: "Target page", searchContent: "Search query", textContent: "Text content", operationContent: "Operations", imageCount: "Image count", tools: { generateImage: "Generate image", viewImage: "View image", executeCommand: "Run command", editFiles: "Edit files", searchWeb: "Search the web", canvasOps: "Canvas operations", readCanvas: "Read canvas", readSelection: "Read selection", exportSnapshot: "Export snapshot", createNode: "Create node", addAttachments: "Add attachment images", createText: "Create text", createTexts: "Create text nodes", createConfig: "Create generation config", createImageFlow: "Create image flow", createGenerationFlow: "Create generation flow", generateText: "Generate text", generateVideo: "Generate video", generateAudio: "Generate audio", updateNode: "Update node", updateText: "Update text", moveNodes: "Move nodes", resizeNode: "Resize node", deleteNodes: "Delete nodes", connectNodes: "Connect nodes", selectNodes: "Select nodes", setViewport: "Adjust viewport", runGeneration: "Run generation", openPage: "Open page" } },
        eventMore: { toolRunning: "{{action}}…", openedRoute: "Opened {{route}}", canvasCount: "{{count}} canvases", promptCount: "Found {{count}} prompts", assetCount: "{{count}} assets", assetAdded: "Added to My Assets", generationStatus: "{{total}} tasks: {{queued}} queued, {{running}} running, {{succeeded}} succeeded, {{failed}} failed", workbenchExecuted: "Executed in the workbench", workbenchConfigRead: "Workbench configuration read", canvasRead: "Current canvas read", selectionRead: "Current selection read", textNodes: "{{count}} text nodes", imageNodes: "{{count}} images", configNodes: "{{count}} config nodes", videoNodes: "{{count}} videos", audioNodes: "{{count}} audio nodes", groupNodes: "{{count}} groups", otherNodes: "{{count}} other nodes", connections: "{{count}} connections", emptyCanvas: "The canvas is empty", executeTool: "Run {{tool}}", thinking: "Thinking...", operationRunning: "{{operation}} is running...", organizingCanvas: "Canvas read; Codex is organizing the result...", operationCompleted: "{{operation}} completed; Codex is continuing...", attachmentPrompt: "Please process the uploaded image attachments.", routes: { home: "Home", canvas: "Canvas", canvasProject: "Selected canvas", image: "Image Studio", video: "Video Studio", prompts: "Prompt Center", assets: "My Assets", config: "Settings" } },
        runtime: {
            mcpStarting: "Starting MCP: {{name}}", mcpConnecting: "Connecting tools and loading the available tool list", mcpReadyNamed: "MCP ready: {{name}}", toolsReady: "Tool list loaded. You can start chatting.", mcpFailedNamed: "MCP failed to start: {{name}}", mcpCanceledNamed: "MCP startup canceled: {{name}}", toolInitFailed: "The tool service could not finish initializing", mcpServicesStarting: "Starting MCP services", toolServicesPending: "{{count}} tool services are still initializing", checkingToolServices: "Checking tool service status", conversationInitializing: "Initializing the Codex conversation", conversationCreating: "Creating the conversation and starting canvas tools", someMcpFailed: "Some MCP services failed to initialize", remainingToolsReady: "The remaining tools are ready. You can start chatting.", conversationInitFailed: "Codex conversation initialization failed", conversationCreateFailed: "Could not create the Codex conversation", mcpServicesReady: "{{count}} MCP services initialized", toolInitCanceled: "Tool service initialization was canceled", mcpStatusComplete: "MCP status check completed", mcpListRead: "Loaded the complete tool service list returned by Codex",
            historyReadFailed: "Failed to read history", conversationSyncFailed: "Failed to sync conversation", agentOutdated: "The local Agent is outdated. Restart Canvas Agent and reconnect.", restartRequired: "Agent restart required", versionMismatch: "Agent version mismatch", awaitingApproval: "Awaiting approval", codexRunning: "Codex is running", connected: "Connected", localAgentConnected: "Local Agent connected", processingFailed: "Processing failed", completed: "Completed", approvalGranted: "Permission approved", approvalCanceled: "Permission canceled", log: "Log", connectionLostDescription: "The local Agent connection failed or was interrupted", connectionFailedDescription: "Connection failed. Check the address and token.", connectionLost: "Connection lost", connectionFailed: "Connection failed", modelListFailed: "Failed to load model list",
            imageTooLarge: "Image too large", imagePayloadTooLarge: "Image attachments exceed 30 MB. Remove some before sending.", imagesSent: "Sent {{count}} images", canvasReferencesSent: "Referenced {{count}} canvas assets", someCanvasReferencesMissing: "Some referenced canvas assets no longer exist", canvasReferencesMissing: "The referenced canvas assets no longer exist. Select them again.", readingCanvasImages: "Reading canvas images", canvasImageReadFailed: "Failed to read canvas images", tooManyImages: "Too many images", imageCountLimit: "Uploaded and referenced canvas images are limited to {{count}} in total.", sending: "Sending", defaultModel: "Default model", defaultEffort: "Default effort", sendTask: "Send task", attachmentCount: "{{count}} attachments", canvasReferenceCount: "{{count}} canvas assets", attachmentsOnly: "Attachments only", canvasReferencesOnly: "Canvas assets", startConversationFailed: "Failed to start conversation", attachmentHistoryFailed: "Failed to save attachment history", sendFailed: "Send failed", conversationSynced: "Conversation synced", taskStillRunning: "Task is still running", stopping: "Stopping", stopTask: "Stop task", taskStopped: "Task stopped", stopFailed: "Failed to stop", imageLimit: "Image attachments are limited to about 30 MB.", imageReadFailed: "Failed to read image", pendingCanvasTool: "Another canvas tool call is awaiting confirmation", awaitingConfirmation: "Awaiting confirmation", toolCompleted: "{{tool}} completed", toolExecutionFailed: "Tool execution failed", openCanvasFirst: "The canvas is not open. Use site_navigate to open it first.", canvasOperationFailed: "Canvas operation failed", canvasToolCanceled: "The user canceled the canvas tool call",
            submittingApproval: "Submitting permission decision", waitingCodexApproval: "Waiting for Codex to confirm permission", approvalFailed: "Permission approval failed", enableFullAccess: "Enable full access", fullAccessDescription: "Codex will run without sandbox restrictions and can access the internet and any local files. Use this only when you trust the current task.", enableFullAccessAction: "Enable full access", offline: "Offline", addressRequired: "Enter the local Agent address", agentNotFound: "No local Agent was found. Use the Codex plugin or start Canvas Agent manually.", invalidAddress: "The local Agent address is invalid", connecting: "Connecting", creatingConversation: "Creating conversation", newConversation: "New conversation", newConversationFailed: "Failed to create conversation", conversationResumed: "Conversation resumed", resumeConversationFailed: "Failed to resume conversation", recordsDeleted: "Deleted {{count}} records", deleteConversationFailed: "Failed to delete conversation", deleteConversations: "Delete {{count}} conversations", deleteConversationsDescription: "This cannot be undone. Continue?", importGeneratedImages: "Import generated images", addedToSourceCanvas: "Added to the source canvas", imageGenerated: "Image generated", noImageAttachments: "No image attachments to add", invalidAttachmentNode: "Invalid image attachment node parameters", attachmentReadFailed: "Failed to read image attachment", referenceImage: "Reference image", generatedImageReadFailed: "Failed to read the image generated by Codex", generatedImageName: "Generated image {{index}}",
        },
    },
    locale: {
        zhCN: "简体中文",
        enUS: "English",
    },
};
