feat(webui): support image uploads in composer and message bubbles

This commit is contained in:
Xubin Ren
2026-04-23 00:07:27 +08:00
committed by Xubin Ren
parent c1e7aa5504
commit 61a28c2c0a
39 changed files with 3670 additions and 124 deletions
+31 -2
View File
@@ -64,7 +64,19 @@
"placeholderOpening": "Opening a new chat…",
"inputAria": "Message input",
"sendHint": "Enter to send · Shift+Enter for newline",
"send": "Send message"
"send": "Send message",
"attachImage": "Attach image",
"encoding": "Encoding…",
"remove": "Remove attachment",
"normalizedSizeHint": "{{orig}} → {{current}} (auto)",
"imageRejected": {
"unsupported_type": "Unsupported file type",
"too_many_images": "Max {{max}} images per message",
"magic_mismatch": "File doesn't look like a real image",
"decode_failed": "Couldn't decode this image",
"too_large": "Image is too large — try a smaller one",
"io": "Couldn't read this file"
}
},
"scrollToBottom": "Scroll to bottom"
},
@@ -72,12 +84,29 @@
"streaming": "streaming",
"assistantTyping": "Assistant is typing",
"toolSingle": "Using a tool",
"toolMany": "Used {{count}} tools"
"toolMany": "Used {{count}} tools",
"imageAttachment": "Image attachment"
},
"lightbox": {
"title": "Image preview",
"open": "View image",
"prev": "Previous image",
"next": "Next image",
"close": "Close image preview"
},
"code": {
"fallbackLanguage": "code",
"copyAria": "Copy code",
"copy": "Copy",
"copied": "Copied"
},
"common": {
"dismiss": "Dismiss"
},
"errors": {
"messageTooBig": {
"title": "Message too large",
"body": "The server rejected your last message because it exceeded the size limit. Remove some images or try smaller files, then send again."
}
}
}
+31 -2
View File
@@ -64,7 +64,19 @@
"placeholderOpening": "Abriendo un nuevo chat…",
"inputAria": "Entrada de mensaje",
"sendHint": "Enter para enviar · Shift+Enter para nueva línea",
"send": "Enviar mensaje"
"send": "Enviar mensaje",
"attachImage": "Adjuntar imagen",
"encoding": "Procesando…",
"remove": "Quitar adjunto",
"normalizedSizeHint": "{{orig}} → {{current}} (auto)",
"imageRejected": {
"unsupported_type": "Tipo de archivo no compatible",
"too_many_images": "Máximo {{max}} imágenes por mensaje",
"magic_mismatch": "El archivo no parece una imagen real",
"decode_failed": "No se pudo decodificar esta imagen",
"too_large": "Imagen demasiado grande — prueba una más pequeña",
"io": "No se pudo leer este archivo"
}
},
"scrollToBottom": "Desplazarse al final"
},
@@ -72,12 +84,29 @@
"streaming": "transmitiendo",
"assistantTyping": "El asistente está escribiendo",
"toolSingle": "Usando una herramienta",
"toolMany": "Se usaron {{count}} herramientas"
"toolMany": "Se usaron {{count}} herramientas",
"imageAttachment": "Imagen adjunta"
},
"lightbox": {
"title": "Vista previa de imagen",
"open": "Ver imagen",
"prev": "Imagen anterior",
"next": "Imagen siguiente",
"close": "Cerrar vista previa"
},
"code": {
"fallbackLanguage": "código",
"copyAria": "Copiar código",
"copy": "Copiar",
"copied": "Copiado"
},
"common": {
"dismiss": "Cerrar"
},
"errors": {
"messageTooBig": {
"title": "Mensaje demasiado grande",
"body": "El servidor rechazó tu último mensaje por superar el tamaño permitido. Quita algunas imágenes o usa archivos más pequeños y vuelve a enviarlo."
}
}
}
+31 -2
View File
@@ -64,7 +64,19 @@
"placeholderOpening": "Ouverture dune nouvelle discussion…",
"inputAria": "Champ de message",
"sendHint": "Entrée pour envoyer · Maj+Entrée pour un retour à la ligne",
"send": "Envoyer le message"
"send": "Envoyer le message",
"attachImage": "Joindre une image",
"encoding": "Traitement…",
"remove": "Retirer la pièce jointe",
"normalizedSizeHint": "{{orig}} → {{current}} (auto)",
"imageRejected": {
"unsupported_type": "Type de fichier non pris en charge",
"too_many_images": "Maximum {{max}} images par message",
"magic_mismatch": "Ce fichier n'est pas une image",
"decode_failed": "Impossible de décoder cette image",
"too_large": "Image trop grande — essayez-en une plus petite",
"io": "Impossible de lire ce fichier"
}
},
"scrollToBottom": "Faire défiler vers le bas"
},
@@ -72,12 +84,29 @@
"streaming": "en cours de génération",
"assistantTyping": "Lassistant est en train d’écrire",
"toolSingle": "Utilisation dun outil",
"toolMany": "{{count}} outils utilisés"
"toolMany": "{{count}} outils utilisés",
"imageAttachment": "Pièce jointe image"
},
"lightbox": {
"title": "Aperçu de limage",
"open": "Voir limage",
"prev": "Image précédente",
"next": "Image suivante",
"close": "Fermer laperçu"
},
"code": {
"fallbackLanguage": "code",
"copyAria": "Copier le code",
"copy": "Copier",
"copied": "Copié"
},
"common": {
"dismiss": "Fermer"
},
"errors": {
"messageTooBig": {
"title": "Message trop volumineux",
"body": "Le serveur a rejeté votre dernier message car il dépasse la taille autorisée. Retirez des images ou choisissez des fichiers plus légers, puis renvoyez-le."
}
}
}
+31 -2
View File
@@ -64,7 +64,19 @@
"placeholderOpening": "Membuka obrolan baru…",
"inputAria": "Input pesan",
"sendHint": "Enter untuk kirim · Shift+Enter untuk baris baru",
"send": "Kirim pesan"
"send": "Kirim pesan",
"attachImage": "Lampirkan gambar",
"encoding": "Memproses…",
"remove": "Hapus lampiran",
"normalizedSizeHint": "{{orig}} → {{current}} (auto)",
"imageRejected": {
"unsupported_type": "Tipe file tidak didukung",
"too_many_images": "Maksimal {{max}} gambar per pesan",
"magic_mismatch": "File ini tampaknya bukan gambar asli",
"decode_failed": "Tidak dapat mendekode gambar ini",
"too_large": "Gambar terlalu besar — coba yang lebih kecil",
"io": "Tidak dapat membaca file ini"
}
},
"scrollToBottom": "Gulir ke bawah"
},
@@ -72,12 +84,29 @@
"streaming": "sedang mengalir",
"assistantTyping": "Asisten sedang mengetik",
"toolSingle": "Menggunakan sebuah alat",
"toolMany": "Menggunakan {{count}} alat"
"toolMany": "Menggunakan {{count}} alat",
"imageAttachment": "Lampiran gambar"
},
"lightbox": {
"title": "Pratinjau gambar",
"open": "Lihat gambar",
"prev": "Gambar sebelumnya",
"next": "Gambar berikutnya",
"close": "Tutup pratinjau"
},
"code": {
"fallbackLanguage": "kode",
"copyAria": "Salin kode",
"copy": "Salin",
"copied": "Tersalin"
},
"common": {
"dismiss": "Tutup"
},
"errors": {
"messageTooBig": {
"title": "Pesan terlalu besar",
"body": "Server menolak pesan terakhir karena melebihi batas ukuran. Hapus beberapa gambar atau gunakan berkas yang lebih kecil, lalu coba lagi."
}
}
}
+31 -2
View File
@@ -64,7 +64,19 @@
"placeholderOpening": "新しいチャットを開いています…",
"inputAria": "メッセージ入力欄",
"sendHint": "Enter で送信 · Shift+Enter で改行",
"send": "メッセージを送信"
"send": "メッセージを送信",
"attachImage": "画像を添付",
"encoding": "処理中…",
"remove": "添付を削除",
"normalizedSizeHint": "{{orig}} → {{current}}(自動圧縮)",
"imageRejected": {
"unsupported_type": "対応していないファイル形式です",
"too_many_images": "1 メッセージにつき最大 {{max}} 枚です",
"magic_mismatch": "画像ファイルではないようです",
"decode_failed": "この画像をデコードできません",
"too_large": "画像が大きすぎます。小さいものを選んでください",
"io": "このファイルを読み込めません"
}
},
"scrollToBottom": "一番下へスクロール"
},
@@ -72,12 +84,29 @@
"streaming": "生成中",
"assistantTyping": "アシスタントが入力中",
"toolSingle": "ツールを使用中",
"toolMany": "{{count}} 個のツールを使用"
"toolMany": "{{count}} 個のツールを使用",
"imageAttachment": "画像の添付"
},
"lightbox": {
"title": "画像プレビュー",
"open": "画像を表示",
"prev": "前の画像",
"next": "次の画像",
"close": "プレビューを閉じる"
},
"code": {
"fallbackLanguage": "コード",
"copyAria": "コードをコピー",
"copy": "コピー",
"copied": "コピーしました"
},
"common": {
"dismiss": "閉じる"
},
"errors": {
"messageTooBig": {
"title": "メッセージが大きすぎます",
"body": "サイズ上限を超えたため、直前のメッセージはサーバーに拒否されました。画像を減らすか、より小さいファイルに差し替えて再送してください。"
}
}
}
+31 -2
View File
@@ -64,7 +64,19 @@
"placeholderOpening": "새 채팅을 여는 중…",
"inputAria": "메시지 입력",
"sendHint": "Enter로 전송 · Shift+Enter로 줄바꿈",
"send": "메시지 보내기"
"send": "메시지 보내기",
"attachImage": "이미지 첨부",
"encoding": "처리 중…",
"remove": "첨부 제거",
"normalizedSizeHint": "{{orig}} → {{current}} (자동 압축)",
"imageRejected": {
"unsupported_type": "지원하지 않는 파일 형식입니다",
"too_many_images": "메시지당 최대 {{max}}장까지 가능합니다",
"magic_mismatch": "이미지 파일이 아닌 것 같습니다",
"decode_failed": "이 이미지를 디코딩할 수 없습니다",
"too_large": "이미지가 너무 큽니다. 더 작은 걸로 시도해 주세요",
"io": "이 파일을 읽을 수 없습니다"
}
},
"scrollToBottom": "맨 아래로 스크롤"
},
@@ -72,12 +84,29 @@
"streaming": "생성 중",
"assistantTyping": "도우미가 입력 중",
"toolSingle": "도구 사용 중",
"toolMany": "도구 {{count}}개 사용됨"
"toolMany": "도구 {{count}}개 사용됨",
"imageAttachment": "이미지 첨부"
},
"lightbox": {
"title": "이미지 미리보기",
"open": "이미지 보기",
"prev": "이전 이미지",
"next": "다음 이미지",
"close": "미리보기 닫기"
},
"code": {
"fallbackLanguage": "코드",
"copyAria": "코드 복사",
"copy": "복사",
"copied": "복사됨"
},
"common": {
"dismiss": "닫기"
},
"errors": {
"messageTooBig": {
"title": "메시지가 너무 큽니다",
"body": "마지막 메시지가 서버의 크기 제한을 초과하여 거부되었습니다. 이미지를 줄이거나 더 작은 파일로 바꿔서 다시 보내 주세요."
}
}
}
+31 -2
View File
@@ -64,7 +64,19 @@
"placeholderOpening": "Đang mở cuộc trò chuyện mới…",
"inputAria": "Ô nhập tin nhắn",
"sendHint": "Enter để gửi · Shift+Enter để xuống dòng",
"send": "Gửi tin nhắn"
"send": "Gửi tin nhắn",
"attachImage": "Đính kèm ảnh",
"encoding": "Đang xử lý…",
"remove": "Xóa tệp đính kèm",
"normalizedSizeHint": "{{orig}} → {{current}} (tự động)",
"imageRejected": {
"unsupported_type": "Loại tệp không được hỗ trợ",
"too_many_images": "Tối đa {{max}} ảnh mỗi tin nhắn",
"magic_mismatch": "Tệp này không phải là một ảnh thực",
"decode_failed": "Không thể giải mã ảnh này",
"too_large": "Ảnh quá lớn — hãy thử ảnh nhỏ hơn",
"io": "Không thể đọc tệp này"
}
},
"scrollToBottom": "Cuộn xuống cuối"
},
@@ -72,12 +84,29 @@
"streaming": "đang truyền",
"assistantTyping": "Trợ lý đang nhập",
"toolSingle": "Đang dùng một công cụ",
"toolMany": "Đã dùng {{count}} công cụ"
"toolMany": "Đã dùng {{count}} công cụ",
"imageAttachment": "Tệp hình ảnh đính kèm"
},
"lightbox": {
"title": "Xem trước ảnh",
"open": "Xem ảnh",
"prev": "Ảnh trước",
"next": "Ảnh tiếp theo",
"close": "Đóng xem trước"
},
"code": {
"fallbackLanguage": "mã",
"copyAria": "Sao chép mã",
"copy": "Sao chép",
"copied": "Đã sao chép"
},
"common": {
"dismiss": "Đóng"
},
"errors": {
"messageTooBig": {
"title": "Tin nhắn quá lớn",
"body": "Máy chủ đã từ chối tin nhắn trước vì vượt quá giới hạn kích thước. Hãy bớt ảnh hoặc chọn tệp nhỏ hơn rồi thử lại."
}
}
}
+31 -2
View File
@@ -64,7 +64,19 @@
"placeholderOpening": "正在打开新对话…",
"inputAria": "消息输入框",
"sendHint": "Enter 发送 · Shift+Enter 换行",
"send": "发送消息"
"send": "发送消息",
"attachImage": "添加图片",
"encoding": "处理中…",
"remove": "移除附件",
"normalizedSizeHint": "{{orig}} → {{current}}(已自动压缩)",
"imageRejected": {
"unsupported_type": "不支持的文件类型",
"too_many_images": "每条消息最多 {{max}} 张图片",
"magic_mismatch": "文件看起来不像真实的图片",
"decode_failed": "无法解码这张图片",
"too_large": "图片太大,请换一张小一点的",
"io": "无法读取该文件"
}
},
"scrollToBottom": "滚动到底部"
},
@@ -72,12 +84,29 @@
"streaming": "流式输出中",
"assistantTyping": "助手正在输入",
"toolSingle": "正在使用工具",
"toolMany": "已使用 {{count}} 个工具"
"toolMany": "已使用 {{count}} 个工具",
"imageAttachment": "图片附件"
},
"lightbox": {
"title": "图片预览",
"open": "查看图片",
"prev": "上一张",
"next": "下一张",
"close": "关闭预览"
},
"code": {
"fallbackLanguage": "代码",
"copyAria": "复制代码",
"copy": "复制",
"copied": "已复制"
},
"common": {
"dismiss": "关闭"
},
"errors": {
"messageTooBig": {
"title": "消息过大",
"body": "服务端因超过大小限制拒收了上一条消息。可移除部分图片或使用更小的图片后重试。"
}
}
}
+31 -2
View File
@@ -64,7 +64,19 @@
"placeholderOpening": "正在開啟新對話…",
"inputAria": "訊息輸入框",
"sendHint": "Enter 送出 · Shift+Enter 換行",
"send": "送出訊息"
"send": "送出訊息",
"attachImage": "附加圖片",
"encoding": "處理中…",
"remove": "移除附件",
"normalizedSizeHint": "{{orig}} → {{current}}(已自動壓縮)",
"imageRejected": {
"unsupported_type": "不支援的檔案類型",
"too_many_images": "每則訊息最多 {{max}} 張圖片",
"magic_mismatch": "檔案看起來不像真正的圖片",
"decode_failed": "無法解碼這張圖片",
"too_large": "圖片太大,請換一張小一點的",
"io": "無法讀取這個檔案"
}
},
"scrollToBottom": "捲動到底部"
},
@@ -72,12 +84,29 @@
"streaming": "串流輸出中",
"assistantTyping": "助理正在輸入",
"toolSingle": "正在使用工具",
"toolMany": "已使用 {{count}} 個工具"
"toolMany": "已使用 {{count}} 個工具",
"imageAttachment": "圖片附件"
},
"lightbox": {
"title": "圖片預覽",
"open": "檢視圖片",
"prev": "上一張",
"next": "下一張",
"close": "關閉預覽"
},
"code": {
"fallbackLanguage": "程式碼",
"copyAria": "複製程式碼",
"copy": "複製",
"copied": "已複製"
},
"common": {
"dismiss": "關閉"
},
"errors": {
"messageTooBig": {
"title": "訊息過大",
"body": "伺服器因超過大小限制拒收了上一則訊息。可移除部分圖片或改用較小的圖片後再試。"
}
}
}