Files
smesh/src/components/TranslateButton/index.tsx
2025-09-20 22:00:28 +08:00

95 lines
2.6 KiB
TypeScript

import { ExtendedKind } from '@/constants'
import { useTranslatedEvent } from '@/hooks'
import { toTranslation } from '@/lib/link'
import { cn, detectLanguage } from '@/lib/utils'
import { useSecondaryPage } from '@/PageManager'
import { useTranslationService } from '@/providers/TranslationServiceProvider'
import { Languages, Loader } from 'lucide-react'
import { Event, kinds } from 'nostr-tools'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
export default function TranslateButton({
event,
className
}: {
event: Event
className?: string
}) {
const { i18n } = useTranslation()
const { push } = useSecondaryPage()
const { translateEvent, showOriginalEvent } = useTranslationService()
const [translating, setTranslating] = useState(false)
const translatedEvent = useTranslatedEvent(event.id)
const supported = useMemo(
() =>
[
kinds.ShortTextNote,
kinds.Highlights,
ExtendedKind.COMMENT,
ExtendedKind.PICTURE,
ExtendedKind.POLL,
ExtendedKind.RELAY_REVIEW
].includes(event.kind),
[event]
)
const needTranslation = useMemo(() => {
const detected = detectLanguage(event.content)
if (!detected) return false
if (detected === 'und') return true
return !i18n.language.startsWith(detected)
}, [event, i18n.language])
if (!supported || !needTranslation) {
return null
}
const handleTranslate = async () => {
if (translating) return
setTranslating(true)
await translateEvent(event)
.catch((error) => {
toast.error(
'Translation failed: ' + (error.message || 'An error occurred while translating the note')
)
if (error.message === 'Insufficient balance.') {
push(toTranslation())
}
})
.finally(() => {
setTranslating(false)
})
}
const showOriginal = () => {
showOriginalEvent(event.id)
}
return (
<button
className={cn(
'flex items-center text-muted-foreground hover:text-pink-400 px-2 py-1 h-full disabled:text-muted-foreground [&_svg]:size-4 [&_svg]:shrink-0 transition-colors',
className
)}
disabled={translating}
onClick={(e) => {
e.stopPropagation()
if (translatedEvent) {
showOriginal()
} else {
handleTranslate()
}
}}
>
{translating ? (
<Loader className="animate-spin" />
) : (
<Languages className={translatedEvent ? 'text-pink-400 hover:text-pink-400/60' : ''} />
)}
</button>
)
}