Files
bsky-social-app/src/view/com/composer/select-language/PostLanguageSelect.tsx
T
Samuel Newman 512ce3d5d0 ALF content language dialog (#9471)
Co-authored-by: Eric Bailey <git@esb.lol>
2026-02-18 08:57:32 -08:00

176 lines
5.4 KiB
TypeScript

import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {LANG_DROPDOWN_HITSLOP} from '#/lib/constants'
import {codeToLanguageName} from '#/locale/helpers'
import {
toPostLanguages,
useLanguagePrefs,
useLanguagePrefsApi,
} from '#/state/preferences/languages'
import {atoms as a, useTheme} from '#/alf'
import {Button, type ButtonProps} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import {LanguageSelectDialog} from '#/components/dialogs/LanguageSelectDialog'
import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRightIcon} from '#/components/icons/Chevron'
import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe'
import * as Menu from '#/components/Menu'
import {Text} from '#/components/Typography'
export function PostLanguageSelect({
currentLanguages: currentLanguagesProp,
onSelectLanguage,
}: {
currentLanguages?: string[]
onSelectLanguage?: (language: string) => void
}) {
const {_} = useLingui()
const langPrefs = useLanguagePrefs()
const setLangPrefs = useLanguagePrefsApi()
const languageDialogControl = Dialog.useDialogControl()
const dedupedHistory = Array.from(
new Set([...langPrefs.postLanguageHistory, langPrefs.postLanguage]),
)
const currentLanguages =
currentLanguagesProp ?? toPostLanguages(langPrefs.postLanguage)
const onSelectLanguages = (languages: string[]) => {
let langsString = languages.join(',')
if (!langsString) {
langsString = langPrefs.primaryLanguage
}
setLangPrefs.setPostLanguage(langsString)
onSelectLanguage?.(langsString)
}
if (
dedupedHistory.length === 1 &&
dedupedHistory[0] === langPrefs.postLanguage
) {
return (
<>
<LanguageBtn onPress={languageDialogControl.open} />
<LanguageSelectDialog
titleText={<Trans>Choose post languages</Trans>}
subtitleText={
<Trans>Select up to 3 languages used in this post</Trans>
}
control={languageDialogControl}
currentLanguages={currentLanguages}
onSelectLanguages={onSelectLanguages}
maxLanguages={3}
/>
</>
)
}
return (
<>
<Menu.Root>
<Menu.Trigger label={_(msg`Select post language`)}>
{({props}) => (
<LanguageBtn currentLanguages={currentLanguages} {...props} />
)}
</Menu.Trigger>
<Menu.Outer>
<Menu.Group>
{dedupedHistory.map(historyItem => {
const langCodes = historyItem.split(',')
const langName = langCodes
.map(code => codeToLanguageName(code, langPrefs.appLanguage))
.join(' + ')
return (
<Menu.Item
key={historyItem}
label={_(msg`Select ${langName}`)}
onPress={() => {
setLangPrefs.setPostLanguage(historyItem)
onSelectLanguage?.(historyItem)
}}>
<Menu.ItemText>{langName}</Menu.ItemText>
<Menu.ItemRadio
selected={currentLanguages.includes(historyItem)}
/>
</Menu.Item>
)
})}
</Menu.Group>
<Menu.Divider />
<Menu.Item
label={_(msg`More languages...`)}
onPress={languageDialogControl.open}>
<Menu.ItemText>
<Trans>More languages...</Trans>
</Menu.ItemText>
<Menu.ItemIcon icon={ChevronRightIcon} />
</Menu.Item>
</Menu.Outer>
</Menu.Root>
<LanguageSelectDialog
titleText={<Trans>Choose post languages</Trans>}
subtitleText={<Trans>Select up to 3 languages used in this post</Trans>}
control={languageDialogControl}
currentLanguages={currentLanguages}
onSelectLanguages={onSelectLanguages}
maxLanguages={3}
/>
</>
)
}
function LanguageBtn(
props: Omit<ButtonProps, 'label' | 'children'> & {
currentLanguages?: string[]
},
) {
const {_} = useLingui()
const langPrefs = useLanguagePrefs()
const t = useTheme()
const postLanguagesPref = toPostLanguages(langPrefs.postLanguage)
const currentLanguages = props.currentLanguages ?? postLanguagesPref
return (
<Button
testID="selectLangBtn"
size="small"
hitSlop={LANG_DROPDOWN_HITSLOP}
label={_(
msg({
message: `Post language selection`,
comment: `Accessibility label for button that opens dialog to choose post language settings`,
}),
)}
accessibilityHint={_(msg`Opens post language settings`)}
style={[a.mr_xs]}
{...props}>
{({pressed, hovered}) => {
const color =
pressed || hovered ? t.palette.primary_300 : t.palette.primary_500
if (currentLanguages.length > 0) {
return (
<Text
style={[
{color},
a.font_semi_bold,
a.text_sm,
a.leading_snug,
{maxWidth: 100},
]}
numberOfLines={1}>
{currentLanguages
.map(lang => codeToLanguageName(lang, langPrefs.appLanguage))
.join(', ')}
</Text>
)
} else {
return <GlobeIcon size="xs" style={{color}} />
}
}}
</Button>
)
}