Language selection and suggestion UX improvements (#9067)

* feat: don't retain accepted language suggestion after finishing or exiting post (#8886)

* feat: don't retain accepted language suggestion after finishing or exiting post

* fix: rebase fixes

* fix: rebase fixes

* chore: lint

* Rename onChange for clarity

* Improve logic in composer

* Handle user override more explicitly

* Drill in onSelectLanguage callback into dialog too

* Fix typo

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Make text crystal clear

* Handle multiple languages

---------

Co-authored-by: Elijah Seed-Arita <elijaharita@gmail.com>
Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
This commit is contained in:
Eric Bailey
2025-10-02 09:18:52 -05:00
committed by GitHub
parent 5fd52b3d30
commit 02b189a40e
6 changed files with 241 additions and 63 deletions
+55 -6
View File
@@ -88,6 +88,7 @@ import {
import {useModalControls} from '#/state/modals'
import {useRequireAltTextEnabled} from '#/state/preferences'
import {
fromPostLanguages,
toPostLanguages,
useLanguagePrefs,
useLanguagePrefsApi,
@@ -197,6 +198,44 @@ export const ComposePost = ({
const [publishingStage, setPublishingStage] = useState('')
const [error, setError] = useState('')
/**
* A temporary local reference to a language suggestion that the user has
* accepted. This overrides the global post language preference, but is not
* stored permanently.
*/
const [acceptedLanguageSuggestion, setAcceptedLanguageSuggestion] = useState<
string | null
>(null)
/**
* The language(s) of the post being replied to.
*/
const [replyToLanguages, setReplyToLanguages] = useState<string[]>(
replyTo?.langs || [],
)
/**
* The currently selected languages of the post. Prefer local temporary
* language suggestion over global lang prefs, if available.
*/
const currentLanguages = useMemo(
() =>
acceptedLanguageSuggestion
? [acceptedLanguageSuggestion]
: toPostLanguages(langPrefs.postLanguage),
[acceptedLanguageSuggestion, langPrefs.postLanguage],
)
/**
* When the user selects a language from the composer language selector,
* clear any temporary language suggestions they may have selected
* previously, and any we might try to suggest to them.
*/
const onSelectLanguage = () => {
setAcceptedLanguageSuggestion(null)
setReplyToLanguages([])
}
const [composerState, composerDispatch] = useReducer(
composerReducer,
{
@@ -414,7 +453,7 @@ export const ComposePost = ({
thread,
replyTo: replyTo?.uri,
onStateChange: setPublishingStage,
langs: toPostLanguages(langPrefs.postLanguage),
langs: currentLanguages,
})
).uris[0]
@@ -490,7 +529,7 @@ export const ComposePost = ({
isPartOfThread: thread.posts.length > 1,
hasLink: !!post.embed.link,
hasQuote: !!post.embed.quote,
langs: langPrefs.postLanguage,
langs: fromPostLanguages(currentLanguages),
logContext: 'Composer',
})
index++
@@ -557,7 +596,7 @@ export const ComposePost = ({
thread,
canPost,
isPublishing,
langPrefs.postLanguage,
currentLanguages,
onClose,
onPost,
onPostSuccess,
@@ -654,8 +693,9 @@ export const ComposePost = ({
<>
<SuggestedLanguage
text={activePost.richtext.text}
// NOTE(@elijaharita): currently just choosing the first language if any exists
replyToLanguage={replyTo?.langs?.[0]}
replyToLanguages={replyToLanguages}
currentLanguages={currentLanguages}
onAcceptSuggestedLanguage={setAcceptedLanguageSuggestion}
/>
<ComposerPills
isReply={!!replyTo}
@@ -678,6 +718,8 @@ export const ComposePost = ({
type: 'add_post',
})
}}
currentLanguages={currentLanguages}
onSelectLanguage={onSelectLanguage}
/>
</>
)
@@ -1289,6 +1331,8 @@ function ComposerFooter({
onEmojiButtonPress,
onSelectVideo,
onAddPost,
currentLanguages,
onSelectLanguage,
}: {
post: PostDraft
dispatch: (action: PostAction) => void
@@ -1297,6 +1341,8 @@ function ComposerFooter({
onError: (error: string) => void
onSelectVideo: (postId: string, asset: ImagePickerAsset) => void
onAddPost: () => void
currentLanguages: string[]
onSelectLanguage?: (language: string) => void
}) {
const t = useTheme()
const {_} = useLingui()
@@ -1450,7 +1496,10 @@ function ComposerFooter({
<PlusIcon size="lg" />
</Button>
)}
<PostLanguageSelect />
<PostLanguageSelect
currentLanguages={currentLanguages}
onSelectLanguage={onSelectLanguage}
/>
<CharProgress
count={post.shortenedGraphemeLength}
style={{width: 65}}