diff --git a/web/app/components/workflow/comment/comment-input.tsx b/web/app/components/workflow/comment/comment-input.tsx index 5e51c403bd..8196b990a2 100644 --- a/web/app/components/workflow/comment/comment-input.tsx +++ b/web/app/components/workflow/comment/comment-input.tsx @@ -1,5 +1,6 @@ import type { FC } from 'react' import { memo, useCallback, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' import Avatar from '@/app/components/base/avatar' import { useAppContext } from '@/context/app-context' import { MentionInput } from './mention-input' @@ -13,6 +14,7 @@ type CommentInputProps = { export const CommentInput: FC = memo(({ position, onSubmit, onCancel }) => { const [content, setContent] = useState('') + const { t } = useTranslation() const { userProfile } = useAppContext() useEffect(() => { @@ -71,7 +73,7 @@ export const CommentInput: FC = memo(({ position, onSubmit, o value={content} onChange={setContent} onSubmit={handleMentionSubmit} - placeholder="Add a comment" + placeholder={t('workflow.comments.placeholder.add')} autoFocus className="relative" /> diff --git a/web/app/components/workflow/comment/mention-input.tsx b/web/app/components/workflow/comment/mention-input.tsx index beee0c010c..48c957c479 100644 --- a/web/app/components/workflow/comment/mention-input.tsx +++ b/web/app/components/workflow/comment/mention-input.tsx @@ -4,6 +4,7 @@ import type { FC, ReactNode } from 'react' import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { createPortal } from 'react-dom' import { useParams } from 'next/navigation' +import { useTranslation } from 'react-i18next' import { RiArrowUpLine, RiAtLine } from '@remixicon/react' import Textarea from 'react-textarea-autosize' import Button from '@/app/components/base/button' @@ -29,7 +30,7 @@ export const MentionInput: FC = memo(({ onChange, onSubmit, onCancel, - placeholder = 'Add a comment', + placeholder, disabled = false, loading = false, className, @@ -37,6 +38,7 @@ export const MentionInput: FC = memo(({ autoFocus = false, }) => { const params = useParams() + const { t } = useTranslation() const appId = params.appId as string const textareaRef = useRef(null) @@ -46,6 +48,7 @@ export const MentionInput: FC = memo(({ const [mentionPosition, setMentionPosition] = useState(0) const [selectedMentionIndex, setSelectedMentionIndex] = useState(0) const [mentionedUserIds, setMentionedUserIds] = useState([]) + const resolvedPlaceholder = placeholder ?? t('workflow.comments.placeholder.add') const mentionNameList = useMemo(() => { const names = mentionUsers @@ -306,7 +309,7 @@ export const MentionInput: FC = memo(({ 'body-lg-regular relative z-10 w-full resize-none bg-transparent p-1 leading-6 text-transparent caret-primary-500 outline-none', 'placeholder:text-text-tertiary', )} - placeholder={placeholder} + placeholder={resolvedPlaceholder} autoFocus={autoFocus} minRows={isEditing ? 4 : 1} maxRows={4} @@ -345,7 +348,7 @@ export const MentionInput: FC = memo(({
diff --git a/web/app/components/workflow/comment/thread.tsx b/web/app/components/workflow/comment/thread.tsx index ad5d2955a8..67d11fd4d9 100644 --- a/web/app/components/workflow/comment/thread.tsx +++ b/web/app/components/workflow/comment/thread.tsx @@ -3,6 +3,7 @@ import type { FC, ReactNode } from 'react' import { memo, useCallback, useEffect, useMemo, useState } from 'react' import { useReactFlow, useViewport } from 'reactflow' +import { useTranslation } from 'react-i18next' import { RiArrowDownSLine, RiArrowUpSLine, RiCheckboxCircleFill, RiCheckboxCircleLine, RiCloseLine, RiDeleteBinLine, RiMoreFill } from '@remixicon/react' import Avatar from '@/app/components/base/avatar' import Divider from '@/app/components/base/divider' @@ -146,6 +147,7 @@ export const CommentThread: FC = memo(({ const { flowToScreenPosition } = useReactFlow() const viewport = useViewport() const { userProfile } = useAppContext() + const { t } = useTranslation() const [replyContent, setReplyContent] = useState('') const [activeReplyMenuId, setActiveReplyMenuId] = useState(null) const [editingReply, setEditingReply] = useState<{ id: string; content: string }>({ id: '', content: '' }) @@ -221,14 +223,14 @@ export const CommentThread: FC = memo(({ >
-
Comment
+
{t('workflow.comments.panelTitle')}
@@ -237,7 +239,7 @@ export const CommentThread: FC = memo(({ disabled={comment.resolved || loading} className={cn('flex h-6 w-6 items-center justify-center rounded-lg text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary disabled:cursor-not-allowed disabled:text-text-disabled disabled:hover:bg-transparent disabled:hover:text-text-disabled')} onClick={onResolve} - aria-label='Resolve comment' + aria-label={t('workflow.comments.aria.resolveComment')} > {comment.resolved ? : } @@ -247,7 +249,7 @@ export const CommentThread: FC = memo(({ disabled={!canGoPrev || loading} className={cn('flex h-6 w-6 items-center justify-center rounded-lg text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary disabled:cursor-not-allowed disabled:text-text-disabled disabled:hover:bg-transparent disabled:hover:text-text-disabled')} onClick={onPrev} - aria-label='Previous comment' + aria-label={t('workflow.comments.aria.previousComment')} > @@ -256,7 +258,7 @@ export const CommentThread: FC = memo(({ disabled={!canGoNext || loading} className={cn('flex h-6 w-6 items-center justify-center rounded-lg text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary disabled:cursor-not-allowed disabled:text-text-disabled disabled:hover:bg-transparent disabled:hover:text-text-disabled')} onClick={onNext} - aria-label='Next comment' + aria-label={t('workflow.comments.aria.nextComment')} > @@ -264,7 +266,7 @@ export const CommentThread: FC = memo(({ type='button' className='flex h-6 w-6 items-center justify-center rounded-lg text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary' onClick={onClose} - aria-label='Close comment' + aria-label={t('workflow.comments.aria.closeComment')} > @@ -273,7 +275,7 @@ export const CommentThread: FC = memo(({
= memo(({ e.stopPropagation() setActiveReplyMenuId(prev => prev === reply.id ? null : reply.id) }} - aria-label='Reply actions' + aria-label={t('workflow.comments.aria.replyActions')} > @@ -307,7 +309,7 @@ export const CommentThread: FC = memo(({ className='flex w-full items-center justify-start px-3 py-2 text-left text-sm text-text-secondary hover:bg-state-base-hover' onClick={() => handleStartEdit(reply)} > - Edit reply + {t('workflow.comments.actions.editReply')}
)} @@ -329,7 +331,7 @@ export const CommentThread: FC = memo(({ onChange={newContent => setEditingReply(prev => prev ? { ...prev, content: newContent } : prev)} onSubmit={handleEditSubmit} onCancel={handleCancelEdit} - placeholder="Edit reply" + placeholder={t('workflow.comments.placeholder.editReply')} disabled={loading} loading={loading} isEditing={true} @@ -340,7 +342,7 @@ export const CommentThread: FC = memo(({ ) : ( = memo(({
{loading && (
- Loading… + {t('workflow.comments.loading')}
)} {onReply && ( @@ -363,7 +365,7 @@ export const CommentThread: FC = memo(({
@@ -372,7 +374,7 @@ export const CommentThread: FC = memo(({ value={replyContent} onChange={setReplyContent} onSubmit={handleReplySubmit} - placeholder='Reply' + placeholder={t('workflow.comments.placeholder.reply')} disabled={loading} loading={loading} className='px-2' diff --git a/web/i18n/de-DE/workflow.ts b/web/i18n/de-DE/workflow.ts index 9c83e5af20..6461ae7033 100644 --- a/web/i18n/de-DE/workflow.ts +++ b/web/i18n/de-DE/workflow.ts @@ -192,6 +192,30 @@ const translation = { nodeDragStop: 'Knoten verschoben', nodeDelete: 'Knoten gelöscht', }, + comments: { + panelTitle: 'Kommentar', + loading: 'Laden…', + placeholder: { + add: 'Kommentar hinzufügen', + reply: 'Antworten', + editReply: 'Antwort bearbeiten', + }, + aria: { + deleteComment: 'Kommentar löschen', + resolveComment: 'Kommentar abschließen', + previousComment: 'Vorheriger Kommentar', + nextComment: 'Nächster Kommentar', + closeComment: 'Kommentar schließen', + replyActions: 'Antwortaktionen', + }, + actions: { + editReply: 'Antwort bearbeiten', + deleteReply: 'Antwort löschen', + }, + fallback: { + user: 'Benutzer', + }, + }, errorMsg: { fieldRequired: '{{field}} ist erforderlich', authRequired: 'Autorisierung ist erforderlich', diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index 9ee6c19d75..542f4a9a0d 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -198,6 +198,30 @@ const translation = { noteDelete: 'Note deleted', edgeDelete: 'Node disconnected', }, + comments: { + panelTitle: 'Comment', + loading: 'Loading…', + placeholder: { + add: 'Add a comment', + reply: 'Reply', + editReply: 'Edit reply', + }, + aria: { + deleteComment: 'Delete comment', + resolveComment: 'Resolve comment', + previousComment: 'Previous comment', + nextComment: 'Next comment', + closeComment: 'Close comment', + replyActions: 'Reply actions', + }, + actions: { + editReply: 'Edit reply', + deleteReply: 'Delete reply', + }, + fallback: { + user: 'User', + }, + }, errorMsg: { fieldRequired: '{{field}} is required', rerankModelRequired: 'A configured Rerank Model is required', diff --git a/web/i18n/es-ES/workflow.ts b/web/i18n/es-ES/workflow.ts index 1a7c62eab8..2e375d8e70 100644 --- a/web/i18n/es-ES/workflow.ts +++ b/web/i18n/es-ES/workflow.ts @@ -192,6 +192,30 @@ const translation = { nodeDescriptionChange: 'Descripción del nodo cambiada', nodeResize: 'Nodo redimensionado', }, + comments: { + panelTitle: 'Comentario', + loading: 'Cargando…', + placeholder: { + add: 'Añadir un comentario', + reply: 'Responder', + editReply: 'Editar respuesta', + }, + aria: { + deleteComment: 'Eliminar comentario', + resolveComment: 'Resolver comentario', + previousComment: 'Comentario anterior', + nextComment: 'Comentario siguiente', + closeComment: 'Cerrar comentario', + replyActions: 'Acciones de respuesta', + }, + actions: { + editReply: 'Editar respuesta', + deleteReply: 'Eliminar respuesta', + }, + fallback: { + user: 'Usuario', + }, + }, errorMsg: { fieldRequired: 'Se requiere {{field}}', authRequired: 'Se requiere autorización', diff --git a/web/i18n/fa-IR/workflow.ts b/web/i18n/fa-IR/workflow.ts index 6abbcb5c52..093bf6e1cb 100644 --- a/web/i18n/fa-IR/workflow.ts +++ b/web/i18n/fa-IR/workflow.ts @@ -192,6 +192,30 @@ const translation = { nodeDescriptionChange: 'شرح نود تغییر کرد', nodeChange: 'نود تغییر کرد', }, + comments: { + panelTitle: 'دیدگاه', + loading: 'در حال بارگذاری…', + placeholder: { + add: 'افزودن دیدگاه', + reply: 'پاسخ', + editReply: 'ویرایش پاسخ', + }, + aria: { + deleteComment: 'حذف دیدگاه', + resolveComment: 'حل‌کردن دیدگاه', + previousComment: 'دیدگاه قبلی', + nextComment: 'دیدگاه بعدی', + closeComment: 'بستن دیدگاه', + replyActions: 'عملیات پاسخ', + }, + actions: { + editReply: 'ویرایش پاسخ', + deleteReply: 'حذف پاسخ', + }, + fallback: { + user: 'کاربر', + }, + }, errorMsg: { fieldRequired: '{{field}} الزامی است', authRequired: 'احراز هویت ضروری است', diff --git a/web/i18n/fr-FR/workflow.ts b/web/i18n/fr-FR/workflow.ts index e68f254273..309ee33cdc 100644 --- a/web/i18n/fr-FR/workflow.ts +++ b/web/i18n/fr-FR/workflow.ts @@ -192,6 +192,30 @@ const translation = { nodeAdd: 'Nœud ajouté', nodeDescriptionChange: 'La description du nœud a changé', }, + comments: { + panelTitle: 'Commentaire', + loading: 'Chargement…', + placeholder: { + add: 'Ajouter un commentaire', + reply: 'Répondre', + editReply: 'Modifier la réponse', + }, + aria: { + deleteComment: 'Supprimer le commentaire', + resolveComment: 'Résoudre le commentaire', + previousComment: 'Commentaire précédent', + nextComment: 'Commentaire suivant', + closeComment: 'Fermer le commentaire', + replyActions: 'Actions de réponse', + }, + actions: { + editReply: 'Modifier la réponse', + deleteReply: 'Supprimer la réponse', + }, + fallback: { + user: 'Utilisateur', + }, + }, errorMsg: { fieldRequired: '{{field}} est requis', authRequired: 'Autorisation requise', diff --git a/web/i18n/hi-IN/workflow.ts b/web/i18n/hi-IN/workflow.ts index 9bbfc05f61..5f2e53a4b0 100644 --- a/web/i18n/hi-IN/workflow.ts +++ b/web/i18n/hi-IN/workflow.ts @@ -195,6 +195,30 @@ const translation = { nodePaste: 'नोड चिपका हुआ', nodeDescriptionChange: 'नोड का वर्णन बदल गया', }, + comments: { + panelTitle: 'टिप्पणी', + loading: 'लोड हो रहा है…', + placeholder: { + add: 'टिप्पणी जोड़ें', + reply: 'जवाब दें', + editReply: 'जवाब संपादित करें', + }, + aria: { + deleteComment: 'टिप्पणी हटाएं', + resolveComment: 'टिप्पणी समाधान करें', + previousComment: 'पिछली टिप्पणी', + nextComment: 'अगली टिप्पणी', + closeComment: 'टिप्पणी बंद करें', + replyActions: 'जवाब क्रियाएं', + }, + actions: { + editReply: 'जवाब संपादित करें', + deleteReply: 'जवाब हटाएं', + }, + fallback: { + user: 'उपयोगकर्ता', + }, + }, errorMsg: { fieldRequired: '{{field}} आवश्यक है', authRequired: 'प्राधिकरण आवश्यक है', diff --git a/web/i18n/id-ID/workflow.ts b/web/i18n/id-ID/workflow.ts index 7bc9b631dd..cf03b0f794 100644 --- a/web/i18n/id-ID/workflow.ts +++ b/web/i18n/id-ID/workflow.ts @@ -186,6 +186,30 @@ const translation = { edgeDelete: 'Node terputus', nodeChange: 'Node diubah', }, + comments: { + panelTitle: 'Komentar', + loading: 'Memuat…', + placeholder: { + add: 'Tambahkan komentar', + reply: 'Balas', + editReply: 'Edit balasan', + }, + aria: { + deleteComment: 'Hapus komentar', + resolveComment: 'Selesaikan komentar', + previousComment: 'Komentar sebelumnya', + nextComment: 'Komentar berikutnya', + closeComment: 'Tutup komentar', + replyActions: 'Aksi balasan', + }, + actions: { + editReply: 'Edit balasan', + deleteReply: 'Hapus balasan', + }, + fallback: { + user: 'Pengguna', + }, + }, errorMsg: { fields: { variable: 'Nama Variabel', diff --git a/web/i18n/it-IT/workflow.ts b/web/i18n/it-IT/workflow.ts index 1df67ba454..b977a07ad2 100644 --- a/web/i18n/it-IT/workflow.ts +++ b/web/i18n/it-IT/workflow.ts @@ -197,6 +197,30 @@ const translation = { nodeDragStop: 'Nodo spostato', nodeConnect: 'Nodo connesso', }, + comments: { + panelTitle: 'Commento', + loading: 'Caricamento…', + placeholder: { + add: 'Aggiungi un commento', + reply: 'Rispondi', + editReply: 'Modifica risposta', + }, + aria: { + deleteComment: 'Elimina commento', + resolveComment: 'Risolvi commento', + previousComment: 'Commento precedente', + nextComment: 'Commento successivo', + closeComment: 'Chiudi commento', + replyActions: 'Azioni di risposta', + }, + actions: { + editReply: 'Modifica risposta', + deleteReply: 'Elimina risposta', + }, + fallback: { + user: 'Utente', + }, + }, errorMsg: { fieldRequired: '{{field}} è richiesto', authRequired: 'È richiesta l\'autorizzazione', diff --git a/web/i18n/ja-JP/workflow.ts b/web/i18n/ja-JP/workflow.ts index 203f8221cc..3fd17afb92 100644 --- a/web/i18n/ja-JP/workflow.ts +++ b/web/i18n/ja-JP/workflow.ts @@ -196,6 +196,30 @@ const translation = { noteDelete: '注釈が削除されました', edgeDelete: 'ブロックの接続が解除されました', }, + comments: { + panelTitle: 'コメント', + loading: '読み込み中…', + placeholder: { + add: 'コメントを追加', + reply: '返信', + editReply: '返信を編集', + }, + aria: { + deleteComment: 'コメントを削除', + resolveComment: 'コメントを解決', + previousComment: '前のコメント', + nextComment: '次のコメント', + closeComment: 'コメントを閉じる', + replyActions: '返信アクション', + }, + actions: { + editReply: '返信を編集', + deleteReply: '返信を削除', + }, + fallback: { + user: 'ユーザー', + }, + }, errorMsg: { fieldRequired: '{{field}} は必須です', rerankModelRequired: 'Rerank モデルが設定されていません', diff --git a/web/i18n/ko-KR/workflow.ts b/web/i18n/ko-KR/workflow.ts index 70fd324f82..7e78f7788d 100644 --- a/web/i18n/ko-KR/workflow.ts +++ b/web/i18n/ko-KR/workflow.ts @@ -200,6 +200,30 @@ const translation = { edgeDelete: '노드가 연결이 끊어졌습니다.', nodeTitleChange: '노드 제목이 변경됨', }, + comments: { + panelTitle: '댓글', + loading: '불러오는 중…', + placeholder: { + add: '댓글 추가', + reply: '답글', + editReply: '답글 편집', + }, + aria: { + deleteComment: '댓글 삭제', + resolveComment: '댓글 해결', + previousComment: '이전 댓글', + nextComment: '다음 댓글', + closeComment: '댓글 닫기', + replyActions: '답글 작업', + }, + actions: { + editReply: '답글 편집', + deleteReply: '답글 삭제', + }, + fallback: { + user: '사용자', + }, + }, errorMsg: { fieldRequired: '{{field}}가 필요합니다', authRequired: '인증이 필요합니다', diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index a832bb54e0..30b74f2255 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -198,6 +198,30 @@ const translation = { noteDelete: '注释已删除', edgeDelete: '块已断开连接', }, + comments: { + panelTitle: '评论', + loading: '加载中…', + placeholder: { + add: '添加评论', + reply: '回复', + editReply: '编辑回复', + }, + aria: { + deleteComment: '删除评论', + resolveComment: '解决评论', + previousComment: '上一条评论', + nextComment: '下一条评论', + closeComment: '关闭评论', + replyActions: '回复操作', + }, + actions: { + editReply: '编辑回复', + deleteReply: '删除回复', + }, + fallback: { + user: '用户', + }, + }, errorMsg: { fieldRequired: '{{field}} 不能为空', rerankModelRequired: '未配置 Rerank 模型', diff --git a/web/i18n/zh-Hant/workflow.ts b/web/i18n/zh-Hant/workflow.ts index ee10c976ed..91d190fb2b 100644 --- a/web/i18n/zh-Hant/workflow.ts +++ b/web/i18n/zh-Hant/workflow.ts @@ -192,6 +192,30 @@ const translation = { edgeDelete: '區塊已斷開連接', noteDelete: '註釋已刪除', }, + comments: { + panelTitle: '評論', + loading: '載入中…', + placeholder: { + add: '新增評論', + reply: '回覆', + editReply: '編輯回覆', + }, + aria: { + deleteComment: '刪除評論', + resolveComment: '解決評論', + previousComment: '上一則評論', + nextComment: '下一則評論', + closeComment: '關閉評論', + replyActions: '回覆操作', + }, + actions: { + editReply: '編輯回覆', + deleteReply: '刪除回覆', + }, + fallback: { + user: '使用者', + }, + }, errorMsg: { fieldRequired: '{{field}} 不能為空', authRequired: '請先授權',