Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client
117
fork

Configure Feed

Select the types of activity you want to include in your feed.

change translation engine tweak

vs code did some weird auto formatting n that sketches me out

authored by

Daniela Henkel and committed by tangled.org 472772fd 0cdc78b5

+207 -57
+16 -4
src/lib/hooks/useTranslate.ts
··· 1 1 import {useCallback} from 'react' 2 2 import * as IntentLauncher from 'expo-intent-launcher' 3 3 4 - import {getTranslatorLink} from '#/locale/helpers' 4 + import {getTranslatorLink, getTranslatorLinkKagi} from '#/locale/helpers' 5 + import {useTranslationServicePreference} from '#/state/preferences/translation-service-preference' 5 6 import {IS_ANDROID} from '#/env' 6 7 import {useOpenLink} from './useOpenLink' 7 8 8 9 export function useTranslate() { 9 10 const openLink = useOpenLink() 11 + 12 + const translationServicePreference = useTranslationServicePreference() 10 13 11 14 return useCallback( 12 15 async (text: string, language: string) => { 13 - const translateUrl = getTranslatorLink(text, language) 14 - if (IS_ANDROID) { 16 + let translateUrl 17 + 18 + // if ur curious why this isnt a switch case, good question, for some reason making this a switch case breaks the functionality 19 + // it is a mystery https://www.youtube.com/watch?v=fq3abPnEEGE 20 + if (translationServicePreference == 'kagi') { 21 + translateUrl = getTranslatorLinkKagi(text, language) 22 + } else { 23 + translateUrl = getTranslatorLink(text, language) 24 + } 25 + 26 + if (IS_ANDROID && translationServicePreference == 'google') { 15 27 try { 16 28 // use getApplicationIconAsync to determine if the translate app is installed 17 29 if ( ··· 49 61 await openLink(translateUrl) 50 62 } 51 63 }, 52 - [openLink], 64 + [openLink, translationServicePreference], 53 65 ) 54 66 }
+7
src/locale/helpers.ts
··· 127 127 return bcp47Match.basicFilter(lang, targetLangs).length > 0 128 128 } 129 129 130 + // we cant hook into functions like this, so we will make other translator functions n swap between em 130 131 export function getTranslatorLink(text: string, lang: string): string { 131 132 return `https://translate.google.com/?sl=auto&tl=${lang}&text=${encodeURIComponent( 133 + text, 134 + )}` 135 + } 136 + 137 + export function getTranslatorLinkKagi(text: string, lang: string): string { 138 + return `https://translate.kagi.com/?from=auto&to=${lang}&text=${encodeURIComponent( 132 139 text, 133 140 )}` 134 141 }
+24 -5
src/screens/PostThread/components/ThreadItemAnchor.tsx
··· 17 17 import {sanitizeDisplayName} from '#/lib/strings/display-names' 18 18 import {sanitizeHandle} from '#/lib/strings/handles' 19 19 import {niceDate} from '#/lib/strings/time' 20 - import {getTranslatorLink, isPostInLanguage} from '#/locale/helpers' 20 + import { 21 + getTranslatorLink, 22 + getTranslatorLinkKagi, 23 + isPostInLanguage, 24 + } from '#/locale/helpers' 21 25 import { 22 26 POST_TOMBSTONE, 23 27 type Shadow, ··· 31 35 import {useDisableRepostsMetrics} from '#/state/preferences/disable-reposts-metrics' 32 36 import {useDisableSavesMetrics} from '#/state/preferences/disable-saves-metrics' 33 37 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 38 + import {useTranslationServicePreference} from '#/state/preferences/translation-service-preference' 34 39 import {type ThreadItem} from '#/state/queries/usePostThread/types' 35 40 import {useSession} from '#/state/session' 36 41 import {type OnPostSuccessData} from '#/state/shell/composer' ··· 566 571 const isRootPost = !('reply' in post.record) 567 572 const langPrefs = useLanguagePrefs() 568 573 574 + const translationServicePreference = useTranslationServicePreference() 575 + 569 576 const needsTranslation = useMemo( 570 577 () => 571 578 Boolean( ··· 617 624 <InlineLinkText 618 625 // overridden to open an intent on android, but keep 619 626 // as anchor tag for accessibility 620 - to={getTranslatorLink( 621 - post.record.text, 622 - langPrefs.primaryLanguage, 623 - )} 627 + to={ 628 + // in case u want to expand this to allow other services to be u would do this after the kagi one 629 + // : translationServicePreference === "insert service name" 630 + // ? getTranslatorLink(post.record.text, langPrefs.primaryLanguage, "insert service name") 631 + // atm i cant really think of another service that lets u easily do this so its only kagi for now 632 + // the default itll use if its not any of the checks is google!! 633 + translationServicePreference === 'kagi' 634 + ? getTranslatorLinkKagi( 635 + post.record.text, 636 + langPrefs.primaryLanguage, 637 + ) 638 + : getTranslatorLink( 639 + post.record.text, 640 + langPrefs.primaryLanguage, 641 + ) 642 + } 624 643 label={_(msg`Translate`)} 625 644 style={[a.text_sm]} 626 645 onPress={onTranslatePress}>
+43
src/screens/Settings/DeerSettings.tsx
··· 103 103 useSetShowLinkInHandle, 104 104 useShowLinkInHandle, 105 105 } from '#/state/preferences/show-link-in-handle.tsx' 106 + import { 107 + useSetTranslationServicePreference, 108 + useTranslationServicePreference, 109 + } from '#/state/preferences/translation-service-preference' 106 110 import {useProfilesQuery} from '#/state/queries/profile' 107 111 import * as SettingsList from '#/screens/Settings/components/SettingsList' 108 112 import {atoms as a, useBreakpoints} from '#/alf' ··· 113 117 import {Atom_Stroke2_Corner0_Rounded as DeerIcon} from '#/components/icons/Atom' 114 118 import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink' 115 119 import {Eye_Stroke2_Corner0_Rounded as VisibilityIcon} from '#/components/icons/Eye' 120 + import {Earth_Stroke2_Corner2_Rounded as EarthIcon} from '#/components/icons/Globe' 116 121 import {Lab_Stroke2_Corner0_Rounded as _BeakerIcon} from '#/components/icons/Lab' 117 122 import {PaintRoller_Stroke2_Corner2_Rounded as PaintRollerIcon} from '#/components/icons/PaintRoller' 118 123 import {RaisingHand4Finger_Stroke2_Corner0_Rounded as RaisingHandIcon} from '#/components/icons/RaisingHand' ··· 326 331 327 332 const showLinkInHandle = useShowLinkInHandle() 328 333 const setShowLinkInHandle = useSetShowLinkInHandle() 334 + 335 + const translationServicePreference = useTranslationServicePreference() 336 + const setTranslationServicePreference = useSetTranslationServicePreference() 329 337 330 338 return ( 331 339 <Layout.Screen> ··· 614 622 access to features locked behind email verification. 615 623 </Trans> 616 624 </Admonition> 625 + </SettingsList.Group> 626 + 627 + <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 628 + <SettingsList.ItemIcon icon={EarthIcon} /> 629 + <SettingsList.ItemText> 630 + <Trans>Translation Engine</Trans> 631 + </SettingsList.ItemText> 632 + 633 + <Admonition type="info" style={[a.flex_1]}> 634 + <Trans>Choose the engine to use when translating posts.</Trans> 635 + </Admonition> 636 + 637 + <Toggle.Item 638 + name="service_google" 639 + label={_(msg`Use Google Translate`)} 640 + value={translationServicePreference === 'google'} 641 + onChange={() => setTranslationServicePreference('google')} 642 + style={[a.w_full]}> 643 + <Toggle.LabelText style={[a.flex_1]}> 644 + <Trans>Use Google Translate</Trans> 645 + </Toggle.LabelText> 646 + <Toggle.Radio /> 647 + </Toggle.Item> 648 + 649 + <Toggle.Item 650 + name="service_kagi" 651 + label={_(msg`Use Kagi Translate`)} 652 + value={translationServicePreference === 'kagi'} 653 + onChange={() => setTranslationServicePreference('kagi')} 654 + style={[a.w_full]}> 655 + <Toggle.LabelText style={[a.flex_1]}> 656 + <Trans>Use Kagi Translate</Trans> 657 + </Toggle.LabelText> 658 + <Toggle.Radio /> 659 + </Toggle.Item> 617 660 </SettingsList.Group> 618 661 619 662 <SettingsList.Group contentContainerStyle={[a.gap_sm]}>
+3
src/state/persisted/schema.ts
··· 171 171 172 172 showExternalShareButtons: z.boolean().optional(), 173 173 174 + translationServicePreference: z.enum(['google', 'kagi']), 175 + 174 176 /** @deprecated */ 175 177 mutedThreads: z.array(z.string()), 176 178 trendingDisabled: z.boolean().optional(), ··· 279 281 highQualityImages: false, 280 282 hideUnreplyablePosts: false, 281 283 showExternalShareButtons: false, 284 + translationServicePreference: 'google', 282 285 } 283 286 284 287 export function tryParse(rawData: string): Schema | undefined {
+57 -48
src/state/preferences/index.tsx
··· 37 37 import {Provider as RepostCarouselProvider} from './repost-carousel-enabled' 38 38 import {Provider as ShowLinkInHandleProvider} from './show-link-in-handle' 39 39 import {Provider as SubtitlesProvider} from './subtitles' 40 + import {Provider as TranslationServicePreferenceProvider} from './translation-service-preference' 40 41 import {Provider as TrendingSettingsProvider} from './trending' 41 42 import {Provider as UsedStarterPacksProvider} from './used-starter-packs' 42 43 ··· 59 60 export {useLabelDefinitions} from './label-defs' 60 61 export {useLanguagePrefs, useLanguagePrefsApi} from './languages' 61 62 export {useSetSubtitlesEnabled, useSubtitlesEnabled} from './subtitles' 63 + export { 64 + useSetTranslationServicePreference, 65 + useTranslationServicePreference, 66 + } from './translation-service-preference' 62 67 63 68 export function Provider({children}: React.PropsWithChildren<{}>) { 64 69 return ( ··· 66 71 <AltTextRequiredProvider> 67 72 <ExternalShareButtonsProvider> 68 73 <GoLinksProvider> 69 - <NoAppLabelersProvider> 74 + <NoAppLabelersProvider> 70 75 <DirectFetchRecordsProvider> 71 76 <ConstellationProvider> 72 - <ConstellationInstanceProvider> 73 - <DeerVerificationProvider> 74 - <NoDiscoverProvider> 75 - <ShowLinkInHandleProvider> 77 + <ConstellationInstanceProvider> 78 + <DeerVerificationProvider> 79 + <NoDiscoverProvider> 80 + <ShowLinkInHandleProvider> 76 81 <LargeAltBadgeProvider> 77 82 <ExternalEmbedsProvider> 78 83 <HiddenPostsProvider> 79 - <HighQualityImagesProvider> 84 + <HighQualityImagesProvider> 80 85 <InAppBrowserProvider> 81 86 <DisableHapticsProvider> 82 87 <AutoplayProvider> ··· 84 89 <SubtitlesProvider> 85 90 <TrendingSettingsProvider> 86 91 <RepostCarouselProvider> 87 - <KawaiiProvider> 88 - <HideFeedsPromoTabProvider> 89 - <DisableViaRepostNotificationProvider> 90 - <DisableLikesMetricsProvider> 91 - <DisableRepostsMetricsProvider> 92 - <DisableQuotesMetricsProvider> 93 - <DisableSavesMetricsProvider> 94 - <DisableReplyMetricsProvider> 95 - <DisableFollowersMetricsProvider> 96 - <DisableFollowingMetricsProvider> 97 - <DisableFollowedByMetricsProvider> 98 - <DisablePostsMetricsProvider> 99 - <HideSimilarAccountsRecommProvider> 100 - <HideUnreplyablePostsProvider> 101 - <EnableSquareAvatarsProvider> 102 - <EnableSquareButtonsProvider> 103 - <DisableVerifyEmailReminderProvider> 104 - {children} 105 - </DisableVerifyEmailReminderProvider> 106 - </EnableSquareButtonsProvider> 107 - </EnableSquareAvatarsProvider> 108 - </HideUnreplyablePostsProvider> 109 - </HideSimilarAccountsRecommProvider> 110 - </DisablePostsMetricsProvider> 111 - </DisableFollowedByMetricsProvider> 112 - </DisableFollowingMetricsProvider> 113 - </DisableFollowersMetricsProvider> 114 - </DisableReplyMetricsProvider> 115 - </DisableSavesMetricsProvider> 116 - </DisableQuotesMetricsProvider> 117 - </DisableRepostsMetricsProvider> 118 - </DisableLikesMetricsProvider> 119 - </DisableViaRepostNotificationProvider> 120 - </HideFeedsPromoTabProvider> 121 - </KawaiiProvider> 122 - </RepostCarouselProvider> 92 + <KawaiiProvider> 93 + <HideFeedsPromoTabProvider> 94 + <DisableViaRepostNotificationProvider> 95 + <DisableLikesMetricsProvider> 96 + <DisableRepostsMetricsProvider> 97 + <DisableQuotesMetricsProvider> 98 + <DisableSavesMetricsProvider> 99 + <DisableReplyMetricsProvider> 100 + <DisableFollowersMetricsProvider> 101 + <DisableFollowingMetricsProvider> 102 + <DisableFollowedByMetricsProvider> 103 + <DisablePostsMetricsProvider> 104 + <HideSimilarAccountsRecommProvider> 105 + <HideUnreplyablePostsProvider> 106 + <EnableSquareAvatarsProvider> 107 + <EnableSquareButtonsProvider> 108 + <DisableVerifyEmailReminderProvider> 109 + <TranslationServicePreferenceProvider> 110 + { 111 + children 112 + } 113 + </TranslationServicePreferenceProvider> 114 + </DisableVerifyEmailReminderProvider> 115 + </EnableSquareButtonsProvider> 116 + </EnableSquareAvatarsProvider> 117 + </HideUnreplyablePostsProvider> 118 + </HideSimilarAccountsRecommProvider> 119 + </DisablePostsMetricsProvider> 120 + </DisableFollowedByMetricsProvider> 121 + </DisableFollowingMetricsProvider> 122 + </DisableFollowersMetricsProvider> 123 + </DisableReplyMetricsProvider> 124 + </DisableSavesMetricsProvider> 125 + </DisableQuotesMetricsProvider> 126 + </DisableRepostsMetricsProvider> 127 + </DisableLikesMetricsProvider> 128 + </DisableViaRepostNotificationProvider> 129 + </HideFeedsPromoTabProvider> 130 + </KawaiiProvider> 131 + </RepostCarouselProvider> 123 132 </TrendingSettingsProvider> 124 133 </SubtitlesProvider> 125 134 </UsedStarterPacksProvider> 126 135 </AutoplayProvider> 127 136 </DisableHapticsProvider> 128 137 </InAppBrowserProvider> 129 - </HighQualityImagesProvider> 138 + </HighQualityImagesProvider> 130 139 </HiddenPostsProvider> 131 140 </ExternalEmbedsProvider> 132 141 </LargeAltBadgeProvider> 133 - </ShowLinkInHandleProvider> 134 - </NoDiscoverProvider> 135 - </DeerVerificationProvider> 136 - </ConstellationInstanceProvider> 142 + </ShowLinkInHandleProvider> 143 + </NoDiscoverProvider> 144 + </DeerVerificationProvider> 145 + </ConstellationInstanceProvider> 137 146 </ConstellationProvider> 138 147 </DirectFetchRecordsProvider> 139 - </NoAppLabelersProvider> 148 + </NoAppLabelersProvider> 140 149 </GoLinksProvider> 141 150 </ExternalShareButtonsProvider> 142 151 </AltTextRequiredProvider>
+57
src/state/preferences/translation-service-preference.tsx
··· 1 + import React from 'react' 2 + 3 + import * as persisted from '#/state/persisted' 4 + 5 + type StateContext = persisted.Schema['translationServicePreference'] 6 + type SetContext = (v: persisted.Schema['translationServicePreference']) => void 7 + 8 + const stateContext = React.createContext<StateContext>( 9 + persisted.defaults.translationServicePreference, 10 + ) 11 + const setContext = React.createContext<SetContext>( 12 + (_: persisted.Schema['translationServicePreference']) => {}, 13 + ) 14 + 15 + export function Provider({children}: React.PropsWithChildren<{}>) { 16 + const [state, setState] = React.useState( 17 + persisted.get('translationServicePreference'), 18 + ) 19 + 20 + const setStateWrapped = React.useCallback( 21 + ( 22 + translationServicePreference: persisted.Schema['translationServicePreference'], 23 + ) => { 24 + setState(translationServicePreference) 25 + persisted.write( 26 + 'translationServicePreference', 27 + translationServicePreference, 28 + ) 29 + }, 30 + [setState], 31 + ) 32 + 33 + React.useEffect(() => { 34 + return persisted.onUpdate( 35 + 'translationServicePreference', 36 + nextTranslationServicePreference => { 37 + setState(nextTranslationServicePreference) 38 + }, 39 + ) 40 + }, [setStateWrapped]) 41 + 42 + return ( 43 + <stateContext.Provider value={state}> 44 + <setContext.Provider value={setStateWrapped}> 45 + {children} 46 + </setContext.Provider> 47 + </stateContext.Provider> 48 + ) 49 + } 50 + 51 + export function useTranslationServicePreference() { 52 + return React.useContext(stateContext) 53 + } 54 + 55 + export function useSetTranslationServicePreference() { 56 + return React.useContext(setContext) 57 + }