fix: ui/ux

This commit is contained in:
Pleasurecruise 2025-05-29 15:13:24 +08:00
parent 4310d42bd5
commit 86d7e0240b
No known key found for this signature in database
GPG Key ID: E6385136096279B6
6 changed files with 91 additions and 63 deletions

View File

@ -1766,6 +1766,7 @@
"close": "Close",
"closed": "Translation closed",
"copied": "Translation content copied",
"detected.language": "Detected Language",
"empty": "Translation content is empty",
"not.found": "Translation content not found",
"confirm": {

View File

@ -1798,7 +1798,8 @@
"tooltip.newline": "改行",
"menu": {
"description": "對當前輸入框內容進行翻譯"
}
},
"detected.language": "検出された言語"
},
"tray": {
"quit": "終了",

View File

@ -1791,14 +1791,15 @@
"model": "Настройки модели",
"model_desc": "Модель, используемая для службы перевода",
"bidirectional": "Настройки двунаправленного перевода",
"directional_tip": "После включения поддерживается только двунаправленный перевод между исходным и целевым языками",
"scroll_sync": "Настройки синхронизации прокрутки"
"scroll_sync": "Настройки синхронизации прокрутки",
"bidirectional_tip": "Если включено, перевод будет выполняться в обоих направлениях, исходный текст будет переведен на целевой язык и наоборот."
},
"title": "Перевод",
"tooltip.newline": "Перевести",
"menu": {
"description": "Перевести содержимое текущего ввода"
}
},
"detected.language": "Обнаруженный язык"
},
"tray": {
"quit": "Выйти",

View File

@ -1798,7 +1798,8 @@
"scroll_sync": "滚动同步设置"
},
"title": "翻译",
"tooltip.newline": "换行"
"tooltip.newline": "换行",
"detected.language": "检测到的语言"
},
"tray": {
"quit": "退出",

View File

@ -1798,7 +1798,8 @@
"tooltip.newline": "換行",
"menu": {
"description": "對當前輸入框內容進行翻譯"
}
},
"detected.language": "檢測到的語言"
},
"tray": {
"quit": "結束",

View File

@ -18,7 +18,7 @@ import {
detectLanguage,
determineTargetLanguage
} from '@renderer/utils/translate'
import { Button, Empty, Flex, Modal, Popconfirm, Select, Space, Switch, Tooltip } from 'antd'
import { Button, Dropdown, Empty, Flex, Modal, Popconfirm, Select, Space, Switch, Tooltip } from 'antd'
import TextArea, { TextAreaRef } from 'antd/es/input/TextArea'
import dayjs from 'dayjs'
import { useLiveQuery } from 'dexie-react-hooks'
@ -214,7 +214,7 @@ const TranslatePage: FC = () => {
const [isBidirectional, setIsBidirectional] = useState(false)
const [bidirectionalPair, setBidirectionalPair] = useState<[string, string]>(['english', 'chinese'])
const [settingsVisible, setSettingsVisible] = useState(false)
const [originalTargetLanguage, setOriginalTargetLanguage] = useState<string | null>(null)
const [detectedLanguage, setDetectedLanguage] = useState<string | null>(null)
const contentContainerRef = useRef<HTMLDivElement>(null)
const textAreaRef = useRef<TextAreaRef>(null)
const outputTextRef = useRef<HTMLDivElement>(null)
@ -289,6 +289,8 @@ const TranslatePage: FC = () => {
setLoading(true)
try {
const sourceLanguage = await detectLanguage(text)
console.log('检测到的语言:', sourceLanguage)
setDetectedLanguage(sourceLanguage)
const result = determineTargetLanguage(sourceLanguage, targetLanguage, isBidirectional, bidirectionalPair)
if (!result.success) {
let errorMessage = ''
@ -337,11 +339,6 @@ const TranslatePage: FC = () => {
const toggleBidirectional = (value: boolean) => {
setIsBidirectional(value)
db.settings.put({ id: 'translate:bidirectional:enabled', value })
if (!value && originalTargetLanguage) {
setTargetLanguage(originalTargetLanguage)
setOriginalTargetLanguage(null)
}
}
const onCopy = () => {
@ -450,70 +447,96 @@ const TranslatePage: FC = () => {
<HistoryContainner $historyDrawerVisible={historyDrawerVisible}>
<OperationBar>
<span style={{ fontSize: 16 }}>{t('translate.history.title')}</span>
<Popconfirm
title={t('translate.history.clear')}
description={t('translate.history.clear_description')}
onConfirm={clearHistory}
okText={t('settings.data.nutstore.new_folder.button.confirm')}
cancelText={t('settings.data.nutstore.new_folder.button.cancel')}>
<Button type="text" size="small" danger icon={<DeleteOutlined />}>
{t('translate.history.clear')}
</Button>
</Popconfirm>
{!isEmpty(translateHistory) && (
<Popconfirm
title={t('translate.history.clear')}
description={t('translate.history.clear_description')}
onConfirm={clearHistory}>
<Button type="text" size="small" danger icon={<DeleteOutlined />}>
{t('translate.history.clear')}
</Button>
</Popconfirm>
)}
</OperationBar>
{translateHistory && translateHistory.length > 0 ? (
{translateHistory && translateHistory.length ? (
<HistoryList>
{translateHistory.map((history) => (
<HistoryListItem key={history.id} onClick={() => onHistoryItemClick(history)}>
<HistoryListItemTitle>{history.sourceText}</HistoryListItemTitle>
<Flex justify="space-between" style={{ marginTop: 5 }}>
<HistoryListItemDate>{dayjs(history.createdAt).format('MM-DD HH:mm')}</HistoryListItemDate>
<Button
size="small"
type="text"
icon={<DeleteOutlined />}
onClick={(e) => {
e.stopPropagation()
deleteHistory(history.id)
}}
/>
</Flex>
</HistoryListItem>
{translateHistory.map((item) => (
<Dropdown
key={item.id}
trigger={['contextMenu']}
menu={{
items: [
{
key: 'delete',
label: t('translate.history.delete'),
icon: <DeleteOutlined />,
danger: true,
onClick: () => deleteHistory(item.id)
}
]
}}>
<HistoryListItem onClick={() => onHistoryItemClick(item)}>
<Flex justify="space-between" vertical gap={4} style={{ width: '100%' }}>
<HistoryListItemTitle>{item.sourceText}</HistoryListItemTitle>
<HistoryListItemTitle>{item.targetText}</HistoryListItemTitle>
<HistoryListItemDate>{dayjs(item.createdAt).format('MM/DD HH:mm')}</HistoryListItemDate>
</Flex>
</HistoryListItem>
</Dropdown>
))}
</HistoryList>
) : (
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t('translate.history.empty')} />
<Flex justify="center" align="center" style={{ flex: 1 }}>
<Empty description={t('translate.history.empty')} />
</Flex>
)}
</HistoryContainner>
<InputContainer>
<OperationBar>
<div style={{ width: '100%', display: 'flex', justifyContent: 'flex-end', gap: '8px' }}>
<Flex align="center" gap={20}>
<Select
showSearch
value="auto"
style={{ width: 180 }}
optionFilterProp="label"
disabled
options={[
{
label: detectedLanguage
? t(`languages.${detectedLanguage}`)
: t('translate.detected.language'),
value: 'auto'
}
]}
/>
<Button
type="text"
icon={<Settings2 size={18} color="var(--color-icon)" />}
icon={<Settings2 size={18} />}
onClick={() => setSettingsVisible(true)}
style={{ color: 'var(--color-text-2)', display: 'flex' }}
/>
<Tooltip
mouseEnterDelay={0.5}
styles={{ body: { fontSize: '12px' } }}
title={
<div style={{ textAlign: 'center' }}>
Enter: {t('translate.button.translate')}
<br />
Shift + Enter: {t('translate.tooltip.newline')}
</div>
}>
<TranslateButton
type="primary"
loading={loading}
onClick={onTranslate}
disabled={!text.trim()}
icon={<SendOutlined />}>
{t('translate.button.translate')}
</TranslateButton>
</Tooltip>
</div>
</Flex>
<Tooltip
mouseEnterDelay={0.5}
styles={{ body: { fontSize: '12px' } }}
title={
<div style={{ textAlign: 'center' }}>
Enter: {t('translate.button.translate')}
<br />
Shift + Enter: {t('translate.tooltip.newline')}
</div>
}>
<TranslateButton
type="primary"
loading={loading}
onClick={onTranslate}
disabled={!text.trim()}
icon={<SendOutlined />}>
{t('translate.button.translate')}
</TranslateButton>
</Tooltip>
</OperationBar>
<Textarea