Pass key as argument to useTranslate hook
This commit is contained in:
@@ -3,7 +3,7 @@ import {Platform, View} from 'react-native'
|
|||||||
import {Trans, useLingui} from '@lingui/react/macro'
|
import {Trans, useLingui} from '@lingui/react/macro'
|
||||||
|
|
||||||
import {HITSLOP_30} from '#/lib/constants'
|
import {HITSLOP_30} from '#/lib/constants'
|
||||||
import {useTranslate, useTranslationKey} from '#/lib/translation'
|
import {useTranslate} from '#/lib/translation'
|
||||||
import {codeToLanguageName, languageName} from '#/locale/helpers'
|
import {codeToLanguageName, languageName} from '#/locale/helpers'
|
||||||
import {LANGUAGES} from '#/locale/languages'
|
import {LANGUAGES} from '#/locale/languages'
|
||||||
import {useLanguagePrefs} from '#/state/preferences'
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
@@ -21,21 +21,19 @@ export function TranslatedPost({
|
|||||||
translationKey: string
|
translationKey: string
|
||||||
postText: string
|
postText: string
|
||||||
}) {
|
}) {
|
||||||
const {translationState} = useTranslate()
|
const {translationState} = useTranslate({key: translationKey})
|
||||||
// Register this component as using this translation key with focus-based cleanup
|
|
||||||
useTranslationKey(translationKey)
|
|
||||||
|
|
||||||
if (translationState[translationKey]?.status === 'loading') {
|
if (translationState.status === 'loading') {
|
||||||
return <TranslationLoading />
|
return <TranslationLoading />
|
||||||
}
|
}
|
||||||
|
|
||||||
if (translationState[translationKey]?.status === 'success') {
|
if (translationState.status === 'success') {
|
||||||
return (
|
return (
|
||||||
<TranslationResult
|
<TranslationResult
|
||||||
translationKey={translationKey}
|
translationKey={translationKey}
|
||||||
postText={postText}
|
postText={postText}
|
||||||
sourceLanguage={translationState[translationKey]?.sourceLanguage}
|
sourceLanguage={translationState.sourceLanguage}
|
||||||
translatedText={translationState[translationKey]?.translatedText}
|
translatedText={translationState.translatedText}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -119,7 +117,7 @@ function TranslationLanguageSelect({
|
|||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const langPrefs = useLanguagePrefs()
|
const langPrefs = useLanguagePrefs()
|
||||||
const {translate} = useTranslate()
|
const {translate} = useTranslate({key: translationKey})
|
||||||
|
|
||||||
const items = useMemo(
|
const items = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@@ -149,7 +147,6 @@ function TranslationLanguageSelect({
|
|||||||
targetLanguage: langPrefs.primaryLanguage,
|
targetLanguage: langPrefs.primaryLanguage,
|
||||||
})
|
})
|
||||||
void translate({
|
void translate({
|
||||||
key: translationKey,
|
|
||||||
text: postText,
|
text: postText,
|
||||||
targetLangCode: langPrefs.primaryLanguage,
|
targetLangCode: langPrefs.primaryLanguage,
|
||||||
sourceLangCode,
|
sourceLangCode,
|
||||||
|
|||||||
@@ -135,7 +135,9 @@ let PostMenuItems = ({
|
|||||||
const {hidePost} = useHiddenPostsApi()
|
const {hidePost} = useHiddenPostsApi()
|
||||||
const feedFeedback = useFeedFeedbackContext()
|
const feedFeedback = useFeedFeedbackContext()
|
||||||
const openLink = useOpenLink()
|
const openLink = useOpenLink()
|
||||||
const {clearTranslation, translate, translationState} = useTranslate()
|
const {clearTranslation, translate, translationState} = useTranslate({
|
||||||
|
key: post.uri,
|
||||||
|
})
|
||||||
const navigation = useNavigation<NavigationProp>()
|
const navigation = useNavigation<NavigationProp>()
|
||||||
const {mutedWordsDialogControl} = useGlobalDialogsControlContext()
|
const {mutedWordsDialogControl} = useGlobalDialogsControlContext()
|
||||||
const blockPromptControl = useDialogControl()
|
const blockPromptControl = useDialogControl()
|
||||||
@@ -190,8 +192,6 @@ let PostMenuItems = ({
|
|||||||
return makeProfileLink(postAuthor, 'post', urip.rkey)
|
return makeProfileLink(postAuthor, 'post', urip.rkey)
|
||||||
}, [postUri, postAuthor])
|
}, [postUri, postAuthor])
|
||||||
|
|
||||||
const translationKey = post.uri
|
|
||||||
|
|
||||||
const onDeletePost = () => {
|
const onDeletePost = () => {
|
||||||
deletePostMutate({uri: postUri}).then(
|
deletePostMutate({uri: postUri}).then(
|
||||||
() => {
|
() => {
|
||||||
@@ -259,7 +259,6 @@ let PostMenuItems = ({
|
|||||||
|
|
||||||
const onPressTranslate = () => {
|
const onPressTranslate = () => {
|
||||||
void translate({
|
void translate({
|
||||||
key: translationKey,
|
|
||||||
text: record.text,
|
text: record.text,
|
||||||
targetLangCode: langPrefs.primaryLanguage,
|
targetLangCode: langPrefs.primaryLanguage,
|
||||||
forceGoogleTranslate,
|
forceGoogleTranslate,
|
||||||
@@ -465,7 +464,7 @@ let PostMenuItems = ({
|
|||||||
|
|
||||||
const onSignIn = () => requireSignIn(() => {})
|
const onSignIn = () => requireSignIn(() => {})
|
||||||
|
|
||||||
const onPressHideTranslation = () => clearTranslation(translationKey)
|
const onPressHideTranslation = () => clearTranslation()
|
||||||
|
|
||||||
const isDiscoverDebugUser =
|
const isDiscoverDebugUser =
|
||||||
IS_INTERNAL ||
|
IS_INTERNAL ||
|
||||||
@@ -501,7 +500,7 @@ let PostMenuItems = ({
|
|||||||
<Menu.Group>
|
<Menu.Group>
|
||||||
{!hideInPWI || hasSession ? (
|
{!hideInPWI || hasSession ? (
|
||||||
<>
|
<>
|
||||||
{translationState[translationKey]?.status === 'loading' ? (
|
{translationState.status === 'loading' ? (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
testID="postDropdownTranslateBtn"
|
testID="postDropdownTranslateBtn"
|
||||||
label={l`Translating…`}
|
label={l`Translating…`}
|
||||||
@@ -509,7 +508,7 @@ let PostMenuItems = ({
|
|||||||
<Menu.ItemText>{l`Translating…`}</Menu.ItemText>
|
<Menu.ItemText>{l`Translating…`}</Menu.ItemText>
|
||||||
<Menu.ItemIcon icon={Translate} position="right" />
|
<Menu.ItemIcon icon={Translate} position="right" />
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
) : translationState[translationKey]?.status === 'success' ? (
|
) : translationState.status === 'success' ? (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
testID="postDropdownTranslateBtn"
|
testID="postDropdownTranslateBtn"
|
||||||
label={l`Hide translation`}
|
label={l`Hide translation`}
|
||||||
|
|||||||
@@ -6,8 +6,17 @@ export const Context = createContext<{
|
|||||||
translationState: Record<string, TranslationState>
|
translationState: Record<string, TranslationState>
|
||||||
translate: (parameters: {
|
translate: (parameters: {
|
||||||
key: string
|
key: string
|
||||||
|
/**
|
||||||
|
* The text to be translated.
|
||||||
|
*/
|
||||||
text: string
|
text: string
|
||||||
|
/**
|
||||||
|
* The language to translate the text into.
|
||||||
|
*/
|
||||||
targetLangCode: string
|
targetLangCode: string
|
||||||
|
/**
|
||||||
|
* The source language of the text. Will auto-detect if not provided.
|
||||||
|
*/
|
||||||
sourceLangCode?: string
|
sourceLangCode?: string
|
||||||
/**
|
/**
|
||||||
* Whether to force the use of Google Translate. Default is false.
|
* Whether to force the use of Google Translate. Default is false.
|
||||||
|
|||||||
@@ -77,31 +77,46 @@ async function attemptTranslation(
|
|||||||
*
|
*
|
||||||
* Web uses index.web.ts which always opens Google Translate.
|
* Web uses index.web.ts which always opens Google Translate.
|
||||||
*/
|
*/
|
||||||
export function useTranslate() {
|
export function useTranslate({key}: {key: string}) {
|
||||||
const context = useContext(Context)
|
const context = useContext(Context)
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'useTranslate must be used within a TranslateOnDeviceProvider',
|
'useTranslate must be used within a TranslateOnDeviceProvider',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return context
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook to register a component as using a translation key.
|
|
||||||
* Automatically handles ref counting with screen focus management
|
|
||||||
* via useFocusEffect and cleans up the translation when the component
|
|
||||||
* loses focus.
|
|
||||||
*/
|
|
||||||
export function useTranslationKey(key: string) {
|
|
||||||
const {acquireTranslation} = useTranslate()
|
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
const cleanup = acquireTranslation(key)
|
if (!key) return
|
||||||
|
const cleanup = context.acquireTranslation(key)
|
||||||
return cleanup
|
return cleanup
|
||||||
}, [key, acquireTranslation]),
|
}, [key, context]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const translate = useCallback(
|
||||||
|
async (params: {
|
||||||
|
text: string
|
||||||
|
targetLangCode: string
|
||||||
|
sourceLangCode?: string
|
||||||
|
forceGoogleTranslate?: boolean
|
||||||
|
}) => {
|
||||||
|
return context.translate({...params, key})
|
||||||
|
},
|
||||||
|
[key, context],
|
||||||
|
)
|
||||||
|
|
||||||
|
const clearTranslation = useCallback(
|
||||||
|
() => context.clearTranslation(key),
|
||||||
|
[key, context],
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
translationState: context.translationState[key] ?? {
|
||||||
|
status: 'idle',
|
||||||
|
},
|
||||||
|
translate,
|
||||||
|
clearTranslation,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Provider({children}: React.PropsWithChildren<unknown>) {
|
export function Provider({children}: React.PropsWithChildren<unknown>) {
|
||||||
@@ -184,7 +199,6 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
|||||||
await googleTranslate(text, targetLangCode, sourceLangCode)
|
await googleTranslate(text, targetLangCode, sourceLangCode)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
|
|
||||||
setTranslationState(prev => ({
|
setTranslationState(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[key]: {status: 'loading'},
|
[key]: {status: 'loading'},
|
||||||
|
|||||||
@@ -11,18 +11,54 @@ const acquireTranslation = (_key: string) => {
|
|||||||
}
|
}
|
||||||
const clearTranslation = (_key: string) => {}
|
const clearTranslation = (_key: string) => {}
|
||||||
|
|
||||||
export function useTranslationKey(_key: string) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Web always opens Google Translate.
|
* Web always opens Google Translate.
|
||||||
*/
|
*/
|
||||||
export function useTranslate() {
|
export function useTranslate(key: string) {
|
||||||
const context = useContext(Context)
|
const context = useContext(Context)
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'useTranslate must be used within a TranslateOnDeviceProvider',
|
'useTranslate must be used within a TranslateOnDeviceProvider',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always call hooks in consistent order
|
||||||
|
const translate = useCallback(
|
||||||
|
async (params: {
|
||||||
|
text: string
|
||||||
|
targetLangCode: string
|
||||||
|
sourceLangCode?: string
|
||||||
|
}) => {
|
||||||
|
if (!key) {
|
||||||
|
throw new Error(
|
||||||
|
'translate requires a key. Either pass key to useTranslate() or use context.translate() with key parameter',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return context.translate({...params, key})
|
||||||
|
},
|
||||||
|
[key, context],
|
||||||
|
)
|
||||||
|
|
||||||
|
const clearTranslation = useCallback(() => {
|
||||||
|
if (!key) {
|
||||||
|
throw new Error(
|
||||||
|
'clearTranslation requires a key. Either pass key to useTranslate() or use context.clearTranslation() with key parameter',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return context.clearTranslation(key)
|
||||||
|
}, [key, context])
|
||||||
|
|
||||||
|
// If a key is provided, return wrapped versions that automatically use the key
|
||||||
|
if (key) {
|
||||||
|
return {
|
||||||
|
translationState: context.translationState[key] ?? {
|
||||||
|
status: 'idle' as const,
|
||||||
|
},
|
||||||
|
translate,
|
||||||
|
clearTranslation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user