diff --git a/src/locale/helpers.ts b/src/locale/helpers.ts
index 433dbaec60..8b3bf5f3d8 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 e24fdcf3e1..1c2e126c81 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 0000000000..987d89d360
--- /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,
+ },
+})