From 472772fddb35a43bfe2abb81d230578b00545b4a Mon Sep 17 00:00:00 2001 From: Daniela Henkel Date: Sun, 25 Jan 2026 04:15:51 +0100 Subject: [PATCH] change translation engine tweak vs code did some weird auto formatting n that sketches me out --- src/lib/hooks/useTranslate.ts | 20 +++- src/locale/helpers.ts | 7 ++ .../components/ThreadItemAnchor.tsx | 29 ++++- src/screens/Settings/DeerSettings.tsx | 43 +++++++ src/state/persisted/schema.ts | 3 + src/state/preferences/index.tsx | 105 ++++++++++-------- .../translation-service-preference.tsx | 57 ++++++++++ 7 files changed, 207 insertions(+), 57 deletions(-) create mode 100644 src/state/preferences/translation-service-preference.tsx diff --git a/src/lib/hooks/useTranslate.ts b/src/lib/hooks/useTranslate.ts index 822452bb3..945c02183 100644 --- a/src/lib/hooks/useTranslate.ts +++ b/src/lib/hooks/useTranslate.ts @@ -1,17 +1,29 @@ import {useCallback} from 'react' import * as IntentLauncher from 'expo-intent-launcher' -import {getTranslatorLink} from '#/locale/helpers' +import {getTranslatorLink, getTranslatorLinkKagi} from '#/locale/helpers' +import {useTranslationServicePreference} from '#/state/preferences/translation-service-preference' import {IS_ANDROID} from '#/env' import {useOpenLink} from './useOpenLink' export function useTranslate() { const openLink = useOpenLink() + const translationServicePreference = useTranslationServicePreference() + return useCallback( async (text: string, language: string) => { - const translateUrl = getTranslatorLink(text, language) - if (IS_ANDROID) { + let translateUrl + + // if ur curious why this isnt a switch case, good question, for some reason making this a switch case breaks the functionality + // it is a mystery https://www.youtube.com/watch?v=fq3abPnEEGE + if (translationServicePreference == 'kagi') { + translateUrl = getTranslatorLinkKagi(text, language) + } else { + translateUrl = getTranslatorLink(text, language) + } + + if (IS_ANDROID && translationServicePreference == 'google') { try { // use getApplicationIconAsync to determine if the translate app is installed if ( @@ -49,6 +61,6 @@ export function useTranslate() { await openLink(translateUrl) } }, - [openLink], + [openLink, translationServicePreference], ) } diff --git a/src/locale/helpers.ts b/src/locale/helpers.ts index 9c1b669ca..7b2c7186e 100644 --- a/src/locale/helpers.ts +++ b/src/locale/helpers.ts @@ -127,12 +127,19 @@ export function isPostInLanguage( return bcp47Match.basicFilter(lang, targetLangs).length > 0 } +// we cant hook into functions like this, so we will make other translator functions n swap between em export function getTranslatorLink(text: string, lang: string): string { return `https://translate.google.com/?sl=auto&tl=${lang}&text=${encodeURIComponent( text, )}` } +export function getTranslatorLinkKagi(text: string, lang: string): string { + return `https://translate.kagi.com/?from=auto&to=${lang}&text=${encodeURIComponent( + text, + )}` +} + /** * Returns a valid `appLanguage` value from an arbitrary string. * diff --git a/src/screens/PostThread/components/ThreadItemAnchor.tsx b/src/screens/PostThread/components/ThreadItemAnchor.tsx index 3998349d6..983fb889a 100644 --- a/src/screens/PostThread/components/ThreadItemAnchor.tsx +++ b/src/screens/PostThread/components/ThreadItemAnchor.tsx @@ -17,7 +17,11 @@ import {makeProfileLink} from '#/lib/routes/links' import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' import {niceDate} from '#/lib/strings/time' -import {getTranslatorLink, isPostInLanguage} from '#/locale/helpers' +import { + getTranslatorLink, + getTranslatorLinkKagi, + isPostInLanguage, +} from '#/locale/helpers' import { POST_TOMBSTONE, type Shadow, @@ -31,6 +35,7 @@ import {useDisableQuotesMetrics} from '#/state/preferences/disable-quotes-metric import {useDisableRepostsMetrics} from '#/state/preferences/disable-reposts-metrics' import {useDisableSavesMetrics} from '#/state/preferences/disable-saves-metrics' import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' +import {useTranslationServicePreference} from '#/state/preferences/translation-service-preference' import {type ThreadItem} from '#/state/queries/usePostThread/types' import {useSession} from '#/state/session' import {type OnPostSuccessData} from '#/state/shell/composer' @@ -566,6 +571,8 @@ function ExpandedPostDetails({ const isRootPost = !('reply' in post.record) const langPrefs = useLanguagePrefs() + const translationServicePreference = useTranslationServicePreference() + const needsTranslation = useMemo( () => Boolean( @@ -617,10 +624,22 @@ function ExpandedPostDetails({ diff --git a/src/screens/Settings/DeerSettings.tsx b/src/screens/Settings/DeerSettings.tsx index 73855bad9..3ca3c2c65 100644 --- a/src/screens/Settings/DeerSettings.tsx +++ b/src/screens/Settings/DeerSettings.tsx @@ -103,6 +103,10 @@ import { useSetShowLinkInHandle, useShowLinkInHandle, } from '#/state/preferences/show-link-in-handle.tsx' +import { + useSetTranslationServicePreference, + useTranslationServicePreference, +} from '#/state/preferences/translation-service-preference' import {useProfilesQuery} from '#/state/queries/profile' import * as SettingsList from '#/screens/Settings/components/SettingsList' import {atoms as a, useBreakpoints} from '#/alf' @@ -113,6 +117,7 @@ import * as Toggle from '#/components/forms/Toggle' import {Atom_Stroke2_Corner0_Rounded as DeerIcon} from '#/components/icons/Atom' import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink' import {Eye_Stroke2_Corner0_Rounded as VisibilityIcon} from '#/components/icons/Eye' +import {Earth_Stroke2_Corner2_Rounded as EarthIcon} from '#/components/icons/Globe' import {Lab_Stroke2_Corner0_Rounded as _BeakerIcon} from '#/components/icons/Lab' import {PaintRoller_Stroke2_Corner2_Rounded as PaintRollerIcon} from '#/components/icons/PaintRoller' import {RaisingHand4Finger_Stroke2_Corner0_Rounded as RaisingHandIcon} from '#/components/icons/RaisingHand' @@ -327,6 +332,9 @@ export function DeerSettingsScreen({}: Props) { const showLinkInHandle = useShowLinkInHandle() const setShowLinkInHandle = useSetShowLinkInHandle() + const translationServicePreference = useTranslationServicePreference() + const setTranslationServicePreference = useSetTranslationServicePreference() + return ( @@ -616,6 +624,41 @@ export function DeerSettingsScreen({}: Props) { + + + + Translation Engine + + + + Choose the engine to use when translating posts. + + + setTranslationServicePreference('google')} + style={[a.w_full]}> + + Use Google Translate + + + + + setTranslationServicePreference('kagi')} + style={[a.w_full]}> + + Use Kagi Translate + + + + + diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts index 0e7b12b98..41b2c0e23 100644 --- a/src/state/persisted/schema.ts +++ b/src/state/persisted/schema.ts @@ -171,6 +171,8 @@ const schema = z.object({ showExternalShareButtons: z.boolean().optional(), + translationServicePreference: z.enum(['google', 'kagi']), + /** @deprecated */ mutedThreads: z.array(z.string()), trendingDisabled: z.boolean().optional(), @@ -279,6 +281,7 @@ export const defaults: Schema = { highQualityImages: false, hideUnreplyablePosts: false, showExternalShareButtons: false, + translationServicePreference: 'google', } export function tryParse(rawData: string): Schema | undefined { diff --git a/src/state/preferences/index.tsx b/src/state/preferences/index.tsx index 519511d84..218ab99e3 100644 --- a/src/state/preferences/index.tsx +++ b/src/state/preferences/index.tsx @@ -37,6 +37,7 @@ import {Provider as NoDiscoverProvider} from './no-discover-fallback' import {Provider as RepostCarouselProvider} from './repost-carousel-enabled' import {Provider as ShowLinkInHandleProvider} from './show-link-in-handle' import {Provider as SubtitlesProvider} from './subtitles' +import {Provider as TranslationServicePreferenceProvider} from './translation-service-preference' import {Provider as TrendingSettingsProvider} from './trending' import {Provider as UsedStarterPacksProvider} from './used-starter-packs' @@ -59,6 +60,10 @@ export { export {useLabelDefinitions} from './label-defs' export {useLanguagePrefs, useLanguagePrefsApi} from './languages' export {useSetSubtitlesEnabled, useSubtitlesEnabled} from './subtitles' +export { + useSetTranslationServicePreference, + useTranslationServicePreference, +} from './translation-service-preference' export function Provider({children}: React.PropsWithChildren<{}>) { return ( @@ -66,17 +71,17 @@ export function Provider({children}: React.PropsWithChildren<{}>) { - + - - - - + + + + - + @@ -84,59 +89,63 @@ export function Provider({children}: React.PropsWithChildren<{}>) { - - - - - - - - - - - - - - - - - - {children} - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + { + children + } + + + + + + + + + + + + + + + + + + + - + - - - - + + + + - + diff --git a/src/state/preferences/translation-service-preference.tsx b/src/state/preferences/translation-service-preference.tsx new file mode 100644 index 000000000..978dd24cd --- /dev/null +++ b/src/state/preferences/translation-service-preference.tsx @@ -0,0 +1,57 @@ +import React from 'react' + +import * as persisted from '#/state/persisted' + +type StateContext = persisted.Schema['translationServicePreference'] +type SetContext = (v: persisted.Schema['translationServicePreference']) => void + +const stateContext = React.createContext( + persisted.defaults.translationServicePreference, +) +const setContext = React.createContext( + (_: persisted.Schema['translationServicePreference']) => {}, +) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const [state, setState] = React.useState( + persisted.get('translationServicePreference'), + ) + + const setStateWrapped = React.useCallback( + ( + translationServicePreference: persisted.Schema['translationServicePreference'], + ) => { + setState(translationServicePreference) + persisted.write( + 'translationServicePreference', + translationServicePreference, + ) + }, + [setState], + ) + + React.useEffect(() => { + return persisted.onUpdate( + 'translationServicePreference', + nextTranslationServicePreference => { + setState(nextTranslationServicePreference) + }, + ) + }, [setStateWrapped]) + + return ( + + + {children} + + + ) +} + +export function useTranslationServicePreference() { + return React.useContext(stateContext) +} + +export function useSetTranslationServicePreference() { + return React.useContext(setContext) +} -- 2.51.2