import {useEffect, useState} from 'react' import {View} from 'react-native' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import lande from 'lande' import {code3ToCode2Strict, codeToLanguageName} from '#/locale/helpers' import { toPostLanguages, useLanguagePrefs, useLanguagePrefsApi, } from '#/state/preferences/languages' import {atoms as a, useTheme} from '#/alf' import {Button, ButtonText} from '#/components/Button' import {Earth_Stroke2_Corner2_Rounded as EarthIcon} from '#/components/icons/Globe' import {Text} from '#/components/Typography' // fallbacks for safari const onIdle = globalThis.requestIdleCallback || (cb => setTimeout(cb, 1)) const cancelIdle = globalThis.cancelIdleCallback || clearTimeout export function SuggestedLanguage({ text, replyToLanguage, }: { text: string replyToLanguage?: string }) { const [suggestedLanguage, setSuggestedLanguage] = useState< string | undefined >(text.length === 0 ? replyToLanguage : undefined) const langPrefs = useLanguagePrefs() const setLangPrefs = useLanguagePrefsApi() const t = useTheme() const {_} = useLingui() useEffect(() => { // For replies, suggest the language of the post being replied to if no text // has been typed yet if (replyToLanguage && text.length === 0) { setSuggestedLanguage(replyToLanguage) return } const textTrimmed = text.trim() // Don't run the language model on small posts, the results are likely // to be inaccurate anyway. if (textTrimmed.length < 40) { setSuggestedLanguage(undefined) return } const idle = onIdle(() => { setSuggestedLanguage(guessLanguage(textTrimmed)) }) return () => cancelIdle(idle) }, [text, replyToLanguage]) if ( suggestedLanguage && !toPostLanguages(langPrefs.postLanguage).includes(suggestedLanguage) ) { const suggestedLanguageName = codeToLanguageName( suggestedLanguage, langPrefs.appLanguage, ) return ( Are you writing in{' '} {suggestedLanguageName}? ) } else { return null } } /** * This function is using the lande language model to attempt to detect the language * We want to only make suggestions when we feel a high degree of certainty * The magic numbers are based on debugging sessions against some test strings */ function guessLanguage(text: string): string | undefined { const scores = lande(text).filter(([_lang, value]) => value >= 0.0002) // if the model has multiple items with a score higher than 0.0002, it isn't certain enough if (scores.length !== 1) { return undefined } const [lang, value] = scores[0] // if the model doesn't give a score of 0.97 or above, it isn't certain enough if (value < 0.97) { return undefined } return code3ToCode2Strict(lang) }