feat(ui): i18n for prompt editor components

This commit is contained in:
吹雪 2026-06-10 22:53:17 +09:00
parent 06e934a367
commit 524569b9ae
12 changed files with 275 additions and 68 deletions

View file

@ -1,4 +1,5 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Modal, Form, Select, Upload, Button, Divider } from "antd";
import { TextInput } from "@tremor/react";
import { UploadOutlined } from "@ant-design/icons";
@ -22,6 +23,7 @@ interface PromptFormData {
}
const AddPromptForm: React.FC<AddPromptFormProps> = ({ visible, onClose, accessToken, onSuccess }) => {
const { t } = useTranslation();
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [fileList, setFileList] = useState<UploadFile[]>([]);
@ -40,12 +42,12 @@ const AddPromptForm: React.FC<AddPromptFormProps> = ({ visible, onClose, accessT
console.log("values: ", values);
if (!accessToken) {
NotificationsManager.fromBackend("Access token is required");
NotificationsManager.fromBackend(t("promptsPage.addPromptForm.accessTokenRequired"));
return;
}
if (promptIntegration === "dotprompt" && fileList.length === 0) {
NotificationsManager.fromBackend("Please upload a .prompt file");
NotificationsManager.fromBackend(t("promptsPage.addPromptForm.uploadPromptFileRequired"));
return;
}
@ -75,7 +77,7 @@ const AddPromptForm: React.FC<AddPromptFormProps> = ({ visible, onClose, accessT
};
} catch (conversionError) {
console.error("Error converting prompt file:", conversionError);
NotificationsManager.fromBackend("Failed to convert prompt file to JSON");
NotificationsManager.fromBackend(t("promptsPage.addPromptForm.conversionFailed"));
setLoading(false);
return;
}
@ -84,12 +86,12 @@ const AddPromptForm: React.FC<AddPromptFormProps> = ({ visible, onClose, accessT
// Create the prompt
try {
await createPromptCall(accessToken, promptData);
NotificationsManager.success("Prompt created successfully!");
NotificationsManager.success(t("promptsPage.addPromptForm.createSuccess"));
handleCancel();
onSuccess();
} catch (createError) {
console.error("Error creating prompt:", createError);
NotificationsManager.fromBackend("Failed to create prompt");
NotificationsManager.fromBackend(t("promptsPage.addPromptForm.createFailed"));
}
} catch (error) {
console.error("Form validation error:", error);
@ -101,10 +103,10 @@ const AddPromptForm: React.FC<AddPromptFormProps> = ({ visible, onClose, accessT
const uploadProps: UploadProps = {
beforeUpload: (file) => {
if (!file.name.endsWith(".prompt")) {
NotificationsManager.fromBackend("Please upload a .prompt file");
NotificationsManager.fromBackend(t("promptsPage.addPromptForm.uploadPromptFileRequired"));
return false;
}
return false; // Prevent automatic upload
return false;
},
fileList,
onChange: ({ fileList: newFileList }) => {
@ -117,35 +119,39 @@ const AddPromptForm: React.FC<AddPromptFormProps> = ({ visible, onClose, accessT
return (
<Modal
title="Add New Prompt"
title={t("promptsPage.addPromptForm.title")}
open={visible}
onCancel={handleCancel}
footer={[
<Button key="cancel" onClick={handleCancel}>
Cancel
{t("common.cancel")}
</Button>,
<Button key="submit" loading={loading} onClick={handleSubmit}>
Create Prompt
{t("promptsPage.addPromptForm.createPrompt")}
</Button>,
]}
width={600}
>
<Form form={form} layout="vertical" requiredMark={false}>
<Form.Item
label="Prompt ID"
label={t("promptsPage.addPromptForm.promptIdLabel")}
name="prompt_id"
rules={[
{ required: true, message: "Please enter a prompt ID" },
{ required: true, message: t("promptsPage.addPromptForm.promptIdRequired") },
{
pattern: /^[a-zA-Z0-9_-]+$/,
message: "Prompt ID can only contain letters, numbers, underscores, and hyphens",
message: t("promptsPage.addPromptForm.promptIdPattern"),
},
]}
>
<TextInput placeholder="Enter unique prompt ID (e.g., my_prompt_id)" />
<TextInput placeholder={t("promptsPage.addPromptForm.promptIdPlaceholder")} />
</Form.Item>
<Form.Item label="Prompt Integration" name="prompt_integration" initialValue="dotprompt">
<Form.Item
label={t("promptsPage.addPromptForm.integrationLabel")}
name="prompt_integration"
initialValue="dotprompt"
>
<Select value={promptIntegration} onChange={setPromptIntegration}>
<Option value="dotprompt">dotprompt</Option>
</Select>
@ -154,11 +160,18 @@ const AddPromptForm: React.FC<AddPromptFormProps> = ({ visible, onClose, accessT
{promptIntegration === "dotprompt" && (
<>
<Divider />
<Form.Item label="Prompt File" extra="Upload a .prompt file that follows the Dotprompt specification">
<Form.Item
label={t("promptsPage.addPromptForm.fileLabel")}
extra={t("promptsPage.addPromptForm.fileExtra")}
>
<Upload {...uploadProps}>
<Button icon={<UploadOutlined />}>Select .prompt File</Button>
<Button icon={<UploadOutlined />}>{t("promptsPage.addPromptForm.selectFile")}</Button>
</Upload>
{fileList.length > 0 && <div className="mt-2 text-sm text-gray-600">Selected: {fileList[0].name}</div>}
{fileList.length > 0 && (
<div className="mt-2 text-sm text-gray-600">
{t("promptsPage.addPromptForm.selected", { name: fileList[0].name })}
</div>
)}
</Form.Item>
</>
)}

View file

@ -1,4 +1,5 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Card, Text } from "@tremor/react";
import VariableTextArea from "../variable_textarea";
@ -8,11 +9,17 @@ interface DeveloperMessageCardProps {
}
const DeveloperMessageCard: React.FC<DeveloperMessageCardProps> = ({ value, onChange }) => {
const { t } = useTranslation();
return (
<Card className="p-3">
<Text className="block mb-2 text-sm font-medium">Developer message</Text>
<Text className="text-gray-500 text-xs mb-2">Optional system instructions for the model</Text>
<VariableTextArea value={value} onChange={onChange} rows={3} placeholder="e.g., You are a helpful assistant..." />
<Text className="block mb-2 text-sm font-medium">{t("promptsPage.developerMessageCard.title")}</Text>
<Text className="text-gray-500 text-xs mb-2">{t("promptsPage.developerMessageCard.subtitle")}</Text>
<VariableTextArea
value={value}
onChange={onChange}
rows={3}
placeholder={t("promptsPage.developerMessageCard.placeholder")}
/>
</Card>
);
};

View file

@ -1,4 +1,5 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { PromptType } from "./types";
import { convertToDotPrompt } from "./utils";
@ -7,13 +8,14 @@ interface DotpromptViewTabProps {
}
const DotpromptViewTab: React.FC<DotpromptViewTabProps> = ({ prompt }) => {
const { t } = useTranslation();
const dotpromptContent = convertToDotPrompt(prompt);
return (
<div className="p-6">
<div className="mb-4">
<h3 className="text-sm font-medium text-gray-700 mb-2">Generated .prompt file</h3>
<p className="text-xs text-gray-500">This is the dotprompt format that will be saved to the database</p>
<h3 className="text-sm font-medium text-gray-700 mb-2">{t("promptsPage.dotpromptViewTab.title")}</h3>
<p className="text-xs text-gray-500">{t("promptsPage.dotpromptViewTab.subtitle")}</p>
</div>
<div className="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-auto">
<pre className="text-sm text-gray-900 font-mono whitespace-pre-wrap">{dotpromptContent}</pre>

View file

@ -1,4 +1,5 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Text } from "@tremor/react";
import { Input } from "antd";
import { SettingsIcon } from "lucide-react";
@ -23,6 +24,7 @@ const ModelConfigCard: React.FC<ModelConfigCardProps> = ({
onTemperatureChange,
onMaxTokensChange,
}) => {
const { t } = useTranslation();
const [showConfig, setShowConfig] = useState(false);
return (
@ -36,14 +38,14 @@ const ModelConfigCard: React.FC<ModelConfigCardProps> = ({
className="flex items-center gap-2 px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50"
>
<SettingsIcon size={16} />
<span>Parameters</span>
<span>{t("promptsPage.modelConfigCard.parameters")}</span>
</button>
{showConfig && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-30">
<div className="bg-white rounded-lg shadow-xl p-6 w-96">
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold">Model Parameters</h3>
<h3 className="text-lg font-semibold">{t("promptsPage.modelConfigCard.modelParameters")}</h3>
<button onClick={() => setShowConfig(false)} className="text-gray-400 hover:text-gray-600">
✕
</button>
@ -51,7 +53,7 @@ const ModelConfigCard: React.FC<ModelConfigCardProps> = ({
<div className="space-y-4">
<div>
<div className="flex items-center justify-between mb-2">
<Text className="text-sm text-gray-700">Temperature</Text>
<Text className="text-sm text-gray-700">{t("promptsPage.modelConfigCard.temperature")}</Text>
<Input
type="number"
size="small"
@ -66,7 +68,7 @@ const ModelConfigCard: React.FC<ModelConfigCardProps> = ({
</div>
<div>
<div className="flex items-center justify-between mb-2">
<Text className="text-sm text-gray-700">Max Tokens</Text>
<Text className="text-sm text-gray-700">{t("promptsPage.modelConfigCard.maxTokens")}</Text>
<Input
type="number"
size="small"

View file

@ -1,4 +1,5 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Modal, Select, Button as AntdButton, Tabs } from "antd";
import { CodeOutlined } from "@ant-design/icons";
import { Button as TremorButton, Text } from "@tremor/react";
@ -26,6 +27,7 @@ const PromptCodeSnippets: React.FC<PromptCodeSnippetsProps> = ({
version = "1",
proxySettings,
}) => {
const { t } = useTranslation();
const [isModalVisible, setIsModalVisible] = useState(false);
const [selectedLanguage, setSelectedLanguage] = useState<"curl" | "python" | "javascript">("curl");
const [selectedTab, setSelectedTab] = useState("basic");
@ -235,13 +237,19 @@ main();`;
return (
<>
<TremorButton variant="secondary" icon={CodeOutlined} onClick={showModal}>
Get Code
{t("promptsPage.promptCodeSnippets.getCode")}
</TremorButton>
<Modal title="Generated Code" open={isModalVisible} onCancel={handleCancel} footer={null} width={800}>
<Modal
title={t("promptsPage.promptCodeSnippets.modalTitle")}
open={isModalVisible}
onCancel={handleCancel}
footer={null}
width={800}
>
<div className="flex justify-between items-center mb-4">
<div>
<Text className="font-medium block mb-1 text-gray-700">Language</Text>
<Text className="font-medium block mb-1 text-gray-700">{t("promptsPage.promptCodeSnippets.language")}</Text>
<Select
value={selectedLanguage}
onChange={(value) => setSelectedLanguage(value as "curl" | "python" | "javascript")}
@ -256,10 +264,10 @@ main();`;
<AntdButton
onClick={() => {
navigator.clipboard.writeText(generatedCode);
NotificationsManager.success("Copied to clipboard!");
NotificationsManager.success(t("promptsPage.promptCodeSnippets.copiedToClipboard"));
}}
>
Copy to Clipboard
{t("promptsPage.promptCodeSnippets.copyToClipboard")}
</AntdButton>
</div>
@ -267,9 +275,9 @@ main();`;
activeKey={selectedTab}
onChange={setSelectedTab}
items={[
{ label: "Basic", key: "basic" },
{ label: "With Messages", key: "messages" },
{ label: "With Version", key: "version" },
{ label: t("promptsPage.promptCodeSnippets.tabBasic"), key: "basic" },
{ label: t("promptsPage.promptCodeSnippets.tabWithMessages"), key: "messages" },
{ label: t("promptsPage.promptCodeSnippets.tabWithVersion"), key: "version" },
]}
/>

View file

@ -1,4 +1,5 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Button as TremorButton } from "@tremor/react";
import { Input, Select } from "antd";
import { ArrowLeftIcon, SaveIcon, ClockIcon } from "lucide-react";
@ -40,11 +41,12 @@ const PromptEditorHeader: React.FC<PromptEditorHeaderProps> = ({
environment,
onEnvironmentChange,
}) => {
const { t } = useTranslation();
return (
<div className="bg-white border-b border-gray-200 px-6 py-3 flex items-center justify-between">
<div className="flex items-center space-x-3">
<TremorButton icon={ArrowLeftIcon} variant="light" onClick={onBack} size="xs">
Back
{t("common.back")}
</TremorButton>
<Input
value={promptName}
@ -61,13 +63,15 @@ const PromptEditorHeader: React.FC<PromptEditorHeaderProps> = ({
style={{ width: 140 }}
size="small"
options={[
{ label: "Development", value: "development" },
{ label: "Staging", value: "staging" },
{ label: "Production", value: "production" },
{ label: t("promptsPage.promptEditorHeader.envDevelopment"), value: "development" },
{ label: t("promptsPage.promptEditorHeader.envStaging"), value: "staging" },
{ label: t("promptsPage.promptEditorHeader.envProduction"), value: "production" },
]}
/>
<span className="px-2 py-0.5 text-xs bg-gray-100 text-gray-600 rounded">Draft</span>
<span className="text-xs text-gray-400">Unsaved changes</span>
<span className="px-2 py-0.5 text-xs bg-gray-100 text-gray-600 rounded">
{t("promptsPage.promptEditorHeader.draft")}
</span>
<span className="text-xs text-gray-400">{t("promptsPage.promptEditorHeader.unsavedChanges")}</span>
</div>
<div className="flex items-center space-x-2">
<PromptCodeSnippets
@ -80,11 +84,11 @@ const PromptEditorHeader: React.FC<PromptEditorHeaderProps> = ({
/>
{editMode && onShowHistory && (
<TremorButton icon={ClockIcon} variant="secondary" onClick={onShowHistory}>
History
{t("promptsPage.promptEditorHeader.history")}
</TremorButton>
)}
<TremorButton icon={SaveIcon} onClick={onSave} loading={isSaving} disabled={isSaving}>
{editMode ? "Update" : "Save"}
{editMode ? t("common.update") : t("common.save")}
</TremorButton>
</div>
</div>

View file

@ -1,4 +1,5 @@
import React, { useState } from "react";
import { useTranslation, Trans } from "react-i18next";
import { Card, Text } from "@tremor/react";
import { Select } from "antd";
import { PlusIcon, TrashIcon, GripVerticalIcon } from "lucide-react";
@ -22,6 +23,7 @@ const PromptMessagesCard: React.FC<PromptMessagesCardProps> = ({
onRemoveMessage,
onMoveMessage,
}) => {
const { t } = useTranslation();
const [draggedIndex, setDraggedIndex] = useState<number | null>(null);
const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);
@ -51,9 +53,12 @@ const PromptMessagesCard: React.FC<PromptMessagesCardProps> = ({
return (
<Card className="p-3">
<div className="mb-2">
<Text className="text-sm font-medium">Prompt messages</Text>
<Text className="text-sm font-medium">{t("promptsPage.promptMessagesCard.title")}</Text>
<Text className="text-gray-500 text-xs mt-1">
Use <code className="bg-gray-100 px-1 rounded text-xs">{"{{variable}}"}</code> syntax for template variables
<Trans
i18nKey="promptsPage.promptMessagesCard.variableSyntaxHint"
components={{ code: <code className="bg-gray-100 px-1 rounded text-xs" /> }}
/>
</Text>
</div>
<div className="space-y-2">
@ -77,9 +82,9 @@ const PromptMessagesCard: React.FC<PromptMessagesCardProps> = ({
size="small"
bordered={false}
>
<Option value="user">User</Option>
<Option value="assistant">Assistant</Option>
<Option value="system">System</Option>
<Option value="user">{t("promptsPage.promptMessagesCard.roleUser")}</Option>
<Option value="assistant">{t("promptsPage.promptMessagesCard.roleAssistant")}</Option>
<Option value="system">{t("promptsPage.promptMessagesCard.roleSystem")}</Option>
</Select>
<div className="flex items-center gap-1">
{messages.length > 1 && (
@ -97,7 +102,7 @@ const PromptMessagesCard: React.FC<PromptMessagesCardProps> = ({
value={message.content}
onChange={(value) => onUpdateMessage(index, "content", value)}
rows={3}
placeholder="Enter prompt content..."
placeholder={t("promptsPage.promptMessagesCard.contentPlaceholder")}
/>
</div>
</div>
@ -105,7 +110,7 @@ const PromptMessagesCard: React.FC<PromptMessagesCardProps> = ({
</div>
<button onClick={onAddMessage} className="mt-2 text-xs text-blue-600 hover:text-blue-700 flex items-center">
<PlusIcon size={14} className="mr-1" />
Add message
{t("promptsPage.promptMessagesCard.addMessage")}
</button>
</Card>
);

View file

@ -1,4 +1,5 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Button as TremorButton, Text } from "@tremor/react";
import { Input, Modal } from "antd";
@ -19,34 +20,33 @@ const PublishModal: React.FC<PublishModalProps> = ({
onPublish,
onCancel,
}) => {
const { t } = useTranslation();
return (
<Modal
title="Publish Prompt"
title={t("promptsPage.publishModal.title")}
open={visible}
onCancel={onCancel}
footer={[
<div key="footer" className="flex justify-end gap-2">
<TremorButton variant="secondary" onClick={onCancel}>
Cancel
{t("common.cancel")}
</TremorButton>
<TremorButton onClick={onPublish} loading={isSaving}>
Publish
{t("promptsPage.publishModal.publish")}
</TremorButton>
</div>,
]}
>
<div className="py-4">
<Text className="mb-2">Name</Text>
<Text className="mb-2">{t("common.name")}</Text>
<Input
value={promptName}
onChange={(e) => onNameChange(e.target.value)}
placeholder="Enter prompt name"
placeholder={t("promptsPage.publishModal.namePlaceholder")}
onPressEnter={onPublish}
autoFocus
/>
<Text className="text-gray-500 text-xs mt-2">
Published prompts can be used in API calls and are versioned for easy tracking.
</Text>
<Text className="text-gray-500 text-xs mt-2">{t("promptsPage.publishModal.versionedHint")}</Text>
</div>
</Modal>
);

View file

@ -1,4 +1,5 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Card, Text } from "@tremor/react";
import { PlusIcon, TrashIcon } from "lucide-react";
import { Tool } from "./types";
@ -11,17 +12,18 @@ interface ToolsCardProps {
}
const ToolsCard: React.FC<ToolsCardProps> = ({ tools, onAddTool, onEditTool, onRemoveTool }) => {
const { t } = useTranslation();
return (
<Card className="p-3">
<div className="flex items-center justify-between mb-2">
<Text className="text-sm font-medium">Tools</Text>
<Text className="text-sm font-medium">{t("promptsPage.toolsCard.title")}</Text>
<button onClick={onAddTool} className="text-xs text-blue-600 hover:text-blue-700 flex items-center">
<PlusIcon size={14} className="mr-1" />
Add
{t("common.add")}
</button>
</div>
{tools.length === 0 ? (
<Text className="text-gray-500 text-xs">No tools added</Text>
<Text className="text-gray-500 text-xs">{t("promptsPage.toolsCard.noTools")}</Text>
) : (
<div className="space-y-2">
{tools.map((tool, index) => (
@ -35,7 +37,7 @@ const ToolsCard: React.FC<ToolsCardProps> = ({ tools, onAddTool, onEditTool, onR
</div>
<div className="flex items-center space-x-1 ml-2">
<button onClick={() => onEditTool(index)} className="text-xs text-blue-600 hover:text-blue-700">
Edit
{t("common.edit")}
</button>
<button onClick={() => onRemoveTool(index)} className="text-gray-400 hover:text-red-500">
<TrashIcon size={14} />

View file

@ -1,5 +1,6 @@
import { Drawer, List, Skeleton, Tag, Typography } from "antd";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { getPromptVersions, PromptSpec } from "../../networking";
const { Text } = Typography;
@ -21,6 +22,7 @@ const VersionHistorySidePanel: React.FC<VersionHistorySidePanelProps> = ({
activeVersionId,
onSelectVersion,
}) => {
const { t } = useTranslation();
const [versions, setVersions] = useState<PromptSpec[]>([]);
const [loading, setLoading] = useState(false);
@ -68,18 +70,18 @@ const VersionHistorySidePanel: React.FC<VersionHistorySidePanelProps> = ({
return (
<Drawer
title="Version History"
title={t("promptsPage.versionHistorySidePanel.title")}
placement="right"
onClose={onClose}
open={isOpen}
width={400}
mask={false} // Allow interacting with the main editor while drawer is open
mask={false}
maskClosable={false}
>
{loading ? (
<Skeleton active paragraph={{ rows: 4 }} />
) : versions.length === 0 ? (
<div className="text-center py-8 text-gray-500">No version history available.</div>
<div className="text-center py-8 text-gray-500">{t("promptsPage.versionHistorySidePanel.noHistory")}</div>
) : (
<List
dataSource={versions}
@ -113,13 +115,13 @@ const VersionHistorySidePanel: React.FC<VersionHistorySidePanelProps> = ({
<Tag className="m-0">{getVersionNumber(item)}</Tag>
{index === 0 && (
<Tag color="blue" className="m-0">
Latest
{t("promptsPage.versionHistorySidePanel.latest")}
</Tag>
)}
</div>
{isSelected && (
<Tag color="green" className="m-0">
Active
{t("promptsPage.versionHistorySidePanel.active")}
</Tag>
)}
</div>
@ -127,7 +129,9 @@ const VersionHistorySidePanel: React.FC<VersionHistorySidePanelProps> = ({
<div className="flex flex-col gap-1">
<Text className="text-sm text-gray-600 font-medium">{formatDate(item.created_at)}</Text>
<Text type="secondary" className="text-xs">
{item.prompt_info?.prompt_type === "db" ? "Saved to Database" : "Config Prompt"}
{item.prompt_info?.prompt_type === "db"
? t("promptsPage.versionHistorySidePanel.savedToDatabase")
: t("promptsPage.versionHistorySidePanel.configPrompt")}
</Text>
</div>
</div>

View file

@ -4486,5 +4486,85 @@
"deleteModalMessage": "Are you sure you want to delete this fallback? This action cannot be undone.",
"deleteModalResourceTitle": "Fallback Information"
}
},
"promptsPage": {
"addPromptForm": {
"title": "Add New Prompt",
"createPrompt": "Create Prompt",
"accessTokenRequired": "Access token is required",
"uploadPromptFileRequired": "Please upload a .prompt file",
"conversionFailed": "Failed to convert prompt file to JSON",
"createSuccess": "Prompt created successfully!",
"createFailed": "Failed to create prompt",
"promptIdLabel": "Prompt ID",
"promptIdRequired": "Please enter a prompt ID",
"promptIdPattern": "Prompt ID can only contain letters, numbers, underscores, and hyphens",
"promptIdPlaceholder": "Enter unique prompt ID (e.g., my_prompt_id)",
"integrationLabel": "Prompt Integration",
"fileLabel": "Prompt File",
"fileExtra": "Upload a .prompt file that follows the Dotprompt specification",
"selectFile": "Select .prompt File",
"selected": "Selected: {{name}}"
},
"developerMessageCard": {
"title": "Developer message",
"subtitle": "Optional system instructions for the model",
"placeholder": "e.g., You are a helpful assistant..."
},
"dotpromptViewTab": {
"title": "Generated .prompt file",
"subtitle": "This is the dotprompt format that will be saved to the database"
},
"modelConfigCard": {
"parameters": "Parameters",
"modelParameters": "Model Parameters",
"temperature": "Temperature",
"maxTokens": "Max Tokens"
},
"promptCodeSnippets": {
"getCode": "Get Code",
"modalTitle": "Generated Code",
"language": "Language",
"copyToClipboard": "Copy to Clipboard",
"copiedToClipboard": "Copied to clipboard!",
"tabBasic": "Basic",
"tabWithMessages": "With Messages",
"tabWithVersion": "With Version"
},
"promptEditorHeader": {
"envDevelopment": "Development",
"envStaging": "Staging",
"envProduction": "Production",
"draft": "Draft",
"unsavedChanges": "Unsaved changes",
"history": "History"
},
"promptMessagesCard": {
"title": "Prompt messages",
"variableSyntaxHint": "Use <code>{{variable}}</code> syntax for template variables",
"roleUser": "User",
"roleAssistant": "Assistant",
"roleSystem": "System",
"contentPlaceholder": "Enter prompt content...",
"addMessage": "Add message"
},
"publishModal": {
"title": "Publish Prompt",
"publish": "Publish",
"namePlaceholder": "Enter prompt name",
"versionedHint": "Published prompts can be used in API calls and are versioned for easy tracking."
},
"toolsCard": {
"title": "Tools",
"noTools": "No tools added"
},
"versionHistorySidePanel": {
"title": "Version History",
"noHistory": "No version history available.",
"latest": "Latest",
"active": "Active",
"savedToDatabase": "Saved to Database",
"configPrompt": "Config Prompt"
}
}
}

View file

@ -4486,5 +4486,85 @@
"deleteModalMessage": "确定要删除此回退吗?此操作无法撤销。",
"deleteModalResourceTitle": "回退信息"
}
},
"promptsPage": {
"addPromptForm": {
"title": "添加新提示词",
"createPrompt": "创建提示词",
"accessTokenRequired": "访问令牌不能为空",
"uploadPromptFileRequired": "请上传 .prompt 文件",
"conversionFailed": "提示词文件转换为 JSON 失败",
"createSuccess": "提示词创建成功!",
"createFailed": "创建提示词失败",
"promptIdLabel": "提示词 ID",
"promptIdRequired": "请输入提示词 ID",
"promptIdPattern": "提示词 ID 只能包含字母、数字、下划线和连字符",
"promptIdPlaceholder": "输入唯一提示词 ID(如:my_prompt_id)",
"integrationLabel": "提示词集成",
"fileLabel": "提示词文件",
"fileExtra": "上传符合 Dotprompt 规范的 .prompt 文件",
"selectFile": "选择 .prompt 文件",
"selected": "已选择:{{name}}"
},
"developerMessageCard": {
"title": "开发者消息",
"subtitle": "可选的模型系统指令",
"placeholder": "例如:你是一个有帮助的助手..."
},
"dotpromptViewTab": {
"title": "生成的 .prompt 文件",
"subtitle": "这是将保存到数据库的 dotprompt 格式"
},
"modelConfigCard": {
"parameters": "参数",
"modelParameters": "模型参数",
"temperature": "Temperature",
"maxTokens": "最大 Token 数"
},
"promptCodeSnippets": {
"getCode": "获取代码",
"modalTitle": "生成的代码",
"language": "语言",
"copyToClipboard": "复制到剪贴板",
"copiedToClipboard": "已复制到剪贴板!",
"tabBasic": "基础",
"tabWithMessages": "含消息",
"tabWithVersion": "含版本"
},
"promptEditorHeader": {
"envDevelopment": "开发",
"envStaging": "预发布",
"envProduction": "生产",
"draft": "草稿",
"unsavedChanges": "有未保存的更改",
"history": "历史"
},
"promptMessagesCard": {
"title": "提示词消息",
"variableSyntaxHint": "使用 <code>{{variable}}</code> 语法定义模板变量",
"roleUser": "用户",
"roleAssistant": "助手",
"roleSystem": "系统",
"contentPlaceholder": "输入提示词内容...",
"addMessage": "添加消息"
},
"publishModal": {
"title": "发布提示词",
"publish": "发布",
"namePlaceholder": "输入提示词名称",
"versionedHint": "已发布的提示词可在 API 调用中使用,并支持版本管理以便追踪。"
},
"toolsCard": {
"title": "工具",
"noTools": "暂无工具"
},
"versionHistorySidePanel": {
"title": "版本历史",
"noHistory": "暂无版本历史。",
"latest": "最新",
"active": "当前",
"savedToDatabase": "已保存到数据库",
"configPrompt": "配置提示词"
}
}
}