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'
|
Platform.OS === 'ios' && typeof Platform.Version === 'string'
|
||||||
? parseInt(Platform.Version.split('.')[0], 10)
|
? parseInt(Platform.Version.split('.')[0], 10)
|
||||||
: 0
|
: 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
|
* 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
|
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
|
// 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
|
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)',
|
'(min-resolution: 2dppx)',
|
||||||
).matches
|
).matches
|
||||||
export const IS_LIQUID_GLASS: boolean = false
|
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 {useCallback, useContext, useEffect, useMemo, useState} from 'react'
|
||||||
import {LayoutAnimation, Platform} from 'react-native'
|
import {LayoutAnimation, Platform} from 'react-native'
|
||||||
import {getLocales} from 'expo-localization'
|
import {getLocales} from 'expo-localization'
|
||||||
import {
|
import {onTranslateTask} from '@bsky.app/expo-translate-text'
|
||||||
isTranslationSupported,
|
|
||||||
onTranslateTask,
|
|
||||||
} from '@bsky.app/expo-translate-text'
|
|
||||||
import {type TranslationTaskResult} from '@bsky.app/expo-translate-text/build/ExpoTranslateText.types'
|
import {type TranslationTaskResult} from '@bsky.app/expo-translate-text/build/ExpoTranslateText.types'
|
||||||
import {useLingui} from '@lingui/react/macro'
|
import {useLingui} from '@lingui/react/macro'
|
||||||
import {useFocusEffect} from '@react-navigation/native'
|
import {useFocusEffect} from '@react-navigation/native'
|
||||||
|
|
||||||
import {useGoogleTranslate} from '#/lib/hooks/useGoogleTranslate'
|
import {useGoogleTranslate} from '#/lib/hooks/useGoogleTranslate'
|
||||||
|
import {codeToLanguageName} from '#/locale/helpers'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
import {useAnalytics} from '#/analytics'
|
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 {Context} from './context'
|
||||||
import {
|
import {
|
||||||
type ContextType,
|
type ContextType,
|
||||||
@@ -25,6 +24,11 @@ import {guessLanguage} from './utils'
|
|||||||
export * from './types'
|
export * from './types'
|
||||||
export * from './utils'
|
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.
|
* 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
|
* 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 : ''
|
typeof result.translatedTexts === 'string' ? result.translatedTexts : ''
|
||||||
|
|
||||||
if (translatedText === input) {
|
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 === '') {
|
if (translatedText === '') {
|
||||||
throw new Error('Translation result is empty.')
|
throw new Error(E_EMPTY_RESULT)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -159,6 +163,7 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
|||||||
>({})
|
>({})
|
||||||
const [refCounts, setRefCounts] = useState<Record<string, number>>({})
|
const [refCounts, setRefCounts] = useState<Record<string, number>>({})
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
|
const langPrefs = useLanguagePrefs()
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const googleTranslate = useGoogleTranslate()
|
const googleTranslate = useGoogleTranslate()
|
||||||
|
|
||||||
@@ -235,7 +240,7 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
|||||||
googleTranslate: shouldForceGoogleTranslate,
|
googleTranslate: shouldForceGoogleTranslate,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (shouldForceGoogleTranslate || !isTranslationSupported()) {
|
if (shouldForceGoogleTranslate || !IS_TRANSLATION_SUPPORTED) {
|
||||||
await googleTranslate(
|
await googleTranslate(
|
||||||
text,
|
text,
|
||||||
expectedTargetLanguage,
|
expectedTargetLanguage,
|
||||||
@@ -280,7 +285,8 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
|||||||
postLanguages: possibleSourceLanguages,
|
postLanguages: possibleSourceLanguages,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
|
const e = err as Error
|
||||||
logger.error('Failed to translate text on device', {safeMessage: e})
|
logger.error('Failed to translate text on device', {safeMessage: e})
|
||||||
// On-device translation failed (language pack missing or user
|
// On-device translation failed (language pack missing or user
|
||||||
// dismissed the download prompt).
|
// dismissed the download prompt).
|
||||||
@@ -295,6 +301,21 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
|||||||
textLength: text.length,
|
textLength: text.length,
|
||||||
})
|
})
|
||||||
let errorMessage = l`Device failed to translate :(`
|
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) {
|
if (!IS_ANDROID) {
|
||||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
|
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(
|
const ctx = useMemo(
|
||||||
|
|||||||
Reference in New Issue
Block a user