feat: add translate selection (#1010)

* feat: add translate selection

* chore: add default translate value

* feat: optimize trigger translation shotcut and add TanslateLanguageVarious

* fix

* fix: add database migrate version
This commit is contained in:
Chen Tao 2025-02-10 13:19:46 +08:00 committed by GitHub
parent f3940159b3
commit 3d8748a61a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 85 additions and 15 deletions

View File

@ -1,5 +1,6 @@
import { LoadingOutlined, TranslationOutlined } from '@ant-design/icons'
import { useDefaultModel } from '@renderer/hooks/useAssistant'
import { useSettings } from '@renderer/hooks/useSettings'
import { fetchTranslate } from '@renderer/services/ApiService'
import { getDefaultTopic, getDefaultTranslateAssistant } from '@renderer/services/AssistantService'
import { getUserMessage } from '@renderer/services/MessagesService'
@ -20,6 +21,7 @@ const TranslateButton: FC<Props> = ({ text, onTranslated, disabled, style, isLoa
const { t } = useTranslation()
const { translateModel } = useDefaultModel()
const [isTranslating, setIsTranslating] = useState(false)
const { targetLanguage } = useSettings()
const translateConfirm = () => {
return window?.modal?.confirm({
@ -49,7 +51,7 @@ const TranslateButton: FC<Props> = ({ text, onTranslated, disabled, style, isLoa
setIsTranslating(true)
try {
const assistant = getDefaultTranslateAssistant('english', text)
const assistant = getDefaultTranslateAssistant(targetLanguage, text)
const message = getUserMessage({
assistant,
topic: getDefaultTopic('default'),
@ -75,7 +77,10 @@ const TranslateButton: FC<Props> = ({ text, onTranslated, disabled, style, isLoa
}, [isLoading])
return (
<Tooltip placement="top" title={t('chat.input.translate')} arrow>
<Tooltip
placement="top"
title={t('chat.input.translate', { target_language: t(`languages.${targetLanguage.toString()}`) })}
arrow>
<ToolbarButton onClick={handleTranslate} disabled={disabled || isTranslating} style={style} type="text">
{isTranslating ? <LoadingOutlined spin /> : <TranslationOutlined />}
</ToolbarButton>

View File

@ -3,13 +3,14 @@ import {
SendMessageShortcut,
setSendMessageShortcut as _setSendMessageShortcut,
setSidebarIcons,
setTargetLanguage,
setTheme,
SettingsState,
setTopicPosition,
setTray,
setWindowStyle
} from '@renderer/store/settings'
import { SidebarIcon, ThemeMode } from '@renderer/types'
import { SidebarIcon, ThemeMode, TranslateLanguageVarious } from '@renderer/types'
export function useSettings() {
const settings = useAppSelector((state) => state.settings)
@ -30,6 +31,9 @@ export function useSettings() {
setWindowStyle(windowStyle: 'transparent' | 'opaque') {
dispatch(setWindowStyle(windowStyle))
},
setTargetLanguage(targetLanguage: TranslateLanguageVarious) {
dispatch(setTargetLanguage(targetLanguage))
},
setTopicPosition(topicPosition: 'left' | 'right') {
dispatch(setTopicPosition(topicPosition))
},

View File

@ -86,7 +86,7 @@
"input.send": "Send",
"input.settings": "Settings",
"input.topics": " Topics ",
"input.translate": "Translate to English",
"input.translate": "Translate to {{target_language}}",
"input.upload": "Upload image or document file",
"input.web_search": "Enable web search",
"input.knowledge_base": "Knowledge Base",
@ -462,6 +462,12 @@
"display.custom.css": "Custom CSS",
"display.custom.css.placeholder": "/* Put custom CSS here */",
"input.auto_translate_with_space": "Quickly translate with 3 spaces",
"input.target_language": "Target language",
"input.target_language.chinese": "Simplified Chinese",
"input.target_language.chinese-traditional": "Traditional Chinese",
"input.target_language.english": "English",
"input.target_language.japanese": "Japanese",
"input.target_language.russian": "Russian",
"messages.divider": "Show divider between messages",
"messages.input.paste_long_text_as_file": "Paste long text as file",
"messages.input.send_shortcuts": "Send shortcuts",

View File

@ -81,7 +81,7 @@
"input.send": "送信",
"input.settings": "設定",
"input.topics": " トピック ",
"input.translate": "英語に翻訳",
"input.translate": "{{target_language}}に翻訳",
"input.upload": "画像またはドキュメントをアップロード",
"input.web_search": "ウェブ検索を有効にする",
"input.knowledge_base": "ナレッジベース",
@ -453,6 +453,12 @@
"display.minApp.disabled": "非表示ミニプログラム",
"display.minApp.empty": "非表示にしたいアプレットを左からここまでドラッグします",
"input.auto_translate_with_space": "スペースを3回押して翻訳",
"input.target_language": "目標言語",
"input.target_language.chinese": "簡体字中国語",
"input.target_language.chinese-traditional": "繁体字中国語",
"input.target_language.english": "英語",
"input.target_language.japanese": "日本語",
"input.target_language.russian": "ロシア語",
"messages.divider": "メッセージ間に区切り線を表示",
"messages.input.paste_long_text_as_file": "長いテキストをファイルとして貼り付け",
"messages.input.send_shortcuts": "送信ショートカット",

View File

@ -81,7 +81,7 @@
"input.send": "Отправить",
"input.settings": "Настройки",
"input.topics": " Топики ",
"input.translate": "Перевести на английский",
"input.translate": "Перевести на {{target_language}}",
"input.upload": "Загрузить изображение или документ",
"input.web_search": "Включить веб-поиск",
"input.knowledge_base": "База знаний",
@ -454,6 +454,12 @@
"display.custom.css": "Пользовательский CSS",
"display.custom.css.placeholder": "/* Здесь введите пользовательский CSS */",
"input.auto_translate_with_space": "Быстрый перевод с помощью 3-х пробелов",
"input.target_language": "Целевой язык",
"input.target_language.chinese": "Китайский упрощенный",
"input.target_language.chinese-traditional": "Китайский традиционный",
"input.target_language.english": "Английский",
"input.target_language.japanese": "Японский",
"input.target_language.russianinput.translate": "Русский",
"messages.divider": "Показывать разделитель между сообщениями",
"messages.input.paste_long_text_as_file": "Вставлять длинный текст как файл",
"messages.input.send_shortcuts": "Горячие клавиши для отправки",

View File

@ -86,7 +86,7 @@
"input.send": "发送",
"input.settings": "设置",
"input.topics": " 话题 ",
"input.translate": "翻译成英文",
"input.translate": "翻译成{{target_language}}",
"input.upload": "上传图片或文档",
"input.web_search": "开启网络搜索",
"input.knowledge_base": "知识库",
@ -460,6 +460,12 @@
"display.custom.css": "自定义 CSS",
"display.custom.css.placeholder": "/* 这里写自定义CSS */",
"input.auto_translate_with_space": "快速敲击3次空格翻译",
"input.target_language": "目标语言",
"input.target_language.chinese": "简体中文",
"input.target_language.chinese-traditional": "繁体中文",
"input.target_language.english": "英文",
"input.target_language.japanese": "日文",
"input.target_language.russian": "俄文",
"messages.divider": "消息分割线",
"messages.input.paste_long_text_as_file": "长文本粘贴为文件",
"messages.input.send_shortcuts": "发送快捷键",

View File

@ -86,7 +86,7 @@
"input.send": "發送",
"input.settings": "設定",
"input.topics": " 話題 ",
"input.translate": "翻譯成英文",
"input.translate": "翻譯成{{target_language}}",
"input.upload": "上傳圖片或文檔",
"input.web_search": "開啟網路搜索",
"input.knowledge_base": "知識庫",
@ -459,6 +459,12 @@
"display.custom.css": "自定義 CSS",
"display.custom.css.placeholder": "/* 這裡寫自定義 CSS */",
"input.auto_translate_with_space": "快速敲擊3次空格翻譯",
"input.target_language": "目標語言",
"input.target_language.chinese": "簡體中文",
"input.target_language.chinese-traditional": "繁體中文",
"input.target_language.english": "英文",
"input.target_language.japanese": "日文",
"input.target_language.russian": "俄文",
"messages.divider": "訊息間顯示分隔線",
"messages.input.paste_long_text_as_file": "將長文本貼上為檔案",
"messages.input.send_shortcuts": "發送快捷鍵",

View File

@ -58,13 +58,13 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic }) => {
const [inputFocus, setInputFocus] = useState(false)
const { assistant, addTopic, model, setModel, updateAssistant } = useAssistant(_assistant.id)
const {
targetLanguage,
sendMessageShortcut,
fontSize,
pasteLongTextAsFile,
pasteLongTextThreshold,
showInputEstimatedTokens,
clickAssistantToShowTopic,
language,
autoTranslateWithSpace,
sidebarIcons
} = useSettings()
@ -152,7 +152,7 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic }) => {
try {
setIsTranslating(true)
const translatedText = await translateText(text, 'english')
const translatedText = await translateText(text, targetLanguage)
translatedText && setText(translatedText)
setTimeout(() => resizeTextArea(), 0)
} catch (error) {
@ -539,9 +539,7 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic }) => {
/>
</ToolbarMenu>
<ToolbarMenu>
{!language.startsWith('en') && (
<TranslateButton text={text} onTranslated={onTranslated} isLoading={isTranslating} />
)}
<TranslateButton text={text} onTranslated={onTranslated} isLoading={isTranslating} />
{generating && (
<Tooltip placement="top" title={t('chat.input.pause')} arrow>
<ToolbarButton type="text" onClick={onPause} style={{ marginRight: -2, marginTop: 1 }}>

View File

@ -29,7 +29,7 @@ import {
setShowInputEstimatedTokens,
setShowMessageDivider
} from '@renderer/store/settings'
import { Assistant, AssistantSettings, ThemeMode } from '@renderer/types'
import { Assistant, AssistantSettings, ThemeMode, TranslateLanguageVarious } from '@renderer/types'
import { Col, InputNumber, Row, Select, Slider, Switch, Tooltip } from 'antd'
import { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
@ -59,6 +59,8 @@ const SettingsTab: FC<Props> = (props) => {
showInputEstimatedTokens,
sendMessageShortcut,
setSendMessageShortcut,
targetLanguage,
setTargetLanguage,
pasteLongTextAsFile,
renderInputMessageAsMarkdown,
codeShowLineNumbers,
@ -378,6 +380,25 @@ const SettingsTab: FC<Props> = (props) => {
<SettingDivider />
</>
)}
<SettingRow>
<SettingRowTitleSmall>{t('settings.input.target_language')}</SettingRowTitleSmall>
<Select
defaultValue={'english' as TranslateLanguageVarious}
size="small"
value={targetLanguage}
menuItemSelectedIcon={<CheckOutlined />}
options={[
{ value: 'chinese', label: t('settings.input.target_language.chinese') },
{ value: 'chinese-traditional', label: t('settings.input.target_language.chinese-traditional') },
{ value: 'english', label: t('settings.input.target_language.english') },
{ value: 'japanese', label: t('settings.input.target_language.japanese') },
{ value: 'russian', label: t('settings.input.target_language.russian') }
]}
onChange={(value) => setTargetLanguage(value)}
style={{ width: 135 }}
/>
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitleSmall>{t('settings.messages.input.send_shortcuts')}</SettingRowTitleSmall>
<Select

View File

@ -921,6 +921,10 @@ const migrateConfig = {
enabled: false
})
return state
},
'63': (state: RootState) => {
state.settings.targetLanguage = 'english'
return state
}
}

View File

@ -1,6 +1,6 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { TRANSLATE_PROMPT } from '@renderer/config/prompts'
import { CodeStyleVarious, LanguageVarious, ThemeMode } from '@renderer/types'
import { CodeStyleVarious, LanguageVarious, ThemeMode, TranslateLanguageVarious } from '@renderer/types'
export type SendMessageShortcut = 'Enter' | 'Shift+Enter' | 'Ctrl+Enter' | 'Command+Enter'
@ -21,6 +21,7 @@ export interface SettingsState {
showTopics: boolean
sendMessageShortcut: SendMessageShortcut
language: LanguageVarious
targetLanguage: TranslateLanguageVarious
proxyMode: 'system' | 'custom' | 'none'
proxyUrl?: string
userName: string
@ -73,6 +74,7 @@ const initialState: SettingsState = {
showTopics: true,
sendMessageShortcut: 'Enter',
language: navigator.language as LanguageVarious,
targetLanguage: 'english' as TranslateLanguageVarious,
proxyMode: 'system',
proxyUrl: undefined,
userName: '',
@ -139,6 +141,9 @@ const settingsSlice = createSlice({
state.language = action.payload
window.electron.ipcRenderer.send('miniwindow-reload')
},
setTargetLanguage: (state, action: PayloadAction<TranslateLanguageVarious>) => {
state.targetLanguage = action.payload
},
setProxyMode: (state, action: PayloadAction<'system' | 'custom' | 'none'>) => {
state.proxyMode = action.payload
},
@ -269,6 +274,7 @@ export const {
toggleShowTopics,
setSendMessageShortcut,
setLanguage,
setTargetLanguage,
setProxyMode,
setProxyUrl,
setUserName,

View File

@ -180,6 +180,8 @@ export enum ThemeMode {
export type LanguageVarious = 'zh-CN' | 'zh-TW' | 'en-US' | 'ru-RU' | 'ja-JP'
export type TranslateLanguageVarious = 'chinese' | 'chinese-traditional' | 'english' | 'japanese' | 'russian'
export type CodeStyleVarious = BuiltinTheme | 'auto'
export type WebDavConfig = {