Rename translation properties for clarity (#10061)

This commit is contained in:
Eric Bailey
2026-03-17 13:59:28 -05:00
committed by GitHub
parent b9a3256e51
commit 45df50ec19
12 changed files with 251 additions and 174 deletions
+64 -59
View File
@@ -1,12 +1,14 @@
import {useCallback, useMemo} from 'react'
import {Platform, type StyleProp, type TextStyle, View} from 'react-native'
import {type AppBskyFeedDefs} from '@atproto/api'
import {type AppBskyFeedDefs, AppBskyFeedPost} from '@atproto/api'
import {Trans, useLingui} from '@lingui/react/macro'
import {HITSLOP_30} from '#/lib/constants'
import {useGoogleTranslate} from '#/lib/hooks/useGoogleTranslate'
import {useTranslate} from '#/lib/translation'
import {type TranslationFunction} from '#/lib/translation'
import {
type TranslationFunction,
type TranslationFunctionParams,
} from '#/lib/translation'
import {
codeToLanguageName,
getPostLanguageTags,
@@ -26,26 +28,39 @@ import * as Select from '#/components/Select'
import {Text} from '#/components/Typography'
import {useAnalytics} from '#/analytics'
import {IS_WEB} from '#/env'
import * as bsky from '#/types/bsky'
const X_ICON_OFFSET = 16
export function TranslatedPost({
hideTranslateLink = false,
post,
postText,
postTextStyle = a.text_md,
}: {
hideTranslateLink?: boolean
post: AppBskyFeedDefs.PostView
postText: string
postTextStyle?: StyleProp<TextStyle>
}) {
const langPrefs = useLanguagePrefs()
const {clearTranslation, translate, translationState} = useTranslate({
key: post.uri,
postLangCodes: getPostLanguageTags(post),
})
const record = useMemo<AppBskyFeedPost.Record | undefined>(() => {
return bsky.dangerousIsType<AppBskyFeedPost.Record>(
post.record,
AppBskyFeedPost.isRecord,
)
? post.record
: undefined
}, [post])
const initialTranslationParams = useMemo<TranslationFunctionParams>(() => {
return {
text: record?.text || '',
expectedTargetLanguage: langPrefs.primaryLanguage,
possibleSourceLanguages: getPostLanguageTags(post),
}
}, [post, record, langPrefs])
const needsTranslation = useMemo(() => {
if (hideTranslateLink) return false
return !isPostInLanguage(post, [langPrefs.primaryLanguage])
@@ -57,11 +72,11 @@ export function TranslatedPost({
case 'success':
return (
<TranslationResult
clearTranslation={clearTranslation}
translate={translate}
postText={postText}
clearTranslation={clearTranslation}
initialTranslationParams={initialTranslationParams}
postTextStyle={postTextStyle}
sourceLanguage={
resultSourceLanguage={
translationState.sourceLanguage ?? null // Fallback primarily for iOS
}
translatedText={translationState.translatedText}
@@ -70,19 +85,18 @@ export function TranslatedPost({
case 'error':
return (
<TranslationError
translate={translate}
clearTranslation={clearTranslation}
message={translationState.message}
postText={postText}
primaryLanguage={langPrefs.primaryLanguage}
initialTranslationParams={initialTranslationParams}
/>
)
default:
return (
needsTranslation && (
<TranslationLink
postText={postText}
primaryLanguage={langPrefs.primaryLanguage}
translate={translate}
initialTranslationParams={initialTranslationParams}
/>
)
)
@@ -105,31 +119,18 @@ function TranslationLoading() {
}
function TranslationLink({
postText,
primaryLanguage,
translate,
initialTranslationParams,
}: {
postText: string
primaryLanguage: string
translate: TranslationFunction
initialTranslationParams: TranslationFunctionParams
}) {
const t = useTheme()
const {t: l} = useLingui()
const ax = useAnalytics()
const handleTranslate = useCallback(() => {
void translate({
text: postText,
targetLangCode: primaryLanguage,
})
ax.metric('translate', {
os: Platform.OS,
sourceLanguages: [], // todo: get from post maybe?
targetLanguage: primaryLanguage,
textLength: postText.length,
})
}, [ax, postText, primaryLanguage, translate])
void translate(initialTranslationParams)
}, [initialTranslationParams, translate])
return (
<View
@@ -161,22 +162,24 @@ function TranslationLink({
}
function TranslationError({
translate,
clearTranslation,
message,
postText,
primaryLanguage,
initialTranslationParams,
}: {
translate: TranslationFunction
clearTranslation: () => void
message: string
postText: string
primaryLanguage: string
initialTranslationParams: TranslationFunctionParams
}) {
const t = useTheme()
const {t: l} = useLingui()
const translate = useGoogleTranslate()
const handleFallback = () => {
void translate(postText, primaryLanguage)
void translate({
...initialTranslationParams,
forceGoogleTranslate: true,
})
}
return (
@@ -247,24 +250,24 @@ function TranslationError({
function TranslationResult({
clearTranslation,
translate,
postText,
postTextStyle,
sourceLanguage,
resultSourceLanguage,
translatedText,
initialTranslationParams,
}: {
clearTranslation: () => void
translate: TranslationFunction
postText: string
postTextStyle?: StyleProp<TextStyle>
sourceLanguage: string | null
resultSourceLanguage: string | null
translatedText: string
initialTranslationParams: TranslationFunctionParams
}) {
const t = useTheme()
const langPrefs = useLanguagePrefs()
const {i18n, t: l} = useLingui()
const langName = sourceLanguage
? codeToLanguageName(sourceLanguage, i18n.locale)
const langName = resultSourceLanguage
? codeToLanguageName(resultSourceLanguage, i18n.locale)
: undefined
const flattenedStyle = flatten(postTextStyle) ?? {}
@@ -323,7 +326,7 @@ function TranslationResult({
<Trans>Translated</Trans>
</Text>
)}
{sourceLanguage != null && (
{resultSourceLanguage != null && (
<>
<Text
style={[
@@ -336,9 +339,9 @@ function TranslationResult({
&middot;{' '}
</Text>
<TranslationLanguageSelect
sourceLanguage={sourceLanguage}
resultSourceLanguage={resultSourceLanguage}
translate={translate}
postText={postText}
initialTranslationParams={initialTranslationParams}
/>
</>
)}
@@ -362,12 +365,12 @@ function TranslationResult({
function TranslationLanguageSelect({
translate,
postText,
sourceLanguage,
resultSourceLanguage,
initialTranslationParams,
}: {
translate: TranslationFunction
postText: string
sourceLanguage: string
resultSourceLanguage: string
initialTranslationParams: TranslationFunctionParams
}) {
const t = useTheme()
const ax = useAnalytics()
@@ -383,8 +386,8 @@ function TranslationLanguageSelect({
)
.sort((a, b) => {
// Prioritize sourceLanguage at the top
if (a.code2 === sourceLanguage) return -1
if (b.code2 === sourceLanguage) return 1
if (a.code2 === resultSourceLanguage) return -1
if (b.code2 === resultSourceLanguage) return 1
// Localized sort
return languageName(a, langPrefs.appLanguage).localeCompare(
languageName(b, langPrefs.appLanguage),
@@ -395,26 +398,28 @@ function TranslationLanguageSelect({
label: languageName(l, langPrefs.appLanguage), // The viewer may not be familiar with the source language, so localize the name
value: l.code2,
})),
[langPrefs, sourceLanguage],
[langPrefs, resultSourceLanguage],
)
const handleChangeTranslationLanguage = (sourceLangCode: string) => {
ax.metric('translate:override', {
os: Platform.OS,
sourceLanguage: sourceLangCode,
targetLanguage: langPrefs.primaryLanguage,
possibleSourceLanguages: initialTranslationParams.possibleSourceLanguages,
expectedSourceLanguage: sourceLangCode,
expectedTargetLanguage: initialTranslationParams.expectedTargetLanguage,
resultSourceLanguage,
})
void translate({
text: postText,
targetLangCode: langPrefs.primaryLanguage,
sourceLangCode,
sourceSelection: 'manual',
text: initialTranslationParams.text,
expectedTargetLanguage: initialTranslationParams.expectedTargetLanguage,
expectedSourceLanguage: sourceLangCode,
possibleSourceLanguages: initialTranslationParams.possibleSourceLanguages,
})
}
return (
<Select.Root
value={sourceLanguage}
value={resultSourceLanguage}
onValueChange={handleChangeTranslationLanguage}>
<Select.Trigger label={l`Change the source language`}>
{({props}) => {
@@ -8,7 +8,7 @@ import {
import * as Clipboard from 'expo-clipboard'
import {
type AppBskyFeedDefs,
AppBskyFeedPost,
type AppBskyFeedPost,
type AppBskyFeedThreadgate,
AtUri,
type RichText as RichTextAPI,
@@ -96,7 +96,6 @@ import * as Prompt from '#/components/Prompt'
import * as Toast from '#/components/Toast'
import {useAnalytics} from '#/analytics'
import {IS_INTERNAL} from '#/env'
import * as bsky from '#/types/bsky'
let PostMenuItems = ({
post,
@@ -138,7 +137,6 @@ let PostMenuItems = ({
const openLink = useOpenLink()
const {clearTranslation, translate, translationState} = useTranslate({
key: post.uri,
postLangCodes: getPostLanguageTags(post),
forceGoogleTranslate,
})
const navigation = useNavigation<NavigationProp>()
@@ -279,22 +277,9 @@ let PostMenuItems = ({
const onPressTranslate = () => {
void translate({
text: record.text,
targetLangCode: langPrefs.primaryLanguage,
expectedTargetLanguage: langPrefs.primaryLanguage,
possibleSourceLanguages: getPostLanguageTags(post),
})
if (
bsky.dangerousIsType<AppBskyFeedPost.Record>(
post.record,
AppBskyFeedPost.isRecord,
)
) {
ax.metric('translate', {
os: Platform.OS,
sourceLanguages: post.record.langs ?? [],
targetLanguage: langPrefs.primaryLanguage,
textLength: post.record.text.length,
})
}
}
const onHidePost = () => {
+3 -2
View File
@@ -68,9 +68,10 @@ export let MessageContextMenu = ({
ax.metric('translate', {
os: Platform.OS,
sourceLanguages: [],
targetLanguage: langPrefs.primaryLanguage,
possibleSourceLanguages: [], // N/A for chats
expectedTargetLanguage: langPrefs.primaryLanguage,
textLength: message.text.length,
googleTranslate: true,
})
}, [ax, langPrefs.primaryLanguage, message.text, translate])