tooot/src/components/Timeline/Shared/Translate.tsx

136 lines
4.2 KiB
TypeScript
Raw Normal View History

2021-05-23 22:40:42 +02:00
import { ParseHTML } from '@components/Parse'
import CustomText from '@components/Text'
2022-11-04 23:38:29 +01:00
import getLanguage from '@helpers/getLanguage'
2021-05-19 20:40:16 +02:00
import { useTranslateQuery } from '@utils/queryHooks/translate'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
2022-02-01 22:27:29 +01:00
import * as Localization from 'expo-localization'
2022-06-09 01:47:38 +02:00
import React, { useEffect, useState } from 'react'
2021-05-19 20:40:16 +02:00
import { useTranslation } from 'react-i18next'
import { Pressable } from 'react-native'
2021-05-19 23:28:01 +02:00
import { Circle } from 'react-native-animated-spinkit'
2022-06-09 01:47:38 +02:00
import detectLanguage from 'react-native-language-detection'
2021-05-19 20:40:16 +02:00
export interface Props {
highlighted: boolean
2022-11-04 23:38:29 +01:00
status: Pick<Mastodon.Status, 'language' | 'spoiler_text' | 'content' | 'emojis'>
2021-05-19 20:40:16 +02:00
}
const TimelineTranslate = React.memo(
({ highlighted, status }: Props) => {
if (!highlighted) {
return null
}
2021-05-19 23:28:01 +02:00
const { t } = useTranslation('componentTimeline')
2022-02-12 14:51:01 +01:00
const { colors } = useTheme()
2021-05-19 23:28:01 +02:00
2022-11-04 23:38:29 +01:00
const text = status.spoiler_text ? [status.spoiler_text, status.content] : [status.content]
2021-05-23 22:40:42 +02:00
for (const i in text) {
2021-05-19 23:28:01 +02:00
for (const emoji of status.emojis) {
text[i] = text[i].replaceAll(`:${emoji.shortcode}:`, ' ')
2021-05-19 23:28:01 +02:00
}
text[i] = text[i]
.replace(/(<([^>]+)>)/gi, ' ')
.replace(/@.*? /gi, ' ')
.replace(/#.*? /gi, ' ')
.replace(/http(s):\/\/.*? /gi, ' ')
2021-05-19 23:28:01 +02:00
}
2021-05-19 20:40:16 +02:00
2022-06-09 01:47:38 +02:00
const [detectedLanguage, setDetectedLanguage] = useState<string>('')
useEffect(() => {
const detect = async () => {
const result = await detectLanguage(text.join(`\n\n`)).catch(() => {
// No need to log language detection failure
})
result?.detected && setDetectedLanguage(result.detected.slice(0, 2))
2022-06-09 01:47:38 +02:00
}
detect()
}, [])
2022-11-04 23:38:29 +01:00
const settingsLanguage = getLanguage()
const targetLanguage = settingsLanguage?.startsWith('en')
? Localization.locale || settingsLanguage || 'en'
: settingsLanguage || Localization.locale || 'en'
2022-06-09 01:47:38 +02:00
2021-05-19 23:28:01 +02:00
const [enabled, setEnabled] = useState(false)
const { refetch, data, isLoading, isSuccess, isError } = useTranslateQuery({
2022-06-09 01:47:38 +02:00
source: detectedLanguage,
target: targetLanguage,
2021-05-23 22:40:42 +02:00
text,
2021-05-19 23:28:01 +02:00
options: { enabled }
2021-05-19 20:40:16 +02:00
})
2022-06-09 01:47:38 +02:00
if (!detectedLanguage) {
return null
}
2022-06-10 16:52:55 +02:00
if (Localization.locale.slice(0, 2).includes(detectedLanguage)) {
2022-06-09 01:47:38 +02:00
return null
}
2022-06-10 16:52:55 +02:00
if (settingsLanguage?.slice(0, 2).includes(detectedLanguage)) {
2022-06-09 01:47:38 +02:00
return null
}
2021-05-19 20:40:16 +02:00
return (
<>
2021-05-19 23:28:01 +02:00
<Pressable
2022-04-30 21:47:17 +02:00
style={{
flexDirection: 'row',
alignItems: 'center',
paddingVertical: StyleConstants.Spacing.S,
paddingBottom: isSuccess ? 0 : undefined
}}
2021-05-19 23:28:01 +02:00
onPress={() => {
if (enabled) {
if (!isSuccess) {
refetch()
}
} else {
setEnabled(true)
}
2021-05-19 20:40:16 +02:00
}}
>
<CustomText
fontStyle='M'
2021-05-19 23:28:01 +02:00
style={{
2022-11-04 23:38:29 +01:00
color: isLoading || isSuccess ? colors.secondary : isError ? colors.red : colors.blue
2021-05-19 23:28:01 +02:00
}}
>
{isError
2021-05-23 22:40:42 +02:00
? t('shared.translate.failed')
: isSuccess
2022-02-08 22:19:24 +01:00
? typeof data?.error === 'string'
? t(`shared.translate.${data.error}`)
: t('shared.translate.succeed', {
provider: data?.provider,
source: data?.sourceLanguage
})
2021-05-19 23:28:01 +02:00
: t('shared.translate.default')}
</CustomText>
<CustomText>
2022-11-04 23:38:29 +01:00
{__DEV__ ? ` Source: ${detectedLanguage}; Target: ${targetLanguage}` : undefined}
</CustomText>
2021-05-19 23:28:01 +02:00
{isLoading ? (
<Circle
size={StyleConstants.Font.Size.M}
2022-02-12 14:51:01 +01:00
color={colors.disabled}
2021-05-19 23:28:01 +02:00
style={{ marginLeft: StyleConstants.Spacing.S }}
/>
) : null}
</Pressable>
2022-02-08 22:19:24 +01:00
{data && data.error === undefined
2021-05-23 22:40:42 +02:00
? data.text.map((d, i) => (
2022-08-09 00:44:56 +02:00
<ParseHTML key={i} content={d} size={'M'} numberOfLines={999} />
2021-05-23 22:40:42 +02:00
))
: null}
2021-05-19 20:40:16 +02:00
</>
)
},
2022-04-30 21:47:17 +02:00
(prev, next) =>
prev.status.content === next.status.content &&
prev.status.spoiler_text === next.status.spoiler_text
2021-05-19 20:40:16 +02:00
)
export default TimelineTranslate