From fa7a6e18d804dc2d058a799b46b53f44556fa5ce Mon Sep 17 00:00:00 2001
From: lawvs <18554747+lawvs@users.noreply.github.com>
Date: Fri, 26 Sep 2025 16:29:02 +0800
Subject: [PATCH] feat(i18n): add translations for task management features
- Implemented internationalization for task scheduling, actions, and modal titles.
- Updated existing components to utilize translation functions for better localization support.
---
.../modules/ai-task/components/task-item.tsx | 80 +++++++++++--------
.../modules/ai-task/components/task-list.tsx | 8 +-
.../renderer/src/modules/settings/tabs/ai.tsx | 2 +-
.../tabs/ai/tasks/TaskSchedulingSection.tsx | 16 ++--
locales/ai/en.json | 36 +++++++++
locales/ai/ja.json | 36 +++++++++
locales/ai/zh-CN.json | 36 +++++++++
7 files changed, 167 insertions(+), 47 deletions(-)
diff --git a/apps/desktop/layer/renderer/src/modules/ai-task/components/task-item.tsx b/apps/desktop/layer/renderer/src/modules/ai-task/components/task-item.tsx
index 0feb0ece6..ac23436ef 100644
--- a/apps/desktop/layer/renderer/src/modules/ai-task/components/task-item.tsx
+++ b/apps/desktop/layer/renderer/src/modules/ai-task/components/task-item.tsx
@@ -1,6 +1,7 @@
import { cn } from "@follow/utils/utils"
import type { AITask, TaskSchedule } from "@follow-app/client-sdk"
import dayjs from "dayjs"
+import type { TFunction } from "i18next"
import { memo, useCallback, useMemo, useState } from "react"
import { useTranslation } from "react-i18next"
import { toast } from "sonner"
@@ -20,29 +21,42 @@ import {
} from "../query"
import { AITaskModal } from "./ai-task-modal"
-const formatScheduleText = (schedule: TaskSchedule) => {
- if (!schedule) return "Unknown schedule"
-
+const formatScheduleText = (schedule: TaskSchedule, t: TFunction<"ai", undefined>) => {
+ if (!schedule) return t("tasks.schedule.unknown")
switch (schedule.type) {
case "once": {
const date = dayjs(schedule.date)
- return `Once on ${date.format("MMM D, YYYY")} at ${date.format("h:mm A")}`
+ return t("tasks.schedule.once", {
+ date: date.format("MMM D, YYYY"),
+ time: date.format("h:mm A"),
+ })
}
case "daily": {
const time = dayjs(schedule.timeOfDay)
- return `Daily at ${time.format("h:mm A")}`
+ return t("tasks.schedule.daily", { time: time.format("h:mm A") })
}
case "weekly": {
- const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
+ const days = [
+ t("days.sunday", { ns: "common" }),
+ t("days.monday", { ns: "common" }),
+ t("days.tuesday", { ns: "common" }),
+ t("days.wednesday", { ns: "common" }),
+ t("days.thursday", { ns: "common" }),
+ t("days.friday", { ns: "common" }),
+ t("days.saturday", { ns: "common" }),
+ ]
const time = dayjs(schedule.timeOfDay)
- return `Weekly on ${days[schedule.dayOfWeek]} at ${time.format("h:mm A")}`
+ return t("tasks.schedule.weekly", {
+ day: days[schedule.dayOfWeek],
+ time: time.format("h:mm A"),
+ })
}
case "monthly": {
const time = dayjs(schedule.timeOfDay)
- return `Monthly on day ${schedule.dayOfMonth} at ${time.format("h:mm A")}`
+ return t("tasks.schedule.monthly", { day: schedule.dayOfMonth, time: time.format("h:mm A") })
}
default: {
- return "Unknown schedule"
+ return t("tasks.schedule.unknown")
}
}
}
@@ -86,7 +100,7 @@ export const TaskItem = memo(({ task }: { task: AITask }) => {
const updateTaskMutation = useUpdateAITaskMutation()
const testRunMutation = useTestRunAITaskMutation()
const { ask } = useDialog()
- const { t } = useTranslation()
+ const { t } = useTranslation("ai")
const sessions = useAIChatSessionListQuery()
// const chatActions = useChatActions()
const [openingReport, setOpeningReport] = useState(false)
@@ -100,7 +114,7 @@ export const TaskItem = memo(({ task }: { task: AITask }) => {
const handleEditTask = (task: AITask) => {
present({
- title: "Edit AI Task",
+ title: t("tasks.modal.edit_title"),
content: () => ,
})
}
@@ -109,7 +123,7 @@ export const TaskItem = memo(({ task }: { task: AITask }) => {
const handleOpenReport = useCallback(async () => {
if (!taskSession) {
- toast.error("No report session found for this task yet.")
+ toast.error(t("tasks.toast.no_report"))
return
}
setOpeningReport(true)
@@ -117,7 +131,7 @@ export const TaskItem = memo(({ task }: { task: AITask }) => {
await AIChatSessionService.fetchAndPersistMessages(taskSession)
} catch (e) {
console.error("Failed to sync chat session messages:", e)
- toast.error("Failed to load chat messages")
+ toast.error(t("tasks.toast.load_failed"))
}
setAIPanelVisibility(true)
const chatActions = ChatSliceActions.getActiveInstance()
@@ -126,8 +140,8 @@ export const TaskItem = memo(({ task }: { task: AITask }) => {
}
chatActions?.switchToChat(taskSession.chatId)
setOpeningReport(false)
- toast("Switch to the chat panel to view reports.")
- }, [taskSession])
+ toast(t("tasks.toast.switch_to_chat"))
+ }, [taskSession, t])
const actions: ActionButton[] = [
// Only show if the task has at least one run
@@ -136,7 +150,7 @@ export const TaskItem = memo(({ task }: { task: AITask }) => {
{
icon: "i-mgc-history-cute-re" as const,
onClick: handleOpenReport,
- title: "View reports",
+ title: t("tasks.actions.view_reports"),
loading: openingReport,
disabled: openingReport,
} satisfies ActionButton,
@@ -146,34 +160,32 @@ export const TaskItem = memo(({ task }: { task: AITask }) => {
icon: "i-mgc-test-tube-cute-re" as const,
onClick: async () => {
try {
- const loadingId = toast.loading(
- "Starting test run… This may take about 1 minute. You can view the result in the Chat panel.",
- )
+ const loadingId = toast.loading(t("tasks.toast.test_start"))
await testRunMutation.mutateAsync({ id: task.id })
- toast.success("Test run finished. You can view the report in the Chat panel.", {
+ toast.success(t("tasks.toast.test_success"), {
id: loadingId,
})
} catch (error) {
console.error("Failed to run test:", error)
- toast.error("Failed to run test. Please try again.")
+ toast.error(t("tasks.toast.test_failed"))
}
},
- title: "Test run",
+ title: t("tasks.actions.test_run"),
disabled: testRunMutation.isPending,
loading: testRunMutation.isPending,
},
{
icon: "i-mgc-edit-cute-re",
onClick: () => handleEditTask(task),
- title: "Edit task",
+ title: t("tasks.actions.edit_task"),
},
{
icon: "i-mgc-delete-2-cute-re",
onClick: async () => {
const confirmed = await ask({
- title: "Delete Task",
+ title: t("tasks.modal.delete_title"),
// translation fallback pattern; primary key then default string
- message: `Are you sure you want to delete the task "${task.name}"?`,
+ message: t("tasks.modal.delete_confirm", { name: task.name }),
confirmText: t("words.delete", { ns: "common" }),
cancelText: t("words.cancel", { ns: "common" }),
variant: "danger",
@@ -181,13 +193,13 @@ export const TaskItem = memo(({ task }: { task: AITask }) => {
if (!confirmed) return
try {
await deleteTaskMutation.mutateAsync({ id: task.id })
- toast.success("Task deleted successfully")
+ toast.success(t("tasks.toast.delete_success"))
} catch (error) {
console.error("Failed to delete task:", error)
- toast.error("Failed to delete task. Please try again.")
+ toast.error(t("tasks.toast.delete_failed"))
}
},
- title: "Delete task",
+ title: t("tasks.actions.delete_task"),
disabled: isDeleting,
loading: isDeleting,
},
@@ -210,20 +222,20 @@ export const TaskItem = memo(({ task }: { task: AITask }) => {
)}
{status === "paused" && }
- {status.charAt(0).toUpperCase() + status.slice(1)}
+ {t(`tasks.status.${status}`)}
- Schedule: {" "}
- {formatScheduleText(task.schedule)}
+ {t("tasks.fields.schedule")} {" "}
+ {formatScheduleText(task.schedule, t)}
- Prompt: {task.prompt}
+ {t("tasks.fields.prompt")} {task.prompt}
{task.createdAt && (
- Created: {" "}
+ {t("tasks.fields.created")} {" "}
{dayjs(task.createdAt).format("MMM D, YYYY h:mm A")}
)}
@@ -238,7 +250,7 @@ export const TaskItem = memo(({ task }: { task: AITask }) => {
await updateTaskMutation.mutateAsync({ id: task.id, isEnabled: !task.isEnabled })
} catch (error) {
console.error("Failed to toggle task:", error)
- toast.error("Failed to update task. Please try again.")
+ toast.error(t("tasks.toast.update_failed"))
}
}}
/>
diff --git a/apps/desktop/layer/renderer/src/modules/ai-task/components/task-list.tsx b/apps/desktop/layer/renderer/src/modules/ai-task/components/task-list.tsx
index d1e6b8537..0cd1c9336 100644
--- a/apps/desktop/layer/renderer/src/modules/ai-task/components/task-list.tsx
+++ b/apps/desktop/layer/renderer/src/modules/ai-task/components/task-list.tsx
@@ -1,5 +1,6 @@
import { cn } from "@follow/utils/utils"
import { memo } from "react"
+import { useTranslation } from "react-i18next"
import { useAITaskListQuery } from "../query"
import { TaskItem } from "./task-item"
@@ -10,6 +11,7 @@ interface TaskListProps {
export const AITaskList = memo
(({ className }) => {
const tasks = useAITaskListQuery()
+ const { t } = useTranslation("ai")
if (tasks === undefined) {
return null
@@ -21,10 +23,8 @@ export const AITaskList = memo(({ className }) => {
- No scheduled tasks
-
- Create your first AI task to automate your workflows.
-
+ {t("tasks.empty.title")}
+ {t("tasks.empty.desc")}
)
}
diff --git a/apps/desktop/layer/renderer/src/modules/settings/tabs/ai.tsx b/apps/desktop/layer/renderer/src/modules/settings/tabs/ai.tsx
index 6e63bdf72..5ce84d086 100644
--- a/apps/desktop/layer/renderer/src/modules/settings/tabs/ai.tsx
+++ b/apps/desktop/layer/renderer/src/modules/settings/tabs/ai.tsx
@@ -60,7 +60,7 @@ export const SettingAI = () => {
,
{
type: "title",
- value: "Task Scheduling",
+ value: t("tasks.section.title"),
},
TaskSchedulingSection,
AISecurityDisclosureSection,
diff --git a/apps/desktop/layer/renderer/src/modules/settings/tabs/ai/tasks/TaskSchedulingSection.tsx b/apps/desktop/layer/renderer/src/modules/settings/tabs/ai/tasks/TaskSchedulingSection.tsx
index aad5c4bf5..a2e778db2 100644
--- a/apps/desktop/layer/renderer/src/modules/settings/tabs/ai/tasks/TaskSchedulingSection.tsx
+++ b/apps/desktop/layer/renderer/src/modules/settings/tabs/ai/tasks/TaskSchedulingSection.tsx
@@ -1,6 +1,7 @@
import { Button } from "@follow/components/ui/button/index.js"
import { Label } from "@follow/components/ui/label/index.js"
import { useCallback } from "react"
+import { useTranslation } from "react-i18next"
import { useModalStack } from "~/components/ui/modal/stacked/hooks"
import { AITaskList, AITaskModal, useCanCreateNewAITask } from "~/modules/ai-task"
@@ -8,25 +9,24 @@ import { AITaskList, AITaskModal, useCanCreateNewAITask } from "~/modules/ai-tas
export const TaskSchedulingSection = () => {
const { present } = useModalStack()
const canCreateNewTask = useCanCreateNewAITask()
+ const { t } = useTranslation("ai")
const handleCreateTask = useCallback(() => {
present({
- title: "New AI Task",
+ title: t("tasks.modal.new_title"),
content: () => ,
})
- }, [present])
+ }, [present, t])
return (
-
{"Schedule AI Tasks"}
+
{t("tasks.manage.title")}
- {"Create and manage automated AI tasks that run on your schedule."}
+ {t("tasks.manage.desc")}
{!canCreateNewTask && (
-
- {" (Limit reached: maximum number of tasks reached)"}
-
+ {t("tasks.manage.limit_reached")}
)}
@@ -38,7 +38,7 @@ export const TaskSchedulingSection = () => {
onClick={handleCreateTask}
>
- New Task
+ {t("tasks.actions.new_task")}
diff --git a/locales/ai/en.json b/locales/ai/en.json
index 9a6080362..4b82274db 100644
--- a/locales/ai/en.json
+++ b/locales/ai/en.json
@@ -181,10 +181,27 @@
"shortcuts.updated": "Shortcut updated successfully",
"shortcuts.validation.required": "Name and prompt are required",
"summary_not_available": "Summary not available",
+ "tasks.actions.delete_task": "Delete task",
+ "tasks.actions.edit_task": "Edit task",
+ "tasks.actions.new_task": "New Task",
"tasks.actions.schedule": "Schedule Task",
"tasks.actions.scheduling": "Scheduling...",
+ "tasks.actions.test_run": "Test run",
"tasks.actions.update": "Update Task",
"tasks.actions.updating": "Updating...",
+ "tasks.actions.view_reports": "View reports",
+ "tasks.empty.desc": "Create your first AI task to automate your workflows.",
+ "tasks.empty.title": "No scheduled tasks",
+ "tasks.fields.created": "Created:",
+ "tasks.fields.prompt": "Prompt:",
+ "tasks.fields.schedule": "Schedule:",
+ "tasks.manage.desc": "Create and manage automated AI tasks that run on your schedule.",
+ "tasks.manage.limit_reached": "(Limit reached: maximum number of tasks reached)",
+ "tasks.manage.title": "Schedule AI Tasks",
+ "tasks.modal.delete_confirm": "Are you sure you want to delete the task \"{{name}}\"?",
+ "tasks.modal.delete_title": "Delete Task",
+ "tasks.modal.edit_title": "Edit AI Task",
+ "tasks.modal.new_title": "New AI Task",
"tasks.name": "Task Name",
"tasks.name_placeholder": "Enter a descriptive name for your task...",
"tasks.notify.coming_soon": "Coming soon",
@@ -193,13 +210,32 @@
"tasks.prompt": "Prompt",
"tasks.prompt_helper": "Provide clear, specific instructions for the AI to execute",
"tasks.prompt_placeholder": "Describe what you want the AI to do when this task runs...",
+ "tasks.schedule.daily": "Daily at {{time}}",
+ "tasks.schedule.monthly": "Monthly on day {{day}} at {{time}}",
+ "tasks.schedule.once": "Once on {{date}} at {{time}}",
+ "tasks.schedule.unknown": "Unknown schedule",
+ "tasks.schedule.weekly": "Weekly on {{day}} at {{time}}",
"tasks.section.info": "Task Information",
"tasks.section.instructions": "AI Instructions",
"tasks.section.notifications": "Notifications",
"tasks.section.schedule": "Schedule Configuration",
+ "tasks.section.title": "AI Task",
+ "tasks.status.completed": "Completed",
+ "tasks.status.paused": "Paused",
+ "tasks.status.scheduled": "Scheduled",
+ "tasks.status.unknown": "Unknown",
"tasks.toast.create_error": "Failed to schedule AI task. Please try again.",
"tasks.toast.created": "AI task scheduled successfully",
+ "tasks.toast.delete_failed": "Failed to delete task. Please try again.",
+ "tasks.toast.delete_success": "Task deleted successfully",
+ "tasks.toast.load_failed": "Failed to load chat messages",
+ "tasks.toast.no_report": "No report session found for this task yet.",
+ "tasks.toast.switch_to_chat": "Switch to the chat panel to view reports.",
+ "tasks.toast.test_failed": "Failed to run test. Please try again.",
+ "tasks.toast.test_start": "Starting test run… This may take about 1 minute. You can view the result in the Chat panel.",
+ "tasks.toast.test_success": "Test run finished. You can view the report in the Chat panel.",
"tasks.toast.update_error": "Failed to update AI task. Please try again.",
+ "tasks.toast.update_failed": "Failed to update task. Please try again.",
"tasks.toast.updated": "AI task updated successfully",
"tasks.validation.date_future": "Scheduled date must be in the future",
"tasks.validation.prompt_max": "Prompt must be less than 2000 characters",
diff --git a/locales/ai/ja.json b/locales/ai/ja.json
index 90beb531e..18433d268 100644
--- a/locales/ai/ja.json
+++ b/locales/ai/ja.json
@@ -147,10 +147,27 @@
"shortcuts.updated": "ショートカットが正常に更新されました",
"shortcuts.validation.required": "名前とプロンプトは必須です",
"summary_not_available": "要約は利用できません",
+ "tasks.actions.delete_task": "タスクを削除",
+ "tasks.actions.edit_task": "タスクを編集",
+ "tasks.actions.new_task": "新規タスク",
"tasks.actions.schedule": "タスクをスケジュール",
"tasks.actions.scheduling": "スケジュール中...",
+ "tasks.actions.test_run": "テスト実行",
"tasks.actions.update": "タスクを更新",
"tasks.actions.updating": "更新中...",
+ "tasks.actions.view_reports": "レポートを見る",
+ "tasks.empty.desc": "最初の AI タスクを作成してワークフローを自動化しましょう。",
+ "tasks.empty.title": "予定されたタスクはありません",
+ "tasks.fields.created": "作成日時:",
+ "tasks.fields.prompt": "プロンプト:",
+ "tasks.fields.schedule": "スケジュール:",
+ "tasks.manage.desc": "スケジュールに従って自動実行される AI タスクを作成・管理します。",
+ "tasks.manage.limit_reached": "(最大タスク数に達しました)",
+ "tasks.manage.title": "AI タスクをスケジュール",
+ "tasks.modal.delete_confirm": "タスク \"{{name}}\" を削除してもよろしいですか?",
+ "tasks.modal.delete_title": "タスクを削除",
+ "tasks.modal.edit_title": "AI タスクを編集",
+ "tasks.modal.new_title": "新規 AI タスク",
"tasks.name": "タスク名",
"tasks.name_placeholder": "タスクのわかりやすい名前を入力...",
"tasks.notify.coming_soon": "近日公開",
@@ -159,13 +176,32 @@
"tasks.prompt": "プロンプト",
"tasks.prompt_helper": "AIが実行するための明確で具体的な指示を提供してください",
"tasks.prompt_placeholder": "このタスクが実行されるときにAIに何をさせたいかを記述...",
+ "tasks.schedule.daily": "毎日 {{time}}",
+ "tasks.schedule.monthly": "毎月 {{day}} 日 {{time}}",
+ "tasks.schedule.once": "{{date}} {{time}} 単回",
+ "tasks.schedule.unknown": "不明なスケジュール",
+ "tasks.schedule.weekly": "毎週{{day}} {{time}}",
"tasks.section.info": "タスク情報",
"tasks.section.instructions": "AI 指示",
"tasks.section.notifications": "通知",
"tasks.section.schedule": "スケジュール設定",
+ "tasks.section.title": "AI タスク",
+ "tasks.status.completed": "完了",
+ "tasks.status.paused": "一時停止",
+ "tasks.status.scheduled": "予定済み",
+ "tasks.status.unknown": "不明",
"tasks.toast.create_error": "AIタスクのスケジュールに失敗しました。もう一度お試しください。",
"tasks.toast.created": "AIタスクが正常にスケジュールされました",
+ "tasks.toast.delete_failed": "タスクの削除に失敗しました。もう一度お試しください。",
+ "tasks.toast.delete_success": "タスクが削除されました",
+ "tasks.toast.load_failed": "チャットメッセージの読み込みに失敗しました",
+ "tasks.toast.no_report": "このタスクのレポートセッションはまだありません。",
+ "tasks.toast.switch_to_chat": "レポートを見るにはチャットパネルに切り替えてください。",
+ "tasks.toast.test_failed": "テスト実行に失敗しました。もう一度お試しください。",
+ "tasks.toast.test_start": "テスト実行を開始…約1分かかる場合があります。結果はチャットパネルで確認できます。",
+ "tasks.toast.test_success": "テスト実行が完了しました。レポートはチャットパネルで確認できます。",
"tasks.toast.update_error": "AIタスクの更新に失敗しました。もう一度お試しください。",
+ "tasks.toast.update_failed": "タスクの更新に失敗しました。もう一度お試しください。",
"tasks.toast.updated": "AIタスクが正常に更新されました",
"tasks.validation.date_future": "スケジュール日時は未来である必要があります",
"tasks.validation.prompt_max": "プロンプトは2000文字未満である必要があります",
diff --git a/locales/ai/zh-CN.json b/locales/ai/zh-CN.json
index 1657eb431..a0ca2187b 100644
--- a/locales/ai/zh-CN.json
+++ b/locales/ai/zh-CN.json
@@ -175,10 +175,27 @@
"shortcuts.updated": "快捷方式更新成功",
"shortcuts.validation.required": "名称和提示为必填项",
"summary_not_available": "摘要不可用",
+ "tasks.actions.delete_task": "删除任务",
+ "tasks.actions.edit_task": "编辑任务",
+ "tasks.actions.new_task": "新建任务",
"tasks.actions.schedule": "安排任务",
"tasks.actions.scheduling": "正在安排...",
+ "tasks.actions.test_run": "测试运行",
"tasks.actions.update": "更新任务",
"tasks.actions.updating": "正在更新...",
+ "tasks.actions.view_reports": "查看报告",
+ "tasks.empty.desc": "创建您的第一个 AI 任务以自动化您的工作流程。",
+ "tasks.empty.title": "暂无计划任务",
+ "tasks.fields.created": "创建时间:",
+ "tasks.fields.prompt": "指令:",
+ "tasks.fields.schedule": "计划:",
+ "tasks.manage.desc": "创建并管理按计划自动运行的 AI 任务。",
+ "tasks.manage.limit_reached": "(已达到最大任务数量限制)",
+ "tasks.manage.title": "计划 AI 任务",
+ "tasks.modal.delete_confirm": "确定要删除任务 \"{{name}}\" 吗?",
+ "tasks.modal.delete_title": "删除任务",
+ "tasks.modal.edit_title": "编辑 AI 任务",
+ "tasks.modal.new_title": "新建 AI 任务",
"tasks.name": "任务名称",
"tasks.name_placeholder": "输入一个描述性的任务名称...",
"tasks.notify.coming_soon": "即将推出",
@@ -187,13 +204,32 @@
"tasks.prompt": "指令",
"tasks.prompt_helper": "请提供清晰、具体的指令供 AI 执行",
"tasks.prompt_placeholder": "描述当此任务运行时您希望 AI 做什么...",
+ "tasks.schedule.daily": "每天 {{time}}",
+ "tasks.schedule.monthly": "每月第 {{day}} 天 {{time}}",
+ "tasks.schedule.once": "{{date}} {{time}} 单次",
+ "tasks.schedule.unknown": "未知计划",
+ "tasks.schedule.weekly": "每周{{day}} {{time}}",
"tasks.section.info": "任务信息",
"tasks.section.instructions": "AI 指令",
"tasks.section.notifications": "通知",
"tasks.section.schedule": "计划配置",
+ "tasks.section.title": "AI 任务",
+ "tasks.status.completed": "已完成",
+ "tasks.status.paused": "已暂停",
+ "tasks.status.scheduled": "已计划",
+ "tasks.status.unknown": "未知",
"tasks.toast.create_error": "安排 AI 任务失败,请重试。",
"tasks.toast.created": "AI 任务安排成功",
+ "tasks.toast.delete_failed": "删除任务失败,请重试。",
+ "tasks.toast.delete_success": "任务删除成功",
+ "tasks.toast.load_failed": "加载聊天消息失败",
+ "tasks.toast.no_report": "此任务尚无报告会话。",
+ "tasks.toast.switch_to_chat": "切换到聊天面板查看报告。",
+ "tasks.toast.test_failed": "测试运行失败,请重试。",
+ "tasks.toast.test_start": "开始测试运行…大约需要 1 分钟。您可以在聊天面板查看结果。",
+ "tasks.toast.test_success": "测试运行完成。您可以在聊天面板查看报告。",
"tasks.toast.update_error": "更新 AI 任务失败,请重试。",
+ "tasks.toast.update_failed": "更新任务失败,请重试。",
"tasks.toast.updated": "AI 任务更新成功",
"tasks.validation.date_future": "计划时间必须是未来的时间",
"tasks.validation.prompt_max": "指令必须少于 2000 个字符",