From ffce872adbcf368b342a3147bdcfd80b8b460dda Mon Sep 17 00:00:00 2001 From: DS Boyce <260543580+ds-boyce@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:49:13 -0800 Subject: [PATCH] Add error handling with Google Translate link --- package.json | 2 +- src/components/Post/Translated/index.tsx | 80 +++++++++++++++++++++++- src/lib/translation/index.tsx | 18 ++++-- src/lib/translation/types.ts | 4 ++ yarn.lock | 8 +-- 5 files changed, 100 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index f01c01b7af..f4bbe343b6 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/Post/Translated/index.tsx b/src/components/Post/Translated/index.tsx index 049f21178b..ed5f05aa40 100644 --- a/src/components/Post/Translated/index.tsx +++ b/src/components/Post/Translated/index.tsx @@ -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 ( + + ) + } + if (translationState.status === 'loading') { return } @@ -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 ( + + + + + + {' '} + {message} + + + + + + + + + + Try Google Translate + + + + + ) +} + function TranslationResult({ clearTranslation, translate, @@ -213,7 +282,12 @@ function TranslationResult({ )} {sourceLanguage != null && ( <> - + {' '} ·{' '} @@ -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})}> - + Change diff --git a/src/lib/translation/index.tsx b/src/lib/translation/index.tsx index 964c75db15..3f7f2c69b9 100644 --- a/src/lib/translation/index.tsx +++ b/src/lib/translation/index.tsx @@ -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) { >({}) const [refCounts, setRefCounts] = useState>({}) const ax = useAnalytics() + const {t: l} = useLingui() const googleTranslate = useGoogleTranslate() useEffect(() => { @@ -235,12 +243,12 @@ export function Provider({children}: React.PropsWithChildren) { 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) { [key]: {status: 'loading'}, })) }, - [ax, googleTranslate], + [ax, googleTranslate, l], ) const ctx = useMemo( diff --git a/src/lib/translation/types.ts b/src/lib/translation/types.ts index 23eb73ba1e..4bf2d021e7 100644 --- a/src/lib/translation/types.ts +++ b/src/lib/translation/types.ts @@ -9,6 +9,10 @@ export type TranslationState = sourceLanguage: TranslationTaskResult['sourceLanguage'] targetLanguage: TranslationTaskResult['targetLanguage'] } + | { + status: 'error' + message: string + } export type TranslationFunctionParams = { /** diff --git a/yarn.lock b/yarn.lock index 26658a61f9..7cfca5e096 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"