Add error handling with Google Translate link
This commit is contained in:
+1
-1
@@ -85,7 +85,7 @@
|
||||
"@braintree/sanitize-url": "^6.0.2",
|
||||
"@bsky.app/alf": "^0.1.7",
|
||||
"@bsky.app/expo-image-crop-tool": "^0.5.0",
|
||||
"@bsky.app/expo-translate-text": "^0.2.4",
|
||||
"@bsky.app/expo-translate-text": "^0.2.5",
|
||||
"@bsky.app/react-native-mmkv": "2.12.5",
|
||||
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
|
||||
"@emoji-mart/react": "^1.1.1",
|
||||
|
||||
@@ -18,6 +18,7 @@ import {atoms as a, native, useTheme} from '#/alf'
|
||||
import {Button} from '#/components/Button'
|
||||
import {ArrowRight_Stroke2_Corner0_Rounded as ArrowRight} from '#/components/icons/Arrow'
|
||||
import {TimesLarge_Stroke2_Corner0_Rounded as Times} from '#/components/icons/Times'
|
||||
import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning'
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as Select from '#/components/Select'
|
||||
@@ -45,6 +46,17 @@ export function TranslatedPost({
|
||||
[post, langPrefs.primaryLanguage],
|
||||
)
|
||||
|
||||
if (translationState.status === 'error') {
|
||||
return (
|
||||
<TranslationError
|
||||
clearTranslation={clearTranslation}
|
||||
message={translationState.message}
|
||||
postText={postText}
|
||||
primaryLanguage={langPrefs.primaryLanguage}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (translationState.status === 'loading') {
|
||||
return <TranslationLoading />
|
||||
}
|
||||
@@ -137,6 +149,63 @@ function TranslationLink({
|
||||
)
|
||||
}
|
||||
|
||||
function TranslationError({
|
||||
clearTranslation,
|
||||
message,
|
||||
postText,
|
||||
primaryLanguage,
|
||||
}: {
|
||||
clearTranslation: () => void
|
||||
message: string
|
||||
postText: string
|
||||
primaryLanguage: string
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {t: l} = useLingui()
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
a.px_lg,
|
||||
a.py_md,
|
||||
a.mt_sm,
|
||||
a.border,
|
||||
a.rounded_lg,
|
||||
t.atoms.border_contrast_high,
|
||||
]}>
|
||||
<View
|
||||
style={[a.flex_row, a.flex_wrap, a.align_center, a.justify_between]}>
|
||||
<View style={[a.flex_row, a.align_center, a.mb_sm]}>
|
||||
<Warning size="sm" fill={t.atoms.text_contrast_medium.color} />
|
||||
<Text style={[a.text_xs, a.font_medium, t.atoms.text_contrast_high]}>
|
||||
{' '}
|
||||
{message}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={[a.flex_row, a.align_center, a.mb_xs]}>
|
||||
<Button
|
||||
label={l`Hide translation`}
|
||||
hitSlop={HITSLOP_30}
|
||||
hoverStyle={native({opacity: 0.5})}
|
||||
onPress={clearTranslation}>
|
||||
<Times size="sm" fill={t.atoms.text_contrast_medium.color} />
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
<View style={[a.flex_row, a.align_center]}>
|
||||
<Text>
|
||||
<InlineLinkText
|
||||
to={getTranslatorLink(postText, primaryLanguage)}
|
||||
label={l`Try Google Translate`}
|
||||
style={[a.text_xs, a.font_medium]}>
|
||||
<Trans>Try Google Translate</Trans>
|
||||
</InlineLinkText>
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
function TranslationResult({
|
||||
clearTranslation,
|
||||
translate,
|
||||
@@ -213,7 +282,12 @@ function TranslationResult({
|
||||
)}
|
||||
{sourceLanguage != null && (
|
||||
<>
|
||||
<Text style={[a.text_sm, t.atoms.text_contrast_medium]}>
|
||||
<Text
|
||||
style={[
|
||||
a.text_xs,
|
||||
a.font_medium,
|
||||
t.atoms.text_contrast_medium,
|
||||
]}>
|
||||
{' '}
|
||||
·{' '}
|
||||
</Text>
|
||||
@@ -250,6 +324,7 @@ function TranslationLanguageSelect({
|
||||
postText: string
|
||||
sourceLanguage: string
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {t: l} = useLingui()
|
||||
const langPrefs = useLanguagePrefs()
|
||||
@@ -300,7 +375,8 @@ function TranslationLanguageSelect({
|
||||
{...props}
|
||||
hitSlop={HITSLOP_30}
|
||||
hoverStyle={native({opacity: 0.5})}>
|
||||
<Text style={[a.text_xs, a.font_medium]}>
|
||||
<Text
|
||||
style={[a.text_xs, a.font_medium, t.atoms.text_contrast_high]}>
|
||||
<Trans>Change</Trans>
|
||||
</Text>
|
||||
</Button>
|
||||
|
||||
@@ -2,6 +2,7 @@ import {useCallback, useContext, useEffect, useMemo, useState} from 'react'
|
||||
import {LayoutAnimation, Platform} from 'react-native'
|
||||
import {getLocales} from 'expo-localization'
|
||||
import {type TranslationTaskResult} from '@bsky.app/expo-translate-text/build/ExpoTranslateText.types'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
|
||||
import {useGoogleTranslate} from '#/lib/hooks/useGoogleTranslate'
|
||||
@@ -61,9 +62,15 @@ async function attemptTranslation(
|
||||
})
|
||||
|
||||
// Since `input` is always a string, the result should always be a string.
|
||||
const translatedText =
|
||||
typeof result.translatedTexts === 'string' ? result.translatedTexts : ''
|
||||
|
||||
if (translatedText === input) {
|
||||
throw new Error('Translation result is the same as the source text.')
|
||||
}
|
||||
|
||||
return {
|
||||
translatedText:
|
||||
typeof result.translatedTexts === 'string' ? result.translatedTexts : '',
|
||||
translatedText,
|
||||
targetLanguage: result.targetLanguage,
|
||||
sourceLanguage: result.sourceLanguage ?? sourceLangCode ?? null, // iOS doesn't return the source language
|
||||
}
|
||||
@@ -125,6 +132,7 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
||||
>({})
|
||||
const [refCounts, setRefCounts] = useState<Record<string, number>>({})
|
||||
const ax = useAnalytics()
|
||||
const {t: l} = useLingui()
|
||||
const googleTranslate = useGoogleTranslate()
|
||||
|
||||
useEffect(() => {
|
||||
@@ -235,12 +243,12 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
||||
sourceLanguage: sourceLangCode ?? null,
|
||||
targetLanguage: targetLangCode,
|
||||
})
|
||||
let errorMessage = l`Device failed to translate. :(`
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
|
||||
setTranslationState(prev => ({
|
||||
...prev,
|
||||
[key]: {status: 'idle'},
|
||||
[key]: {status: 'error', message: errorMessage},
|
||||
}))
|
||||
await googleTranslate(text, targetLangCode, sourceLangCode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +262,7 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
||||
[key]: {status: 'loading'},
|
||||
}))
|
||||
},
|
||||
[ax, googleTranslate],
|
||||
[ax, googleTranslate, l],
|
||||
)
|
||||
|
||||
const ctx = useMemo(
|
||||
|
||||
@@ -9,6 +9,10 @@ export type TranslationState =
|
||||
sourceLanguage: TranslationTaskResult['sourceLanguage']
|
||||
targetLanguage: TranslationTaskResult['targetLanguage']
|
||||
}
|
||||
| {
|
||||
status: 'error'
|
||||
message: string
|
||||
}
|
||||
|
||||
export type TranslationFunctionParams = {
|
||||
/**
|
||||
|
||||
@@ -3731,10 +3731,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@bsky.app/expo-image-crop-tool/-/expo-image-crop-tool-0.5.0.tgz#4308fbde5c15e6be9122601797bc3d9549c95e31"
|
||||
integrity sha512-gmhQr2HWTRFyPO00fn5OmtiEVtikXusHMrN5Zoq26pu1VZX3zVE+aoc668etTqrvsQcm2Qu8fo96k5F3Wu+6wg==
|
||||
|
||||
"@bsky.app/expo-translate-text@^0.2.4":
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@bsky.app/expo-translate-text/-/expo-translate-text-0.2.4.tgz#6e7f20f286111ee4d550c0c84f57393fc215a675"
|
||||
integrity sha512-7mvFggNfkJEufI5A3WnjfjdN3H9P6Dpx7CpDkA9npWqA8Cb2icXq3k3nz3MaXGrVKTYiJnytAffYtos7mPoeOg==
|
||||
"@bsky.app/expo-translate-text@^0.2.5":
|
||||
version "0.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@bsky.app/expo-translate-text/-/expo-translate-text-0.2.5.tgz#eb0bf41522b710b11e64d14a06d4ec770a72ad20"
|
||||
integrity sha512-nWGxK8bwKN6G7AtN7bvCIyO3Ynbzeg+NDzfGcWh0nEfuP4gKTrFO6QnBMMcZ9r+SzLP3EryqEs0AzeZ56n6Y+A==
|
||||
|
||||
"@bsky.app/react-native-mmkv@2.12.5":
|
||||
version "2.12.5"
|
||||
|
||||
Reference in New Issue
Block a user