From 95d771b3a559caa4ebd7e800d46c6a003744d92b Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 12 Jan 2024 10:20:17 -0800 Subject: Suggest post language correction (#2486) * feat: suggested language * fix: wording correction * Factor out SuggestedLanguage into a separate component * Tighten the language-suggestion confidence to avoid false positives * Tweak the copy and UI * Add function fallbacks for safari --------- Co-authored-by: Mary --- src/locale/helpers.ts | 8 ++ src/view/com/composer/Composer.tsx | 2 + .../composer/select-language/SuggestedLanguage.tsx | 101 +++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 src/view/com/composer/select-language/SuggestedLanguage.tsx (limited to 'src') diff --git a/src/locale/helpers.ts b/src/locale/helpers.ts index 433dbaec6..8b3bf5f3d 100644 --- a/src/locale/helpers.ts +++ b/src/locale/helpers.ts @@ -22,6 +22,14 @@ export function code3ToCode2(lang: string): string { return lang } +export function code3ToCode2Strict(lang: string): string | undefined { + if (lang.length === 3) { + return LANGUAGES_MAP_CODE3[lang]?.code2 + } + + return undefined +} + export function codeToLanguageName(lang: string): string { const lang2 = code3ToCode2(lang) return LANGUAGES_MAP_CODE2[lang2]?.name || lang diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index e24fdcf3e..1c2e126c8 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -45,6 +45,7 @@ import {Gallery} from './photos/Gallery' import {MAX_GRAPHEME_LENGTH} from 'lib/constants' import {LabelsBtn} from './labels/LabelsBtn' import {SelectLangBtn} from './select-language/SelectLangBtn' +import {SuggestedLanguage} from './select-language/SuggestedLanguage' import {insertMentionAt} from 'lib/strings/mention-manip' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -454,6 +455,7 @@ export const ComposePost = observer(function ComposePost({ ))} ) : null} + {canSelectImages ? ( <> diff --git a/src/view/com/composer/select-language/SuggestedLanguage.tsx b/src/view/com/composer/select-language/SuggestedLanguage.tsx new file mode 100644 index 000000000..987d89d36 --- /dev/null +++ b/src/view/com/composer/select-language/SuggestedLanguage.tsx @@ -0,0 +1,101 @@ +import React, {useEffect, useState} from 'react' +import {StyleSheet, View} from 'react-native' +import lande from 'lande' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {Text} from '../../util/text/Text' +import {Button} from '../../util/forms/Button' +import {code3ToCode2Strict, codeToLanguageName} from '#/locale/helpers' +import { + toPostLanguages, + useLanguagePrefs, + useLanguagePrefsApi, +} from '#/state/preferences/languages' +import {usePalette} from '#/lib/hooks/usePalette' +import {s} from '#/lib/styles' +import { + FontAwesomeIcon, + FontAwesomeIconStyle, +} from '@fortawesome/react-native-fontawesome' + +// fallbacks for safari +const onIdle = globalThis.requestIdleCallback || (cb => setTimeout(cb, 1)) +const cancelIdle = globalThis.cancelIdleCallback || clearTimeout + +export function SuggestedLanguage({text}: {text: string}) { + const [suggestedLanguage, setSuggestedLanguage] = useState() + const langPrefs = useLanguagePrefs() + const setLangPrefs = useLanguagePrefsApi() + const pal = usePalette('default') + const {_} = useLingui() + + useEffect(() => { + 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(() => { + // Only select languages that have a high confidence and convert to code2 + const result = lande(textTrimmed).filter( + ([lang, value]) => value >= 0.97 && code3ToCode2Strict(lang), + ) + + setSuggestedLanguage( + result.length > 0 ? code3ToCode2Strict(result[0][0]) : undefined, + ) + }) + + return () => cancelIdle(idle) + }, [text]) + + return suggestedLanguage && + !toPostLanguages(langPrefs.postLanguage).includes(suggestedLanguage) ? ( + + + + + Are you writing in{' '} + + {codeToLanguageName(suggestedLanguage)} + + ? + + + + + + ) : null +} + +const styles = StyleSheet.create({ + infoBar: { + flexDirection: 'row', + alignItems: 'center', + gap: 10, + borderWidth: 1, + borderRadius: 6, + paddingHorizontal: 16, + paddingVertical: 12, + marginHorizontal: 10, + marginBottom: 10, + }, +}) -- cgit 1.4.1