Handle more translation errors (#10160)
This commit is contained in:
Vendored
+8
@@ -10,6 +10,10 @@ const iOSMajorVersion =
|
||||
Platform.OS === 'ios' && typeof Platform.Version === 'string'
|
||||
? parseInt(Platform.Version.split('.')[0], 10)
|
||||
: 0
|
||||
const androidPlatformVersion =
|
||||
Platform.OS === 'android' && typeof Platform.Version === 'number'
|
||||
? Platform.Version
|
||||
: 0
|
||||
|
||||
/**
|
||||
* The semver version of the app, specified in our `package.json`.file. On
|
||||
@@ -49,3 +53,7 @@ export const IS_WEB_FIREFOX: boolean = false
|
||||
export const IS_HIGH_DPI: boolean = true
|
||||
// ideally we'd use isLiquidGlassAvailable() from expo-glass-effect but checking iOS version is good enough for now
|
||||
export const IS_LIQUID_GLASS: boolean = iOSMajorVersion >= 26
|
||||
// So we can avoid attempting on-device translation when we know it's unsupported.
|
||||
export const IS_TRANSLATION_SUPPORTED: boolean =
|
||||
(IS_IOS && iOSMajorVersion >= 18) ||
|
||||
(IS_ANDROID && androidPlatformVersion > 22)
|
||||
|
||||
Vendored
+1
@@ -48,3 +48,4 @@ export const IS_HIGH_DPI: boolean = window.matchMedia(
|
||||
'(min-resolution: 2dppx)',
|
||||
).matches
|
||||
export const IS_LIQUID_GLASS: boolean = false
|
||||
export const IS_TRANSLATION_SUPPORTED: boolean = false
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import {useCallback, useContext, useEffect, useMemo, useState} from 'react'
|
||||
import {LayoutAnimation, Platform} from 'react-native'
|
||||
import {getLocales} from 'expo-localization'
|
||||
import {
|
||||
isTranslationSupported,
|
||||
onTranslateTask,
|
||||
} from '@bsky.app/expo-translate-text'
|
||||
import {onTranslateTask} from '@bsky.app/expo-translate-text'
|
||||
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'
|
||||
import {codeToLanguageName} from '#/locale/helpers'
|
||||
import {logger} from '#/logger'
|
||||
import {useLanguagePrefs} from '#/state/preferences'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_ANDROID, IS_IOS} from '#/env'
|
||||
import {IS_ANDROID, IS_IOS, IS_TRANSLATION_SUPPORTED} from '#/env'
|
||||
import {Context} from './context'
|
||||
import {
|
||||
type ContextType,
|
||||
@@ -25,6 +24,11 @@ import {guessLanguage} from './utils'
|
||||
export * from './types'
|
||||
export * from './utils'
|
||||
|
||||
const E_SAME_AS_SOURCE_LANGUAGE =
|
||||
'Translation result is the same as the source text.'
|
||||
const E_EMPTY_RESULT = 'Translation result is empty.'
|
||||
const E_INVALID_SOURCE_LANGUAGE = 'Invalid source language'
|
||||
|
||||
/**
|
||||
* Attempts on-device translation via @bsky.app/expo-translate-text.
|
||||
* Uses a lazy import to avoid crashing if the native module isn't linked into
|
||||
@@ -80,11 +84,11 @@ async function attemptTranslation(
|
||||
typeof result.translatedTexts === 'string' ? result.translatedTexts : ''
|
||||
|
||||
if (translatedText === input) {
|
||||
throw new Error('Translation result is the same as the source text.')
|
||||
throw new Error(E_SAME_AS_SOURCE_LANGUAGE)
|
||||
}
|
||||
|
||||
if (translatedText === '') {
|
||||
throw new Error('Translation result is empty.')
|
||||
throw new Error(E_EMPTY_RESULT)
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -159,6 +163,7 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
||||
>({})
|
||||
const [refCounts, setRefCounts] = useState<Record<string, number>>({})
|
||||
const ax = useAnalytics()
|
||||
const langPrefs = useLanguagePrefs()
|
||||
const {t: l} = useLingui()
|
||||
const googleTranslate = useGoogleTranslate()
|
||||
|
||||
@@ -235,7 +240,7 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
||||
googleTranslate: shouldForceGoogleTranslate,
|
||||
})
|
||||
|
||||
if (shouldForceGoogleTranslate || !isTranslationSupported()) {
|
||||
if (shouldForceGoogleTranslate || !IS_TRANSLATION_SUPPORTED) {
|
||||
await googleTranslate(
|
||||
text,
|
||||
expectedTargetLanguage,
|
||||
@@ -280,7 +285,8 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
||||
postLanguages: possibleSourceLanguages,
|
||||
},
|
||||
}))
|
||||
} catch (e) {
|
||||
} catch (err) {
|
||||
const e = err as Error
|
||||
logger.error('Failed to translate text on device', {safeMessage: e})
|
||||
// On-device translation failed (language pack missing or user
|
||||
// dismissed the download prompt).
|
||||
@@ -295,6 +301,21 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
||||
textLength: text.length,
|
||||
})
|
||||
let errorMessage = l`Device failed to translate :(`
|
||||
if (e.message === E_SAME_AS_SOURCE_LANGUAGE) {
|
||||
errorMessage = l`Translation to the same language is unavailable on your device.`
|
||||
}
|
||||
if (e.message === E_EMPTY_RESULT) {
|
||||
errorMessage = l`No translation received from your device.`
|
||||
}
|
||||
if (
|
||||
expectedSourceLanguage &&
|
||||
e.message.includes(E_INVALID_SOURCE_LANGUAGE)
|
||||
) {
|
||||
errorMessage = l`${codeToLanguageName(
|
||||
expectedSourceLanguage,
|
||||
langPrefs.appLanguage,
|
||||
)} is not supported by your device.`
|
||||
}
|
||||
if (!IS_ANDROID) {
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
|
||||
}
|
||||
@@ -304,7 +325,7 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
||||
}))
|
||||
}
|
||||
},
|
||||
[ax, googleTranslate, l],
|
||||
[ax, googleTranslate, l, langPrefs.appLanguage],
|
||||
)
|
||||
|
||||
const ctx = useMemo(
|
||||
|
||||
Reference in New Issue
Block a user