diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts index 11204f30907..1381f66b5d4 100644 --- a/src/state/persisted/schema.ts +++ b/src/state/persisted/schema.ts @@ -71,7 +71,7 @@ const schema = z.object({ contentLanguages: z.array(z.string()), /** * The language(s) the user is currently posting in, configured within the - * composer. Multiple languages are psearate by commas. + * composer. Multiple languages are separated by commas. * * BCP-47 2-letter language code without region. */ diff --git a/src/state/preferences/languages.tsx b/src/state/preferences/languages.tsx index 14ba62dba98..5d4336814c3 100644 --- a/src/state/preferences/languages.tsx +++ b/src/state/preferences/languages.tsx @@ -156,6 +156,10 @@ export function toPostLanguages(postLanguage: string): string[] { return postLanguage.split(',').filter(Boolean) } +export function fromPostLanguages(languages: string[]): string { + return languages.filter(Boolean).join(',') +} + export function hasPostLanguage(postLanguage: string, code2: string): boolean { return toPostLanguages(postLanguage).includes(code2) } diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index badb0bb9f96..8cbb2d37baf 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -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( + 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 = ({ <> ) @@ -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({ )} - + void +}) { const {_} = useLingui() const langPrefs = useLanguagePrefs() const setLangPrefs = useLanguagePrefsApi() @@ -27,6 +33,9 @@ export function PostLanguageSelect() { new Set([...langPrefs.postLanguageHistory, langPrefs.postLanguage]), ) + const currentLanguages = + currentLanguagesProp ?? toPostLanguages(langPrefs.postLanguage) + if ( dedupedHistory.length === 1 && dedupedHistory[0] === langPrefs.postLanguage @@ -34,7 +43,10 @@ export function PostLanguageSelect() { return ( <> - + ) } @@ -43,7 +55,9 @@ export function PostLanguageSelect() { <> - {({props}) => } + {({props}) => ( + + )} @@ -56,10 +70,13 @@ export function PostLanguageSelect() { setLangPrefs.setPostLanguage(historyItem)}> + onPress={() => { + setLangPrefs.setPostLanguage(historyItem) + onSelectLanguage?.(historyItem) + }}> {langName} ) @@ -77,17 +94,26 @@ export function PostLanguageSelect() { - + ) } -function LanguageBtn(props: Omit) { +function LanguageBtn( + props: Omit & { + currentLanguages?: string[] + }, +) { const {_} = useLingui() const langPrefs = useLanguagePrefs() const t = useTheme() const postLanguagesPref = toPostLanguages(langPrefs.postLanguage) + const currentLanguages = props.currentLanguages ?? postLanguagesPref return ( - ) - } else { - return null - } + + ) } /**