run codemod on every file

This commit is contained in:
Samuel Newman
2026-07-24 13:58:08 +03:00
parent 82c505f286
commit 91a87536de
289 changed files with 2468 additions and 3422 deletions
@@ -9,8 +9,7 @@ import {
} from 'react' } from 'react'
import {Dimensions, View} from 'react-native' import {Dimensions, View} from 'react-native'
import * as Linking from 'expo-linking' import * as Linking from 'expo-linking'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {retry} from '#/lib/async/retry' import {retry} from '#/lib/async/retry'
@@ -132,7 +131,7 @@ export function Provider({children}: {children?: React.ReactNode}) {
export function RedirectOverlay() { export function RedirectOverlay() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {isOpen} = useRedirectOverlayContext() const {isOpen} = useRedirectOverlayContext()
const {gtMobile} = useBreakpoints() const {gtMobile} = useBreakpoints()
@@ -162,7 +161,7 @@ export function RedirectOverlay() {
<View <View
role="dialog" role="dialog"
aria-role="dialog" aria-role="dialog"
aria-label={_(msg`Verifying your age assurance status`)}> aria-label={l`Verifying your age assurance status`}>
<View style={[a.pb_3xl, {width: 300}]}> <View style={[a.pb_3xl, {width: 300}]}>
<Inner /> <Inner />
</View> </View>
@@ -175,7 +174,7 @@ export function RedirectOverlay() {
function Inner() { function Inner() {
const t = useTheme() const t = useTheme()
const ax = useAnalytics() const ax = useAnalytics()
const {_} = useLingui() const {t: l} = useLingui()
const agent = useAgent() const agent = useAgent()
const polling = useRef(false) const polling = useRef(false)
const unmounted = useRef(false) const unmounted = useRef(false)
@@ -262,7 +261,7 @@ function Inner() {
<View style={[a.w_full, a.pt_lg]}> <View style={[a.w_full, a.pt_lg]}>
<Button <Button
label={_(msg`Close`)} label={l`Close`}
size="large" size="large"
variant="solid" variant="solid"
color="secondary" color="secondary"
@@ -318,7 +317,7 @@ function Inner() {
{error && ( {error && (
<View style={[a.w_full, a.pt_lg]}> <View style={[a.w_full, a.pt_lg]}>
<Button <Button
label={_(msg`Close`)} label={l`Close`}
size="large" size="large"
variant="solid" variant="solid"
color="secondary" color="secondary"
+1 -1
View File
@@ -83,7 +83,7 @@ function createLogger(
warn: logger.warn.bind(logger), warn: logger.warn.bind(logger),
error: logger.error.bind(logger), error: logger.error.bind(logger),
useChild: (context: Exclude<Logger['context'], undefined>) => { useChild: (context: Exclude<Logger['context'], undefined>) => {
return useMemo(() => createLogger(context, metadata), [context, metadata]) return useMemo(() => createLogger(context, metadata), [context])
}, },
Context: Logger.Context, Context: Logger.Context,
} }
+6 -7
View File
@@ -1,8 +1,7 @@
import {Fragment, useCallback} from 'react' import {Fragment, useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {type AppBskyActorDefs} from '@atproto/api' import {type AppBskyActorDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {isJwtExpired} from '#/lib/jwt' import {isJwtExpired} from '#/lib/jwt'
@@ -33,7 +32,7 @@ export function AccountList({
}) { }) {
const {currentAccount, accounts} = useSession() const {currentAccount, accounts} = useSession()
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {data: profiles} = useProfilesQuery({ const {data: profiles} = useProfilesQuery({
handles: accounts.map(acc => acc.did), handles: accounts.map(acc => acc.did),
}) })
@@ -67,7 +66,7 @@ export function AccountList({
testID="chooseAddAccountBtn" testID="chooseAddAccountBtn"
style={[a.flex_1]} style={[a.flex_1]}
onPress={pendingDid ? undefined : onPressAddAccount} onPress={pendingDid ? undefined : onPressAddAccount}
label={_(msg`Sign in to account that is not listed`)}> label={l`Sign in to account that is not listed`}>
{({hovered, pressed}) => ( {({hovered, pressed}) => (
<View <View
style={[ style={[
@@ -114,7 +113,7 @@ function AccountItem({
isPendingAccount: boolean isPendingAccount: boolean
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {isActive: live} = useActorStatus(profile) const {isActive: live} = useActorStatus(profile)
const onPress = useCallback(() => { const onPress = useCallback(() => {
@@ -131,8 +130,8 @@ function AccountItem({
onPress={onPress} onPress={onPress}
label={ label={
isCurrentAccount isCurrentAccount
? _(msg`Continue as ${account.handle} (currently signed in)`) ? l`Continue as ${account.handle} (currently signed in)`
: _(msg`Sign in as ${account.handle}`) : l`Sign in as ${account.handle}`
}> }>
{({hovered, pressed}) => ( {({hovered, pressed}) => (
<View <View
+5 -6
View File
@@ -1,6 +1,5 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {sanitizeAppLanguageSetting} from '#/locale/helpers' import {sanitizeAppLanguageSetting} from '#/locale/helpers'
@@ -14,7 +13,7 @@ import {Earth_Stroke2_Corner2_Rounded as EarthIcon} from './icons/Globe'
export function AppLanguageDropdown() { export function AppLanguageDropdown() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const langPrefs = useLanguagePrefs() const langPrefs = useLanguagePrefs()
@@ -38,7 +37,7 @@ export function AppLanguageDropdown() {
<Select.Root <Select.Root
value={sanitizeAppLanguageSetting(langPrefs.appLanguage)} value={sanitizeAppLanguageSetting(langPrefs.appLanguage)}
onValueChange={onChangeAppLanguage}> onValueChange={onChangeAppLanguage}>
<Select.Trigger label={_(msg`Change app language`)}> <Select.Trigger label={l`Change app language`}>
{({props}) => ( {({props}) => (
<Button <Button
{...props} {...props}
@@ -60,7 +59,7 @@ export function AppLanguageDropdown() {
]}> ]}>
<ButtonIcon icon={EarthIcon} size="md" /> <ButtonIcon icon={EarthIcon} size="md" />
<Select.ValueText <Select.ValueText
placeholder={_(msg`Select an app language`)} placeholder={l`Select an app language`}
style={[t.atoms.text_contrast_medium]} style={[t.atoms.text_contrast_medium]}
/> />
<Select.Icon style={[t.atoms.text_contrast_medium]} /> <Select.Icon style={[t.atoms.text_contrast_medium]} />
@@ -68,7 +67,7 @@ export function AppLanguageDropdown() {
)} )}
</Select.Trigger> </Select.Trigger>
<Select.Content <Select.Content
label={_(msg`Select language`)} label={l`Select language`}
renderItem={({label, value}) => ( renderItem={({label, value}) => (
<Select.Item value={value} label={label} style={web([a.pointer])}> <Select.Item value={value} label={label} style={web([a.pointer])}>
<Select.ItemIndicator /> <Select.ItemIndicator />
+7 -8
View File
@@ -7,8 +7,7 @@ import Animated, {
useAnimatedStyle, useAnimatedStyle,
} from 'react-native-reanimated' } from 'react-native-reanimated'
import {BlurView} from 'expo-blur' import {BlurView} from 'expo-blur'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {useContextMenuContext} from './context' import {useContextMenuContext} from './context'
@@ -32,7 +31,7 @@ export function Backdrop(props: Props) {
} }
function BlurredBackdrop({animation, intensity = 50, onPress}: Props) { function BlurredBackdrop({animation, intensity = 50, onPress}: Props) {
const {_} = useLingui() const {t: l} = useLingui()
const animatedProps = useAnimatedProps(() => ({ const animatedProps = useAnimatedProps(() => ({
intensity: interpolate( intensity: interpolate(
@@ -50,8 +49,8 @@ function BlurredBackdrop({animation, intensity = 50, onPress}: Props) {
tint="systemMaterialDark"> tint="systemMaterialDark">
<Pressable <Pressable
style={a.flex_1} style={a.flex_1}
accessibilityLabel={_(msg`Close menu`)} accessibilityLabel={l`Close menu`}
accessibilityHint={_(msg`Tap to close context menu`)} accessibilityHint={l`Tap to close context menu`}
onPress={onPress} onPress={onPress}
/> />
</AnimatedBlurView> </AnimatedBlurView>
@@ -60,7 +59,7 @@ function BlurredBackdrop({animation, intensity = 50, onPress}: Props) {
function OpacityBackdrop({animation, onPress}: Props) { function OpacityBackdrop({animation, onPress}: Props) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const animatedStyle = useAnimatedStyle(() => ({ const animatedStyle = useAnimatedStyle(() => ({
opacity: interpolate( opacity: interpolate(
@@ -76,8 +75,8 @@ function OpacityBackdrop({animation, onPress}: Props) {
style={[a.absolute, a.inset_0, t.atoms.bg_contrast_975, animatedStyle]}> style={[a.absolute, a.inset_0, t.atoms.bg_contrast_975, animatedStyle]}>
<Pressable <Pressable
style={a.flex_1} style={a.flex_1}
accessibilityLabel={_(msg`Close menu`)} accessibilityLabel={l`Close menu`}
accessibilityHint={_(msg`Tap to close context menu`)} accessibilityHint={l`Tap to close context menu`}
onPress={onPress} onPress={onPress}
/> />
</Animated.View> </Animated.View>
+4 -5
View File
@@ -5,8 +5,7 @@ import Animated, {
type SharedValue, type SharedValue,
useAnimatedStyle, useAnimatedStyle,
} from 'react-native-reanimated' } from 'react-native-reanimated'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {useContextMenuContext} from './context' import {useContextMenuContext} from './context'
@@ -21,7 +20,7 @@ export function Backdrop({
onPress?: () => void onPress?: () => void
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {mode} = useContextMenuContext() const {mode} = useContextMenuContext()
const reduced = mode === 'auxiliary-only' const reduced = mode === 'auxiliary-only'
@@ -42,8 +41,8 @@ export function Backdrop({
style={[a.absolute, a.inset_0, t.atoms.bg_contrast_975, animatedStyle]}> style={[a.absolute, a.inset_0, t.atoms.bg_contrast_975, animatedStyle]}>
<Pressable <Pressable
style={a.flex_1} style={a.flex_1}
accessibilityLabel={_(msg`Close menu`)} accessibilityLabel={l`Close menu`}
accessibilityHint={_(msg`Tap to close context menu`)} accessibilityHint={l`Tap to close context menu`}
onPress={onPress} onPress={onPress}
/> />
</Animated.View> </Animated.View>
+3 -4
View File
@@ -45,8 +45,7 @@ import {
import {captureRef} from 'react-native-view-shot' import {captureRef} from 'react-native-view-shot'
import {scheduleOnRN} from 'react-native-worklets' import {scheduleOnRN} from 'react-native-worklets'
import {Image, type ImageErrorEventData} from 'expo-image' import {Image, type ImageErrorEventData} from 'expo-image'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {useIsFocused} from '@react-navigation/native' import {useIsFocused} from '@react-navigation/native'
import flattenReactChildren from 'react-keyed-flatten-children' import flattenReactChildren from 'react-keyed-flatten-children'
@@ -453,7 +452,7 @@ function TriggerClone({
onDisplay: () => void onDisplay: () => void
label: string label: string
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const animatedStyles = useAnimatedStyle(() => { const animatedStyles = useAnimatedStyle(() => {
const anim = animation.get() const anim = animation.get()
@@ -504,7 +503,7 @@ function TriggerClone({
height: measurement.height, height: measurement.height,
}} }}
accessibilityLabel={label} accessibilityLabel={label}
accessibilityHint={_(msg`The subject of the context menu`)} accessibilityHint={l`The subject of the context menu`}
accessibilityIgnoresInvertColors={false} accessibilityIgnoresInvertColors={false}
cachePolicy="none" cachePolicy="none"
/> />
+4 -5
View File
@@ -26,8 +26,7 @@ import Animated, {
} from 'react-native-reanimated' } from 'react-native-reanimated'
import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {scheduleOnRN} from 'react-native-worklets' import {scheduleOnRN} from 'react-native-worklets'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {ScrollProvider} from '#/lib/ScrollContext' import {ScrollProvider} from '#/lib/ScrollContext'
import {logger} from '#/logger' import {logger} from '#/logger'
@@ -386,7 +385,7 @@ export function Handle({
fill?: string fill?: string
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {screenReaderEnabled} = useA11y() const {screenReaderEnabled} = useA11y()
const {close} = useDialogContext() const {close} = useDialogContext()
@@ -395,8 +394,8 @@ export function Handle({
<Pressable <Pressable
accessible={screenReaderEnabled} accessible={screenReaderEnabled}
onPress={() => close()} onPress={() => close()}
accessibilityLabel={_(msg`Dismiss`)} accessibilityLabel={l`Dismiss`}
accessibilityHint={_(msg`Double tap to close the dialog`)}> accessibilityHint={l`Double tap to close the dialog`}>
<View <View
style={[ style={[
a.rounded_sm, a.rounded_sm,
+5 -6
View File
@@ -17,8 +17,7 @@ import {
View, View,
type ViewStyle, type ViewStyle,
} from 'react-native' } from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {DismissableLayer, FocusGuards, FocusScope} from 'radix-ui/internal' import {DismissableLayer, FocusGuards, FocusScope} from 'radix-ui/internal'
import {RemoveScrollBar} from 'react-remove-scroll-bar' import {RemoveScrollBar} from 'react-remove-scroll-bar'
@@ -55,7 +54,7 @@ export function Outer({
onClose, onClose,
webOptions, webOptions,
}: React.PropsWithChildren<DialogOuterProps>) { }: React.PropsWithChildren<DialogOuterProps>) {
const {_} = useLingui() const {t: l} = useLingui()
const {gtMobile} = useBreakpoints() const {gtMobile} = useBreakpoints()
const [isOpen, setIsOpen] = useState(false) const [isOpen, setIsOpen] = useState(false)
const {setDialogIsOpen} = useDialogStateControlContext() const {setDialogIsOpen} = useDialogStateControlContext()
@@ -126,7 +125,7 @@ export function Outer({
<RemoveScrollBar /> <RemoveScrollBar />
<Pressable <Pressable
accessibilityHint={undefined} accessibilityHint={undefined}
accessibilityLabel={_(msg`Close active dialog`)} accessibilityLabel={l`Close active dialog`}
onPress={handleBackgroundPress}> onPress={handleBackgroundPress}>
<View <View
style={[ style={[
@@ -321,7 +320,7 @@ export function FlatListFooter({
} }
export function Close() { export function Close() {
const {_} = useLingui() const {t: l} = useLingui()
const {close} = useContext(Context) const {close} = useContext(Context)
return ( return (
<View <View
@@ -339,7 +338,7 @@ export function Close() {
color="secondary" color="secondary"
shape="round" shape="round"
onPress={() => close()} onPress={() => close()}
label={_(msg`Close active dialog`)}> label={l`Close active dialog`}>
<ButtonIcon icon={X} size="md" /> <ButtonIcon icon={X} size="md" />
</Button> </Button>
</View> </View>
+6 -15
View File
@@ -14,8 +14,7 @@ import {
Text, Text,
View, View,
} from 'react-native' } from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {useA11y} from '#/state/a11y' import {useA11y} from '#/state/a11y'
@@ -40,7 +39,7 @@ export function FocusScope({children}: {children: React.ReactNode}) {
* remain within the active content section. * remain within the active content section.
*/ */
function FocusTrap({children}: {children: React.ReactNode}) { function FocusTrap({children}: {children: React.ReactNode}) {
const {_} = useLingui() const {t: l} = useLingui()
const child = useRef<View>(null) const child = useRef<View>(null)
/* /*
@@ -84,12 +83,8 @@ function FocusTrap({children}: {children: React.ReactNode}) {
<> <>
<Pressable <Pressable
accessible accessible
accessibilityLabel={_( accessibilityLabel={l`You've reached the start of the active content.`}
msg`You've reached the start of the active content.`, accessibilityHint={l`Please go back, or activate this element to return to the start of the active content.`}
)}
accessibilityHint={_(
msg`Please go back, or activate this element to return to the start of the active content.`,
)}
accessibilityActions={[{name: 'activate', label: 'activate'}]} accessibilityActions={[{name: 'activate', label: 'activate'}]}
onAccessibilityAction={event => { onAccessibilityAction={event => {
switch (event.nativeEvent.actionName) { switch (event.nativeEvent.actionName) {
@@ -108,12 +103,8 @@ function FocusTrap({children}: {children: React.ReactNode}) {
{decoratedChildren} {decoratedChildren}
</View> </View>
<Pressable <Pressable
accessibilityLabel={_( accessibilityLabel={l`You've reached the end of the active content.`}
msg`You've reached the end of the active content.`, accessibilityHint={l`Please go back, or activate this element to return to the start of the active content.`}
)}
accessibilityHint={_(
msg`Please go back, or activate this element to return to the start of the active content.`,
)}
accessibilityActions={[{name: 'activate', label: 'activate'}]} accessibilityActions={[{name: 'activate', label: 'activate'}]}
onAccessibilityAction={event => { onAccessibilityAction={event => {
switch (event.nativeEvent.actionName) { switch (event.nativeEvent.actionName) {
+15 -20
View File
@@ -5,8 +5,7 @@ import {
View, View,
type ViewStyle, type ViewStyle,
} from 'react-native' } from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {DraggableScrollView} from '#/view/com/pager/DraggableScrollView' import {DraggableScrollView} from '#/view/com/pager/DraggableScrollView'
@@ -46,7 +45,7 @@ export function InterestTabs({
gutterWidth?: number gutterWidth?: number
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const listRef = useRef<ScrollView>(null) const listRef = useRef<ScrollView>(null)
const [totalWidth, setTotalWidth] = useState(0) const [totalWidth, setTotalWidth] = useState(0)
const [scrollX, setScrollX] = useState(0) const [scrollX, setScrollX] = useState(0)
@@ -255,7 +254,7 @@ export function InterestTabs({
}), }),
]}> ]}>
<Button <Button
label={_(msg`Scroll left`)} label={l`Scroll left`}
onPress={scrollLeft} onPress={scrollLeft}
onPressIn={() => startContinuousScroll('left')} onPressIn={() => startContinuousScroll('left')}
onPressOut={stopContinuousScroll} onPressOut={stopContinuousScroll}
@@ -289,7 +288,7 @@ export function InterestTabs({
}), }),
]}> ]}>
<Button <Button
label={_(msg`Scroll right`)} label={l`Scroll right`}
onPress={scrollRight} onPress={scrollRight}
onPressIn={() => startContinuousScroll('right')} onPressIn={() => startContinuousScroll('right')}
onPressOut={stopContinuousScroll} onPressOut={stopContinuousScroll}
@@ -327,22 +326,18 @@ function Tab({
onLayout: (index: number, x: number, width: number) => void onLayout: (index: number, x: number, width: number) => void
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const label = active const label = active
? _( ? l({
msg({ message: `"${interestsDisplayName}" category (active)`,
message: `"${interestsDisplayName}" category (active)`, comment:
comment: 'Accessibility label for a category (e.g. Art, Video Games, Sports, etc.) that shows suggested accounts for the user to follow. The tab is currently selected.',
'Accessibility label for a category (e.g. Art, Video Games, Sports, etc.) that shows suggested accounts for the user to follow. The tab is currently selected.', })
}), : l({
) message: `Select "${interestsDisplayName}" category`,
: _( comment:
msg({ 'Accessibility label for a category (e.g. Art, Video Games, Sports, etc.) that shows suggested accounts for the user to follow. The tab is not currently active and can be selected.',
message: `Select "${interestsDisplayName}" category`, })
comment:
'Accessibility label for a category (e.g. Art, Video Games, Sports, etc.) that shows suggested accounts for the user to follow. The tab is not currently active and can be selected.',
}),
)
return ( return (
<View <View
@@ -1,8 +1,7 @@
import {Fragment, useMemo} from 'react' import {Fragment, useMemo} from 'react'
import {Text as RNText} from 'react-native' import {Text as RNText} from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import { import {
type CountryCode, type CountryCode,
@@ -28,7 +27,7 @@ export function InternationalPhoneCodeSelect({
value?: CountryCode value?: CountryCode
onChange: (value: CountryCode) => void onChange: (value: CountryCode) => void
}) { }) {
const {_, i18n} = useLingui() const {t: l, i18n} = useLingui()
const location = useGeolocation() const location = useGeolocation()
const defaultCountry = useMemo(() => { const defaultCountry = useMemo(() => {
@@ -65,7 +64,7 @@ export function InternationalPhoneCodeSelect({
return ( return (
<Select.Root value={value} onValueChange={onChange as (v: string) => void}> <Select.Root value={value} onValueChange={onChange as (v: string) => void}>
<Select.Trigger label={_(msg`Select telephone code`)}> <Select.Trigger label={l`Select telephone code`}>
<Select.ValueText placeholder="+..." webOverrideValue={selected}> <Select.ValueText placeholder="+..." webOverrideValue={selected}>
{selected => ( {selected => (
<> <>
@@ -77,7 +76,7 @@ export function InternationalPhoneCodeSelect({
<Select.Icon /> <Select.Icon />
</Select.Trigger> </Select.Trigger>
<Select.Content <Select.Content
label={_(msg`Country code`)} label={l`Country code`}
items={items} items={items}
renderItem={item => ( renderItem={item => (
<Fragment key={item.value}> <Fragment key={item.value}>
+5 -8
View File
@@ -1,7 +1,6 @@
import {View} from 'react-native' import {View} from 'react-native'
import {type AppBskyLabelerDefs} from '@atproto/api' import {type AppBskyLabelerDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Plural, Trans} from '@lingui/react/macro' import {Plural, Trans} from '@lingui/react/macro'
import {getLabelingServiceTitle} from '#/lib/moderation' import {getLabelingServiceTitle} from '#/lib/moderation'
@@ -52,14 +51,14 @@ export function Title({value}: {value: string}) {
} }
export function Description({value, handle}: {value?: string; handle: string}) { export function Description({value, handle}: {value?: string; handle: string}) {
const {_} = useLingui() const {t: l} = useLingui()
return value ? ( return value ? (
<Text numberOfLines={2}> <Text numberOfLines={2}>
<RichText value={value} /> <RichText value={value} />
</Text> </Text>
) : ( ) : (
<Text emoji style={[a.leading_snug]}> <Text emoji style={[a.leading_snug]}>
{_(msg`By ${sanitizeHandle(handle, '@')}`)} {l`By ${sanitizeHandle(handle, '@')}`}
</Text> </Text>
) )
} }
@@ -150,7 +149,7 @@ export function Link({
children, children,
labeler, labeler,
}: LabelingServiceProps & Pick<LinkProps, 'children'>) { }: LabelingServiceProps & Pick<LinkProps, 'children'>) {
const {_} = useLingui() const {t: l} = useLingui()
return ( return (
<InternalLink <InternalLink
@@ -160,9 +159,7 @@ export function Link({
name: labeler.creator.did, name: labeler.creator.did,
}, },
}} }}
label={_( label={l`View the labeling service provided by @${labeler.creator.handle}`}>
msg`View the labeling service provided by @${labeler.creator.handle}`,
)}>
{children} {children}
</InternalLink> </InternalLink>
) )
+4 -5
View File
@@ -1,5 +1,4 @@
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {sanitizeAppLanguageSetting} from '#/locale/helpers' import {sanitizeAppLanguageSetting} from '#/locale/helpers'
import {APP_LANGUAGES} from '#/locale/languages' import {APP_LANGUAGES} from '#/locale/languages'
@@ -21,7 +20,7 @@ export function LanguageSelect({
label?: string label?: string
disabledBlueskySupportedLanguageSanitization?: boolean disabledBlueskySupportedLanguageSanitization?: boolean
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const selectValue = const selectValue =
value && !disabledBlueskySupportedLanguageSanitization value && !disabledBlueskySupportedLanguageSanitization
? sanitizeAppLanguageSetting(value) ? sanitizeAppLanguageSetting(value)
@@ -38,8 +37,8 @@ export function LanguageSelect({
return ( return (
<Select.Root value={selectValue} onValueChange={handleOnChange}> <Select.Root value={selectValue} onValueChange={handleOnChange}>
<Select.Trigger label={_(msg`Select language`)}> <Select.Trigger label={l`Select language`}>
<Select.ValueText placeholder={_(msg`Select language`)} /> <Select.ValueText placeholder={l`Select language`} />
<Select.Icon /> <Select.Icon />
</Select.Trigger> </Select.Trigger>
<Select.Content <Select.Content
+5 -6
View File
@@ -1,7 +1,6 @@
import {createContext, useCallback, useContext} from 'react' import {createContext, useCallback, useContext} from 'react'
import {type GestureResponderEvent, Keyboard, View} from 'react-native' import {type GestureResponderEvent, Keyboard, View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
import {type NavigationProp} from '#/lib/routes/types' import {type NavigationProp} from '#/lib/routes/types'
@@ -112,7 +111,7 @@ export function Slot({children}: {children?: React.ReactNode}) {
} }
export function BackButton({onPress, style, ...props}: Partial<ButtonProps>) { export function BackButton({onPress, style, ...props}: Partial<ButtonProps>) {
const {_} = useLingui() const {t: l} = useLingui()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
const onPressBack = useCallback( const onPressBack = useCallback(
@@ -131,7 +130,7 @@ export function BackButton({onPress, style, ...props}: Partial<ButtonProps>) {
return ( return (
<Slot> <Slot>
<Button <Button
label={_(msg`Go back`)} label={l`Go back`}
size="small" size="small"
variant="ghost" variant="ghost"
color="secondary" color="secondary"
@@ -151,7 +150,7 @@ export function BackButton({onPress, style, ...props}: Partial<ButtonProps>) {
} }
export function MenuButton() { export function MenuButton() {
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const setDrawerOpen = useSetDrawerOpen() const setDrawerOpen = useSetDrawerOpen()
const {gtMobile} = useBreakpoints() const {gtMobile} = useBreakpoints()
@@ -165,7 +164,7 @@ export function MenuButton() {
return gtMobile ? null : ( return gtMobile ? null : (
<Slot> <Slot>
<Button <Button
label={_(msg`Open drawer menu`)} label={l`Open drawer menu`}
size="small" size="small"
variant="ghost" variant="ghost"
color="secondary" color="secondary"
+4 -7
View File
@@ -1,7 +1,6 @@
import {useCallback, useMemo, useState} from 'react' import {useCallback, useMemo, useState} from 'react'
import {type AppBskyFeedGetLikes as GetLikes} from '@atproto/api' import {type AppBskyFeedGetLikes as GetLikes} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
import {cleanError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
@@ -27,7 +26,7 @@ function keyExtractor(item: GetLikes.Like) {
} }
export function LikedByList({uri}: {uri: string}) { export function LikedByList({uri}: {uri: string}) {
const {_} = useLingui() const {t: l} = useLingui()
const initialNumToRender = useInitialNumToRender() const initialNumToRender = useInitialNumToRender()
const [isPTRing, setIsPTRing] = useState(false) const [isPTRing, setIsPTRing] = useState(false)
@@ -81,10 +80,8 @@ export function LikedByList({uri}: {uri: string}) {
isLoading={isUriLoading || isLikedByLoading} isLoading={isUriLoading || isLikedByLoading}
isError={isError} isError={isError}
emptyType="results" emptyType="results"
emptyTitle={_(msg`No likes yet`)} emptyTitle={l`No likes yet`}
emptyMessage={_( emptyMessage={l`Nobody has liked this yet. Maybe you should be the first!`}
msg`Nobody has liked this yet. Maybe you should be the first!`,
)}
errorMessage={cleanError(resolveError || error)} errorMessage={cleanError(resolveError || error)}
onRetry={isError ? refetch : undefined} onRetry={isError ? refetch : undefined}
topBorder={false} topBorder={false}
+4 -6
View File
@@ -6,8 +6,7 @@ import {
moderateUserList, moderateUserList,
type ModerationUI, type ModerationUI,
} from '@atproto/api' } from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
@@ -115,7 +114,7 @@ export function TitleAndByline({
modUi?: ModerationUI modUi?: ModerationUI
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {currentAccount} = useSession() const {currentAccount} = useSession()
return ( return (
@@ -142,15 +141,14 @@ export function TitleAndByline({
</Text> </Text>
</Hider.Content> </Hider.Content>
</Hider.Outer> </Hider.Outer>
{creator && ( {creator && (
<Text <Text
emoji emoji
style={[a.leading_snug, t.atoms.text_contrast_medium]} style={[a.leading_snug, t.atoms.text_contrast_medium]}
numberOfLines={1}> numberOfLines={1}>
{purpose === MODLIST {purpose === MODLIST
? _(msg`Moderation list by ${sanitizeHandle(creator.handle, '@')}`) ? l`Moderation list by ${sanitizeHandle(creator.handle, '@')}`
: _(msg`List by ${sanitizeHandle(creator.handle, '@')}`)} : l`List by ${sanitizeHandle(creator.handle, '@')}`}
</Text> </Text>
)} )}
</View> </View>
+9 -14
View File
@@ -1,7 +1,6 @@
import {memo} from 'react' import {memo} from 'react'
import {type StyleProp, View, type ViewStyle} from 'react-native' import {type StyleProp, View, type ViewStyle} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {cleanError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
@@ -75,7 +74,7 @@ function ListFooterMaybeError({
onRetry?: () => Promise<unknown> onRetry?: () => Promise<unknown>
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
if (!error) return null if (!error) return null
@@ -101,7 +100,7 @@ function ListFooterMaybeError({
</Text> </Text>
<Button <Button
variant="solid" variant="solid"
label={_(msg`Press to retry`)} label={l`Press to retry`}
style={[ style={[
a.align_center, a.align_center,
a.justify_center, a.justify_center,
@@ -156,7 +155,7 @@ let ListMaybePlaceholder = ({
useEmptyState?: boolean useEmptyState?: boolean
}): React.ReactNode => { }): React.ReactNode => {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {gtMobile, gtTablet} = useBreakpoints() const {gtMobile, gtTablet} = useBreakpoints()
if (isLoading) { if (isLoading) {
@@ -181,8 +180,8 @@ let ListMaybePlaceholder = ({
if (isError) { if (isError) {
return ( return (
<Error <Error
title={errorTitle ?? _(msg`Oops!`)} title={errorTitle ?? l`Oops!`}
message={errorMessage ?? _(msg`Something went wrong!`)} message={errorMessage ?? l`Something went wrong!`}
onRetry={onRetry} onRetry={onRetry}
onGoBack={onGoBack} onGoBack={onGoBack}
hideBackButton={hideBackButton} hideBackButton={hideBackButton}
@@ -199,9 +198,7 @@ let ListMaybePlaceholder = ({
icon={emptyStateIcon} icon={emptyStateIcon}
message={ message={
emptyMessage ?? emptyMessage ??
(emptyType === 'results' (emptyType === 'results' ? l`No results found` : l`Page not found`)
? _(msg`No results found`)
: _(msg`Page not found`))
} }
button={emptyStateButton} button={emptyStateButton}
/> />
@@ -214,13 +211,11 @@ let ListMaybePlaceholder = ({
<Error <Error
title={ title={
emptyTitle ?? emptyTitle ??
(emptyType === 'results' (emptyType === 'results' ? l`No results found` : l`Page not found`)
? _(msg`No results found`)
: _(msg`Page not found`))
} }
message={ message={
emptyMessage ?? emptyMessage ??
_(msg`We're sorry! We can't find the page you were looking for.`) l`We're sorry! We can't find the page you were looking for.`
} }
onRetry={onRetry} onRetry={onRetry}
onGoBack={onGoBack} onGoBack={onGoBack}
+3 -6
View File
@@ -6,8 +6,7 @@ import {
View, View,
type ViewStyle, type ViewStyle,
} from 'react-native' } from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {DropdownMenu} from 'radix-ui' import {DropdownMenu} from 'radix-ui'
import {useA11y} from '#/state/a11y' import {useA11y} from '#/state/a11y'
@@ -62,7 +61,7 @@ export function Root({
}: React.PropsWithChildren<{ }: React.PropsWithChildren<{
control?: Dialog.DialogControlProps control?: Dialog.DialogControlProps
}>) { }>) {
const {_} = useLingui() const {t: l} = useLingui()
const defaultControl = useMenuControl() const defaultControl = useMenuControl()
const context = useMemo<ContextType>( const context = useMemo<ContextType>(
() => ({ () => ({
@@ -89,9 +88,7 @@ export function Root({
style={[a.fixed, a.inset_0, a.z_50]} style={[a.fixed, a.inset_0, a.z_50]}
onPress={() => context.control.close()} onPress={() => context.control.close()}
accessibilityHint="" accessibilityHint=""
accessibilityLabel={_( accessibilityLabel={l`Context menu backdrop, click to close the menu.`}
msg`Context menu backdrop, click to close the menu.`,
)}
/> />
</Portal> </Portal>
)} )}
+10 -19
View File
@@ -1,8 +1,7 @@
import {useMemo, useState} from 'react' import {useMemo, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {type AppBskyActorDefs, moderateProfile} from '@atproto/api' import {type AppBskyActorDefs, moderateProfile} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {differenceInSeconds} from 'date-fns' import {differenceInSeconds} from 'date-fns'
@@ -28,7 +27,7 @@ export function NewskieDialog({
disabled?: boolean disabled?: boolean
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const control = useDialogControl() const control = useDialogControl()
const createdAt = profile.createdAt const createdAt = profile.createdAt
@@ -45,9 +44,7 @@ export function NewskieDialog({
<View style={[a.pr_2xs]}> <View style={[a.pr_2xs]}>
<Button <Button
disabled={disabled} disabled={disabled}
label={_( label={l`This user is new here. Press for more info about when they joined.`}
msg`This user is new here. Press for more info about when they joined.`,
)}
hitSlop={HITSLOP_10} hitSlop={HITSLOP_10}
onPress={control.open}> onPress={control.open}>
{({hovered, pressed}) => ( {({hovered, pressed}) => (
@@ -60,7 +57,6 @@ export function NewskieDialog({
/> />
)} )}
</Button> </Button>
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
<Dialog.Handle /> <Dialog.Handle />
<DialogInner profile={profile} createdAt={createdAt} now={now} /> <DialogInner profile={profile} createdAt={createdAt} now={now} />
@@ -79,7 +75,7 @@ function DialogInner({
now: number now: number
}) { }) {
const control = Dialog.useDialogContext() const control = Dialog.useDialogContext()
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const moderationOpts = useModerationOpts() const moderationOpts = useModerationOpts()
const {currentAccount} = useSession() const {currentAccount} = useSession()
@@ -100,26 +96,22 @@ function DialogInner({
if (isMe) { if (isMe) {
if (profile.joinedViaStarterPack) { if (profile.joinedViaStarterPack) {
return _( return l`You joined Bluesky using a starter pack ${timeAgoString} ago`
msg`You joined Bluesky using a starter pack ${timeAgoString} ago`,
)
} else { } else {
return _(msg`You joined Bluesky ${timeAgoString} ago`) return l`You joined Bluesky ${timeAgoString} ago`
} }
} else { } else {
if (profile.joinedViaStarterPack) { if (profile.joinedViaStarterPack) {
return _( return l`${profileName} joined Bluesky using a starter pack ${timeAgoString} ago`
msg`${profileName} joined Bluesky using a starter pack ${timeAgoString} ago`,
)
} else { } else {
return _(msg`${profileName} joined Bluesky ${timeAgoString} ago`) return l`${profileName} joined Bluesky ${timeAgoString} ago`
} }
} }
} }
return ( return (
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`New user info dialog`)} label={l`New user info dialog`}
style={web({maxWidth: 400})}> style={web({maxWidth: 400})}>
<View style={[a.gap_md]}> <View style={[a.gap_md]}>
<View style={[a.align_center]}> <View style={[a.align_center]}>
@@ -166,7 +158,7 @@ function DialogInner({
{IS_NATIVE && ( {IS_NATIVE && (
<Button <Button
label={_(msg`Close`)} label={l`Close`}
color="secondary" color="secondary"
size="small" size="small"
style={[a.mt_sm]} style={[a.mt_sm]}
@@ -177,7 +169,6 @@ function DialogInner({
</Button> </Button>
)} )}
</View> </View>
<Dialog.Close /> <Dialog.Close />
</Dialog.ScrollableInner> </Dialog.ScrollableInner>
) )
@@ -1,7 +1,6 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useA11y} from '#/state/a11y' import {useA11y} from '#/state/a11y'
@@ -16,7 +15,7 @@ import {IS_ANDROID} from '#/env'
export function Content({state}: {state: PolicyUpdateState}) { export function Content({state}: {state: PolicyUpdateState}) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {screenReaderEnabled} = useA11y() const {screenReaderEnabled} = useA11y()
const handleClose = useCallback(() => { const handleClose = useCallback(() => {
@@ -28,27 +27,27 @@ export function Content({state}: {state: PolicyUpdateState}) {
terms: { terms: {
overridePresentation: false, overridePresentation: false,
to: `https://bsky.social/about/support/tos`, to: `https://bsky.social/about/support/tos`,
label: _(msg`Terms of Service`), label: l`Terms of Service`,
}, },
privacy: { privacy: {
overridePresentation: false, overridePresentation: false,
to: `https://bsky.social/about/support/privacy-policy`, to: `https://bsky.social/about/support/privacy-policy`,
label: _(msg`Privacy Policy`), label: l`Privacy Policy`,
}, },
copyright: { copyright: {
overridePresentation: false, overridePresentation: false,
to: `https://bsky.social/about/support/copyright`, to: `https://bsky.social/about/support/copyright`,
label: _(msg`Copyright Policy`), label: l`Copyright Policy`,
}, },
guidelines: { guidelines: {
overridePresentation: false, overridePresentation: false,
to: `https://bsky.social/about/support/community-guidelines`, to: `https://bsky.social/about/support/community-guidelines`,
label: _(msg`Community Guidelines`), label: l`Community Guidelines`,
}, },
blog: { blog: {
overridePresentation: false, overridePresentation: false,
to: `https://bsky.social/about/blog/08-14-2025-updated-terms-and-policies`, to: `https://bsky.social/about/blog/08-14-2025-updated-terms-and-policies`,
label: _(msg`Our blog post`), label: l`Our blog post`,
}, },
} }
const linkButtonStyles = { const linkButtonStyles = {
@@ -58,10 +57,8 @@ export function Content({state}: {state: PolicyUpdateState}) {
} as const } as const
const label = IS_ANDROID const label = IS_ANDROID
? _( ? l`We’re updating our Terms of Service, Privacy Policy, and Copyright Policy, effective September 15th, 2025. We're also updating our Community Guidelines, and we want your input! These new guidelines will take effect on October 15th, 2025. Learn more about these changes and how to share your thoughts with us by reading our blog post.`
msg`We’re updating our Terms of Service, Privacy Policy, and Copyright Policy, effective September 15th, 2025. We're also updating our Community Guidelines, and we want your input! These new guidelines will take effect on October 15th, 2025. Learn more about these changes and how to share your thoughts with us by reading our blog post.`, : l`We're updating our policies`
)
: _(msg`We're updating our policies`)
return ( return (
<Overlay label={label}> <Overlay label={label}>
@@ -160,10 +157,8 @@ export function Content({state}: {state: PolicyUpdateState}) {
<View style={[a.w_full, a.gap_md]}> <View style={[a.w_full, a.gap_md]}>
<Button <Button
label={_(msg`Continue`)} label={l`Continue`}
accessibilityHint={_( accessibilityHint={l`Tap to acknowledge that you understand and agree to these updates and continue using Bluesky`}
msg`Tap to acknowledge that you understand and agree to these updates and continue using Bluesky`,
)}
color="primary" color="primary"
size="large" size="large"
onPress={handleClose}> onPress={handleClose}>
@@ -6,8 +6,7 @@ import {
} from 'react-native' } from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {type AppBskyEmbedExternal} from '@atproto/api' import {type AppBskyEmbedExternal} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {type EmbedPlayerParams} from '#/lib/strings/embed-player' import {type EmbedPlayerParams} from '#/lib/strings/embed-player'
import {useExternalEmbedsPrefs} from '#/state/preferences' import {useExternalEmbedsPrefs} from '#/state/preferences'
@@ -27,7 +26,7 @@ export function ExternalGif({
}) { }) {
const t = useTheme() const t = useTheme()
const externalEmbedsPrefs = useExternalEmbedsPrefs() const externalEmbedsPrefs = useExternalEmbedsPrefs()
const {_} = useLingui() const {t: l} = useLingui()
const consentDialogControl = useDialogControl() const consentDialogControl = useDialogControl()
// Tracking if the placer has been activated // Tracking if the placer has been activated
@@ -106,8 +105,8 @@ export function ExternalGif({
]} ]}
onPress={onPlayPress} onPress={onPlayPress}
accessibilityRole="button" accessibilityRole="button"
accessibilityHint={_(msg`Plays the GIF`)} accessibilityHint={l`Plays the GIF`}
accessibilityLabel={_(msg`Play ${link.title}`)}> accessibilityLabel={l`Play ${link.title}`}>
<Image <Image
source={{ source={{
uri: uri:
@@ -16,8 +16,7 @@ import {WebView} from 'react-native-webview'
import {scheduleOnRN} from 'react-native-worklets' import {scheduleOnRN} from 'react-native-worklets'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {type AppBskyEmbedExternal} from '@atproto/api' import {type AppBskyEmbedExternal} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
import {type NavigationProp} from '#/lib/routes/types' import {type NavigationProp} from '#/lib/routes/types'
@@ -49,7 +48,7 @@ function PlaceholderOverlay({
isPlayerActive: boolean isPlayerActive: boolean
onPress: (event: GestureResponderEvent) => void onPress: (event: GestureResponderEvent) => void
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
// If the player is active and not loading, we don't want to show the overlay. // If the player is active and not loading, we don't want to show the overlay.
if (isPlayerActive && !isLoading) return null if (isPlayerActive && !isLoading) return null
@@ -58,8 +57,8 @@ function PlaceholderOverlay({
<View style={[a.absolute, a.inset_0, {zIndex: 2}]}> <View style={[a.absolute, a.inset_0, {zIndex: 2}]}>
<Pressable <Pressable
accessibilityRole="button" accessibilityRole="button"
accessibilityLabel={_(msg`Play Video`)} accessibilityLabel={l`Play Video`}
accessibilityHint={_(msg`Plays the video`)} accessibilityHint={l`Plays the video`}
onPress={onPress} onPress={onPress}
style={[a.flex_1, a.justify_center, a.align_center]}> style={[a.flex_1, a.justify_center, a.align_center]}>
{!isPlayerActive ? ( {!isPlayerActive ? (
@@ -1,7 +1,6 @@
import {useRef, useState} from 'react' import {useRef, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {type EmbedPlayerParams} from '#/lib/strings/embed-player' import {type EmbedPlayerParams} from '#/lib/strings/embed-player'
import {useAutoplayDisabled} from '#/state/preferences' import {useAutoplayDisabled} from '#/state/preferences'
@@ -27,7 +26,7 @@ export function GifEmbed({
hideAlt?: boolean hideAlt?: boolean
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const autoplayDisabled = useAutoplayDisabled() const autoplayDisabled = useAutoplayDisabled()
const playerRef = useRef<GifView>(null) const playerRef = useRef<GifView>(null)
@@ -82,7 +81,7 @@ export function GifEmbed({
autoplay={!autoplayDisabled} autoplay={!autoplayDisabled}
onPlayerStateChange={onPlayerStateChange} onPlayerStateChange={onPlayerStateChange}
ref={playerRef} ref={playerRef}
accessibilityHint={_(msg`Animated GIF`)} accessibilityHint={l`Animated GIF`}
accessibilityLabel={altText} accessibilityLabel={altText}
/> />
{!playerState.isPlaying && ( {!playerState.isPlaying && (
@@ -2,8 +2,7 @@ import {useMemo} from 'react'
import {type StyleProp, View, type ViewStyle} from 'react-native' import {type StyleProp, View, type ViewStyle} from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {type AppBskyEmbedExternal} from '@atproto/api' import {type AppBskyEmbedExternal} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {parseAltFromGIFDescription} from '#/lib/gif-alt-text' import {parseAltFromGIFDescription} from '#/lib/gif-alt-text'
import {useHaptics} from '#/lib/haptics' import {useHaptics} from '#/lib/haptics'
@@ -35,7 +34,7 @@ export const ExternalEmbed = ({
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
hideAlt?: boolean hideAlt?: boolean
}) => { }) => {
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const playHaptic = useHaptics() const playHaptic = useHaptics()
const externalEmbedPrefs = useExternalEmbedsPrefs() const externalEmbedPrefs = useExternalEmbedsPrefs()
@@ -85,7 +84,7 @@ export const ExternalEmbed = ({
return ( return (
<Link <Link
label={link.title || _(msg`Open link to ${niceUrl}`)} label={link.title || l`Open link to ${niceUrl}`}
to={link.uri} to={link.uri}
shouldProxy={true} shouldProxy={true}
peek peek
@@ -1,6 +1,5 @@
import {ActivityIndicator, View} from 'react-native' import {ActivityIndicator, View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge' import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge'
@@ -22,15 +21,15 @@ export function GifPresentationControls({
isLoading?: boolean isLoading?: boolean
altText?: string altText?: string
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const largeBadge = useLargeAltBadgeEnabled() const largeBadge = useLargeAltBadgeEnabled()
return ( return (
<> <>
<Button <Button
label={isPlaying ? _(msg`Pause GIF`) : _(msg`Play GIF`)} label={isPlaying ? l`Pause GIF` : l`Play GIF`}
accessibilityHint={_(msg`Plays or pauses the GIF`)} accessibilityHint={l`Plays or pauses the GIF`}
style={[ style={[
a.absolute, a.absolute,
a.align_center, a.align_center,
@@ -1,7 +1,7 @@
import {type StyleProp, type ViewStyle} from 'react-native' import {type StyleProp, type ViewStyle} from 'react-native'
import {View} from 'react-native' import {View} from 'react-native'
import {msg, plural} from '@lingui/core/macro' import {plural} from '@lingui/core/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react/macro'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
@@ -18,7 +18,7 @@ export function TimeIndicator({
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
if (isNaN(time)) { if (isNaN(time)) {
return null return null
@@ -30,12 +30,10 @@ export function TimeIndicator({
return ( return (
<View <View
pointerEvents="none" pointerEvents="none"
accessibilityLabel={_( accessibilityLabel={l`Time remaining: ${plural(Number(time) || 0, {
msg`Time remaining: ${plural(Number(time) || 0, { one: '# second',
one: '# second', other: '# seconds',
other: '# seconds', })}`}
})}`,
)}
accessibilityHint="" accessibilityHint=""
style={[ style={[
{ {
@@ -2,8 +2,7 @@ import {useImperativeHandle, useRef, useState} from 'react'
import {Pressable, type StyleProp, View, type ViewStyle} from 'react-native' import {Pressable, type StyleProp, View, type ViewStyle} from 'react-native'
import {type AppBskyEmbedVideo} from '@atproto/api' import {type AppBskyEmbedVideo} from '@atproto/api'
import {BlueskyVideoView} from '@bsky.app/video' import {BlueskyVideoView} from '@bsky.app/video'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {HITSLOP_30} from '#/lib/constants' import {HITSLOP_30} from '#/lib/constants'
import {useAutoplayDisabled} from '#/state/preferences' import {useAutoplayDisabled} from '#/state/preferences'
@@ -39,7 +38,7 @@ export function VideoEmbedInnerNative({
*/ */
onError?: (error: string) => void onError?: (error: string) => void
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const videoRef = useRef<BlueskyVideoView>(null) const videoRef = useRef<BlueskyVideoView>(null)
const autoplayDisabled = useAutoplayDisabled() const autoplayDisabled = useAutoplayDisabled()
const isWithinMessage = useIsWithinMessage() const isWithinMessage = useIsWithinMessage()
@@ -91,9 +90,7 @@ export function VideoEmbedInnerNative({
setError(e.nativeEvent.error) setError(e.nativeEvent.error)
}} }}
ref={videoRef} ref={videoRef}
accessibilityLabel={ accessibilityLabel={embed.alt ? l`Video: ${embed.alt}` : l`Video`}
embed.alt ? _(msg`Video: ${embed.alt}`) : _(msg`Video`)
}
accessibilityHint="" accessibilityHint=""
/> />
{isGif ? ( {isGif ? (
@@ -144,7 +141,7 @@ function VideoPresentationControls({
timeRemaining: number timeRemaining: number
isPlaying: boolean isPlaying: boolean
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const [muted] = useVideoMuteState() const [muted] = useVideoMuteState()
@@ -159,14 +156,14 @@ function VideoPresentationControls({
<Pressable <Pressable
onPress={enterFullscreen} onPress={enterFullscreen}
style={a.flex_1} style={a.flex_1}
accessibilityLabel={_(msg`Video`)} accessibilityLabel={l`Video`}
accessibilityHint={_(msg`Enters full screen`)} accessibilityHint={l`Enters full screen`}
accessibilityRole="button" accessibilityRole="button"
/> />
<ControlButton <ControlButton
onPress={togglePlayback} onPress={togglePlayback}
label={isPlaying ? _(msg`Pause`) : _(msg`Play`)} label={isPlaying ? l`Pause` : l`Play`}
accessibilityHint={_(msg`Plays or pauses the video`)} accessibilityHint={l`Plays or pauses the video`}
style={{left: 6}}> style={{left: 6}}>
{isPlaying ? ( {isPlaying ? (
<PauseIcon width={13} fill={t.palette.white} /> <PauseIcon width={13} fill={t.palette.white} />
@@ -175,15 +172,14 @@ function VideoPresentationControls({
)} )}
</ControlButton> </ControlButton>
{showTime && <TimeIndicator time={timeRemaining} style={{left: 33}} />} {showTime && <TimeIndicator time={timeRemaining} style={{left: 33}} />}
<ControlButton <ControlButton
onPress={toggleMuted} onPress={toggleMuted}
label={ label={
muted muted
? _(msg({message: `Unmute`, context: 'video'})) ? l({message: `Unmute`, context: 'video'})
: _(msg({message: `Mute`, context: 'video'})) : l({message: `Mute`, context: 'video'})
} }
accessibilityHint={_(msg`Toggles the sound`)} accessibilityHint={l`Toggles the sound`}
style={{right: 6}}> style={{right: 6}}>
{muted ? ( {muted ? (
<MuteIcon width={13} fill={t.palette.white} /> <MuteIcon width={13} fill={t.palette.white} />
@@ -1,7 +1,6 @@
import {useCallback, useEffect, useId, useRef, useState} from 'react' import {useCallback, useEffect, useId, useRef, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import type * as HlsTypes from 'hls.js' import type * as HlsTypes from 'hls.js'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
@@ -36,7 +35,7 @@ export function VideoEmbedInnerWeb({
const [hasSubtitleTrack, setHasSubtitleTrack] = useState(false) const [hasSubtitleTrack, setHasSubtitleTrack] = useState(false)
const [hlsLoading, setHlsLoading] = useState(false) const [hlsLoading, setHlsLoading] = useState(false)
const figId = useId() const figId = useId()
const {_} = useLingui() const {t: l} = useLingui()
const [isFullscreen] = useFullscreen(containerRef) const [isFullscreen] = useFullscreen(containerRef)
const isGif = embed.presentation === 'gif' const isGif = embed.presentation === 'gif'
@@ -63,7 +62,7 @@ export function VideoEmbedInnerWeb({
return ( return (
<View <View
style={[a.flex_1, a.rounded_md, a.overflow_hidden]} style={[a.flex_1, a.rounded_md, a.overflow_hidden]}
accessibilityLabel={_(msg`Embedded video player`)} accessibilityLabel={l`Embedded video player`}
accessibilityHint=""> accessibilityHint="">
<div ref={containerRef} style={{height: '100%', width: '100%'}}> <div ref={containerRef} style={{height: '100%', width: '100%'}}>
<figure style={{margin: 0, position: 'absolute', inset: 0}}> <figure style={{margin: 0, position: 'absolute', inset: 0}}>
@@ -1,6 +1,5 @@
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
@@ -46,14 +45,14 @@ export function Text({children}: {children: React.ReactNode}) {
} }
export function RetryButton({onPress}: {onPress: () => void}) { export function RetryButton({onPress}: {onPress: () => void}) {
const {_} = useLingui() const {t: l} = useLingui()
return ( return (
<Button <Button
onPress={onPress} onPress={onPress}
size="small" size="small"
color="secondary_inverted" color="secondary_inverted"
label={_(msg`Retry`)}> label={l`Retry`}>
<ButtonIcon icon={ArrowRotateIcon} /> <ButtonIcon icon={ArrowRotateIcon} />
<ButtonText> <ButtonText>
<Trans>Retry</Trans> <Trans>Retry</Trans>
@@ -1,7 +1,6 @@
import {useCallback, useEffect, useRef, useState} from 'react' import {useCallback, useEffect, useRef, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {clamp} from '#/lib/numbers' import {clamp} from '#/lib/numbers'
import {atoms as a, useTheme, web} from '#/alf' import {atoms as a, useTheme, web} from '#/alf'
@@ -30,7 +29,7 @@ export function Scrubber({
togglePlayPause: () => void togglePlayPause: () => void
drawFocus: () => void drawFocus: () => void
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const [scrubberActive, setScrubberActive] = useState(false) const [scrubberActive, setScrubberActive] = useState(false)
const { const {
@@ -192,16 +191,12 @@ export function Scrubber({
</View> </View>
<div <div
ref={circleRef} ref={circleRef}
aria-label={_( aria-label={l`Seek slider. Use the arrow keys to seek forwards and backwards, and space to play/pause`}
msg`Seek slider. Use the arrow keys to seek forwards and backwards, and space to play/pause`,
)}
role="slider" role="slider"
aria-valuemax={duration} aria-valuemax={duration}
aria-valuemin={0} aria-valuemin={0}
aria-valuenow={currentTime} aria-valuenow={currentTime}
aria-valuetext={_( aria-valuetext={l`${formatTime(currentTime)} of ${formatTime(duration)}`}
msg`${formatTime(currentTime)} of ${formatTime(duration)}`,
)}
tabIndex={0} tabIndex={0}
onFocus={onFocus} onFocus={onFocus}
onBlur={onBlur} onBlur={onBlur}
@@ -1,7 +1,6 @@
import {useCallback, useEffect, useRef, useState} from 'react' import {useCallback, useEffect, useRef, useState} from 'react'
import {Pressable, View} from 'react-native' import {Pressable, View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {clamp} from '#/lib/numbers' import {clamp} from '#/lib/numbers'
@@ -64,7 +63,7 @@ export function Controls({
canPlay, canPlay,
} = useVideoElement(videoRef) } = useVideoElement(videoRef)
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const subtitlesEnabled = useSubtitlesEnabled() const subtitlesEnabled = useSubtitlesEnabled()
const setSubtitlesEnabled = useSetSubtitlesEnabled() const setSubtitlesEnabled = useSetSubtitlesEnabled()
const { const {
@@ -326,11 +325,7 @@ export function Controls({
onPointerMove={onPointerMoveEmptySpace} onPointerMove={onPointerMoveEmptySpace}
onPointerLeave={onPointerLeaveEmptySpace} onPointerLeave={onPointerLeaveEmptySpace}
accessibilityLabel={ accessibilityLabel={
!focused !focused ? l`Unmute video` : playing ? l`Pause video` : l`Play video`
? _(msg`Unmute video`)
: playing
? _(msg`Pause video`)
: _(msg`Play video`)
} }
accessibilityHint="" accessibilityHint=""
style={[ style={[
@@ -378,8 +373,8 @@ export function Controls({
]}> ]}>
<ControlButton <ControlButton
active={playing} active={playing}
activeLabel={_(msg`Pause`)} activeLabel={l`Pause`}
inactiveLabel={_(msg`Play`)} inactiveLabel={l`Play`}
activeIcon={PauseIcon} activeIcon={PauseIcon}
inactiveIcon={PlayIcon} inactiveIcon={PlayIcon}
onPress={onPressPlayPause} onPress={onPressPlayPause}
@@ -397,8 +392,8 @@ export function Controls({
{hasSubtitleTrack && ( {hasSubtitleTrack && (
<ControlButton <ControlButton
active={subtitlesEnabled} active={subtitlesEnabled}
activeLabel={_(msg`Disable captions`)} activeLabel={l`Disable captions`}
inactiveLabel={_(msg`Enable captions`)} inactiveLabel={l`Enable captions`}
activeIcon={CCActiveIcon} activeIcon={CCActiveIcon}
inactiveIcon={CCInactiveIcon} inactiveIcon={CCInactiveIcon}
onPress={onPressSubtitles} onPress={onPressSubtitles}
@@ -415,8 +410,8 @@ export function Controls({
{!IS_WEB_MOBILE_IOS && ( {!IS_WEB_MOBILE_IOS && (
<ControlButton <ControlButton
active={isFullscreen} active={isFullscreen}
activeLabel={_(msg`Exit fullscreen`)} activeLabel={l`Exit fullscreen`}
inactiveLabel={_(msg`Enter fullscreen`)} inactiveLabel={l`Enter fullscreen`}
activeIcon={ArrowsInIcon} activeIcon={ArrowsInIcon}
inactiveIcon={ArrowsOutIcon} inactiveIcon={ArrowsOutIcon}
onPress={onPressFullscreen} onPress={onPressFullscreen}
@@ -1,8 +1,7 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import Animated, {FadeIn, FadeOut} from 'react-native-reanimated' import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {atoms as a} from '#/alf' import {atoms as a} from '#/alf'
import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute'
@@ -26,7 +25,7 @@ export function VolumeControl({
onEndHover: () => void onEndHover: () => void
drawFocus: () => void drawFocus: () => void
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const [volume, setVolume] = useVideoVolumeState() const [volume, setVolume] = useVideoVolumeState()
const onVolumeChange = useCallback( const onVolumeChange = useCallback(
@@ -77,7 +76,7 @@ export function VolumeControl({
min={0} min={0}
max={100} max={100}
value={sliderVolume} value={sliderVolume}
aria-label={_(msg`Volume`)} aria-label={l`Volume`}
style={ style={
// Ridiculous safari hack for old version of safari. Fixed in sonoma beta -h // Ridiculous safari hack for old version of safari. Fixed in sonoma beta -h
IS_WEB_SAFARI IS_WEB_SAFARI
@@ -93,8 +92,8 @@ export function VolumeControl({
)} )}
<ControlButton <ControlButton
active={muted || volume === 0} active={muted || volume === 0}
activeLabel={_(msg({message: `Unmute`, context: 'video'}))} activeLabel={l({message: `Unmute`, context: 'video'})}
inactiveLabel={_(msg({message: `Mute`, context: 'video'}))} inactiveLabel={l({message: `Mute`, context: 'video'})}
activeIcon={MuteIcon} activeIcon={MuteIcon}
inactiveIcon={UnmuteIcon} inactiveIcon={UnmuteIcon}
onPress={onPressMute} onPress={onPressMute}
@@ -2,8 +2,7 @@ import {useCallback, useEffect, useRef, useState} from 'react'
import {ActivityIndicator, View} from 'react-native' import {ActivityIndicator, View} from 'react-native'
import {ImageBackground} from 'expo-image' import {ImageBackground} from 'expo-image'
import {type AppBskyEmbedVideo} from '@atproto/api' import {type AppBskyEmbedVideo} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import { import {
@@ -70,7 +69,7 @@ export function VideoEmbed({embed}: Props) {
} }
function InnerWrapper({embed}: Props) { function InnerWrapper({embed}: Props) {
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const ref = useRef<{togglePlayback: () => void}>(null) const ref = useRef<{togglePlayback: () => void}>(null)
@@ -175,7 +174,7 @@ function InnerWrapper({embed}: Props) {
onPress={() => { onPress={() => {
ref.current?.togglePlayback() ref.current?.togglePlayback()
}} }}
label={_(msg`Play video`)}> label={l`Play video`}>
{showSpinner ? ( {showSpinner ? (
<View style={[a.align_center, a.justify_center]}> <View style={[a.align_center, a.justify_center]}>
<ActivityIndicator size="large" color="white" /> <ActivityIndicator size="large" color="white" />
@@ -8,8 +8,7 @@ import {
} from 'react' } from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {type AppBskyEmbedVideo} from '@atproto/api' import {type AppBskyEmbedVideo} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary' import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
@@ -288,7 +287,7 @@ function VideoError({
error: unknown error: unknown
retry: () => void retry: () => void
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
let showRetryButton = true let showRetryButton = true
@@ -296,16 +295,14 @@ function VideoError({
let errorClass: string let errorClass: string
if (error instanceof VideoNotFoundError) { if (error instanceof VideoNotFoundError) {
text = _(msg`Video not found.`) text = l`Video not found.`
errorClass = 'VideoNotFoundError' errorClass = 'VideoNotFoundError'
} else if (error instanceof HLSUnsupportedError) { } else if (error instanceof HLSUnsupportedError) {
showRetryButton = false showRetryButton = false
text = _( text = l`This video can’t be played on your device. Your browser or system may be missing the required video codecs (H.264/AAC).`
msg`This video can’t be played on your device. Your browser or system may be missing the required video codecs (H.264/AAC).`,
)
errorClass = 'HLSUnsupportedError' errorClass = 'HLSUnsupportedError'
} else { } else {
text = _(msg`An error occurred while loading the video. Please try again.`) text = l`An error occurred while loading the video. Please try again.`
if (error instanceof HLSFatalError) { if (error instanceof HLSFatalError) {
errorClass = error.detail errorClass = error.detail
} else if (error instanceof Error) { } else if (error instanceof Error) {
+7 -14
View File
@@ -1,8 +1,7 @@
import {memo} from 'react' import {memo} from 'react'
import {type Insets} from 'react-native' import {type Insets} from 'react-native'
import {type AppBskyFeedDefs} from '@atproto/api' import {type AppBskyFeedDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useCleanError} from '#/lib/hooks/useCleanError' import {useCleanError} from '#/lib/hooks/useCleanError'
@@ -30,7 +29,7 @@ export const BookmarkButton = memo(function BookmarkButton({
}): React.ReactNode { }): React.ReactNode {
const t = useTheme() const t = useTheme()
const ax = useAnalytics() const ax = useAnalytics()
const {_} = useLingui() const {t: l} = useLingui()
const {mutateAsync: bookmark} = useBookmarkMutation() const {mutateAsync: bookmark} = useBookmarkMutation()
const cleanError = useCleanError() const cleanError = useCleanError()
const requireAuth = useRequireAuth() const requireAuth = useRequireAuth()
@@ -39,12 +38,10 @@ export const BookmarkButton = memo(function BookmarkButton({
const {viewer} = post const {viewer} = post
const isBookmarked = !!viewer?.bookmarked const isBookmarked = !!viewer?.bookmarked
const undoLabel = _( const undoLabel = l({
msg({ message: `Undo`,
message: `Undo`, context: `Button label to undo saving/removing a post from saved posts.`,
context: `Button label to undo saving/removing a post from saved posts.`, })
}),
)
const save = async () => { const save = async () => {
try { try {
@@ -115,11 +112,7 @@ export const BookmarkButton = memo(function BookmarkButton({
big={big} big={big}
active={isBookmarked} active={isBookmarked}
activeColor={t.palette.primary_500} activeColor={t.palette.primary_500}
label={ label={isBookmarked ? l`Remove from saved posts` : l`Add to saved posts`}
isBookmarked
? _(msg`Remove from saved posts`)
: _(msg`Add to saved posts`)
}
onPress={onHandlePress} onPress={onHandlePress}
hitSlop={hitSlop}> hitSlop={hitSlop}>
<PostControlButtonIcon icon={isBookmarked ? BookmarkFilled : Bookmark} /> <PostControlButtonIcon icon={isBookmarked ? BookmarkFilled : Bookmark} />
+25 -33
View File
@@ -1,7 +1,7 @@
import {memo, useCallback} from 'react' import {memo, useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg, plural} from '@lingui/core/macro' import {plural} from '@lingui/core/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react/macro'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useHaptics} from '#/lib/haptics' import {useHaptics} from '#/lib/haptics'
@@ -37,7 +37,7 @@ let RepostButton = ({
embeddingDisabled, embeddingDisabled,
}: Props): React.ReactNode => { }: Props): React.ReactNode => {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const requireAuth = useRequireAuth() const requireAuth = useRequireAuth()
const dialogControl = Dialog.useDialogControl() const dialogControl = Dialog.useDialogControl()
const formatPostStatCount = useFormatPostStatCount() const formatPostStatCount = useFormatPostStatCount()
@@ -64,26 +64,22 @@ let RepostButton = ({
onLongPress={onLongPress} onLongPress={onLongPress}
label={ label={
isReposted isReposted
? _( ? l({
msg({ message: `Undo repost (${plural(repostCount || 0, {
message: `Undo repost (${plural(repostCount || 0, { one: '# repost',
one: '# repost', other: '# reposts',
other: '# reposts', })})`,
})})`, comment:
comment: 'Accessibility label for the repost button when the post has been reposted, verb followed by number of reposts and noun',
'Accessibility label for the repost button when the post has been reposted, verb followed by number of reposts and noun', })
}), : l({
) message: `Repost (${plural(repostCount || 0, {
: _( one: '# repost',
msg({ other: '# reposts',
message: `Repost (${plural(repostCount || 0, { })})`,
one: '# repost', comment:
other: '# reposts', 'Accessibility label for the repost button when the post has not been reposted, verb form followed by number of reposts and noun form',
})})`, })
comment:
'Accessibility label for the repost button when the post has not been reposted, verb form followed by number of reposts and noun form',
}),
)
}> }>
<PostControlButtonIcon icon={RepostIcon} /> <PostControlButtonIcon icon={RepostIcon} />
{typeof repostCount !== 'undefined' && repostCount > 0 && ( {typeof repostCount !== 'undefined' && repostCount > 0 && (
@@ -121,7 +117,7 @@ let RepostButtonDialogInner = ({
embeddingDisabled: boolean embeddingDisabled: boolean
}): React.ReactNode => { }): React.ReactNode => {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const playHaptic = useHaptics() const playHaptic = useHaptics()
const control = Dialog.useDialogContext() const control = Dialog.useDialogContext()
@@ -143,15 +139,15 @@ let RepostButtonDialogInner = ({
const onPressClose = useCallback(() => control.close(), [control]) const onPressClose = useCallback(() => control.close(), [control])
return ( return (
<Dialog.ScrollableInner label={_(msg`Repost or quote post`)}> <Dialog.ScrollableInner label={l`Repost or quote post`}>
<View style={a.gap_xl}> <View style={a.gap_xl}>
<View style={a.gap_xs}> <View style={a.gap_xs}>
<Button <Button
style={[a.justify_start, a.px_md, a.gap_sm]} style={[a.justify_start, a.px_md, a.gap_sm]}
label={ label={
isReposted isReposted
? _(msg`Remove repost`) ? l`Remove repost`
: _(msg({message: `Repost`, context: 'action'})) : l({message: `Repost`, context: 'action'})
} }
onPress={onPressRepost} onPress={onPressRepost}
size="large" size="large"
@@ -170,11 +166,7 @@ let RepostButtonDialogInner = ({
disabled={embeddingDisabled} disabled={embeddingDisabled}
testID="quoteBtn" testID="quoteBtn"
style={[a.justify_start, a.px_md, a.gap_sm]} style={[a.justify_start, a.px_md, a.gap_sm]}
label={ label={embeddingDisabled ? l`Quote posts disabled` : l`Quote post`}
embeddingDisabled
? _(msg`Quote posts disabled`)
: _(msg`Quote post`)
}
onPress={onPressQuote} onPress={onPressQuote}
size="large" size="large"
variant="ghost" variant="ghost"
@@ -202,7 +194,7 @@ let RepostButtonDialogInner = ({
</Button> </Button>
</View> </View>
<Button <Button
label={_(msg`Cancel quote post`)} label={l`Cancel quote post`}
onPress={onPressClose} onPress={onPressClose}
size="large" size="large"
color="secondary"> color="secondary">
@@ -1,5 +1,4 @@
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {useRequireAuth, useSession} from '#/state/session' import {useRequireAuth, useSession} from '#/state/session'
import {EventStopper} from '#/view/com/util/EventStopper' import {EventStopper} from '#/view/com/util/EventStopper'
@@ -32,7 +31,7 @@ export const RepostButton = ({
embeddingDisabled, embeddingDisabled,
}: Props) => { }: Props) => {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {hasSession} = useSession() const {hasSession} = useSession()
const requireAuth = useRequireAuth() const requireAuth = useRequireAuth()
const formatPostStatCount = useFormatPostStatCount() const formatPostStatCount = useFormatPostStatCount()
@@ -40,7 +39,7 @@ export const RepostButton = ({
return hasSession ? ( return hasSession ? (
<EventStopper onKeyDown={false}> <EventStopper onKeyDown={false}>
<Menu.Root> <Menu.Root>
<Menu.Trigger label={_(msg`Repost or quote post`)}> <Menu.Trigger label={l`Repost or quote post`}>
{({props}) => { {({props}) => {
return ( return (
<PostControlButton <PostControlButton
@@ -64,31 +63,25 @@ export const RepostButton = ({
<Menu.Item <Menu.Item
label={ label={
isReposted isReposted
? _(msg`Undo repost`) ? l`Undo repost`
: _(msg({message: `Repost`, context: `action`})) : l({message: `Repost`, context: `action`})
} }
testID="repostDropdownRepostBtn" testID="repostDropdownRepostBtn"
onPress={onRepost}> onPress={onRepost}>
<Menu.ItemText> <Menu.ItemText>
{isReposted {isReposted
? _(msg`Undo repost`) ? l`Undo repost`
: _(msg({message: `Repost`, context: `action`}))} : l({message: `Repost`, context: `action`})}
</Menu.ItemText> </Menu.ItemText>
<Menu.ItemIcon icon={Repost} position="right" /> <Menu.ItemIcon icon={Repost} position="right" />
</Menu.Item> </Menu.Item>
<Menu.Item <Menu.Item
disabled={embeddingDisabled} disabled={embeddingDisabled}
label={ label={embeddingDisabled ? l`Quote posts disabled` : l`Quote post`}
embeddingDisabled
? _(msg`Quote posts disabled`)
: _(msg`Quote post`)
}
testID="repostDropdownQuoteBtn" testID="repostDropdownQuoteBtn"
onPress={onQuote}> onPress={onQuote}>
<Menu.ItemText> <Menu.ItemText>
{embeddingDisabled {embeddingDisabled ? l`Quote posts disabled` : l`Quote post`}
? _(msg`Quote posts disabled`)
: _(msg`Quote post`)}
</Menu.ItemText> </Menu.ItemText>
<Menu.ItemIcon icon={Quote} position="right" /> <Menu.ItemIcon icon={Quote} position="right" />
</Menu.Item> </Menu.Item>
@@ -100,7 +93,7 @@ export const RepostButton = ({
onPress={() => requireAuth(() => {})} onPress={() => requireAuth(() => {})}
active={isReposted} active={isReposted}
activeColor={t.palette.positive_500} activeColor={t.palette.positive_500}
label={_(msg`Repost or quote post`)} label={l`Repost or quote post`}
big={big}> big={big}>
<PostControlButtonIcon icon={Repost} /> <PostControlButtonIcon icon={Repost} />
{typeof repostCount !== 'undefined' && repostCount > 0 && ( {typeof repostCount !== 'undefined' && repostCount > 0 && (
@@ -4,8 +4,7 @@ import {
moderateProfile, moderateProfile,
type ModerationOpts, type ModerationOpts,
} from '@atproto/api' } from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
@@ -118,7 +117,7 @@ function RecentChatItem({
convo: ConvoWithDetails convo: ConvoWithDetails
primaryMember: ChatBskyActorDefs.ProfileViewBasic primaryMember: ChatBskyActorDefs.ProfileViewBasic
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const primaryProfile = useProfileShadow(primaryMember) const primaryProfile = useProfileShadow(primaryMember)
@@ -143,7 +142,7 @@ function RecentChatItem({
return ( return (
<Button <Button
onPress={onPress} onPress={onPress}
label={_(msg`Send post to ${name}`)} label={l`Send post to ${name}`}
style={[ style={[
a.flex_col, a.flex_col,
{width: WIDTH}, {width: WIDTH},
@@ -7,8 +7,7 @@ import {
AtUri, AtUri,
type RichText as RichTextAPI, type RichText as RichTextAPI,
} from '@atproto/api' } from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {makeProfileLink} from '#/lib/routes/links' import {makeProfileLink} from '#/lib/routes/links'
import {shareUrl} from '#/lib/sharing' import {shareUrl} from '#/lib/sharing'
@@ -48,7 +47,7 @@ let ShareMenuButton = ({
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo' logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
}): React.ReactNode => { }): React.ReactNode => {
const ax = useAnalytics() const ax = useAnalytics()
const {_} = useLingui() const {t: l} = useLingui()
const {feedDescriptor} = useFeedFeedbackContext() const {feedDescriptor} = useFeedFeedbackContext()
const menuControl = useMenuControl() const menuControl = useMenuControl()
@@ -95,7 +94,7 @@ let ShareMenuButton = ({
return ( return (
<EventStopper onKeyDown={false}> <EventStopper onKeyDown={false}>
<Menu.Root control={lazyMenuControl}> <Menu.Root control={lazyMenuControl}>
<Menu.Trigger label={_(msg`Open share menu`)}> <Menu.Trigger label={l`Open share menu`}>
{({props}) => { {({props}) => {
return ( return (
<PostControlButton <PostControlButton
+1 -1
View File
@@ -1,5 +1,5 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react/macro'
/** /**
* This matches `formatCount` from `view/com/util/numeric/format.ts`, but has * This matches `formatCount` from `view/com/util/numeric/format.ts`, but has
+10 -19
View File
@@ -6,8 +6,8 @@ import {
type ModerationOpts, type ModerationOpts,
} from '@atproto/api' } from '@atproto/api'
import {flip, offset, shift, size, useFloating} from '@floating-ui/react-dom' import {flip, offset, shift, size, useFloating} from '@floating-ui/react-dom'
import {msg, plural} from '@lingui/core/macro' import {plural} from '@lingui/core/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
import {getModerationCauseKey} from '#/lib/moderation' import {getModerationCauseKey} from '#/lib/moderation'
@@ -423,7 +423,7 @@ function Inner({
hide: () => void hide: () => void
}) { }) {
const t = useTheme() const t = useTheme()
const {_, i18n} = useLingui() const {t: l, i18n} = useLingui()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const moderation = useMemo( const moderation = useMemo(
() => moderateProfile(profile, moderationOpts), () => moderateProfile(profile, moderationOpts),
@@ -462,7 +462,7 @@ function Inner({
return ( return (
<View> <View>
<View style={[a.flex_row, a.justify_between, a.align_start]}> <View style={[a.flex_row, a.justify_between, a.align_start]}>
<Link to={profileURL} label={_(msg`View profile`)} onPress={hide}> <Link to={profileURL} label={l`View profile`} onPress={hide}>
<UserAvatar <UserAvatar
size={64} size={64}
avatar={profile.avatar} avatar={profile.avatar}
@@ -476,24 +476,20 @@ function Inner({
(isBlockedUser ? ( (isBlockedUser ? (
<Link <Link
to={profileURL} to={profileURL}
label={_(msg`View blocked user's profile`)} label={l`View blocked user's profile`}
onPress={hide} onPress={hide}
size="small" size="small"
color="secondary" color="secondary"
variant="solid" variant="solid"
style={[a.rounded_full]}> style={[a.rounded_full]}>
<ButtonText>{_(msg`View profile`)}</ButtonText> <ButtonText>{l`View profile`}</ButtonText>
</Link> </Link>
) : ( ) : (
<Button <Button
size="small" size="small"
color={profileShadow.viewer?.following ? 'secondary' : 'primary'} color={profileShadow.viewer?.following ? 'secondary' : 'primary'}
variant="solid" variant="solid"
label={ label={profileShadow.viewer?.following ? l`Following` : l`Follow`}
profileShadow.viewer?.following
? _(msg`Following`)
: _(msg`Follow`)
}
style={[a.rounded_full]} style={[a.rounded_full]}
onPress={profileShadow.viewer?.following ? unfollow : follow}> onPress={profileShadow.viewer?.following ? unfollow : follow}>
<ButtonIcon <ButtonIcon
@@ -501,15 +497,12 @@ function Inner({
icon={profileShadow.viewer?.following ? Check : Plus} icon={profileShadow.viewer?.following ? Check : Plus}
/> />
<ButtonText> <ButtonText>
{profileShadow.viewer?.following {profileShadow.viewer?.following ? l`Following` : l`Follow`}
? _(msg`Following`)
: _(msg`Follow`)}
</ButtonText> </ButtonText>
</Button> </Button>
))} ))}
</View> </View>
<Link to={profileURL} label={l`View profile`} onPress={hide}>
<Link to={profileURL} label={_(msg`View profile`)} onPress={hide}>
<View style={[a.pb_sm, a.flex_1]}> <View style={[a.pb_sm, a.flex_1]}>
<View style={[a.flex_row, a.align_center, a.pt_md, a.pb_xs]}> <View style={[a.flex_row, a.align_center, a.pt_md, a.pb_xs]}>
<Text <Text
@@ -540,7 +533,6 @@ function Inner({
<ProfileHeaderHandle profile={profileShadow} disableTaps /> <ProfileHeaderHandle profile={profileShadow} disableTaps />
</View> </View>
</Link> </Link>
{isBlockedUser && ( {isBlockedUser && (
<View style={[a.flex_row, a.flex_wrap, a.gap_xs]}> <View style={[a.flex_row, a.flex_wrap, a.gap_xs]}>
{moderation.ui('profileView').alerts.map(cause => ( {moderation.ui('profileView').alerts.map(cause => (
@@ -553,7 +545,6 @@ function Inner({
))} ))}
</View> </View>
)} )}
{!isBlockedUser && ( {!isBlockedUser && (
<> <>
<View style={[a.flex_row, a.flex_wrap, a.gap_md, a.pt_xs]}> <View style={[a.flex_row, a.flex_wrap, a.gap_md, a.pt_xs]}>
@@ -569,7 +560,7 @@ function Inner({
</InlineLinkText> </InlineLinkText>
<InlineLinkText <InlineLinkText
to={makeProfileLink(profile, 'follows')} to={makeProfileLink(profile, 'follows')}
label={_(msg`${following} following`)} label={l`${following} following`}
style={[t.atoms.text]} style={[t.atoms.text]}
onPress={hide}> onPress={hide}>
<Text style={[a.text_md, a.font_semi_bold]}>{following} </Text> <Text style={[a.text_md, a.font_semi_bold]}>{following} </Text>
+3 -4
View File
@@ -15,8 +15,7 @@ import Animated, {
} from 'react-native-reanimated' } from 'react-native-reanimated'
import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {scheduleOnRN} from 'react-native-worklets' import {scheduleOnRN} from 'react-native-worklets'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Portal} from '#/components/Portal' import {Portal} from '#/components/Portal'
@@ -40,7 +39,7 @@ export const ProgressGuideToast = forwardRef<
ProgressGuideToastProps ProgressGuideToastProps
>(function ProgressGuideToast({title, subtitle, visibleDuration}, ref) { >(function ProgressGuideToast({title, subtitle, visibleDuration}, ref) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const insets = useSafeAreaInsets() const insets = useSafeAreaInsets()
const [isOpen, setIsOpen] = useState(false) const [isOpen, setIsOpen] = useState(false)
const translateY = useSharedValue(0) const translateY = useSharedValue(0)
@@ -156,7 +155,7 @@ export const ProgressGuideToast = forwardRef<
}, },
]} ]}
onPress={close} onPress={close}
accessibilityLabel={_(msg`Tap to dismiss`)} accessibilityLabel={l`Tap to dismiss`}
accessibilityHint=""> accessibilityHint="">
<AnimatedCheck <AnimatedCheck
fill={t.palette.primary_500} fill={t.palette.primary_500}
+11 -12
View File
@@ -1,7 +1,6 @@
import {useMemo} from 'react' import {useMemo} from 'react'
import {type StyleProp, Text as RNText, type TextStyle} from 'react-native' import {type StyleProp, Text as RNText, type TextStyle} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
@@ -35,7 +34,7 @@ export function RichTextTag({
authorHandle?: string authorHandle?: string
textStyle: StyleProp<TextStyle> textStyle: StyleProp<TextStyle>
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const {isLoading: isPreferencesLoading, data: preferences} = const {isLoading: isPreferencesLoading, data: preferences} =
usePreferencesQuery() usePreferencesQuery()
const { const {
@@ -50,10 +49,10 @@ export function RichTextTag({
} = useRemoveMutedWordsMutation() } = useRemoveMutedWordsMutation()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
const isCashtag = tag.startsWith('$') const isCashtag = tag.startsWith('$')
const label = isCashtag ? _(msg`Cashtag ${tag}`) : _(msg`Hashtag ${tag}`) const label = isCashtag ? l`Cashtag ${tag}` : l`Hashtag ${tag}`
const hint = IS_NATIVE const hint = IS_NATIVE
? _(msg`Long press to open tag menu for ${isCashtag ? tag : `#${tag}`}`) ? l`Long press to open tag menu for ${isCashtag ? tag : `#${tag}`}`
: _(msg`Click to open tag menu for ${isCashtag ? tag : `#${tag}`}`) : l`Click to open tag menu for ${isCashtag ? tag : `#${tag}`}`
const isMuted = Boolean( const isMuted = Boolean(
(preferences?.moderationPrefs.mutedWords?.find( (preferences?.moderationPrefs.mutedWords?.find(
@@ -111,7 +110,7 @@ export function RichTextTag({
<Menu.Outer> <Menu.Outer>
<Menu.Group> <Menu.Group>
<Menu.Item <Menu.Item
label={_(msg`See ${isCashtag ? tag : `#${tag}`} posts`)} label={l`See ${isCashtag ? tag : `#${tag}`} posts`}
onPress={() => { onPress={() => {
navigation.push('Hashtag', { navigation.push('Hashtag', {
tag: encodeURIComponent(tag), tag: encodeURIComponent(tag),
@@ -128,7 +127,7 @@ export function RichTextTag({
</Menu.Item> </Menu.Item>
{authorHandle && !isInvalidHandle(authorHandle) && ( {authorHandle && !isInvalidHandle(authorHandle) && (
<Menu.Item <Menu.Item
label={_(msg`See ${isCashtag ? tag : `#${tag}`} posts by user`)} label={l`See ${isCashtag ? tag : `#${tag}`} posts by user`}
onPress={() => { onPress={() => {
navigation.push('Hashtag', { navigation.push('Hashtag', {
tag: encodeURIComponent(tag), tag: encodeURIComponent(tag),
@@ -150,8 +149,8 @@ export function RichTextTag({
<Menu.Item <Menu.Item
label={ label={
isMuted isMuted
? _(msg`Unmute ${isCashtag ? tag : `#${tag}`}`) ? l`Unmute ${isCashtag ? tag : `#${tag}`}`
: _(msg`Mute ${isCashtag ? tag : `#${tag}`}`) : l`Mute ${isCashtag ? tag : `#${tag}`}`
} }
onPress={() => { onPress={() => {
if (isMuted) { if (isMuted) {
@@ -166,8 +165,8 @@ export function RichTextTag({
}}> }}>
<Menu.ItemText> <Menu.ItemText>
{isMuted {isMuted
? _(msg`Unmute ${isCashtag ? tag : `#${tag}`}`) ? l`Unmute ${isCashtag ? tag : `#${tag}`}`
: _(msg`Mute ${isCashtag ? tag : `#${tag}`}`)} : l`Mute ${isCashtag ? tag : `#${tag}`}`}
</Menu.ItemText> </Menu.ItemText>
<Menu.ItemIcon icon={isPreferencesLoading ? Loader : Mute} /> <Menu.ItemIcon icon={isPreferencesLoading ? Loader : Mute} />
</Menu.Item> </Menu.Item>
+3 -4
View File
@@ -7,8 +7,7 @@ import {
useState, useState,
} from 'react' } from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {Button, ButtonIcon, ButtonText} from '#/components/Button'
@@ -170,7 +169,7 @@ function ContentInner<T>({
valueExtractor, valueExtractor,
...context ...context
}: ContentProps<T> & ContextType) { }: ContentProps<T> & ContextType) {
const {_} = useLingui() const {t: l} = useLingui()
const [headerHeight, setHeaderHeight] = useState(61) const [headerHeight, setHeaderHeight] = useState(61)
const render = useCallback( const render = useCallback(
@@ -196,7 +195,7 @@ function ContentInner<T>({
]}> ]}>
<Dialog.HeaderText <Dialog.HeaderText
style={[a.flex_1, a.px_xl, a.text_left, a.font_bold, a.text_2xl]}> style={[a.flex_1, a.px_xl, a.text_left, a.font_bold, a.text_2xl]}>
{label ?? _(msg`Select an option`)} {label ?? l`Select an option`}
</Dialog.HeaderText> </Dialog.HeaderText>
</Dialog.Header> </Dialog.Header>
<Dialog.Handle /> <Dialog.Handle />
@@ -1,7 +1,6 @@
import {forwardRef, useCallback, useImperativeHandle} from 'react' import {forwardRef, useCallback, useImperativeHandle} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {type FeedDescriptor} from '#/state/queries/post-feed' import {type FeedDescriptor} from '#/state/queries/post-feed'
import {PostFeed} from '#/view/com/posts/PostFeed' import {PostFeed} from '#/view/com/posts/PostFeed'
@@ -20,7 +19,7 @@ interface ProfilesListProps {
export const PostsList = forwardRef<SectionRef, ProfilesListProps>( export const PostsList = forwardRef<SectionRef, ProfilesListProps>(
function PostsListImpl({listUri, headerHeight, scrollElRef}, ref) { function PostsListImpl({listUri, headerHeight, scrollElRef}, ref) {
const feed: FeedDescriptor = `list|${listUri}` const feed: FeedDescriptor = `list|${listUri}`
const {_} = useLingui() const {t: l} = useLingui()
const onScrollToTop = useCallback(() => { const onScrollToTop = useCallback(() => {
scrollElRef.current?.scrollToOffset({ scrollElRef.current?.scrollToOffset({
@@ -38,10 +37,10 @@ export const PostsList = forwardRef<SectionRef, ProfilesListProps>(
<EmptyState <EmptyState
icon={HashtagWideIcon} icon={HashtagWideIcon}
iconSize="2xl" iconSize="2xl"
message={_(msg`This feed is empty.`)} message={l`This feed is empty.`}
/> />
) )
}, [_]) }, [l])
return ( return (
<View> <View>
@@ -7,8 +7,7 @@ import {
type ViewStyle, type ViewStyle,
} from 'react-native' } from 'react-native'
import {type AppBskyGraphDefs} from '@atproto/api' import {type AppBskyGraphDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
@@ -90,7 +89,7 @@ export function ProfileStarterPacks({
const {isTabletOrDesktop} = useWebMediaQueries() const {isTabletOrDesktop} = useWebMediaQueries()
const items = data?.pages.flatMap(page => page.starterPacks) const items = data?.pages.flatMap(page => page.starterPacks)
const {_} = useLingui() const {t: l} = useLingui()
const EmptyComponent = useCallback(() => { const EmptyComponent = useCallback(() => {
if (emptyStateMessage || emptyStateButton || emptyStateIcon) { if (emptyStateMessage || emptyStateButton || emptyStateIcon) {
@@ -101,9 +100,7 @@ export function ProfileStarterPacks({
iconSize="3xl" iconSize="3xl"
message={ message={
emptyStateMessage ?? emptyStateMessage ??
_( l`Starter packs let you share your favorite feeds and people with your friends.`
msg`Starter packs let you share your favorite feeds and people with your friends.`,
)
} }
button={emptyStateButton} button={emptyStateButton}
/> />
@@ -111,7 +108,7 @@ export function ProfileStarterPacks({
) )
} }
return <Empty /> return <Empty />
}, [_, emptyStateMessage, emptyStateButton, emptyStateIcon]) }, [l, emptyStateMessage, emptyStateButton, emptyStateIcon])
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
scrollToTop: () => {}, scrollToTop: () => {},
@@ -193,7 +190,7 @@ export function ProfileStarterPacks({
} }
function CreateAnother() { function CreateAnother() {
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
@@ -207,7 +204,7 @@ function CreateAnother() {
t.atoms.border_contrast_low, t.atoms.border_contrast_low,
]}> ]}>
<Button <Button
label={_(msg`Create a starter pack`)} label={l`Create a starter pack`}
variant="solid" variant="solid"
color="secondary" color="secondary"
size="small" size="small"
@@ -223,7 +220,7 @@ function CreateAnother() {
} }
function Empty() { function Empty() {
const {_} = useLingui() const {t: l} = useLingui()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
const confirmDialogControl = useDialogControl() const confirmDialogControl = useDialogControl()
const followersDialogControl = useDialogControl() const followersDialogControl = useDialogControl()
@@ -303,7 +300,7 @@ function Empty() {
</View> </View>
<View style={[a.flex_row, a.gap_md, {marginLeft: 'auto'}]}> <View style={[a.flex_row, a.gap_md, {marginLeft: 'auto'}]}>
<Button <Button
label={_(msg`Create a starter pack for me`)} label={l`Create a starter pack for me`}
variant="ghost" variant="ghost"
color="primary" color="primary"
size="small" size="small"
@@ -316,7 +313,7 @@ function Empty() {
{isGenerating && <Loader size="md" />} {isGenerating && <Loader size="md" />}
</Button> </Button>
<Button <Button
label={_(msg`Create a starter pack`)} label={l`Create a starter pack`}
variant="ghost" variant="ghost"
color="primary" color="primary"
size="small" size="small"
@@ -333,7 +330,6 @@ function Empty() {
</ButtonText> </ButtonText>
</Button> </Button>
</View> </View>
<Prompt.Outer control={confirmDialogControl}> <Prompt.Outer control={confirmDialogControl}>
<Prompt.Content> <Prompt.Content>
<Prompt.TitleText> <Prompt.TitleText>
@@ -349,12 +345,12 @@ function Empty() {
<Prompt.Actions> <Prompt.Actions>
<Prompt.Action <Prompt.Action
color="primary" color="primary"
cta={_(msg`Choose for me`)} cta={l`Choose for me`}
onPress={generate} onPress={generate}
/> />
<Prompt.Action <Prompt.Action
color="secondary" color="secondary"
cta={_(msg`Let me choose`)} cta={l`Let me choose`}
onPress={() => { onPress={() => {
navigation.navigate('StarterPackWizard', {}) navigation.navigate('StarterPackWizard', {})
}} }}
@@ -363,21 +359,17 @@ function Empty() {
</Prompt.Outer> </Prompt.Outer>
<Prompt.Basic <Prompt.Basic
control={followersDialogControl} control={followersDialogControl}
title={_(msg`Oops!`)} title={l`Oops!`}
description={_( description={l`You must be following at least seven other people to generate a starter pack.`}
msg`You must be following at least seven other people to generate a starter pack.`,
)}
onConfirm={() => {}} onConfirm={() => {}}
showCancel={false} showCancel={false}
/> />
<Prompt.Basic <Prompt.Basic
control={errorDialogControl} control={errorDialogControl}
title={_(msg`Oops!`)} title={l`Oops!`}
description={_( description={l`An error occurred while generating your starter pack. Want to try again?`}
msg`An error occurred while generating your starter pack. Want to try again?`,
)}
onConfirm={generate} onConfirm={generate}
confirmButtonCta={_(msg`Retry`)} confirmButtonCta={l`Retry`}
/> />
</LinearGradientBackground> </LinearGradientBackground>
) )
+10 -14
View File
@@ -4,8 +4,7 @@ import type ViewShot from 'react-native-view-shot'
import {requestPermissionsAsync, saveToLibraryAsync} from 'expo-media-library' import {requestPermissionsAsync, saveToLibraryAsync} from 'expo-media-library'
import * as Sharing from 'expo-sharing' import * as Sharing from 'expo-sharing'
import {type AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' import {type AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {logger} from '#/logger' import {logger} from '#/logger'
@@ -32,7 +31,7 @@ export function QrCodeDialog({
link?: string link?: string
control: DialogControlProps control: DialogControlProps
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const {gtMobile} = useBreakpoints() const {gtMobile} = useBreakpoints()
const [isSaveProcessing, setIsSaveProcessing] = useState(false) const [isSaveProcessing, setIsSaveProcessing] = useState(false)
@@ -65,9 +64,7 @@ export function QrCodeDialog({
if (!res.granted) { if (!res.granted) {
Toast.show( Toast.show(
_( l`You must grant access to your photo library to save a QR code`,
msg`You must grant access to your photo library to save a QR code`,
),
) )
return return
} }
@@ -78,7 +75,7 @@ export function QrCodeDialog({
// works with the add-only permission on iOS (APP-2374) // works with the add-only permission on iOS (APP-2374)
await saveToLibraryAsync(`file://${uri}`) await saveToLibraryAsync(`file://${uri}`)
} catch (e: unknown) { } catch (e: unknown) {
Toast.show(_(msg`An error occurred while saving the QR code!`), { Toast.show(l`An error occurred while saving the QR code!`, {
type: 'error', type: 'error',
}) })
logger.error('Failed to save QR code', {error: e}) logger.error('Failed to save QR code', {error: e})
@@ -118,8 +115,8 @@ export function QrCodeDialog({
setIsSaveProcessing(false) setIsSaveProcessing(false)
Toast.show( Toast.show(
IS_WEB IS_WEB
? _(msg`QR code has been downloaded!`) ? l`QR code has been downloaded!`
: _(msg`QR code saved to your camera roll!`), : l`QR code saved to your camera roll!`,
) )
control.close() control.close()
}) })
@@ -140,7 +137,7 @@ export function QrCodeDialog({
shareType: 'qrcode', shareType: 'qrcode',
qrShareType: 'copy', qrShareType: 'copy',
}) })
Toast.show(_(msg`QR code copied to your clipboard!`)) Toast.show(l`QR code copied to your clipboard!`)
setIsCopyProcessing(false) setIsCopyProcessing(false)
control.close() control.close()
}) })
@@ -165,8 +162,7 @@ export function QrCodeDialog({
return ( return (
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner label={l`Create a QR code for a starter pack`}>
label={_(msg`Create a QR code for a starter pack`)}>
<View style={[a.flex_1, a.align_center, a.gap_5xl]}> <View style={[a.flex_1, a.align_center, a.gap_5xl]}>
<Suspense fallback={<Loading />}> <Suspense fallback={<Loading />}>
{!link ? ( {!link ? (
@@ -181,7 +177,7 @@ export function QrCodeDialog({
gtMobile && [a.flex_row, a.justify_center, a.flex_wrap], gtMobile && [a.flex_row, a.justify_center, a.flex_wrap],
]}> ]}>
<Button <Button
label={_(msg`Copy QR code`)} label={l`Copy QR code`}
color="primary_subtle" color="primary_subtle"
size="large" size="large"
onPress={IS_WEB ? onCopyPress : onSharePress}> onPress={IS_WEB ? onCopyPress : onSharePress}>
@@ -199,7 +195,7 @@ export function QrCodeDialog({
</ButtonText> </ButtonText>
</Button> </Button>
<Button <Button
label={_(msg`Save QR code`)} label={l`Save QR code`}
color="secondary" color="secondary"
size="large" size="large"
onPress={onSavePress}> onPress={onSavePress}>
+6 -7
View File
@@ -1,8 +1,7 @@
import {View} from 'react-native' import {View} from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {type AppBskyGraphDefs} from '@atproto/api' import {type AppBskyGraphDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useSaveImageToMediaLibrary} from '#/lib/media/save-image' import {useSaveImageToMediaLibrary} from '#/lib/media/save-image'
@@ -46,7 +45,7 @@ function ShareDialogInner({
qrDialogControl, qrDialogControl,
control, control,
}: Props) { }: Props) {
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const t = useTheme() const t = useTheme()
const {gtMobile} = useBreakpoints() const {gtMobile} = useBreakpoints()
@@ -71,7 +70,7 @@ function ShareDialogInner({
return ( return (
<> <>
<Dialog.ScrollableInner label={_(msg`Share link dialog`)}> <Dialog.ScrollableInner label={l`Share link dialog`}>
{!imageLoaded || !link ? ( {!imageLoaded || !link ? (
<View style={[a.align_center, a.justify_center, {minHeight: 350}]}> <View style={[a.align_center, a.justify_center, {minHeight: 350}]}>
<Loader size="xl" /> <Loader size="xl" />
@@ -112,7 +111,7 @@ function ShareDialogInner({
], ],
]}> ]}>
<Button <Button
label={IS_WEB ? _(msg`Copy link`) : _(msg`Share link`)} label={IS_WEB ? l`Copy link` : l`Share link`}
color="primary_subtle" color="primary_subtle"
size="large" size="large"
onPress={onShareLink}> onPress={onShareLink}>
@@ -126,7 +125,7 @@ function ShareDialogInner({
</ButtonText> </ButtonText>
</Button> </Button>
<Button <Button
label={_(msg`Share QR code`)} label={l`Share QR code`}
color="primary_subtle" color="primary_subtle"
size="large" size="large"
onPress={() => { onPress={() => {
@@ -141,7 +140,7 @@ function ShareDialogInner({
</Button> </Button>
{IS_NATIVE && ( {IS_NATIVE && (
<Button <Button
label={_(msg`Save image`)} label={l`Save image`}
color="secondary" color="secondary"
size="large" size="large"
onPress={onSave}> onPress={onSave}>
+9 -10
View File
@@ -2,8 +2,7 @@ import {useMemo} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {AppBskyGraphStarterpack, AtUri} from '@atproto/api' import {AppBskyGraphStarterpack, AtUri} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Plural, Trans} from '@lingui/react/macro' import {Plural, Trans} from '@lingui/react/macro'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
@@ -58,7 +57,7 @@ export function Card({
}) { }) {
const {record, creator, joinedAllTimeCount} = starterPack const {record, creator, joinedAllTimeCount} = starterPack
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const {currentAccount} = useSession() const {currentAccount} = useSession()
@@ -87,8 +86,8 @@ export function Card({
style={[a.leading_snug, t.atoms.text_contrast_medium]} style={[a.leading_snug, t.atoms.text_contrast_medium]}
numberOfLines={1}> numberOfLines={1}>
{creator?.did === currentAccount?.did {creator?.did === currentAccount?.did
? _(msg`Starter pack by you`) ? l`Starter pack by you`
: _(msg`Starter pack by ${sanitizeHandle(creator.handle, '@')}`)} : l`Starter pack by ${sanitizeHandle(creator.handle, '@')}`}
</Text> </Text>
</View> </View>
</View> </View>
@@ -113,7 +112,7 @@ export function useStarterPackLink({
}: { }: {
view: bsky.starterPack.AnyStarterPackView view: bsky.starterPack.AnyStarterPackView
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const qc = useQueryClient() const qc = useQueryClient()
const {rkey, handleOrDid} = useMemo(() => { const {rkey, handleOrDid} = useMemo(() => {
const rkey = new AtUri(view.uri).rkey const rkey = new AtUri(view.uri).rkey
@@ -131,8 +130,8 @@ export function useStarterPackLink({
view.record, view.record,
AppBskyGraphStarterpack.isRecord, AppBskyGraphStarterpack.isRecord,
) )
? _(msg`Navigate to ${view.record.name}`) ? l`Navigate to ${view.record.name}`
: _(msg`Navigate to starter pack`), : l`Navigate to starter pack`,
precache, precache,
} }
} }
@@ -145,7 +144,7 @@ export function Link({
onPress?: () => void onPress?: () => void
children: BaseLinkProps['children'] children: BaseLinkProps['children']
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const {record} = starterPack const {record} = starterPack
const {rkey, handleOrDid} = useMemo(() => { const {rkey, handleOrDid} = useMemo(() => {
@@ -166,7 +165,7 @@ export function Link({
return ( return (
<BaseLink <BaseLink
to={`/starter-pack/${handleOrDid}/${rkey}`} to={`/starter-pack/${handleOrDid}/${rkey}`}
label={_(msg`Navigate to ${record.name}`)} label={l`Navigate to ${record.name}`}
onPress={() => { onPress={() => {
precacheResolvedUri( precacheResolvedUri(
queryClient, queryClient,
@@ -6,8 +6,7 @@ import {
type AppBskyFeedDefs, type AppBskyFeedDefs,
type ModerationOpts, type ModerationOpts,
} from '@atproto/api' } from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
@@ -46,7 +45,7 @@ export function WizardEditListDialog({
moderationOpts: ModerationOpts moderationOpts: ModerationOpts
profile: AppBskyActorDefs.ProfileViewDetailed profile: AppBskyActorDefs.ProfileViewDetailed
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const initialNumToRender = useInitialNumToRender() const initialNumToRender = useInitialNumToRender()
@@ -119,7 +118,7 @@ export function WizardEditListDialog({
<View style={{width: 60}}> <View style={{width: 60}}>
{IS_WEB && ( {IS_WEB && (
<Button <Button
label={_(msg`Close`)} label={l`Close`}
variant="ghost" variant="ghost"
color="primary" color="primary"
size="small" size="small"
@@ -7,8 +7,7 @@ import {
type ModerationOpts, type ModerationOpts,
type ModerationUI, type ModerationUI,
} from '@atproto/api' } from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from '#/lib/constants' import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from '#/lib/constants'
@@ -52,15 +51,15 @@ function WizardListCard({
moderationUi: ModerationUI moderationUi: ModerationUI
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
return ( return (
<Toggle.Item <Toggle.Item
name={type === 'user' ? _(msg`Person toggle`) : _(msg`Feed toggle`)} name={type === 'user' ? l`Person toggle` : l`Feed toggle`}
label={ label={
included included
? _(msg`Remove ${displayName} from starter pack`) ? l`Remove ${displayName} from starter pack`
: _(msg`Add ${displayName} to starter pack`) : l`Add ${displayName} to starter pack`
} }
value={included} value={included}
disabled={btnType === 'remove' || disabled} disabled={btnType === 'remove' || disabled}
@@ -103,7 +102,7 @@ function WizardListCard({
<Checkbox /> <Checkbox />
) : !disabled ? ( ) : !disabled ? (
<Button <Button
label={_(msg`Remove`)} label={l`Remove`}
variant="solid" variant="solid"
color="secondary" color="secondary"
size="small" size="small"
+9 -13
View File
@@ -12,8 +12,7 @@ import {
type AppBskyGraphDefs, type AppBskyGraphDefs,
AtUri, AtUri,
} from '@atproto/api' } from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {HITSLOP_10} from '#/lib/constants' import {HITSLOP_10} from '#/lib/constants'
@@ -49,7 +48,7 @@ interface WhoCanReplyProps {
export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) { export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
const t = useTheme() const t = useTheme()
const ax = useAnalytics() const ax = useAnalytics()
const {_} = useLingui() const {t: l} = useLingui()
const infoDialogControl = useDialogControl() const infoDialogControl = useDialogControl()
const editDialogControl = useDialogControl() const editDialogControl = useDialogControl()
@@ -82,10 +81,10 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
settings.length === 1 && settings[0].type === 'everybody' settings.length === 1 && settings[0].type === 'everybody'
const noOneCanReply = settings.length === 1 && settings[0].type === 'nobody' const noOneCanReply = settings.length === 1 && settings[0].type === 'nobody'
const description = anyoneCanReply const description = anyoneCanReply
? _(msg`Everybody can reply`) ? l`Everybody can reply`
: noOneCanReply : noOneCanReply
? _(msg`Replies disabled`) ? l`Replies disabled`
: _(msg`Some people can reply`) : l`Some people can reply`
const onPressOpen = () => { const onPressOpen = () => {
if (IS_NATIVE && Keyboard.isVisible()) { if (IS_NATIVE && Keyboard.isVisible()) {
@@ -112,9 +111,7 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
return ( return (
<> <>
<Button <Button
label={ label={isThreadAuthor ? l`Edit who can reply` : l`Who can reply`}
isThreadAuthor ? _(msg`Edit who can reply`) : _(msg`Who can reply`)
}
onPress={onPressOpen} onPress={onPressOpen}
{...(isThreadAuthor {...(isThreadAuthor
? Platform.select({ ? Platform.select({
@@ -161,7 +158,6 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
</View> </View>
)} )}
</Button> </Button>
{isThreadAuthor ? ( {isThreadAuthor ? (
<PostInteractionSettingsDialog <PostInteractionSettingsDialog
postUri={post.uri} postUri={post.uri}
@@ -213,13 +209,13 @@ function WhoCanReplyDialog({
settings: ThreadgateAllowUISetting[] settings: ThreadgateAllowUISetting[]
embeddingDisabled: boolean embeddingDisabled: boolean
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
return ( return (
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Dialog: adjust who can interact with this post`)} label={l`Dialog: adjust who can interact with this post`}
style={web({maxWidth: 400})}> style={web({maxWidth: 400})}>
<View style={[a.gap_sm]}> <View style={[a.gap_sm]}>
<Text style={[a.font_semi_bold, a.text_xl, a.pb_sm]}> <Text style={[a.font_semi_bold, a.text_xl, a.pb_sm]}>
@@ -233,7 +229,7 @@ function WhoCanReplyDialog({
</View> </View>
{IS_NATIVE && ( {IS_NATIVE && (
<Button <Button
label={_(msg`Close`)} label={l`Close`}
onPress={() => control.close()} onPress={() => control.close()}
size="small" size="small"
variant="solid" variant="solid"
@@ -6,8 +6,7 @@ import {
type ModerationOpts, type ModerationOpts,
type Un$Typed, type Un$Typed,
} from '@atproto/api' } from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import { import {
type InfiniteData, type InfiniteData,
@@ -72,7 +71,7 @@ function DialogInner({
includeProfile?: boolean includeProfile?: boolean
}) { }) {
const ax = useAnalytics() const ax = useAnalytics()
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const agent = useAgent() const agent = useAgent()
const control = Dialog.useDialogContext() const control = Dialog.useDialogContext()
@@ -136,9 +135,7 @@ function DialogInner({
if (!activitySubscription.post && !activitySubscription.reply) { if (!activitySubscription.post && !activitySubscription.reply) {
ax.metric('activitySubscription:disable', {}) ax.metric('activitySubscription:disable', {})
Toast.show( Toast.show(
_( l`You will no longer receive notifications for ${sanitizeHandle(profile.handle, '@')}`,
msg`You will no longer receive notifications for ${sanitizeHandle(profile.handle, '@')}`,
),
{ {
type: 'success', type: 'success',
}, },
@@ -168,15 +165,13 @@ function DialogInner({
}) })
if (!initialState.post && !initialState.reply) { if (!initialState.post && !initialState.reply) {
Toast.show( Toast.show(
_( l`You'll start receiving notifications for ${sanitizeHandle(profile.handle, '@')}!`,
msg`You'll start receiving notifications for ${sanitizeHandle(profile.handle, '@')}!`,
),
{ {
type: 'success', type: 'success',
}, },
) )
} else { } else {
Toast.show(_(msg`Changes saved`), { Toast.show(l`Changes saved`, {
type: 'success', type: 'success',
}) })
} }
@@ -195,7 +190,7 @@ function DialogInner({
if (isDirty) { if (isDirty) {
return { return {
label: _(msg`Save changes`), label: l`Save changes`,
color: hasAny ? 'primary' : 'negative', color: hasAny ? 'primary' : 'negative',
onPress: () => saveChanges(state), onPress: () => saveChanges(state),
disabled: isSaving, disabled: isSaving,
@@ -204,26 +199,26 @@ function DialogInner({
// on web, a disabled save button feels more natural than a massive close button // on web, a disabled save button feels more natural than a massive close button
if (IS_WEB) { if (IS_WEB) {
return { return {
label: _(msg`Save changes`), label: l`Save changes`,
color: 'secondary', color: 'secondary',
disabled: true, disabled: true,
} }
} else { } else {
return { return {
label: _(msg`Cancel`), label: l`Cancel`,
color: 'secondary', color: 'secondary',
onPress: () => control.close(), onPress: () => control.close(),
} }
} }
} }
}, [state, initialState, control, _, isSaving, saveChanges]) }, [state, initialState, control, l, isSaving, saveChanges])
const name = createSanitizedDisplayName(profile, false) const name = createSanitizedDisplayName(profile, false)
return ( return (
<Dialog.ScrollableInner <Dialog.ScrollableInner
style={web({maxWidth: 400})} style={web({maxWidth: 400})}
label={_(msg`Get notified of new posts from ${name}`)}> label={l`Get notified of new posts from ${name}`}>
<View style={[a.gap_lg]}> <View style={[a.gap_lg]}>
<View style={[a.gap_xs]}> <View style={[a.gap_xs]}>
<Text style={[a.font_bold, a.text_2xl]}> <Text style={[a.font_bold, a.text_2xl]}>
@@ -249,12 +244,12 @@ function DialogInner({
)} )}
<Toggle.Group <Toggle.Group
label={_(msg`Subscribe to account activity`)} label={l`Subscribe to account activity`}
values={values} values={values}
onChange={onChange}> onChange={onChange}>
<View style={[a.gap_sm]}> <View style={[a.gap_sm]}>
<Toggle.Item <Toggle.Item
label={_(msg`Posts`)} label={l`Posts`}
name="post" name="post"
style={[ style={[
a.flex_1, a.flex_1,
@@ -271,7 +266,7 @@ function DialogInner({
<Toggle.Switch /> <Toggle.Switch />
</Toggle.Item> </Toggle.Item>
<Toggle.Item <Toggle.Item
label={_(msg`Replies`)} label={l`Replies`}
name="reply" name="reply"
style={[ style={[
a.flex_1, a.flex_1,
@@ -301,7 +296,6 @@ function DialogInner({
{isSaving && <ButtonIcon icon={Loader} />} {isSaving && <ButtonIcon icon={Loader} />}
</Button> </Button>
</View> </View>
<Dialog.Close /> <Dialog.Close />
</Dialog.ScrollableInner> </Dialog.ScrollableInner>
) )
@@ -1,6 +1,5 @@
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {atoms as a, select, useTheme, type ViewStyleProp} from '#/alf' import {atoms as a, select, useTheme, type ViewStyleProp} from '#/alf'
@@ -40,7 +39,7 @@ function Inner({
control: Dialog.DialogControlProps control: Dialog.DialogControlProps
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
return ( return (
@@ -90,7 +89,7 @@ function Inner({
<Trans> <Trans>
Learn more in your{' '} Learn more in your{' '}
<InlineLinkText <InlineLinkText
label={_(msg`Go to account settings`)} label={l`Go to account settings`}
to={'/settings/account'} to={'/settings/account'}
style={[a.text_sm, a.leading_snug, a.font_semi_bold]} style={[a.text_sm, a.leading_snug, a.font_semi_bold]}
onPress={() => { onPress={() => {
@@ -1,8 +1,7 @@
import {useState} from 'react' import {useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {ToolsOzoneReportDefs} from '@atproto/api' import {ToolsOzoneReportDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useMutation} from '@tanstack/react-query' import {useMutation} from '@tanstack/react-query'
@@ -23,12 +22,12 @@ export function AgeAssuranceAppealDialog({
}: { }: {
control: Dialog.DialogControlProps control: Dialog.DialogControlProps
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
return ( return (
<Dialog.Outer control={control}> <Dialog.Outer control={control}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Contact our moderation team`)} label={l`Contact our moderation team`}
style={[web({maxWidth: 400})]}> style={[web({maxWidth: 400})]}>
<Inner control={control} /> <Inner control={control} />
<Dialog.Close /> <Dialog.Close />
@@ -38,7 +37,7 @@ export function AgeAssuranceAppealDialog({
} }
function Inner({control}: {control: Dialog.DialogControlProps}) { function Inner({control}: {control: Dialog.DialogControlProps}) {
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const {gtPhone} = useBreakpoints() const {gtPhone} = useBreakpoints()
@@ -68,22 +67,17 @@ function Inner({control}: {control: Dialog.DialogControlProps}) {
}, },
onError: err => { onError: err => {
logger.error('AgeAssuranceAppealDialog failed', {safeMessage: err}) logger.error('AgeAssuranceAppealDialog failed', {safeMessage: err})
Toast.show( Toast.show(l`Age assurance inquiry failed to send, please try again.`, {
_(msg`Age assurance inquiry failed to send, please try again.`), type: 'error',
{ })
type: 'error',
},
)
}, },
onSuccess: () => { onSuccess: () => {
control.close() control.close()
Toast.show( Toast.show(
_( l({
msg({ message: 'Age assurance inquiry was submitted',
message: 'Age assurance inquiry was submitted', context: 'toast',
context: 'toast', }),
}),
),
) )
}, },
}) })
@@ -93,18 +87,15 @@ function Inner({control}: {control: Dialog.DialogControlProps}) {
<View style={[a.align_start]}> <View style={[a.align_start]}>
<AgeAssuranceBadge /> <AgeAssuranceBadge />
</View> </View>
<Text style={[a.text_2xl, a.font_bold, a.pt_md, a.leading_tight]}> <Text style={[a.text_2xl, a.font_bold, a.pt_md, a.leading_tight]}>
<Trans>Contact us</Trans> <Trans>Contact us</Trans>
</Text> </Text>
<Text style={[a.text_sm, a.pt_sm, a.leading_snug]}> <Text style={[a.text_sm, a.pt_sm, a.leading_snug]}>
<Trans> <Trans>
Please provide any additional details you feel moderators may need in Please provide any additional details you feel moderators may need in
order to properly assess your Age Assurance status. order to properly assess your Age Assurance status.
</Trans> </Trans>
</Text> </Text>
<View style={[a.pt_md]}> <View style={[a.pt_md]}>
<Dialog.Input <Dialog.Input
multiline multiline
@@ -113,13 +104,13 @@ function Inner({control}: {control: Dialog.DialogControlProps}) {
onChangeText={details => { onChangeText={details => {
setDetails(details) setDetails(details)
}} }}
label={_(msg`Additional details (limit 1000 characters)`)} label={l`Additional details (limit 1000 characters)`}
numberOfLines={4} numberOfLines={4}
onSubmitEditing={() => mutate()} onSubmitEditing={() => mutate()}
/> />
<View style={[a.pt_md, a.gap_sm, gtPhone && [a.flex_row_reverse]]}> <View style={[a.pt_md, a.gap_sm, gtPhone && [a.flex_row_reverse]]}>
<Button <Button
label={_(msg`Submit`)} label={l`Submit`}
size="small" size="small"
variant="solid" variant="solid"
color="primary" color="primary"
@@ -130,7 +121,7 @@ function Inner({control}: {control: Dialog.DialogControlProps}) {
{isPending && <ButtonIcon icon={Loader} position="right" />} {isPending && <ButtonIcon icon={Loader} position="right" />}
</Button> </Button>
<Button <Button
label={_(msg`Cancel`)} label={l`Cancel`}
size="small" size="small"
variant="solid" variant="solid"
color="secondary" color="secondary"
@@ -1,7 +1,6 @@
import {useMemo} from 'react' import {useMemo} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs' import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
import {atoms as a, select, useTheme} from '#/alf' import {atoms as a, select, useTheme} from '#/alf'
@@ -43,7 +42,7 @@ export function useInternalState() {
export function AgeAssuranceDismissibleFeedBanner() { export function AgeAssuranceDismissibleFeedBanner() {
const t = useTheme() const t = useTheme()
const ax = useAnalytics() const ax = useAnalytics()
const {_} = useLingui() const {t: l} = useLingui()
const {visible, close} = useInternalState() const {visible, close} = useInternalState()
const copy = useAgeAssuranceCopy() const copy = useAgeAssuranceCopy()
@@ -63,7 +62,7 @@ export function AgeAssuranceDismissibleFeedBanner() {
}, },
]}> ]}>
<Link <Link
label={_(msg`Learn more about age assurance`)} label={l`Learn more about age assurance`}
to="/settings/account" to="/settings/account"
onPress={() => { onPress={() => {
close() close()
@@ -100,9 +99,8 @@ export function AgeAssuranceDismissibleFeedBanner() {
</View> </View>
</View> </View>
</Link> </Link>
<Button <Button
label={_(msg`Don't show again`)} label={l`Don't show again`}
size="small" size="small"
onPress={() => { onPress={() => {
close() close()
@@ -1,6 +1,5 @@
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs' import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
import {atoms as a, type ViewStyleProp} from '#/alf' import {atoms as a, type ViewStyleProp} from '#/alf'
@@ -13,7 +12,7 @@ import {useAgeAssurance} from '#/ageAssurance'
import {useAnalytics} from '#/analytics' import {useAnalytics} from '#/analytics'
export function AgeAssuranceDismissibleNotice({style}: ViewStyleProp & {}) { export function AgeAssuranceDismissibleNotice({style}: ViewStyleProp & {}) {
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const aa = useAgeAssurance() const aa = useAgeAssurance()
const {nux} = useNux(Nux.AgeAssuranceDismissibleNotice) const {nux} = useNux(Nux.AgeAssuranceDismissibleNotice)
@@ -35,7 +34,7 @@ export function AgeAssuranceDismissibleNotice({style}: ViewStyleProp & {}) {
<AgeAssuranceAdmonition>{copy.notice}</AgeAssuranceAdmonition> <AgeAssuranceAdmonition>{copy.notice}</AgeAssuranceAdmonition>
<Button <Button
label={_(msg`Don't show again`)} label={l`Don't show again`}
size="tiny" size="tiny"
variant="solid" variant="solid"
color="secondary_inverted" color="secondary_inverted"
@@ -1,5 +1,4 @@
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {type ViewStyleProp} from '#/alf' import {type ViewStyleProp} from '#/alf'
@@ -9,7 +8,7 @@ import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as RetryIcon} from '
import {refetchConfig} from '#/ageAssurance/data' import {refetchConfig} from '#/ageAssurance/data'
export function AgeAssuranceConfigUnavailableError(props: ViewStyleProp) { export function AgeAssuranceConfigUnavailableError(props: ViewStyleProp) {
const {_} = useLingui() const {t: l} = useLingui()
return ( return (
<Admonition.Outer type="error" style={props.style}> <Admonition.Outer type="error" style={props.style}>
<Admonition.Row> <Admonition.Row>
@@ -25,7 +24,7 @@ export function AgeAssuranceConfigUnavailableError(props: ViewStyleProp) {
</Admonition.Content> </Admonition.Content>
<Admonition.Button <Admonition.Button
color="negative_subtle" color="negative_subtle"
label={_(msg`Retry`)} label={l`Retry`}
onPress={() => refetchConfig().catch(() => {})}> onPress={() => refetchConfig().catch(() => {})}>
<ButtonText> <ButtonText>
<Trans>Retry</Trans> <Trans>Retry</Trans>
@@ -1,8 +1,7 @@
import {useState} from 'react' import {useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {XRPCError} from '@atproto/api' import {XRPCError} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {validate as validateEmail} from 'email-validator' import {validate as validateEmail} from 'email-validator'
@@ -41,15 +40,12 @@ export function AgeAssuranceInitDialog({
}: { }: {
control: Dialog.DialogControlProps control: Dialog.DialogControlProps
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
return ( return (
<Dialog.Outer control={control}> <Dialog.Outer control={control}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_( label={l`Begin the age assurance process by completing the fields below.`}
msg`Begin the age assurance process by completing the fields below.`,
)}
style={[ style={[
web({ web({
maxWidth: 400, maxWidth: 400,
@@ -63,7 +59,7 @@ export function AgeAssuranceInitDialog({
} }
function Inner() { function Inner() {
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const langPrefs = useLanguagePrefs() const langPrefs = useLanguagePrefs()
@@ -98,9 +94,7 @@ function Inner() {
if (tlds && isEmailMaybeInvalid(email, tlds)) { if (tlds && isEmailMaybeInvalid(email, tlds)) {
setEmailError( setEmailError(
_( l`Please double-check that you have entered your email address correctly.`,
msg`Please double-check that you have entered your email address correctly.`,
),
) )
return {status: 'maybe'} return {status: 'maybe'}
} }
@@ -108,7 +102,7 @@ function Inner() {
return {status: 'valid'} return {status: 'valid'}
} }
setEmailError(_(msg`Please enter a valid email address.`)) setEmailError(l`Please enter a valid email address.`)
setDisabled(true) setDisabled(true)
return {status: 'invalid'} return {status: 'invalid'}
@@ -135,15 +129,11 @@ function Inner() {
setSuccess(true) setSuccess(true)
} catch (e) { } catch (e) {
let error: React.ReactNode = _( let error: React.ReactNode = l`Something went wrong, please try again`
msg`Something went wrong, please try again`,
)
if (e instanceof XRPCError) { if (e instanceof XRPCError) {
if (e.error === 'InvalidEmail') { if (e.error === 'InvalidEmail') {
error = _( error = l`Please enter a valid, non-temporary email address. You may need to access this email in the future.`
msg`Please enter a valid, non-temporary email address. You may need to access this email in the future.`,
)
ax.metric('ageAssurance:initDialogError', {code: 'InvalidEmail'}) ax.metric('ageAssurance:initDialogError', {code: 'InvalidEmail'})
} else if (e.error === 'DidTooLong') { } else if (e.error === 'DidTooLong') {
error = ( error = (
@@ -153,7 +143,7 @@ function Inner() {
your account. Please{' '} your account. Please{' '}
<SimpleInlineLinkText <SimpleInlineLinkText
to={createSupportLink({code: SupportCode.AA_DID, email})} to={createSupportLink({code: SupportCode.AA_DID, email})}
label={_(msg`Contact support`)}> label={l`Contact support`}>
contact support contact support
</SimpleInlineLinkText>{' '} </SimpleInlineLinkText>{' '}
for assistance. for assistance.
@@ -197,7 +187,7 @@ function Inner() {
<Trans> <Trans>
We have partnered with{' '} We have partnered with{' '}
<SimpleInlineLinkText <SimpleInlineLinkText
label={_(msg`KWS website`)} label={l`KWS website`}
to={urls.kwsHome} to={urls.kwsHome}
style={[a.text_sm, a.leading_snug]}> style={[a.text_sm, a.leading_snug]}>
KWS KWS
@@ -220,7 +210,7 @@ function Inner() {
{success ? ( {success ? (
<View style={[a.w_full]}> <View style={[a.w_full]}>
<Button <Button
label={_(msg`Close dialog`)} label={l`Close dialog`}
size="large" size="large"
variant="solid" variant="solid"
color="secondary" color="secondary"
@@ -253,8 +243,8 @@ function Inner() {
</TextField.LabelText> </TextField.LabelText>
<TextField.Root isInvalid={!!emailError}> <TextField.Root isInvalid={!!emailError}>
<TextField.Input <TextField.Input
label={_(msg`Your email`)} label={l`Your email`}
placeholder={_(msg`Your email`)} placeholder={l`Your email`}
value={email} value={email}
onChangeText={setEmail} onChangeText={setEmail}
onFocus={() => setEmailError('')} onFocus={() => setEmailError('')}
@@ -289,7 +279,7 @@ function Inner() {
<Trans>Your preferred language</Trans> <Trans>Your preferred language</Trans>
</TextField.LabelText> </TextField.LabelText>
<LanguageSelect <LanguageSelect
label={_(msg`Preferred language`)} label={l`Preferred language`}
value={language} value={language}
onChange={value => { onChange={value => {
setLanguage(value) setLanguage(value)
@@ -310,7 +300,7 @@ function Inner() {
<Button <Button
disabled={disabled} disabled={disabled}
label={_(msg`Begin age assurance process`)} label={l`Begin age assurance process`}
size="large" size="large"
variant="solid" variant="solid"
color="primary" color="primary"
@@ -1,7 +1,6 @@
import {useEffect, useRef, useState} from 'react' import {useEffect, useRef, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {retry} from '#/lib/async/retry' import {retry} from '#/lib/async/retry'
@@ -61,7 +60,7 @@ export function useAgeAssuranceRedirectDialogControl() {
} }
export function AgeAssuranceRedirectDialog() { export function AgeAssuranceRedirectDialog() {
const {_} = useLingui() const {t: l} = useLingui()
const control = useAgeAssuranceRedirectDialogControl() const control = useAgeAssuranceRedirectDialogControl()
// for testing // for testing
@@ -70,9 +69,8 @@ export function AgeAssuranceRedirectDialog() {
return ( return (
<Dialog.Outer control={control.control} onClose={() => control.clear()}> <Dialog.Outer control={control.control} onClose={() => control.clear()}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Verifying your age assurance status`)} label={l`Verifying your age assurance status`}
style={[web({maxWidth: 400})]}> style={[web({maxWidth: 400})]}>
<Inner optimisticState={control.value} /> <Inner optimisticState={control.value} />
</Dialog.ScrollableInner> </Dialog.ScrollableInner>
@@ -83,7 +81,7 @@ export function AgeAssuranceRedirectDialog() {
export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) { export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
const t = useTheme() const t = useTheme()
const ax = useAnalytics() const ax = useAnalytics()
const {_} = useLingui() const {t: l} = useLingui()
const agent = useAgent() const agent = useAgent()
const polling = useRef(false) const polling = useRef(false)
const unmounted = useRef(false) const unmounted = useRef(false)
@@ -171,7 +169,7 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
{IS_NATIVE && ( {IS_NATIVE && (
<View style={[a.w_full, a.pt_lg]}> <View style={[a.w_full, a.pt_lg]}>
<Button <Button
label={_(msg`Close`)} label={l`Close`}
size="large" size="large"
variant="solid" variant="solid"
color="secondary" color="secondary"
@@ -183,7 +181,6 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
</View> </View>
)} )}
</View> </View>
<Dialog.Close /> <Dialog.Close />
</> </>
) )
@@ -230,7 +227,7 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
{error && IS_NATIVE && ( {error && IS_NATIVE && (
<View style={[a.w_full, a.pt_lg]}> <View style={[a.w_full, a.pt_lg]}>
<Button <Button
label={_(msg`Close`)} label={l`Close`}
size="large" size="large"
variant="solid" variant="solid"
color="secondary" color="secondary"
@@ -242,7 +239,6 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
</View> </View>
)} )}
</View> </View>
{error && <Dialog.Close />} {error && <Dialog.Close />}
</> </>
) )
@@ -1,6 +1,5 @@
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {atoms as a} from '#/alf' import {atoms as a} from '#/alf'
@@ -27,7 +26,7 @@ export function AgeRestrictedScreen({
infoText?: string infoText?: string
rightHeaderSlot?: React.ReactNode rightHeaderSlot?: React.ReactNode
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const copy = useAgeAssuranceCopy() const copy = useAgeAssuranceCopy()
const aa = useAgeAssurance() const aa = useAgeAssurance()
@@ -70,7 +69,7 @@ export function AgeRestrictedScreen({
<View <View
style={[a.flex_row, a.justify_between, a.align_center, a.pb_xl]}> style={[a.flex_row, a.justify_between, a.align_center, a.pb_xl]}>
<Link <Link
label={_(msg`Go to account settings`)} label={l`Go to account settings`}
to="/settings/account" to="/settings/account"
size="small" size="small"
variant="solid" variant="solid"
@@ -1,11 +1,10 @@
import {useMemo} from 'react' import {useMemo} from 'react'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {useAgeAssurance} from '#/ageAssurance' import {useAgeAssurance} from '#/ageAssurance'
export function useAgeAssuranceCopy() { export function useAgeAssuranceCopy() {
const {_} = useLingui() const {t: l} = useLingui()
const aa = useAgeAssurance() const aa = useAgeAssurance()
const hasCompletedFlow = aa.state.status === aa.Status.Assured const hasCompletedFlow = aa.state.status === aa.Status.Assured
@@ -13,18 +12,10 @@ export function useAgeAssuranceCopy() {
return useMemo(() => { return useMemo(() => {
return { return {
notice: hasCompletedFlow notice: hasCompletedFlow
? _( ? l`You have completed the Age Assurance process, but based on the results, we cannot be sure that you are 18 years of age or older. Due to laws in your region, certain features on Bluesky must remain restricted until you're able to verify you're an adult.`
msg`You have completed the Age Assurance process, but based on the results, we cannot be sure that you are 18 years of age or older. Due to laws in your region, certain features on Bluesky must remain restricted until you're able to verify you're an adult.`, : l`Due to laws in your region, certain features on Bluesky are currently restricted until you're able to verify you're an adult.`,
) banner: l`The laws in your region require you to verify you're an adult to access certain features. Tap to learn more.`,
: _( chatsInfoText: l`Don't worry! All existing messages and settings are saved and will be available after you verify you're an adult.`,
msg`Due to laws in your region, certain features on Bluesky are currently restricted until you're able to verify you're an adult.`,
),
banner: _(
msg`The laws in your region require you to verify you're an adult to access certain features. Tap to learn more.`,
),
chatsInfoText: _(
msg`Don't worry! All existing messages and settings are saved and will be available after you verify you're an adult.`,
),
} }
}, [_, hasCompletedFlow]) }, [l, hasCompletedFlow])
} }
@@ -2,8 +2,7 @@ import {useMemo} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {LinearGradient} from 'expo-linear-gradient' import {LinearGradient} from 'expo-linear-gradient'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {HITSLOP_10} from '#/lib/constants' import {HITSLOP_10} from '#/lib/constants'
@@ -19,7 +18,7 @@ import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from './country-allow
export function FindContactsBannerNUX() { export function FindContactsBannerNUX() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const {visible, close} = useInternalState() const {visible, close} = useInternalState()
@@ -30,7 +29,7 @@ export function FindContactsBannerNUX() {
<View style={a.w_full}> <View style={a.w_full}>
<Link <Link
to={{screen: 'FindContactsFlow'}} to={{screen: 'FindContactsFlow'}}
label={_(msg`Import contacts to find your friends`)} label={l`Import contacts to find your friends`}
onPress={() => { onPress={() => {
ax.metric('contacts:nux:bannerPressed', {}) ax.metric('contacts:nux:bannerPressed', {})
}} }}
@@ -75,7 +74,7 @@ export function FindContactsBannerNUX() {
</LinearGradient> </LinearGradient>
</Link> </Link>
<Button <Button
label={_(msg`Dismiss banner`)} label={l`Dismiss banner`}
hitSlop={HITSLOP_10} hitSlop={HITSLOP_10}
onPress={close} onPress={close}
style={[a.absolute, {top: 14, right: 14}]} style={[a.absolute, {top: 14, right: 14}]}
@@ -1,13 +1,12 @@
import {View} from 'react-native' import {View} from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
export function ContactsHeroImage() { export function ContactsHeroImage() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
return ( return (
<View <View
@@ -24,9 +23,7 @@ export function ContactsHeroImage() {
source={require('../../../../assets/images/find_friends_illustration.webp')} source={require('../../../../assets/images/find_friends_illustration.webp')}
accessibilityIgnoresInvertColors accessibilityIgnoresInvertColors
style={[a.w_full, {aspectRatio: 1278 / 661}]} style={[a.w_full, {aspectRatio: 1278 / 661}]}
alt={_( alt={l`An illustration depicting user avatars flowing from a contact book into the Bluesky app`}
msg`An illustration depicting user avatars flowing from a contact book into the Bluesky app`,
)}
useAppleWebpCodec useAppleWebpCodec
/> />
</View> </View>
@@ -1,6 +1,5 @@
import {type StyleProp, type TextStyle} from 'react-native' import {type StyleProp, type TextStyle} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {HITSLOP_20} from '#/lib/constants' import {HITSLOP_20} from '#/lib/constants'
@@ -22,7 +21,7 @@ export function InviteInfo({
*/ */
iconOffset?: number iconOffset?: number
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const control = Dialog.useDialogControl() const control = Dialog.useDialogControl()
const style = [a.text_md, a.leading_snug, a.mt_xs] const style = [a.text_md, a.leading_snug, a.mt_xs]
@@ -30,16 +29,15 @@ export function InviteInfo({
return ( return (
<> <>
<Button <Button
label={_(msg`Learn more about how inviting friends works`)} label={l`Learn more about how inviting friends works`}
onPress={control.open} onPress={control.open}
hitSlop={HITSLOP_20} hitSlop={HITSLOP_20}
style={android({transform: [{translateY: iconOffset}]})}> style={android({transform: [{translateY: iconOffset}]})}>
<InfoIcon style={iconStyle} size="sm" /> <InfoIcon style={iconStyle} size="sm" />
</Button> </Button>
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner label={_(msg`Invite Friends`)}> <Dialog.ScrollableInner label={l`Invite Friends`}>
<Text style={[a.text_2xl, a.font_bold]}> <Text style={[a.text_2xl, a.font_bold]}>
<Trans>Invite Friends</Trans> <Trans>Invite Friends</Trans>
</Text> </Text>
@@ -70,7 +68,7 @@ export function InviteInfo({
</Text> </Text>
<Button <Button
label={_(msg`Done`)} label={l`Done`}
onPress={() => control.close()} onPress={() => control.close()}
size="large" size="large"
color="primary" color="primary"
@@ -5,8 +5,7 @@ import {
type TextInputSelectionChangeEvent, type TextInputSelectionChangeEvent,
View, View,
} from 'react-native' } from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {mergeRefs} from '#/lib/merge-refs' import {mergeRefs} from '#/lib/merge-refs'
import {atoms as a, ios, platform, useTheme} from '#/alf' import {atoms as a, ios, platform, useTheme} from '#/alf'
@@ -30,7 +29,7 @@ export function OTPInput({
onComplete?: (code: string) => void onComplete?: (code: string) => void
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const innerRef = useRef<TextInput>(null) const innerRef = useRef<TextInput>(null)
const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
const [selection, setSelection] = useState({start: 0, end: 0}) const [selection, setSelection] = useState({start: 0, end: 0})
@@ -52,7 +51,7 @@ export function OTPInput({
return ( return (
<Pressable <Pressable
accessibilityLabel={_(msg`Focus code input`)} accessibilityLabel={l`Focus code input`}
accessibilityRole="button" accessibilityRole="button"
accessibilityHint="" accessibilityHint=""
style={[a.w_full, a.relative]} style={[a.w_full, a.relative]}
@@ -8,8 +8,8 @@ import {
AppBskyContactImportContacts, AppBskyContactImportContacts,
type Un$Typed, type Un$Typed,
} from '@atproto/api' } from '@atproto/api'
import {msg, t} from '@lingui/core/macro' import {t} from '@lingui/core/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react/macro'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useMutation, useQueryClient} from '@tanstack/react-query' import {useMutation, useQueryClient} from '@tanstack/react-query'
@@ -52,7 +52,7 @@ export function GetContacts({
onCancel: () => void onCancel: () => void
context: 'Onboarding' | 'Standalone' context: 'Onboarding' | 'Standalone'
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const agent = useAgent() const agent = useAgent()
const insets = useSafeAreaInsets() const insets = useSafeAreaInsets()
@@ -143,32 +143,26 @@ export function GetContacts({
}) })
if (isNetworkError(err)) { if (isNetworkError(err)) {
Toast.show( Toast.show(
_( l`There was a problem with your internet connection, please try again`,
msg`There was a problem with your internet connection, please try again`,
),
{type: 'error'}, {type: 'error'},
) )
} else if ( } else if (
err instanceof AppBskyContactImportContacts.TooManyContactsError err instanceof AppBskyContactImportContacts.TooManyContactsError
) { ) {
Toast.show( Toast.show(
_( l`Too many contacts - you've exceeded the number of contacts you can import to find your friends`,
msg`Too many contacts - you've exceeded the number of contacts you can import to find your friends`,
),
{type: 'error'}, {type: 'error'},
) )
} else if ( } else if (
err instanceof AppBskyContactImportContacts.InvalidTokenError err instanceof AppBskyContactImportContacts.InvalidTokenError
) { ) {
Toast.show( Toast.show(
_( l`Could not upload contacts. You need to re-verify your phone number to proceed`,
msg`Could not upload contacts. You need to re-verify your phone number to proceed`,
),
{type: 'error'}, {type: 'error'},
) )
} else { } else {
logger.error('Error uploading contacts', {safeMessage: err}) logger.error('Error uploading contacts', {safeMessage: err})
Toast.show(_(msg`Could not upload contacts. ${cleanError(err)}`), { Toast.show(l`Could not upload contacts. ${cleanError(err)}`, {
type: 'error', type: 'error',
}) })
} }
@@ -270,7 +264,7 @@ export function GetContacts({
</Trans> </Trans>
</Text> </Text>
<Button <Button
label={_(msg`Find my friends`)} label={l`Find my friends`}
size="large" size="large"
color="primary" color="primary"
onPress={() => getContacts()} onPress={() => getContacts()}
@@ -289,7 +283,7 @@ export function GetContacts({
)} )}
</Button> </Button>
<Button <Button
label={_(msg`Cancel`)} label={l`Cancel`}
size="large" size="large"
color="secondary" color="secondary"
onPress={onCancel}> onPress={onCancel}>
+15 -22
View File
@@ -3,8 +3,7 @@ import {Keyboard, View} from 'react-native'
import {KeyboardAvoidingView} from 'react-native-keyboard-controller' import {KeyboardAvoidingView} from 'react-native-keyboard-controller'
import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {AppBskyContactStartPhoneVerification} from '@atproto/api' import {AppBskyContactStartPhoneVerification} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useMutation} from '@tanstack/react-query' import {useMutation} from '@tanstack/react-query'
@@ -53,7 +52,7 @@ export function PhoneInput({
context: 'Onboarding' | 'Standalone' context: 'Onboarding' | 'Standalone'
onSkip: () => void onSkip: () => void
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const t = useTheme() const t = useTheme()
const agent = useAgent() const agent = useAgent()
@@ -98,26 +97,22 @@ export function PhoneInput({
onError: err => { onError: err => {
if (isNetworkError(err)) { if (isNetworkError(err)) {
setError( setError(
_( l`A network error occurred. Please check your internet connection`,
msg`A network error occurred. Please check your internet connection`,
),
) )
} else if ( } else if (
err instanceof err instanceof
AppBskyContactStartPhoneVerification.RateLimitExceededError AppBskyContactStartPhoneVerification.RateLimitExceededError
) { ) {
setError(_(msg`Rate limit exceeded. Please try again later.`)) setError(l`Rate limit exceeded. Please try again later.`)
} else if ( } else if (
err instanceof AppBskyContactStartPhoneVerification.InvalidPhoneError err instanceof AppBskyContactStartPhoneVerification.InvalidPhoneError
) { ) {
setError( setError(
_( l`The verification provider was unable to send a code to your phone number. Please check your phone number and try again.`,
msg`The verification provider was unable to send a code to your phone number. Please check your phone number and try again.`,
),
) )
} else { } else {
logger.error('Verify phone number failed', {safeMessage: err}) logger.error('Verify phone number failed', {safeMessage: err})
setError(_(msg`An error occurred. ${cleanError(err)}`)) setError(l`An error occurred. ${cleanError(err)}`)
} }
}, },
}) })
@@ -139,7 +134,7 @@ export function PhoneInput({
phoneNumber: result.formatted, phoneNumber: result.formatted,
}) })
} else { } else {
setFormatError(result.reason ?? _(msg`Invalid phone number`)) setFormatError(result.reason ?? l`Invalid phone number`)
} }
} }
@@ -157,7 +152,7 @@ export function PhoneInput({
size="small" size="small"
color="secondary" color="secondary"
variant="ghost" variant="ghost"
label={_(msg`Skip contact sharing and continue to the app`)} label={l`Skip contact sharing and continue to the app`}
onPress={onSkip}> onPress={onSkip}>
<ButtonText> <ButtonText>
<Trans>Skip</Trans> <Trans>Skip</Trans>
@@ -201,7 +196,7 @@ export function PhoneInput({
<View style={[a.flex_1]}> <View style={[a.flex_1]}>
<TextField.Root isInvalid={!!formatError || !isFeatureEnabled}> <TextField.Root isInvalid={!!formatError || !isFeatureEnabled}>
<TextField.Input <TextField.Input
label={_(msg`Phone number`)} label={l`Phone number`}
value={phoneNumber} value={phoneNumber}
onChangeText={text => { onChangeText={text => {
if (formatError) setFormatError('') if (formatError) setFormatError('')
@@ -252,7 +247,7 @@ export function PhoneInput({
<View style={[gutters, {paddingBottom}]}> <View style={[gutters, {paddingBottom}]}>
<Button <Button
disabled={!phoneNumber || isPending} disabled={!phoneNumber || isPending}
label={_(msg`Send code`)} label={l`Send code`}
size="large" size="large"
color="primary" color="primary"
onPress={onSubmitNumber}> onPress={onSubmitNumber}>
@@ -269,7 +264,7 @@ export function PhoneInput({
function LegalDisclaimer() { function LegalDisclaimer() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const style = [a.text_xs, t.atoms.text_contrast_medium, a.leading_snug] const style = [a.text_xs, t.atoms.text_contrast_medium, a.leading_snug]
@@ -299,12 +294,10 @@ function LegalDisclaimer() {
time by visiting settings.{' '} time by visiting settings.{' '}
<InlineLinkText <InlineLinkText
to={urls.website.support.findFriendsPrivacyPolicy} to={urls.website.support.findFriendsPrivacyPolicy}
label={_( label={l({
msg({ message: `Learn more about importing contacts`,
message: `Learn more about importing contacts`, context: `english-only-resource`,
context: `english-only-resource`, })}
}),
)}
style={[a.text_xs, a.leading_snug]}> style={[a.text_xs, a.leading_snug]}>
<Trans context="english-only-resource">Learn more</Trans> <Trans context="english-only-resource">Learn more</Trans>
</InlineLinkText> </InlineLinkText>
@@ -4,8 +4,7 @@ import {
AppBskyContactStartPhoneVerification, AppBskyContactStartPhoneVerification,
AppBskyContactVerifyPhone, AppBskyContactVerifyPhone,
} from '@atproto/api' } from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useMutation} from '@tanstack/react-query' import {useMutation} from '@tanstack/react-query'
@@ -41,7 +40,7 @@ export function VerifyNumber({
onSkip: () => void onSkip: () => void
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const agent = useAgent() const agent = useAgent()
const gutters = useGutters([0, 'wide']) const gutters = useGutters([0, 'wide'])
@@ -95,23 +94,19 @@ export function VerifyNumber({
setError({ setError({
retryable: true, retryable: true,
isResendError: false, isResendError: false,
message: _( message: l`A network error occurred. Please check your internet connection.`,
msg`A network error occurred. Please check your internet connection.`,
),
}) })
} else if (err instanceof AppBskyContactVerifyPhone.InvalidCodeError) { } else if (err instanceof AppBskyContactVerifyPhone.InvalidCodeError) {
setError({ setError({
retryable: true, retryable: true,
isResendError: true, isResendError: true,
message: _(msg`This code is invalid. Resend to get a new code.`), message: l`This code is invalid. Resend to get a new code.`,
}) })
} else if (err instanceof AppBskyContactVerifyPhone.InvalidPhoneError) { } else if (err instanceof AppBskyContactVerifyPhone.InvalidPhoneError) {
setError({ setError({
retryable: false, retryable: false,
isResendError: false, isResendError: false,
message: _( message: l`The verification provider was unable to send a code to your phone number. Please check your phone number and try again.`,
msg`The verification provider was unable to send a code to your phone number. Please check your phone number and try again.`,
),
}) })
} else if ( } else if (
err instanceof AppBskyContactVerifyPhone.RateLimitExceededError err instanceof AppBskyContactVerifyPhone.RateLimitExceededError
@@ -119,16 +114,14 @@ export function VerifyNumber({
setError({ setError({
retryable: true, retryable: true,
isResendError: false, isResendError: false,
message: _( message: l`Too many attempts. Please wait a few minutes and try again.`,
msg`Too many attempts. Please wait a few minutes and try again.`,
),
}) })
} else { } else {
logger.error('Verify phone number failed', {safeMessage: err}) logger.error('Verify phone number failed', {safeMessage: err})
setError({ setError({
retryable: true, retryable: true,
isResendError: false, isResendError: false,
message: _(msg`An error occurred. ${cleanError(err)}`), message: l`An error occurred. ${cleanError(err)}`,
}) })
} }
}, },
@@ -140,7 +133,7 @@ export function VerifyNumber({
}, },
onSuccess: () => { onSuccess: () => {
dispatch({type: 'RESEND_VERIFICATION_CODE'}) dispatch({type: 'RESEND_VERIFICATION_CODE'})
Toast.show(_(msg`A new code has been sent`)) Toast.show(l`A new code has been sent`)
}, },
onMutate: () => { onMutate: () => {
setOtpCode('') setOtpCode('')
@@ -151,9 +144,7 @@ export function VerifyNumber({
setError({ setError({
retryable: true, retryable: true,
isResendError: true, isResendError: true,
message: _( message: l`A network error occurred. Please check your internet connection.`,
msg`A network error occurred. Please check your internet connection.`,
),
}) })
} else if ( } else if (
err instanceof AppBskyContactStartPhoneVerification.InvalidPhoneError err instanceof AppBskyContactStartPhoneVerification.InvalidPhoneError
@@ -161,9 +152,7 @@ export function VerifyNumber({
setError({ setError({
retryable: false, retryable: false,
isResendError: true, isResendError: true,
message: _( message: l`The verification provider was unable to send a code to your phone number. Please check your phone number and try again.`,
msg`The verification provider was unable to send a code to your phone number. Please check your phone number and try again.`,
),
}) })
} else if ( } else if (
err instanceof err instanceof
@@ -172,16 +161,14 @@ export function VerifyNumber({
setError({ setError({
retryable: true, retryable: true,
isResendError: true, isResendError: true,
message: _( message: l`Too many codes sent. Please wait a few minutes and try again.`,
msg`Too many codes sent. Please wait a few minutes and try again.`,
),
}) })
} else { } else {
logger.error('Resend failed', {safeMessage: err}) logger.error('Resend failed', {safeMessage: err})
setError({ setError({
retryable: true, retryable: true,
isResendError: true, isResendError: true,
message: _(msg`An error occurred. ${cleanError(err)}`), message: l`An error occurred. ${cleanError(err)}`,
}) })
} }
}, },
@@ -199,7 +186,7 @@ export function VerifyNumber({
size="small" size="small"
color="secondary" color="secondary"
variant="ghost" variant="ghost"
label={_(msg`Skip contact sharing and continue to the app`)} label={l`Skip contact sharing and continue to the app`}
onPress={onSkip}> onPress={onSkip}>
<ButtonText> <ButtonText>
<Trans>Skip</Trans> <Trans>Skip</Trans>
@@ -227,9 +214,7 @@ export function VerifyNumber({
</Text> </Text>
<View style={[a.mt_2xl]}> <View style={[a.mt_2xl]}>
<OTPInput <OTPInput
label={_( label={l`Enter 6-digit code that was sent to your phone number`}
msg`Enter 6-digit code that was sent to your phone number`,
)}
value={otpCode} value={otpCode}
onChange={setOtpCode} onChange={setOtpCode}
onComplete={code => verifyNumber(code)} onComplete={code => verifyNumber(code)}
@@ -276,7 +261,7 @@ function OTPStatus({
onRetry: () => void onRetry: () => void
lastCodeSentAt: Date | null lastCodeSentAt: Date | null
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const [time, setTime] = useState(Date.now()) const [time, setTime] = useState(Date.now())
@@ -301,10 +286,10 @@ function OTPStatus({
if (isSuccess) { if (isSuccess) {
Icon = CircleCheckIcon Icon = CircleCheckIcon
text = _(msg`Phone number verified`) text = l`Phone number verified`
textColor = t.palette.positive_500 textColor = t.palette.positive_500
} else if (isPending) { } else if (isPending) {
text = _(msg`Verifying...`) text = l`Verifying...`
} else if (error) { } else if (error) {
Icon = WarningIcon Icon = WarningIcon
text = error.message text = error.message
@@ -342,12 +327,11 @@ function OTPStatus({
</Text> </Text>
</View> </View>
)} )}
{showRetryButton && ( {showRetryButton && (
<Button <Button
size="small" size="small"
color="secondary_inverted" color="secondary_inverted"
label={_(msg`Retry`)} label={l`Retry`}
onPress={onRetry} onPress={onRetry}
style={[a.mt_2xl]}> style={[a.mt_2xl]}>
<ButtonIcon icon={RetryIcon} /> <ButtonIcon icon={RetryIcon} />
@@ -356,13 +340,12 @@ function OTPStatus({
</ButtonText> </ButtonText>
</Button> </Button>
)} )}
{showResendButton && ( {showResendButton && (
<Button <Button
size="large" size="large"
color="secondary" color="secondary"
variant="ghost" variant="ghost"
label={_(msg`Resend code`)} label={l`Resend code`}
disabled={isResendingCode || isWaiting} disabled={isResendingCode || isWaiting}
onPress={onResend} onPress={onResend}
style={[a.mt_2xl]}> style={[a.mt_2xl]}>
+18 -23
View File
@@ -3,8 +3,7 @@ import {View} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useSafeAreaInsets} from 'react-native-safe-area-context'
import * as SMS from 'expo-sms' import * as SMS from 'expo-sms'
import {type ModerationOpts} from '@atproto/api' import {type ModerationOpts} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Plural, Trans} from '@lingui/react/macro' import {Plural, Trans} from '@lingui/react/macro'
import {useMutation, useQueryClient} from '@tanstack/react-query' import {useMutation, useQueryClient} from '@tanstack/react-query'
@@ -84,7 +83,7 @@ export function ViewMatches({
onNext: () => void onNext: () => void
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const gutter = useGutters([0, 'wide']) const gutter = useGutters([0, 'wide'])
const moderationOpts = useModerationOpts() const moderationOpts = useModerationOpts()
@@ -141,11 +140,11 @@ export function ViewMatches({
}), }),
onSuccess: () => { onSuccess: () => {
setDidFollowAll(true) setDidFollowAll(true)
Toast.show(_(msg`All friends followed!`), {type: 'success'}) Toast.show(l`All friends followed!`, {type: 'success'})
cumulativeFollowCount.current += followableDids.length cumulativeFollowCount.current += followableDids.length
}, },
onError: _err => { onError: _err => {
Toast.show(_(msg`Failed to follow all your friends, please try again`), { Toast.show(l`Failed to follow all your friends, please try again`, {
type: 'error', type: 'error',
}) })
for (const did of followableDids) { for (const did of followableDids) {
@@ -232,15 +231,13 @@ export function ViewMatches({
dispatch({type: 'DISMISS_MATCH_FAILED', payload: {did}}) dispatch({type: 'DISMISS_MATCH_FAILED', payload: {did}})
if (isNetworkError(err)) { if (isNetworkError(err)) {
Toast.show( Toast.show(
_( l`Failed to hide suggestion, please check your internet connection`,
msg`Failed to hide suggestion, please check your internet connection`,
),
{type: 'error'}, {type: 'error'},
) )
} else { } else {
logger.error('Dismissing match failed', {safeMessage: err}) logger.error('Dismissing match failed', {safeMessage: err})
Toast.show( Toast.show(
_(msg`An error occurred while hiding suggestion. ${cleanError(err)}`), l`An error occurred while hiding suggestion. ${cleanError(err)}`,
{type: 'error'}, {type: 'error'},
) )
} }
@@ -273,7 +270,7 @@ export function ViewMatches({
}> }>
{item.count > 1 && ( {item.count > 1 && (
<Button <Button
label={_(msg`Follow all`)} label={l`Follow all`}
size="small" size="small"
color="primary_subtle" color="primary_subtle"
onPress={() => followAll()} onPress={() => followAll()}
@@ -309,7 +306,7 @@ export function ViewMatches({
case 'no matches header': case 'no matches header':
return ( return (
<Header <Header
titleText={_(msg`You got here first`)} titleText={l`You got here first`}
largeTitle largeTitle
subtitleText={ subtitleText={
<Trans> <Trans>
@@ -353,7 +350,7 @@ export function ViewMatches({
]}> ]}>
{context === 'Onboarding' && <OnboardingPosition />} {context === 'Onboarding' && <OnboardingPosition />}
<SearchInput <SearchInput
placeholder={_(msg`Search contacts`)} placeholder={l`Search contacts`}
value={search} value={search}
onFocus={() => { onFocus={() => {
onFocus() onFocus()
@@ -392,7 +389,7 @@ export function ViewMatches({
{paddingBottom: insets.bottom + tokens.space.md}, {paddingBottom: insets.bottom + tokens.space.md},
]}> ]}>
<Button <Button
label={context === 'Onboarding' ? _(msg`Next`) : _(msg`Done`)} label={context === 'Onboarding' ? l`Next` : l`Done`}
onPress={() => { onPress={() => {
if (context === 'Onboarding') { if (context === 'Onboarding') {
ax.metric('onboarding:contacts:nextPressed', { ax.metric('onboarding:contacts:nextPressed', {
@@ -444,19 +441,19 @@ function MatchItem({
}) { }) {
const gutter = useGutters([0, 'wide']) const gutter = useGutters([0, 'wide'])
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const shadow = useProfileShadow(profile) const shadow = useProfileShadow(profile)
const contactName = useMemo(() => { const contactName = useMemo(() => {
if (!contact) return null if (!contact) return null
const name = contact.name ?? contact.firstName ?? contact.lastName const name = contact.name ?? contact.firstName ?? contact.lastName
if (name) return _(msg`Your contact ${name}`) if (name) return l`Your contact ${name}`
const phone = const phone =
contact.phoneNumbers?.find(p => p.isPrimary) ?? contact.phoneNumbers?.[0] contact.phoneNumbers?.find(p => p.isPrimary) ?? contact.phoneNumbers?.[0]
if (phone?.number) return phone.number if (phone?.number) return phone.number
return null return null
}, [contact, _]) }, [contact, l])
if (!moderationOpts) return null if (!moderationOpts) return null
@@ -497,7 +494,7 @@ function MatchItem({
<Button <Button
color="secondary" color="secondary"
variant="ghost" variant="ghost"
label={_(msg`Remove suggestion`)} label={l`Remove suggestion`}
onPress={() => onRemoveSuggestion(profile.did)} onPress={() => onRemoveSuggestion(profile.did)}
hoverStyle={[a.bg_transparent, {opacity: 0.5}]} hoverStyle={[a.bg_transparent, {opacity: 0.5}]}
hitSlop={8}> hitSlop={8}>
@@ -518,7 +515,7 @@ function ContactItem({
}) { }) {
const gutter = useGutters([0, 'wide']) const gutter = useGutters([0, 'wide'])
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const {currentAccount} = useSession() const {currentAccount} = useSession()
@@ -564,7 +561,7 @@ function ContactItem({
</Text> </Text>
{phoneNumber && currentAccount && ( {phoneNumber && currentAccount && (
<Button <Button
label={_(msg`Invite ${name} to join Bluesky`)} label={l`Invite ${name} to join Bluesky`}
color="secondary" color="secondary"
size="small" size="small"
onPress={async () => { onPress={async () => {
@@ -574,12 +571,10 @@ function ContactItem({
try { try {
await SMS.sendSMSAsync( await SMS.sendSMSAsync(
[phoneNumber], [phoneNumber],
_( l`I'm on Bluesky as ${currentAccount.handle} - come find me! https://bsky.app/download`,
msg`I'm on Bluesky as ${currentAccount.handle} - come find me! https://bsky.app/download`,
),
) )
} catch (err) { } catch (err) {
Toast.show(_(msg`Failed to launch SMS app`), {type: 'error'}) Toast.show(l`Failed to launch SMS app`, {type: 'error'})
logger.error('Could not launch SMS', {safeMessage: err}) logger.error('Could not launch SMS', {safeMessage: err})
} }
}}> }}>
@@ -1,7 +1,6 @@
import {useState} from 'react' import {useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {wait} from '#/lib/async/wait' import {wait} from '#/lib/async/wait'
@@ -32,13 +31,12 @@ export function DeviceLocationRequestDialog({
}: Props & { }: Props & {
control: Dialog.DialogOuterProps['control'] control: Dialog.DialogOuterProps['control']
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
return ( return (
<Dialog.Outer control={control}> <Dialog.Outer control={control}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Update your location`)} label={l`Update your location`}
style={[web({maxWidth: 380})]}> style={[web({maxWidth: 380})]}>
<DeviceLocationRequestDialogInner <DeviceLocationRequestDialogInner
onLocationAcquired={onLocationAcquired} onLocationAcquired={onLocationAcquired}
@@ -51,7 +49,7 @@ export function DeviceLocationRequestDialog({
function DeviceLocationRequestDialogInner({onLocationAcquired}: Props) { function DeviceLocationRequestDialogInner({onLocationAcquired}: Props) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {close} = Dialog.useDialogContext() const {close} = Dialog.useDialogContext()
const requestDeviceLocation = useRequestDeviceGeolocation() const requestDeviceLocation = useRequestDeviceGeolocation()
const cleanError = useCleanError() const cleanError = useCleanError()
@@ -78,13 +76,11 @@ function DeviceLocationRequestDialogInner({onLocationAcquired}: Props) {
closeDialog: close, closeDialog: close,
}) })
} else { } else {
setError(_(msg`Failed to resolve location. Please try again.`)) setError(l`Failed to resolve location. Please try again.`)
} }
} else { } else {
setError( setError(
_( l`Unable to access location. You'll need to visit your system settings to enable location services for Bluesky.`,
msg`Unable to access location. You'll need to visit your system settings to enable location services for Bluesky.`,
),
) )
} }
} catch (e: any) { } catch (e: any) {
@@ -114,18 +110,16 @@ function DeviceLocationRequestDialogInner({onLocationAcquired}: Props) {
</Trans> </Trans>
</Text> </Text>
</View> </View>
{error && ( {error && (
<View style={[a.pb_xs]}> <View style={[a.pb_xs]}>
<Admonition type="error">{error}</Admonition> <Admonition type="error">{error}</Admonition>
</View> </View>
)} )}
<View style={[a.gap_sm]}> <View style={[a.gap_sm]}>
{!dialogDisabled && ( {!dialogDisabled && (
<Button <Button
disabled={isRequesting} disabled={isRequesting}
label={_(msg`Allow location access`)} label={l`Allow location access`}
onPress={onPressConfirm} onPress={onPressConfirm}
size={IS_WEB ? 'small' : 'large'} size={IS_WEB ? 'small' : 'large'}
color="primary"> color="primary">
@@ -138,7 +132,7 @@ function DeviceLocationRequestDialogInner({onLocationAcquired}: Props) {
{!IS_WEB && ( {!IS_WEB && (
<Button <Button
label={_(msg`Cancel`)} label={l`Cancel`}
onPress={() => close()} onPress={() => close()}
size={IS_WEB ? 'small' : 'large'} size={IS_WEB ? 'small' : 'large'}
color="secondary"> color="secondary">
+11 -12
View File
@@ -1,8 +1,7 @@
import {memo, useEffect, useMemo, useState} from 'react' import {memo, useEffect, useMemo, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {type AppBskyActorDefs, type AppBskyFeedPost, AtUri} from '@atproto/api' import {type AppBskyActorDefs, type AppBskyFeedPost, AtUri} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {EMBED_SCRIPT} from '#/lib/constants' import {EMBED_SCRIPT} from '#/lib/constants'
@@ -51,7 +50,7 @@ function EmbedDialogInner({
timestamp, timestamp,
}: Omit<EmbedDialogProps, 'control'>) { }: Omit<EmbedDialogProps, 'control'>) {
const t = useTheme() const t = useTheme()
const {_, i18n} = useLingui() const {t: l, i18n} = useLingui()
const [copied, setCopied] = useState(false) const [copied, setCopied] = useState(false)
const [showCustomisation, setShowCustomisation] = useState(false) const [showCustomisation, setShowCustomisation] = useState(false)
const [colorMode, setColorMode] = useState<ColorModeValues>('system') const [colorMode, setColorMode] = useState<ColorModeValues>('system')
@@ -102,7 +101,7 @@ function EmbedDialogInner({
}, [i18n, postUri, postCid, record, timestamp, postAuthor, colorMode]) }, [i18n, postUri, postCid, record, timestamp, postAuthor, colorMode])
return ( return (
<Dialog.Inner label={_(msg`Embed post`)} style={[{maxWidth: 500}]}> <Dialog.Inner label={l`Embed post`} style={[{maxWidth: 500}]}>
<View style={[a.gap_lg]}> <View style={[a.gap_lg]}>
<View style={[a.gap_sm]}> <View style={[a.gap_sm]}>
<Text style={[a.text_2xl, a.font_bold]}> <Text style={[a.text_2xl, a.font_bold]}>
@@ -121,8 +120,8 @@ function EmbedDialogInner({
<Button <Button
label={ label={
showCustomisation showCustomisation
? _(msg`Hide customization options`) ? l`Hide customization options`
: _(msg`Show customization options`) : l`Show customization options`
} }
color="secondary" color="secondary"
variant="ghost" variant="ghost"
@@ -147,21 +146,21 @@ function EmbedDialogInner({
<Trans>Color theme</Trans> <Trans>Color theme</Trans>
</Text> </Text>
<SegmentedControl.Root <SegmentedControl.Root
label={_(msg`Color mode`)} label={l`Color mode`}
type="radio" type="radio"
value={colorMode} value={colorMode}
onChange={setColorMode}> onChange={setColorMode}>
<SegmentedControl.Item value="system" label={_(msg`System`)}> <SegmentedControl.Item value="system" label={l`System`}>
<SegmentedControl.ItemText> <SegmentedControl.ItemText>
<Trans>System</Trans> <Trans>System</Trans>
</SegmentedControl.ItemText> </SegmentedControl.ItemText>
</SegmentedControl.Item> </SegmentedControl.Item>
<SegmentedControl.Item value="light" label={_(msg`Light`)}> <SegmentedControl.Item value="light" label={l`Light`}>
<SegmentedControl.ItemText> <SegmentedControl.ItemText>
<Trans>Light</Trans> <Trans>Light</Trans>
</SegmentedControl.ItemText> </SegmentedControl.ItemText>
</SegmentedControl.Item> </SegmentedControl.Item>
<SegmentedControl.Item value="dark" label={_(msg`Dark`)}> <SegmentedControl.Item value="dark" label={l`Dark`}>
<SegmentedControl.ItemText> <SegmentedControl.ItemText>
<Trans>Dark</Trans> <Trans>Dark</Trans>
</SegmentedControl.ItemText> </SegmentedControl.ItemText>
@@ -175,7 +174,7 @@ function EmbedDialogInner({
<TextField.Root> <TextField.Root>
<TextField.Icon icon={CodeBracketsIcon} /> <TextField.Icon icon={CodeBracketsIcon} />
<TextField.Input <TextField.Input
label={_(msg`Embed HTML code`)} label={l`Embed HTML code`}
editable={false} editable={false}
selection={{start: 0, end: snippet.length}} selection={{start: 0, end: snippet.length}}
value={snippet} value={snippet}
@@ -183,7 +182,7 @@ function EmbedDialogInner({
</TextField.Root> </TextField.Root>
</View> </View>
<Button <Button
label={_(msg`Copy code`)} label={l`Copy code`}
color="primary" color="primary"
size="large" size="large"
onPress={() => { onPress={() => {
+6 -7
View File
@@ -1,7 +1,6 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import { import {
@@ -25,7 +24,7 @@ export function EmbedConsentDialog({
source: EmbedPlayerSource source: EmbedPlayerSource
onAccept: () => void onAccept: () => void
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const setExternalEmbedPref = useSetExternalEmbedPref() const setExternalEmbedPref = useSetExternalEmbedPref()
const onShowAllPress = useCallback(() => { const onShowAllPress = useCallback(() => {
@@ -51,7 +50,7 @@ export function EmbedConsentDialog({
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`External Media`)} label={l`External Media`}
style={web({maxWidth: 400})}> style={web({maxWidth: 400})}>
<View style={a.gap_sm}> <View style={a.gap_sm}>
<Text style={[a.text_2xl, a.font_bold]}> <Text style={[a.text_2xl, a.font_bold]}>
@@ -77,7 +76,7 @@ export function EmbedConsentDialog({
</View> </View>
<View style={a.gap_md}> <View style={a.gap_md}>
<Button <Button
label={_(msg`Enable external media`)} label={l`Enable external media`}
onPress={onShowAllPress} onPress={onShowAllPress}
onAccessibilityEscape={control.close} onAccessibilityEscape={control.close}
color="primary" color="primary"
@@ -87,7 +86,7 @@ export function EmbedConsentDialog({
</ButtonText> </ButtonText>
</Button> </Button>
<Button <Button
label={_(msg`Enable this source only`)} label={l`Enable this source only`}
onPress={onShowPress} onPress={onShowPress}
onAccessibilityEscape={control.close} onAccessibilityEscape={control.close}
color="secondary" color="secondary"
@@ -97,7 +96,7 @@ export function EmbedConsentDialog({
</ButtonText> </ButtonText>
</Button> </Button>
<Button <Button
label={_(msg`No thanks`)} label={l`No thanks`}
onAccessibilityEscape={control.close} onAccessibilityEscape={control.close}
onPress={onHidePress} onPress={onHidePress}
color="secondary" color="secondary"
@@ -1,7 +1,6 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useOpenLink} from '#/lib/hooks/useOpenLink' import {useOpenLink} from '#/lib/hooks/useOpenLink'
@@ -32,7 +31,7 @@ export function InAppBrowserConsentDialog() {
function InAppBrowserConsentInner({href}: {href?: string}) { function InAppBrowserConsentInner({href}: {href?: string}) {
const control = Dialog.useDialogContext() const control = Dialog.useDialogContext()
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const setInAppBrowser = useSetInAppBrowser() const setInAppBrowser = useSetInAppBrowser()
const openLink = useOpenLink() const openLink = useOpenLink()
@@ -60,7 +59,7 @@ function InAppBrowserConsentInner({href}: {href?: string}) {
}, [control]) }, [control])
return ( return (
<Dialog.ScrollableInner label={_(msg`How should we open this link?`)}> <Dialog.ScrollableInner label={l`How should we open this link?`}>
<View style={[a.gap_2xl]}> <View style={[a.gap_2xl]}>
<View style={[a.gap_sm]}> <View style={[a.gap_sm]}>
<Text style={[a.font_bold, a.text_2xl]}> <Text style={[a.font_bold, a.text_2xl]}>
@@ -75,7 +74,7 @@ function InAppBrowserConsentInner({href}: {href?: string}) {
</View> </View>
<View style={[a.gap_sm]}> <View style={[a.gap_sm]}>
<Button <Button
label={_(msg`Use in-app browser`)} label={l`Use in-app browser`}
onPress={onUseIAB} onPress={onUseIAB}
size="large" size="large"
variant="solid" variant="solid"
@@ -85,7 +84,7 @@ function InAppBrowserConsentInner({href}: {href?: string}) {
</ButtonText> </ButtonText>
</Button> </Button>
<Button <Button
label={_(msg`Use my default browser`)} label={l`Use my default browser`}
onPress={onUseLinking} onPress={onUseLinking}
size="large" size="large"
variant="solid" variant="solid"
@@ -96,7 +95,7 @@ function InAppBrowserConsentInner({href}: {href?: string}) {
<ButtonIcon position="right" icon={External} /> <ButtonIcon position="right" icon={External} />
</Button> </Button>
<Button <Button
label={_(msg`Cancel`)} label={l`Cancel`}
onPress={onCancel} onPress={onCancel}
size="large" size="large"
variant="ghost" variant="ghost"
+14 -19
View File
@@ -1,7 +1,6 @@
import {useCallback, useMemo, useState} from 'react' import {useCallback, useMemo, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {languageName} from '#/locale/helpers' import {languageName} from '#/locale/helpers'
@@ -107,7 +106,7 @@ export function DialogInner({
const [search, setSearch] = useState('') const [search, setSearch] = useState('')
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const handleClose = () => { const handleClose = () => {
control.close(() => { control.close(() => {
@@ -218,7 +217,7 @@ export function DialogInner({
size="small" size="small"
color="secondary" color="secondary"
shape="round" shape="round"
label={_(msg`Close dialog`)} label={l`Close dialog`}
onPress={handleClose}> onPress={handleClose}>
<ButtonIcon icon={XIcon} /> <ButtonIcon icon={XIcon} />
</Button> </Button>
@@ -229,8 +228,8 @@ export function DialogInner({
<SearchInput <SearchInput
value={search} value={search}
onChangeText={setSearch} onChangeText={setSearch}
placeholder={_(msg`Search languages`)} placeholder={l`Search languages`}
label={_(msg`Search languages`)} label={l`Search languages`}
maxLength={50} maxLength={50}
onClearText={() => setSearch('')} onClearText={() => setSearch('')}
/> />
@@ -246,13 +245,13 @@ export function DialogInner({
const flatListData = [ const flatListData = [
...(isCheckedRecentEmpty ...(isCheckedRecentEmpty
? [{type: 'header', label: _(msg`Recently used`)}] ? [{type: 'header', label: l`Recently used`}]
: []), : []),
...displayedLanguages.checkedRecent.map(lang => ({type: 'item', lang})), ...displayedLanguages.checkedRecent.map(lang => ({type: 'item', lang})),
...displayedLanguages.uncheckedRecent.map(lang => ({type: 'item', lang})), ...displayedLanguages.uncheckedRecent.map(lang => ({type: 'item', lang})),
...(isDisplayedLanguagesEmpty ...(isDisplayedLanguagesEmpty
? [] ? []
: [{type: 'header', label: _(msg`All languages`)}]), : [{type: 'header', label: l`All languages`}]),
...displayedLanguages.all.map(lang => ({type: 'item', lang})), ...displayedLanguages.all.map(lang => ({type: 'item', lang})),
] ]
@@ -264,7 +263,7 @@ export function DialogInner({
onChange={setCheckedLanguagesCode2} onChange={setCheckedLanguagesCode2}
type="checkbox" type="checkbox"
maxSelections={maxLanguages} maxSelections={maxLanguages}
label={_(msg`Select languages`)} label={l`Select languages`}
style={web([a.contents])}> style={web([a.contents])}>
<Dialog.InnerFlatList <Dialog.InnerFlatList
data={flatListData} data={flatListData}
@@ -319,7 +318,7 @@ export function DialogInner({
<Dialog.FlatListFooter <Dialog.FlatListFooter
onLayout={evt => setFooterHeight(evt.nativeEvent.layout.height)}> onLayout={evt => setFooterHeight(evt.nativeEvent.layout.height)}>
<Button <Button
label={_(msg`Close dialog`)} label={l`Close dialog`}
onPress={handleClose} onPress={handleClose}
color="primary" color="primary"
size="large"> size="large">
@@ -335,23 +334,19 @@ export function DialogInner({
} }
function DialogError({details}: {details?: string}) { function DialogError({details}: {details?: string}) {
const {_} = useLingui() const {t: l} = useLingui()
const control = Dialog.useDialogContext() const control = Dialog.useDialogContext()
return ( return (
<Dialog.ScrollableInner <Dialog.ScrollableInner style={a.gap_md} label={l`An error has occurred`}>
style={a.gap_md}
label={_(msg`An error has occurred`)}>
<Dialog.Close /> <Dialog.Close />
<ErrorScreen <ErrorScreen
title={_(msg`Oh no!`)} title={l`Oh no!`}
message={_( message={l`There was an unexpected issue in the application. Please let us know if this happened to you!`}
msg`There was an unexpected issue in the application. Please let us know if this happened to you!`,
)}
details={details} details={details}
/> />
<Button <Button
label={_(msg`Close dialog`)} label={l`Close dialog`}
onPress={() => control.close()} onPress={() => control.close()}
color="primary" color="primary"
size="large"> size="large">
+7 -8
View File
@@ -1,7 +1,6 @@
import {useCallback, useMemo} from 'react' import {useCallback, useMemo} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useOpenLink} from '#/lib/hooks/useOpenLink' import {useOpenLink} from '#/lib/hooks/useOpenLink'
@@ -49,7 +48,7 @@ function LinkWarningDialogInner({
link?: {href: string; displayText: string; share?: boolean} link?: {href: string; displayText: string; share?: boolean}
}) { }) {
const control = Dialog.useDialogContext() const control = Dialog.useDialogContext()
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const openLink = useOpenLink() const openLink = useOpenLink()
const {gtMobile} = useBreakpoints() const {gtMobile} = useBreakpoints()
@@ -79,8 +78,8 @@ function LinkWarningDialogInner({
style={web({maxWidth: 450})} style={web({maxWidth: 450})}
label={ label={
potentiallyMisleading potentiallyMisleading
? _(msg`Potentially misleading link warning`) ? l`Potentially misleading link warning`
: _(msg`Leaving Bluesky`) : l`Leaving Bluesky`
}> }>
<View style={[a.gap_2xl]}> <View style={[a.gap_2xl]}>
<View style={[a.gap_sm]}> <View style={[a.gap_sm]}>
@@ -109,8 +108,8 @@ function LinkWarningDialogInner({
gtMobile && [a.flex_row_reverse, a.justify_start], gtMobile && [a.flex_row_reverse, a.justify_start],
]}> ]}>
<Button <Button
label={link?.share ? _(msg`Share link`) : _(msg`Visit site`)} label={link?.share ? l`Share link` : l`Visit site`}
accessibilityHint={_(msg`Opens link ${link?.href ?? ''}`)} accessibilityHint={l`Opens link ${link?.href ?? ''}`}
onPress={onPressVisit} onPress={onPressVisit}
size="large" size="large"
variant="solid" variant="solid"
@@ -124,7 +123,7 @@ function LinkWarningDialogInner({
</ButtonText> </ButtonText>
</Button> </Button>
<Button <Button
label={_(msg`Go back`)} label={l`Go back`}
onPress={onCancel} onPress={onCancel}
size="large" size="large"
variant="ghost" variant="ghost"
+27 -36
View File
@@ -1,8 +1,7 @@
import {useCallback, useState} from 'react' import {useCallback, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {type AppBskyActorDefs, sanitizeMutedWordValue} from '@atproto/api' import {type AppBskyActorDefs, sanitizeMutedWordValue} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {logger} from '#/logger' import {logger} from '#/logger'
@@ -50,7 +49,7 @@ export function MutedWordsDialog() {
function MutedWordsInner() { function MutedWordsInner() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {gtMobile} = useBreakpoints() const {gtMobile} = useBreakpoints()
const { const {
isLoading: isPreferencesLoading, isLoading: isPreferencesLoading,
@@ -86,7 +85,7 @@ function MutedWordsInner() {
if (!sanitizedValue || !surfaces.length) { if (!sanitizedValue || !surfaces.length) {
setField('') setField('')
setError(_(msg`Please enter a valid word, tag, or phrase to mute`)) setError(l`Please enter a valid word, tag, or phrase to mute`)
return return
} }
@@ -105,10 +104,10 @@ function MutedWordsInner() {
logger.error(`Failed to save muted word`, {message: e.message}) logger.error(`Failed to save muted word`, {message: e.message})
setError(e.message) setError(e.message)
} }
}, [_, field, targets, addMutedWord, setField, durations, excludeFollowing]) }, [l, field, targets, addMutedWord, setField, durations, excludeFollowing])
return ( return (
<Dialog.ScrollableInner label={_(msg`Manage your muted words and tags`)}> <Dialog.ScrollableInner label={l`Manage your muted words and tags`}>
<View> <View>
<Text <Text
style={[ style={[
@@ -133,8 +132,8 @@ function MutedWordsInner() {
autoCapitalize="none" autoCapitalize="none"
autoComplete="off" autoComplete="off"
returnKeyType="done" returnKeyType="done"
label={_(msg`Enter a word or tag`)} label={l`Enter a word or tag`}
placeholder={_(msg`Enter a word or tag`)} placeholder={l`Enter a word or tag`}
value={field} value={field}
onChangeText={value => { onChangeText={value => {
if (error) { if (error) {
@@ -148,7 +147,7 @@ function MutedWordsInner() {
<View style={[a.pb_xl, a.gap_sm]}> <View style={[a.pb_xl, a.gap_sm]}>
<Toggle.Group <Toggle.Group
label={_(msg`Select how long to mute this word for.`)} label={l`Select how long to mute this word for.`}
type="radio" type="radio"
values={durations} values={durations}
onChange={setDurations}> onChange={setDurations}>
@@ -176,7 +175,7 @@ function MutedWordsInner() {
a.gap_sm, a.gap_sm,
]}> ]}>
<Toggle.Item <Toggle.Item
label={_(msg`Mute this word until you unmute it`)} label={l`Mute this word until you unmute it`}
name="forever" name="forever"
style={[a.flex_1]}> style={[a.flex_1]}>
<TargetToggle> <TargetToggle>
@@ -191,7 +190,7 @@ function MutedWordsInner() {
</Toggle.Item> </Toggle.Item>
<Toggle.Item <Toggle.Item
label={_(msg`Mute this word for 24 hours`)} label={l`Mute this word for 24 hours`}
name="24_hours" name="24_hours"
style={[a.flex_1]}> style={[a.flex_1]}>
<TargetToggle> <TargetToggle>
@@ -215,7 +214,7 @@ function MutedWordsInner() {
a.gap_sm, a.gap_sm,
]}> ]}>
<Toggle.Item <Toggle.Item
label={_(msg`Mute this word for 7 days`)} label={l`Mute this word for 7 days`}
name="7_days" name="7_days"
style={[a.flex_1]}> style={[a.flex_1]}>
<TargetToggle> <TargetToggle>
@@ -230,7 +229,7 @@ function MutedWordsInner() {
</Toggle.Item> </Toggle.Item>
<Toggle.Item <Toggle.Item
label={_(msg`Mute this word for 30 days`)} label={l`Mute this word for 30 days`}
name="30_days" name="30_days"
style={[a.flex_1]}> style={[a.flex_1]}>
<TargetToggle> <TargetToggle>
@@ -248,7 +247,7 @@ function MutedWordsInner() {
</Toggle.Group> </Toggle.Group>
<Toggle.Group <Toggle.Group
label={_(msg`Select what content this mute word should apply to.`)} label={l`Select what content this mute word should apply to.`}
type="radio" type="radio"
values={targets} values={targets}
onChange={setTargets}> onChange={setTargets}>
@@ -264,7 +263,7 @@ function MutedWordsInner() {
<View style={[a.flex_row, a.align_center, a.gap_sm, a.flex_wrap]}> <View style={[a.flex_row, a.align_center, a.gap_sm, a.flex_wrap]}>
<Toggle.Item <Toggle.Item
label={_(msg`Mute this word in post text and tags`)} label={l`Mute this word in post text and tags`}
name="content" name="content"
style={[a.flex_1]}> style={[a.flex_1]}>
<TargetToggle> <TargetToggle>
@@ -280,7 +279,7 @@ function MutedWordsInner() {
</Toggle.Item> </Toggle.Item>
<Toggle.Item <Toggle.Item
label={_(msg`Mute this word in tags only`)} label={l`Mute this word in tags only`}
name="tag" name="tag"
style={[a.flex_1]}> style={[a.flex_1]}>
<TargetToggle> <TargetToggle>
@@ -308,7 +307,7 @@ function MutedWordsInner() {
<Trans>Options:</Trans> <Trans>Options:</Trans>
</Text> </Text>
<Toggle.Item <Toggle.Item
label={_(msg`Do not apply this mute word to users you follow`)} label={l`Do not apply this mute word to users you follow`}
name="exclude_following" name="exclude_following"
style={[a.flex_row, a.justify_between]} style={[a.flex_row, a.justify_between]}
value={excludeFollowing} value={excludeFollowing}
@@ -327,7 +326,7 @@ function MutedWordsInner() {
<View style={[a.pt_xs]}> <View style={[a.pt_xs]}>
<Button <Button
disabled={isPending || !field} disabled={isPending || !field}
label={_(msg`Add mute word with chosen settings`)} label={l`Add mute word with chosen settings`}
size="large" size="large"
color="primary" color="primary"
variant="solid" variant="solid"
@@ -412,7 +411,6 @@ function MutedWordsInner() {
{IS_NATIVE && <View style={{height: 20}} />} {IS_NATIVE && <View style={{height: 20}} />}
</View> </View>
<Dialog.Close /> <Dialog.Close />
</Dialog.ScrollableInner> </Dialog.ScrollableInner>
) )
@@ -423,7 +421,7 @@ function MutedWordRow({
word, word,
}: ViewStyleProp & {word: AppBskyActorDefs.MutedWord}) { }: ViewStyleProp & {word: AppBskyActorDefs.MutedWord}) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {isPending, mutateAsync: removeMutedWord} = useRemoveMutedWordMutation() const {isPending, mutateAsync: removeMutedWord} = useRemoveMutedWordMutation()
const {mutateAsync: updateMutedWord} = useUpdateMutedWordMutation() const {mutateAsync: updateMutedWord} = useUpdateMutedWordMutation()
const control = Prompt.usePromptControl() const control = Prompt.usePromptControl()
@@ -449,15 +447,12 @@ function MutedWordRow({
<> <>
<Prompt.Basic <Prompt.Basic
control={control} control={control}
title={_(msg`Are you sure?`)} title={l`Are you sure?`}
description={_( description={l`This will delete "${word.value}" from your muted words. You can always add it back later.`}
msg`This will delete "${word.value}" from your muted words. You can always add it back later.`,
)}
onConfirm={remove} onConfirm={remove}
confirmButtonCta={_(msg`Remove`)} confirmButtonCta={l`Remove`}
confirmButtonColor="negative" confirmButtonColor="negative"
/> />
<View <View
style={[ style={[
a.flex_row, a.flex_row,
@@ -528,7 +523,7 @@ function MutedWordRow({
{' · '} {' · '}
</Text> </Text>
<Menu.Root> <Menu.Root>
<Menu.Trigger label={_(msg`Renew mute word`)}> <Menu.Trigger label={l`Renew mute word`}>
{({props}) => ( {({props}) => (
<Text <Text
{...props} {...props}
@@ -548,29 +543,25 @@ function MutedWordRow({
</Menu.LabelText> </Menu.LabelText>
<Menu.Group> <Menu.Group>
<Menu.Item <Menu.Item
label={_(msg`24 hours`)} label={l`24 hours`}
onPress={() => renew(1)}> onPress={() => renew(1)}>
<Menu.ItemText> <Menu.ItemText>
<Trans>24 hours</Trans> <Trans>24 hours</Trans>
</Menu.ItemText> </Menu.ItemText>
</Menu.Item> </Menu.Item>
<Menu.Item <Menu.Item label={l`7 days`} onPress={() => renew(7)}>
label={_(msg`7 days`)}
onPress={() => renew(7)}>
<Menu.ItemText> <Menu.ItemText>
<Trans>7 days</Trans> <Trans>7 days</Trans>
</Menu.ItemText> </Menu.ItemText>
</Menu.Item> </Menu.Item>
<Menu.Item <Menu.Item
label={_(msg`30 days`)} label={l`30 days`}
onPress={() => renew(30)}> onPress={() => renew(30)}>
<Menu.ItemText> <Menu.ItemText>
<Trans>30 days</Trans> <Trans>30 days</Trans>
</Menu.ItemText> </Menu.ItemText>
</Menu.Item> </Menu.Item>
<Menu.Item <Menu.Item label={l`Forever`} onPress={() => renew()}>
label={_(msg`Forever`)}
onPress={() => renew()}>
<Menu.ItemText> <Menu.ItemText>
<Trans>Forever</Trans> <Trans>Forever</Trans>
</Menu.ItemText> </Menu.ItemText>
@@ -610,7 +601,7 @@ function MutedWordRow({
</View> </View>
<Button <Button
label={_(msg`Remove mute word from your list`)} label={l`Remove mute word from your list`}
size="tiny" size="tiny"
shape="round" shape="round"
variant="outline" variant="outline"
@@ -5,8 +5,7 @@ import {
type AppBskyFeedPostgate, type AppBskyFeedPostgate,
AtUri, AtUri,
} from '@atproto/api' } from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Plural, Trans} from '@lingui/react/macro' import {Plural, Trans} from '@lingui/react/macro'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
@@ -109,11 +108,11 @@ export function PostInteractionSettingsControlledDialog({
} }
function DialogInner(props: Omit<PostInteractionSettingsFormProps, 'control'>) { function DialogInner(props: Omit<PostInteractionSettingsFormProps, 'control'>) {
const {_} = useLingui() const {t: l} = useLingui()
return ( return (
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Edit post interaction settings`)} label={l`Edit post interaction settings`}
style={[web({maxWidth: 400}), a.w_full]}> style={[web({maxWidth: 400}), a.w_full]}>
<Header /> <Header />
<PostInteractionSettingsForm {...props} /> <PostInteractionSettingsForm {...props} />
@@ -164,7 +163,7 @@ export function PostInteractionSettingsDialogControlledInner(
props: PostInteractionSettingsDialogProps, props: PostInteractionSettingsDialogProps,
) { ) {
const ax = useAnalytics() const ax = useAnalytics()
const {_} = useLingui() const {t: l} = useLingui()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const [isSaving, setIsSaving] = useState(false) const [isSaving, setIsSaving] = useState(false)
@@ -237,9 +236,7 @@ export function PostInteractionSettingsDialogControlledInner(
safeMessage: e.message, safeMessage: e.message,
}) })
Toast.show( Toast.show(
_( l`There was an issue. Please check your internet connection and try again.`,
msg`There was an issue. Please check your internet connection and try again.`,
),
{ {
type: 'error', type: 'error',
}, },
@@ -248,7 +245,7 @@ export function PostInteractionSettingsDialogControlledInner(
setIsSaving(false) setIsSaving(false)
} }
}, [ }, [
_, l,
ax, ax,
props.postUri, props.postUri,
props.rootPostUri, props.rootPostUri,
@@ -263,7 +260,7 @@ export function PostInteractionSettingsDialogControlledInner(
return ( return (
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Edit post interaction settings`)} label={l`Edit post interaction settings`}
style={[web({maxWidth: 400}), a.w_full]}> style={[web({maxWidth: 400}), a.w_full]}>
{isLoading ? ( {isLoading ? (
<View <View
@@ -312,7 +309,7 @@ export function PostInteractionSettingsForm({
onChangePersist, onChangePersist,
}: PostInteractionSettingsFormProps) { }: PostInteractionSettingsFormProps) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const playHaptic = useHaptics() const playHaptic = useHaptics()
const [showLists, setShowLists] = useState(false) const [showLists, setShowLists] = useState(false)
const { const {
@@ -428,7 +425,7 @@ export function PostInteractionSettingsForm({
</Text> </Text>
<Toggle.Group <Toggle.Group
label={_(msg`Set who can reply to your post`)} label={l`Set who can reply to your post`}
type="radio" type="radio"
maxSelections={1} maxSelections={1}
disabled={replySettingsDisabled} disabled={replySettingsDisabled}
@@ -448,7 +445,7 @@ export function PostInteractionSettingsForm({
<Toggle.Item <Toggle.Item
name="everyone" name="everyone"
type="checkbox" type="checkbox"
label={_(msg`Allow anyone to reply`)} label={l`Allow anyone to reply`}
style={[a.flex_1]}> style={[a.flex_1]}>
{({selected}) => ( {({selected}) => (
<Toggle.Panel active={selected}> <Toggle.Panel active={selected}>
@@ -462,7 +459,7 @@ export function PostInteractionSettingsForm({
<Toggle.Item <Toggle.Item
name="nobody" name="nobody"
type="checkbox" type="checkbox"
label={_(msg`Disable replies entirely`)} label={l`Disable replies entirely`}
style={[a.flex_1]}> style={[a.flex_1]}>
{({selected}) => ( {({selected}) => (
<Toggle.Panel active={selected}> <Toggle.Panel active={selected}>
@@ -477,9 +474,7 @@ export function PostInteractionSettingsForm({
</Toggle.Group> </Toggle.Group>
<Toggle.Group <Toggle.Group
label={_( label={l`Set precisely which groups of people can reply to your post`}
msg`Set precisely which groups of people can reply to your post`,
)}
values={toggleGroupValues} values={toggleGroupValues}
onChange={toggleGroupOnChange} onChange={toggleGroupOnChange}
disabled={replySettingsDisabled}> disabled={replySettingsDisabled}>
@@ -487,7 +482,7 @@ export function PostInteractionSettingsForm({
<Toggle.Item <Toggle.Item
name="followers" name="followers"
type="checkbox" type="checkbox"
label={_(msg`Allow your followers to reply`)} label={l`Allow your followers to reply`}
hitSlop={0}> hitSlop={0}>
{({selected}) => ( {({selected}) => (
<Toggle.Panel active={selected} adjacent="trailing"> <Toggle.Panel active={selected} adjacent="trailing">
@@ -501,7 +496,7 @@ export function PostInteractionSettingsForm({
<Toggle.Item <Toggle.Item
name="following" name="following"
type="checkbox" type="checkbox"
label={_(msg`Allow people you follow to reply`)} label={l`Allow people you follow to reply`}
hitSlop={0}> hitSlop={0}>
{({selected}) => ( {({selected}) => (
<Toggle.Panel active={selected} adjacent="both"> <Toggle.Panel active={selected} adjacent="both">
@@ -515,7 +510,7 @@ export function PostInteractionSettingsForm({
<Toggle.Item <Toggle.Item
name="mention" name="mention"
type="checkbox" type="checkbox"
label={_(msg`Allow people you mention to reply`)} label={l`Allow people you mention to reply`}
hitSlop={0}> hitSlop={0}>
{({selected}) => ( {({selected}) => (
<Toggle.Panel active={selected} adjacent="both"> <Toggle.Panel active={selected} adjacent="both">
@@ -530,8 +525,8 @@ export function PostInteractionSettingsForm({
<Button <Button
label={ label={
showLists showLists
? _(msg`Hide lists`) ? l`Hide lists`
: _(msg`Show lists of users to select from`) : l`Show lists of users to select from`
} }
accessibilityRole="togglebutton" accessibilityRole="togglebutton"
hitSlop={0} hitSlop={0}
@@ -595,7 +590,7 @@ export function PostInteractionSettingsForm({
key={list.uri} key={list.uri}
name={`list:${list.uri}`} name={`list:${list.uri}`}
type="checkbox" type="checkbox"
label={_(msg`Allow users in ${list.name} to reply`)} label={l`Allow users in ${list.name} to reply`}
hitSlop={0}> hitSlop={0}>
{({selected}) => ( {({selected}) => (
<Toggle.Panel <Toggle.Panel
@@ -619,14 +614,13 @@ export function PostInteractionSettingsForm({
</Toggle.Group> </Toggle.Group>
</View> </View>
</View> </View>
<Toggle.Item <Toggle.Item
name="quoteposts" name="quoteposts"
type="checkbox" type="checkbox"
label={ label={
quotesEnabled quotesEnabled
? _(msg`Disable quote posts of this post`) ? l`Disable quote posts of this post`
: _(msg`Enable quote posts of this post`) : l`Enable quote posts of this post`
} }
value={quotesEnabled} value={quotesEnabled}
onChange={onChangeQuotesEnabled}> onChange={onChangeQuotesEnabled}>
@@ -639,14 +633,13 @@ export function PostInteractionSettingsForm({
</Toggle.Panel> </Toggle.Panel>
)} )}
</Toggle.Item> </Toggle.Item>
{typeof persist !== 'undefined' && ( {typeof persist !== 'undefined' && (
<View style={[{minHeight: 24}, a.justify_center]}> <View style={[{minHeight: 24}, a.justify_center]}>
{isDirty ? ( {isDirty ? (
<Toggle.Item <Toggle.Item
name="persist" name="persist"
type="checkbox" type="checkbox"
label={_(msg`Save these options for next time`)} label={l`Save these options for next time`}
value={persist} value={persist}
onChange={() => onChangePersist?.(!persist)}> onChange={() => onChangePersist?.(!persist)}>
<Toggle.Checkbox /> <Toggle.Checkbox />
@@ -662,10 +655,9 @@ export function PostInteractionSettingsForm({
)} )}
</View> </View>
)} )}
<Button <Button
disabled={!canSave || isSaving} disabled={!canSave || isSaving}
label={_(msg`Save`)} label={l`Save`}
onPress={onSave} onPress={onSave}
color="primary" color="primary"
size="large"> size="large">
+9 -14
View File
@@ -1,7 +1,6 @@
import {useCallback, useImperativeHandle, useRef, useState} from 'react' import {useCallback, useImperativeHandle, useRef, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {BSKY_SERVICE} from '#/lib/constants' import {BSKY_SERVICE} from '#/lib/constants'
@@ -78,7 +77,7 @@ function DialogInner({
initialCustomAddress: string initialCustomAddress: string
}) { }) {
const control = Dialog.useDialogContext() const control = Dialog.useDialogContext()
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const {accounts} = useSession() const {accounts} = useSession()
const {gtMobile} = useBreakpoints() const {gtMobile} = useBreakpoints()
@@ -135,24 +134,20 @@ function DialogInner({
</Text> </Text>
<SegmentedControl.Root <SegmentedControl.Root
type="tabs" type="tabs"
label={_(msg`Hosting provider`)} label={l`Hosting provider`}
value={fixedOption} value={fixedOption}
onChange={setFixedOption}> onChange={setFixedOption}>
<SegmentedControl.Item <SegmentedControl.Item
testID="bskyServiceSelectBtn" testID="bskyServiceSelectBtn"
value={BSKY_SERVICE} value={BSKY_SERVICE}
label={_(msg`Bluesky`)}> label={l`Bluesky`}>
<SegmentedControl.ItemText> <SegmentedControl.ItemText>{l`Bluesky`}</SegmentedControl.ItemText>
{_(msg`Bluesky`)}
</SegmentedControl.ItemText>
</SegmentedControl.Item> </SegmentedControl.Item>
<SegmentedControl.Item <SegmentedControl.Item
testID="customSelectBtn" testID="customSelectBtn"
value="custom" value="custom"
label={_(msg`Custom`)}> label={l`Custom`}>
<SegmentedControl.ItemText> <SegmentedControl.ItemText>{l`Custom`}</SegmentedControl.ItemText>
{_(msg`Custom`)}
</SegmentedControl.ItemText>
</SegmentedControl.Item> </SegmentedControl.Item>
</SegmentedControl.Root> </SegmentedControl.Root>
@@ -217,7 +212,7 @@ function DialogInner({
</Trans> </Trans>
)}{' '} )}{' '}
<InlineLinkText <InlineLinkText
label={_(msg`Learn more about self hosting your PDS.`)} label={l`Learn more about self hosting your PDS.`}
to="https://atproto.com/guides/self-hosting"> to="https://atproto.com/guides/self-hosting">
<Trans>Learn more.</Trans> <Trans>Learn more.</Trans>
</InlineLinkText> </InlineLinkText>
@@ -234,7 +229,7 @@ function DialogInner({
web: 'small', web: 'small',
})} })}
onPress={() => control.close()} onPress={() => control.close()}
label={_(msg`Done`)}> label={l`Done`}>
<ButtonText> <ButtonText>
<Trans>Done</Trans> <Trans>Done</Trans>
</ButtonText> </ButtonText>
+5 -7
View File
@@ -1,7 +1,6 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useLoggedOutViewControls} from '#/state/shell/logged-out' import {useLoggedOutViewControls} from '#/state/shell/logged-out'
@@ -27,7 +26,7 @@ export function SigninDialog() {
function SigninDialogInner({}: {control: Dialog.DialogOuterProps['control']}) { function SigninDialogInner({}: {control: Dialog.DialogOuterProps['control']}) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {gtMobile} = useBreakpoints() const {gtMobile} = useBreakpoints()
const {requestSwitchToAccount} = useLoggedOutViewControls() const {requestSwitchToAccount} = useLoggedOutViewControls()
const closeAllActiveElements = useCloseAllActiveElements() const closeAllActiveElements = useCloseAllActiveElements()
@@ -44,7 +43,7 @@ function SigninDialogInner({}: {control: Dialog.DialogOuterProps['control']}) {
return ( return (
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Sign in to Bluesky or create a new account`)} label={l`Sign in to Bluesky or create a new account`}
style={[gtMobile ? {width: 'auto', maxWidth: 420} : a.w_full]}> style={[gtMobile ? {width: 'auto', maxWidth: 420} : a.w_full]}>
<View style={[!IS_NATIVE && a.p_2xl]}> <View style={[!IS_NATIVE && a.p_2xl]}>
<View <View
@@ -84,7 +83,7 @@ function SigninDialogInner({}: {control: Dialog.DialogOuterProps['control']}) {
color="primary" color="primary"
size="large" size="large"
onPress={showCreateAccount} onPress={showCreateAccount}
label={_(msg`Create an account`)}> label={l`Create an account`}>
<ButtonText> <ButtonText>
<Trans>Create an account</Trans> <Trans>Create an account</Trans>
</ButtonText> </ButtonText>
@@ -95,7 +94,7 @@ function SigninDialogInner({}: {control: Dialog.DialogOuterProps['control']}) {
color="secondary" color="secondary"
size="large" size="large"
onPress={showSignIn} onPress={showSignIn}
label={_(msg`Sign in`)}> label={l`Sign in`}>
<ButtonText> <ButtonText>
<Trans>Sign in</Trans> <Trans>Sign in</Trans>
</ButtonText> </ButtonText>
@@ -104,7 +103,6 @@ function SigninDialogInner({}: {control: Dialog.DialogOuterProps['control']}) {
{IS_NATIVE && <View style={{height: 10}} />} {IS_NATIVE && <View style={{height: 10}} />}
</View> </View>
<Dialog.Close /> <Dialog.Close />
</Dialog.ScrollableInner> </Dialog.ScrollableInner>
) )
+12 -15
View File
@@ -4,8 +4,7 @@ import {
type AppBskyGraphGetStarterPacksWithMembership, type AppBskyGraphGetStarterPacksWithMembership,
AppBskyGraphStarterpack, AppBskyGraphStarterpack,
} from '@atproto/api' } from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Plural, Trans} from '@lingui/react/macro' import {Plural, Trans} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
@@ -88,7 +87,7 @@ export function StarterPackDialog({
} }
function Empty({onStartWizard}: {onStartWizard: () => void}) { function Empty({onStartWizard}: {onStartWizard: () => void}) {
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
return ( return (
@@ -102,10 +101,9 @@ function Empty({onStartWizard}: {onStartWizard: () => void}) {
<Trans>You have no starter packs.</Trans> <Trans>You have no starter packs.</Trans>
</Text> </Text>
</View> </View>
<View style={[a.align_center]}> <View style={[a.align_center]}>
<Button <Button
label={_(msg`Create starter pack`)} label={l`Create starter pack`}
color="secondary_inverted" color="secondary_inverted"
size="small" size="small"
onPress={onStartWizard}> onPress={onStartWizard}>
@@ -131,7 +129,7 @@ function StarterPackList({
enabled?: boolean enabled?: boolean
}) { }) {
const control = Dialog.useDialogContext() const control = Dialog.useDialogContext()
const {_} = useLingui() const {t: l} = useLingui()
const {data: subject} = useProfileQuery({did: targetDid}) const {data: subject} = useProfileQuery({did: targetDid})
const { const {
@@ -184,7 +182,7 @@ function StarterPackList({
<Trans>Add to starter packs</Trans> <Trans>Add to starter packs</Trans>
</Text> </Text>
<Button <Button
label={_(msg`Close`)} label={l`Close`}
onPress={onClose} onPress={onClose}
variant="ghost" variant="ghost"
color="secondary" color="secondary"
@@ -202,7 +200,7 @@ function StarterPackList({
<Trans>New starter pack</Trans> <Trans>New starter pack</Trans>
</Text> </Text>
<Button <Button
label={_(msg`Create starter pack`)} label={l`Create starter pack`}
color="secondary_inverted" color="secondary_inverted"
size="small" size="small"
onPress={onStartWizard}> onPress={onStartWizard}>
@@ -260,7 +258,7 @@ function StarterPackItem({
}) { }) {
const t = useTheme() const t = useTheme()
const ax = useAnalytics() const ax = useAnalytics()
const {_} = useLingui() const {t: l} = useLingui()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const isSelf = subject?.did === currentAccount?.did const isSelf = subject?.did === currentAccount?.did
@@ -271,26 +269,26 @@ function StarterPackItem({
useListMembershipAddMutation({ useListMembershipAddMutation({
subject, subject,
onSuccess: () => { onSuccess: () => {
Toast.show(_(msg`Added to starter pack`)) Toast.show(l`Added to starter pack`)
}, },
onError: err => { onError: err => {
if (!isNetworkError(err)) { if (!isNetworkError(err)) {
logger.error('Failed to add to starter pack', {safeMessage: err}) logger.error('Failed to add to starter pack', {safeMessage: err})
} }
Toast.show(_(msg`Failed to add to starter pack`), {type: 'error'}) Toast.show(l`Failed to add to starter pack`, {type: 'error'})
}, },
}) })
const {mutate: removeMembership, isPending: isPendingRemove} = const {mutate: removeMembership, isPending: isPendingRemove} =
useListMembershipRemoveMutation({ useListMembershipRemoveMutation({
onSuccess: () => { onSuccess: () => {
Toast.show(_(msg`Removed from starter pack`)) Toast.show(l`Removed from starter pack`)
}, },
onError: err => { onError: err => {
if (!isNetworkError(err)) { if (!isNetworkError(err)) {
logger.error('Failed to remove from starter pack', {safeMessage: err}) logger.error('Failed to remove from starter pack', {safeMessage: err})
} }
Toast.show(_(msg`Failed to remove from starter pack`), {type: 'error'}) Toast.show(l`Failed to remove from starter pack`, {type: 'error'})
}, },
}) })
@@ -371,9 +369,8 @@ function StarterPackItem({
)} )}
</View> </View>
</View> </View>
<Button <Button
label={isInPack ? _(msg`Remove`) : _(msg`Add`)} label={isInPack ? l`Remove` : l`Add`}
color={isInPack ? 'secondary' : 'primary_subtle'} color={isInPack ? 'secondary' : 'primary_subtle'}
size="tiny" size="tiny"
disabled={isPending || isSelf} disabled={isPending || isSelf}
+4 -5
View File
@@ -1,7 +1,6 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher' import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
@@ -17,7 +16,7 @@ export function SwitchAccountDialog({
}: { }: {
control: Dialog.DialogControlProps control: Dialog.DialogControlProps
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const {onPressSwitchAccount, pendingDid} = useAccountSwitcher() const {onPressSwitchAccount, pendingDid} = useAccountSwitcher()
const {setShowLoggedOut} = useLoggedOutViewControls() const {setShowLoggedOut} = useLoggedOutViewControls()
@@ -44,7 +43,7 @@ export function SwitchAccountDialog({
return ( return (
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner label={_(msg`Switch account`)}> <Dialog.ScrollableInner label={l`Switch account`}>
<View style={[a.gap_lg]}> <View style={[a.gap_lg]}>
<Text style={[a.text_2xl, a.font_semi_bold]}> <Text style={[a.text_2xl, a.font_semi_bold]}>
<Trans>Switch account</Trans> <Trans>Switch account</Trans>
@@ -53,7 +52,7 @@ export function SwitchAccountDialog({
<AccountList <AccountList
onSelectAccount={onSelectAccount} onSelectAccount={onSelectAccount}
onSelectOther={onPressAddAccount} onSelectOther={onPressAddAccount}
otherLabel={_(msg`Add account`)} otherLabel={l`Add account`}
pendingDid={pendingDid} pendingDid={pendingDid}
/> />
</View> </View>
@@ -8,8 +8,7 @@ import {
type ComAtprotoRepoApplyWrites, type ComAtprotoRepoApplyWrites,
} from '@atproto/api' } from '@atproto/api'
import {TID} from '@atproto/common-web' import {TID} from '@atproto/common-web'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
@@ -38,7 +37,7 @@ export function CreateListFromStarterPackDialog({
control: Dialog.DialogControlProps control: Dialog.DialogControlProps
starterPack: AppBskyGraphDefs.StarterPackView starterPack: AppBskyGraphDefs.StarterPackView
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const agent = useAgent() const agent = useAgent()
const ax = useAnalytics() const ax = useAnalytics()
@@ -124,7 +123,7 @@ export function CreateListFromStarterPackDialog({
}) })
} catch (e) { } catch (e) {
logger.error('Failed to add members to list', {safeMessage: e}) logger.error('Failed to add members to list', {safeMessage: e})
Toast.show(_(msg`List created, but failed to add some members`), { Toast.show(l`List created, but failed to add some members`, {
type: 'error', type: 'error',
}) })
} }
@@ -145,7 +144,7 @@ export function CreateListFromStarterPackDialog({
nativeOptions={{preventExpansion: true}}> nativeOptions={{preventExpansion: true}}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Create list from starter pack`)} label={l`Create list from starter pack`}
style={web({maxWidth: 400})}> style={web({maxWidth: 400})}>
<View style={[a.gap_lg]}> <View style={[a.gap_lg]}>
<Text style={[a.text_xl, a.font_bold]}> <Text style={[a.text_xl, a.font_bold]}>
@@ -177,7 +176,7 @@ export function CreateListFromStarterPackDialog({
a.pt_sm, a.pt_sm,
]}> ]}>
<Button <Button
label={_(msg`Create list`)} label={l`Create list`}
onPress={onPressCreate} onPress={onPressCreate}
size={platform({ size={platform({
web: 'small', web: 'small',
@@ -189,7 +188,7 @@ export function CreateListFromStarterPackDialog({
</ButtonText> </ButtonText>
</Button> </Button>
<Button <Button
label={_(msg`Cancel`)} label={l`Cancel`}
onPress={() => control.close()} onPress={() => control.close()}
size={platform({ size={platform({
web: 'small', web: 'small',
@@ -205,7 +204,6 @@ export function CreateListFromStarterPackDialog({
<Dialog.Close /> <Dialog.Close />
</Dialog.ScrollableInner> </Dialog.ScrollableInner>
</Dialog.Outer> </Dialog.Outer>
<CreateOrEditListDialog <CreateOrEditListDialog
control={createDialogControl} control={createDialogControl}
purpose="app.bsky.graph.defs#curatelist" purpose="app.bsky.graph.defs#curatelist"
@@ -216,13 +214,12 @@ export function CreateListFromStarterPackDialog({
avatar: starterPack.list?.avatar, avatar: starterPack.list?.avatar,
}} }}
/> />
<Dialog.Outer <Dialog.Outer
control={loadingDialogControl} control={loadingDialogControl}
nativeOptions={{preventDismiss: true}}> nativeOptions={{preventDismiss: true}}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Adding members to list...`)} label={l`Adding members to list...`}
style={web({maxWidth: 400})}> style={web({maxWidth: 400})}>
<View style={[a.align_center, a.gap_lg, a.py_5xl]}> <View style={[a.align_center, a.gap_lg, a.py_5xl]}>
<Loader size="xl" /> <Loader size="xl" />
@@ -1,8 +1,7 @@
import {useCallback, useEffect, useMemo, useState} from 'react' import {useCallback, useEffect, useMemo, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {type AppBskyGraphDefs, RichText as RichTextAPI} from '@atproto/api' import {type AppBskyGraphDefs, RichText as RichTextAPI} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Plural, Trans} from '@lingui/react/macro' import {Plural, Trans} from '@lingui/react/macro'
import {cleanError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
@@ -50,7 +49,7 @@ export function CreateOrEditListDialog({
onSave?: (uri: string) => void onSave?: (uri: string) => void
initialValues?: InitialListValues initialValues?: InitialListValues
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const cancelControl = Dialog.useDialogControl() const cancelControl = Dialog.useDialogControl()
const [dirty, setDirty] = useState(false) const [dirty, setDirty] = useState(false)
@@ -92,13 +91,12 @@ export function CreateOrEditListDialog({
onPressCancel={onPressCancel} onPressCancel={onPressCancel}
initialValues={initialValues} initialValues={initialValues}
/> />
<Prompt.Basic <Prompt.Basic
control={cancelControl} control={cancelControl}
title={_(msg`Discard changes?`)} title={l`Discard changes?`}
description={_(msg`Are you sure you want to discard your changes?`)} description={l`Are you sure you want to discard your changes?`}
onConfirm={() => control.close()} onConfirm={() => control.close()}
confirmButtonCta={_(msg`Discard`)} confirmButtonCta={l`Discard`}
confirmButtonColor="negative" confirmButtonColor="negative"
/> />
</Dialog.Outer> </Dialog.Outer>
@@ -131,7 +129,7 @@ function DialogInner({
}, [list, purpose]) }, [list, purpose])
const isCurateList = activePurpose === 'app.bsky.graph.defs#curatelist' const isCurateList = activePurpose === 'app.bsky.graph.defs#curatelist'
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const agent = useAgent() const agent = useAgent()
const control = Dialog.useDialogContext() const control = Dialog.useDialogContext()
@@ -238,8 +236,8 @@ function DialogInner({
}) })
Toast.show( Toast.show(
isCurateList isCurateList
? _(msg({message: 'User list updated', context: 'toast'})) ? l({message: 'User list updated', context: 'toast'})
: _(msg({message: 'Moderation list updated', context: 'toast'})), : l({message: 'Moderation list updated', context: 'toast'}),
) )
control.close(() => onSave?.(list.uri)) control.close(() => onSave?.(list.uri))
} else { } else {
@@ -252,8 +250,8 @@ function DialogInner({
}) })
Toast.show( Toast.show(
isCurateList isCurateList
? _(msg({message: 'User list created', context: 'toast'})) ? l({message: 'User list created', context: 'toast'})
: _(msg({message: 'Moderation list created', context: 'toast'})), : l({message: 'Moderation list created', context: 'toast'}),
) )
control.close(() => onSave?.(uri)) control.close(() => onSave?.(uri))
} }
@@ -273,7 +271,7 @@ function DialogInner({
activePurpose, activePurpose,
isCurateList, isCurateList,
agent, agent,
_, l,
]) ])
const displayNameTooLong = isOverMaxGraphemeCount({ const displayNameTooLong = isOverMaxGraphemeCount({
@@ -288,7 +286,7 @@ function DialogInner({
const cancelButton = useCallback( const cancelButton = useCallback(
() => ( () => (
<Button <Button
label={_(msg`Cancel`)} label={l`Cancel`}
onPress={onPressCancel} onPress={onPressCancel}
size="small" size="small"
color="primary" color="primary"
@@ -300,13 +298,13 @@ function DialogInner({
</ButtonText> </ButtonText>
</Button> </Button>
), ),
[onPressCancel, _], [onPressCancel, l],
) )
const saveButton = useCallback( const saveButton = useCallback(
() => ( () => (
<Button <Button
label={_(msg`Save`)} label={l`Save`}
onPress={onPressSave} onPress={onPressSave}
disabled={ disabled={
!dirty || !dirty ||
@@ -327,7 +325,7 @@ function DialogInner({
</Button> </Button>
), ),
[ [
_, l,
t, t,
dirty, dirty,
onPressSave, onPressSave,
@@ -360,19 +358,19 @@ function DialogInner({
const title = list const title = list
? isCurateList ? isCurateList
? _(msg`Edit user list`) ? l`Edit user list`
: _(msg`Edit moderation list`) : l`Edit moderation list`
: isCurateList : isCurateList
? _(msg`Create user list`) ? l`Create user list`
: _(msg`Create moderation list`) : l`Create moderation list`
const displayNamePlaceholder = isCurateList const displayNamePlaceholder = isCurateList
? _(msg`e.g. Great Posters`) ? l`e.g. Great Posters`
: _(msg`e.g. Spammers`) : l`e.g. Spammers`
const descriptionPlaceholder = isCurateList const descriptionPlaceholder = isCurateList
? _(msg`e.g. The posters who never miss.`) ? l`e.g. The posters who never miss.`
: _(msg`e.g. Users that repeatedly reply with ads.`) : l`e.g. Users that repeatedly reply with ads.`
return ( return (
<Dialog.ScrollableInner <Dialog.ScrollableInner
@@ -413,7 +411,7 @@ function DialogInner({
<Dialog.Input <Dialog.Input
defaultValue={displayName} defaultValue={displayName}
onChangeText={onChangeDisplayName} onChangeText={onChangeDisplayName}
label={_(msg`Name`)} label={l`Name`}
placeholder={displayNamePlaceholder} placeholder={displayNamePlaceholder}
testID="editListNameInput" testID="editListNameInput"
/> />
@@ -450,7 +448,7 @@ function DialogInner({
defaultValue={descriptionRt.text} defaultValue={descriptionRt.text}
onChangeText={onChangeDescription} onChangeText={onChangeDescription}
multiline multiline
label={_(msg`Description`)} label={l`Description`}
placeholder={descriptionPlaceholder} placeholder={descriptionPlaceholder}
testID="editListDescriptionInput" testID="editListDescriptionInput"
/> />
@@ -1,8 +1,7 @@
import {useCallback, useMemo} from 'react' import {useCallback, useMemo} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {type AppBskyGraphDefs, type ModerationOpts} from '@atproto/api' import {type AppBskyGraphDefs, type ModerationOpts} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {cleanError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
@@ -57,7 +56,7 @@ function DialogInner({
profile: bsky.profile.AnyProfileView, profile: bsky.profile.AnyProfileView,
) => void | undefined ) => void | undefined
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const moderationOpts = useModerationOpts() const moderationOpts = useModerationOpts()
const {data: listMembers} = useAllListMembersQuery(list.uri) const {data: listMembers} = useAllListMembersQuery(list.uri)
@@ -78,7 +77,7 @@ function DialogInner({
return ( return (
<SearchablePeopleList <SearchablePeopleList
title={_(msg`Add people to list`)} title={l`Add people to list`}
renderProfileCard={renderProfileCard} renderProfileCard={renderProfileCard}
/> />
) )
@@ -114,7 +113,7 @@ function UserResult({
) => void | undefined ) => void | undefined
moderationOpts?: ModerationOpts moderationOpts?: ModerationOpts
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const membership = useMemo( const membership = useMemo(
() => getMembership(listMembers, profile.did), () => getMembership(listMembers, profile.did),
[listMembers, profile.did], [listMembers, profile.did],
@@ -122,7 +121,7 @@ function UserResult({
const {mutate: listMembershipAdd, isPending: isAddingPending} = const {mutate: listMembershipAdd, isPending: isAddingPending} =
useListMembershipAddMutation({ useListMembershipAddMutation({
onSuccess: () => { onSuccess: () => {
Toast.show(_(msg`Added to list`)) Toast.show(l`Added to list`)
onChange?.('add', profile) onChange?.('add', profile)
}, },
onError: e => onError: e =>
@@ -133,7 +132,7 @@ function UserResult({
const {mutate: listMembershipRemove, isPending: isRemovingPending} = const {mutate: listMembershipRemove, isPending: isRemovingPending} =
useListMembershipRemoveMutation({ useListMembershipRemoveMutation({
onSuccess: () => { onSuccess: () => {
Toast.show(_(msg`Removed from list`)) Toast.show(l`Removed from list`)
onChange?.('remove', profile) onChange?.('remove', profile)
}, },
onError: e => onError: e =>
@@ -175,8 +174,8 @@ function UserResult({
<Button <Button
label={ label={
membership === false membership === false
? _(msg`Add user to list`) ? l`Add user to list`
: _(msg`Remove user from list`) : l`Remove user from list`
} }
onPress={onToggleMembership} onPress={onToggleMembership}
disabled={isMutating} disabled={isMutating}
@@ -1,8 +1,7 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {atoms as a, useTheme, web} from '#/alf' import {atoms as a, useTheme, web} from '#/alf'
@@ -15,7 +14,7 @@ import {IS_WEB} from '#/env'
export function ActivitySubscriptionsNUX() { export function ActivitySubscriptionsNUX() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const nuxDialogs = useNuxDialogContext() const nuxDialogs = useNuxDialogContext()
const control = Dialog.useDialogControl() const control = Dialog.useDialogControl()
@@ -28,9 +27,8 @@ export function ActivitySubscriptionsNUX() {
return ( return (
<Dialog.Outer control={control} onClose={onClose}> <Dialog.Outer control={control} onClose={onClose}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Introducing activity notifications`)} label={l`Introducing activity notifications`}
style={[web({maxWidth: 400})]} style={[web({maxWidth: 400})]}
contentContainerStyle={[ contentContainerStyle={[
{ {
@@ -110,9 +108,7 @@ export function ActivitySubscriptionsNUX() {
aspectRatio: 398 / 268, aspectRatio: 398 / 268,
}, },
]} ]}
alt={_( alt={l`A screenshot of a profile page with a bell icon next to the follow button, indicating the new activity notifications feature.`}
msg`A screenshot of a profile page with a bell icon next to the follow button, indicating the new activity notifications feature.`,
)}
useAppleWebpCodec useAppleWebpCodec
/> />
</View> </View>
@@ -157,7 +153,7 @@ export function ActivitySubscriptionsNUX() {
{!IS_WEB && ( {!IS_WEB && (
<Button <Button
label={_(msg`Close`)} label={l`Close`}
size="large" size="large"
variant="solid" variant="solid"
color="primary" color="primary"
@@ -2,8 +2,7 @@ import {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {LinearGradient} from 'expo-linear-gradient' import {LinearGradient} from 'expo-linear-gradient'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {atoms as a, useTheme, web} from '#/alf' import {atoms as a, useTheme, web} from '#/alf'
@@ -17,7 +16,7 @@ import {IS_WEB} from '#/env'
export function BookmarksAnnouncement() { export function BookmarksAnnouncement() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const nuxDialogs = useNuxDialogContext() const nuxDialogs = useNuxDialogContext()
const control = Dialog.useDialogControl() const control = Dialog.useDialogControl()
@@ -33,9 +32,8 @@ export function BookmarksAnnouncement() {
onClose={onClose} onClose={onClose}
nativeOptions={{preventExpansion: true}}> nativeOptions={{preventExpansion: true}}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Introducing saved posts AKA bookmarks`)} label={l`Introducing saved posts AKA bookmarks`}
style={[web({maxWidth: 440})]} style={[web({maxWidth: 440})]}
contentContainerStyle={[ contentContainerStyle={[
{ {
@@ -117,13 +115,11 @@ export function BookmarksAnnouncement() {
aspectRatio: 333 / 104, aspectRatio: 333 / 104,
}, },
]} ]}
alt={_( alt={l({
msg({ message: `A screenshot of a post with a new button next to the share button that allows you to save the post to your bookmarks. The post is from @jcsalterego.bsky.social and reads "inventing a saturday that immediately follows monday".`,
message: `A screenshot of a post with a new button next to the share button that allows you to save the post to your bookmarks. The post is from @jcsalterego.bsky.social and reads "inventing a saturday that immediately follows monday".`, comment:
comment: 'Contains a post that originally appeared in English. Consider translating the post text if it makes sense in your language, and noting that the post was translated from English.',
'Contains a post that originally appeared in English. Consider translating the post text if it makes sense in your language, and noting that the post was translated from English.', })}
}),
)}
useAppleWebpCodec useAppleWebpCodec
/> />
</View> </View>
@@ -162,7 +158,7 @@ export function BookmarksAnnouncement() {
{!IS_WEB && ( {!IS_WEB && (
<Button <Button
label={_(msg`Close`)} label={l`Close`}
size="large" size="large"
color="primary" color="primary"
onPress={() => { onPress={() => {
@@ -2,8 +2,7 @@ import {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {LinearGradient} from 'expo-linear-gradient' import {LinearGradient} from 'expo-linear-gradient'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {atoms as a, useTheme, web} from '#/alf' import {atoms as a, useTheme, web} from '#/alf'
@@ -28,7 +27,7 @@ export const enabled = createIsEnabledCheck(props => {
export function DraftsAnnouncement() { export function DraftsAnnouncement() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const nuxDialogs = useNuxDialogContext() const nuxDialogs = useNuxDialogContext()
const control = Dialog.useDialogControl() const control = Dialog.useDialogControl()
@@ -44,9 +43,8 @@ export function DraftsAnnouncement() {
onClose={onClose} onClose={onClose}
nativeOptions={{preventExpansion: true}}> nativeOptions={{preventExpansion: true}}>
<Dialog.Handle fill={t.palette.primary_400} /> <Dialog.Handle fill={t.palette.primary_400} />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Introducing drafts`)} label={l`Introducing drafts`}
style={[web({maxWidth: 440})]} style={[web({maxWidth: 440})]}
contentContainerStyle={[ contentContainerStyle={[
{ {
@@ -94,13 +92,11 @@ export function DraftsAnnouncement() {
aspectRatio: 393 / 226, aspectRatio: 393 / 226,
}, },
]} ]}
alt={_( alt={l({
msg({ message: `A screenshot of the post composer with a new button next to the post button that says "Drafts", with a rainbow firework effect. Below, the text in the composer reads "Hey, did you hear the news? Bluesky has drafts now!!!".`,
message: `A screenshot of the post composer with a new button next to the post button that says "Drafts", with a rainbow firework effect. Below, the text in the composer reads "Hey, did you hear the news? Bluesky has drafts now!!!".`, comment:
comment: 'Contains a post that originally appeared in English. Consider translating the post text if it makes sense in your language, and noting that the post was translated from English.',
'Contains a post that originally appeared in English. Consider translating the post text if it makes sense in your language, and noting that the post was translated from English.', })}
}),
)}
useAppleWebpCodec useAppleWebpCodec
/> />
</View> </View>
@@ -137,7 +133,7 @@ export function DraftsAnnouncement() {
{!IS_WEB && ( {!IS_WEB && (
<Button <Button
label={_(msg`Close`)} label={l`Close`}
size="large" size="large"
color="primary" color="primary"
onPress={() => control.close()} onPress={() => control.close()}
@@ -2,8 +2,7 @@ import {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {LinearGradient} from 'expo-linear-gradient' import {LinearGradient} from 'expo-linear-gradient'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {atoms as a, useTheme, web} from '#/alf' import {atoms as a, useTheme, web} from '#/alf'
@@ -34,7 +33,7 @@ export const enabled = createIsEnabledCheck(props => {
export function FindContactsAnnouncement() { export function FindContactsAnnouncement() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const nuxDialogs = useNuxDialogContext() const nuxDialogs = useNuxDialogContext()
const control = Dialog.useDialogControl() const control = Dialog.useDialogControl()
@@ -51,9 +50,8 @@ export function FindContactsAnnouncement() {
onClose={onClose} onClose={onClose}
nativeOptions={{preventExpansion: true}}> nativeOptions={{preventExpansion: true}}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Introducing finding friends via contacts`)} label={l`Introducing finding friends via contacts`}
style={[web({maxWidth: 440})]} style={[web({maxWidth: 440})]}
contentContainerStyle={[ contentContainerStyle={[
{ {
@@ -75,9 +73,7 @@ export function FindContactsAnnouncement() {
accessibilityIgnoresInvertColors accessibilityIgnoresInvertColors
source={require('../../../../assets/images/find_friends_illustration.webp')} source={require('../../../../assets/images/find_friends_illustration.webp')}
style={[a.w_full, {aspectRatio: 1278 / 661}]} style={[a.w_full, {aspectRatio: 1278 / 661}]}
alt={_( alt={l`An illustration depicting user avatars flowing from a contact book into the Bluesky app`}
msg`An illustration depicting user avatars flowing from a contact book into the Bluesky app`,
)}
useAppleWebpCodec useAppleWebpCodec
/> />
</View> </View>
@@ -113,7 +109,7 @@ export function FindContactsAnnouncement() {
</View> </View>
<Button <Button
label={_(msg`Import Contacts`)} label={l`Import Contacts`}
size="large" size="large"
color="primary" color="primary"
onPress={() => { onPress={() => {
@@ -1,8 +1,7 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {urls} from '#/lib/constants' import {urls} from '#/lib/constants'
@@ -19,7 +18,7 @@ import {IS_NATIVE} from '#/env'
export function InitialVerificationAnnouncement() { export function InitialVerificationAnnouncement() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const ax = useAnalytics() const ax = useAnalytics()
const {gtMobile} = useBreakpoints() const {gtMobile} = useBreakpoints()
const nuxDialogs = useNuxDialogContext() const nuxDialogs = useNuxDialogContext()
@@ -34,9 +33,8 @@ export function InitialVerificationAnnouncement() {
return ( return (
<Dialog.Outer control={control} onClose={onClose}> <Dialog.Outer control={control} onClose={onClose}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Announcing verification on Bluesky`)} label={l`Announcing verification on Bluesky`}
style={[ style={[
gtMobile ? {width: 'auto', maxWidth: 400, minWidth: 200} : a.w_full, gtMobile ? {width: 'auto', maxWidth: 400, minWidth: 200} : a.w_full,
]}> ]}>
@@ -82,9 +80,7 @@ export function InitialVerificationAnnouncement() {
aspectRatio: 353 / 160, aspectRatio: 353 / 160,
}, },
]} ]}
alt={_( alt={l`An illustration showing that Bluesky selects trusted verifiers, and trusted verifiers in turn verify individual user accounts.`}
msg`An illustration showing that Bluesky selects trusted verifiers, and trusted verifiers in turn verify individual user accounts.`,
)}
useAppleWebpCodec useAppleWebpCodec
/> />
</View> </View>
@@ -117,9 +113,7 @@ export function InitialVerificationAnnouncement() {
aspectRatio: 353 / 196, aspectRatio: 353 / 196,
}, },
]} ]}
alt={_( alt={l`An mockup of a iPhone showing the Bluesky app open to the profile of a verified user with a blue checkmark next to their display name.`}
msg`An mockup of a iPhone showing the Bluesky app open to the profile of a verified user with a blue checkmark next to their display name.`,
)}
useAppleWebpCodec useAppleWebpCodec
/> />
</View> </View>
@@ -159,7 +153,7 @@ export function InitialVerificationAnnouncement() {
<Link <Link
overridePresentation overridePresentation
to={urls.website.blog.initialVerificationAnnouncement} to={urls.website.blog.initialVerificationAnnouncement}
label={_(msg`Read blog post`)} label={l`Read blog post`}
size="small" size="small"
variant="solid" variant="solid"
color="primary" color="primary"
@@ -175,7 +169,7 @@ export function InitialVerificationAnnouncement() {
</Link> </Link>
{IS_NATIVE && ( {IS_NATIVE && (
<Button <Button
label={_(msg`Close`)} label={l`Close`}
size="small" size="small"
variant="solid" variant="solid"
color="secondary" color="secondary"
@@ -2,8 +2,7 @@ import {useCallback, useMemo} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {LinearGradient} from 'expo-linear-gradient' import {LinearGradient} from 'expo-linear-gradient'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {atoms as a, select, useTheme, utils, web} from '#/alf' import {atoms as a, select, useTheme, utils, web} from '#/alf'
@@ -31,7 +30,7 @@ export const enabled = createIsEnabledCheck(props => {
export function LiveNowBetaDialog() { export function LiveNowBetaDialog() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const nuxDialogs = useNuxDialogContext() const nuxDialogs = useNuxDialogContext()
const control = Dialog.useDialogControl() const control = Dialog.useDialogControl()
@@ -55,9 +54,8 @@ export function LiveNowBetaDialog() {
onClose={onClose} onClose={onClose}
nativeOptions={{preventExpansion: true}}> nativeOptions={{preventExpansion: true}}>
<Dialog.Handle fill={t.palette.primary_700} /> <Dialog.Handle fill={t.palette.primary_700} />
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`Show when you’re live`)} label={l`Show when you’re live`}
style={[web({maxWidth: 440})]} style={[web({maxWidth: 440})]}
contentContainerStyle={[ contentContainerStyle={[
{ {
@@ -143,13 +141,11 @@ export function LiveNowBetaDialog() {
aspectRatio: 652 / 211, aspectRatio: 652 / 211,
}, },
]} ]}
alt={_( alt={l({
msg({ message: `A screenshot of a post from @esb.lol, showing the user is currently livestreaming content on Twitch. The post reads: "Hello! I'm live on Twitch, and I'm testing Bluesky's latest feature too!"`,
message: `A screenshot of a post from @esb.lol, showing the user is currently livestreaming content on Twitch. The post reads: "Hello! I'm live on Twitch, and I'm testing Bluesky's latest feature too!"`, comment:
comment: 'Contains a post that originally appeared in English. Consider translating the post text if it makes sense in your language, and noting that the post was translated from English.',
'Contains a post that originally appeared in English. Consider translating the post text if it makes sense in your language, and noting that the post was translated from English.', })}
}),
)}
useAppleWebpCodec useAppleWebpCodec
/> />
</View> </View>
@@ -189,7 +185,7 @@ export function LiveNowBetaDialog() {
{!IS_WEB && ( {!IS_WEB && (
<Button <Button
label={_(msg`Close`)} label={l`Close`}
size="large" size="large"
color="primary" color="primary"
onPress={() => { onPress={() => {
+6 -9
View File
@@ -1,8 +1,7 @@
import {Fragment} from 'react' import {Fragment} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {type ModerationCause} from '@atproto/api' import {type ModerationCause} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {listUriToHref} from '#/lib/strings/url-helpers' import {listUriToHref} from '#/lib/strings/url-helpers'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
@@ -19,23 +18,21 @@ export function BlockedByListDialog({
control: DialogControlProps control: DialogControlProps
listBlocks: ModerationCause[] listBlocks: ModerationCause[]
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
return ( return (
<Prompt.Outer control={control} testID="blockedByListDialog"> <Prompt.Outer control={control} testID="blockedByListDialog">
<Prompt.TitleText>{_(msg`User blocked by list`)}</Prompt.TitleText> <Prompt.TitleText>{l`User blocked by list`}</Prompt.TitleText>
<View style={[a.gap_sm, a.pb_lg]}> <View style={[a.gap_sm, a.pb_lg]}>
<Text <Text
selectable selectable
style={[a.text_md, a.leading_snug, t.atoms.text_contrast_high]}> style={[a.text_md, a.leading_snug, t.atoms.text_contrast_high]}>
{_( {l`This account is blocked by one or more of your moderation lists. To unblock, please visit the lists directly and remove this user.`}{' '}
msg`This account is blocked by one or more of your moderation lists. To unblock, please visit the lists directly and remove this user.`,
)}{' '}
</Text> </Text>
<Text style={[a.text_md, a.leading_snug, t.atoms.text_contrast_high]}> <Text style={[a.text_md, a.leading_snug, t.atoms.text_contrast_high]}>
{_(msg`Lists blocking this user:`)}{' '} {l`Lists blocking this user:`}{' '}
{listBlocks.map((block, i) => {listBlocks.map((block, i) =>
block.source.type === 'list' ? ( block.source.type === 'list' ? (
<Fragment key={block.source.list.uri}> <Fragment key={block.source.list.uri}>
@@ -52,7 +49,7 @@ export function BlockedByListDialog({
</Text> </Text>
</View> </View>
<Prompt.Actions> <Prompt.Actions>
<Prompt.Action cta={_(msg`I understand`)} onPress={() => {}} /> <Prompt.Action cta={l`I understand`} onPress={() => {}} />
</Prompt.Actions> </Prompt.Actions>
<Dialog.Close /> <Dialog.Close />
</Prompt.Outer> </Prompt.Outer>
+4 -6
View File
@@ -1,8 +1,7 @@
import {useState} from 'react' import {useState} from 'react'
import {Modal, Pressable, View} from 'react-native' import {Modal, Pressable, View} from 'react-native'
import {SafeAreaView} from 'react-native-safe-area-context' import {SafeAreaView} from 'react-native-safe-area-context'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
@@ -19,19 +18,18 @@ export function EmojiPopup({
onEmojiSelected: (emoji: string) => void onEmojiSelected: (emoji: string) => void
}) { }) {
const [modalVisible, setModalVisible] = useState(false) const [modalVisible, setModalVisible] = useState(false)
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
return ( return (
<> <>
<Pressable <Pressable
accessibilityLabel={_(msg`Open full emoji list`)} accessibilityLabel={l`Open full emoji list`}
accessibilityHint="" accessibilityHint=""
accessibilityRole="button" accessibilityRole="button"
onPress={() => setModalVisible(true)}> onPress={() => setModalVisible(true)}>
{children} {children}
</Pressable> </Pressable>
<Modal <Modal
animationType="slide" animationType="slide"
visible={modalVisible} visible={modalVisible}
@@ -56,7 +54,7 @@ export function EmojiPopup({
<Trans>Add Reaction</Trans> <Trans>Add Reaction</Trans>
</Text> </Text>
<Button <Button
label={_(msg`Close`)} label={l`Close`}
onPress={() => setModalVisible(false)} onPress={() => setModalVisible(false)}
size="small" size="small"
variant="ghost" variant="ghost"
+3 -4
View File
@@ -1,8 +1,7 @@
import {useMemo, useState} from 'react' import {useMemo, useState} from 'react'
import {useWindowDimensions, View} from 'react-native' import {useWindowDimensions, View} from 'react-native'
import {type ChatBskyConvoDefs} from '@atproto/api' import {type ChatBskyConvoDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {atoms as a, tokens, useTheme} from '#/alf' import {atoms as a, tokens, useTheme} from '#/alf'
@@ -25,7 +24,7 @@ export function EmojiReactionPicker({
children?: TriggerProps['children'] children?: TriggerProps['children']
onEmojiSelect: (emoji: string) => void onEmojiSelect: (emoji: string) => void
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const t = useTheme() const t = useTheme()
const isFromSelf = message.sender?.did === currentAccount?.did const isFromSelf = message.sender?.did === currentAccount?.did
@@ -77,7 +76,7 @@ export function EmojiReactionPicker({
return ( return (
<ContextMenu.Item <ContextMenu.Item
position={position} position={position}
label={_(msg`React with ${emoji}`)} label={l`React with ${emoji}`}
key={emoji} key={emoji}
onPress={() => onEmojiSelect(emoji)} onPress={() => onEmojiSelect(emoji)}
unstyled unstyled
+4 -5
View File
@@ -1,8 +1,7 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {type AppBskyActorDefs} from '@atproto/api' import {type AppBskyActorDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
@@ -22,7 +21,7 @@ export function MessageProfileButton({
}: { }: {
profile: AppBskyActorDefs.ProfileViewDetailed profile: AppBskyActorDefs.ProfileViewDetailed
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const t = useTheme() const t = useTheme()
const ax = useAnalytics() const ax = useAnalytics()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
@@ -35,7 +34,7 @@ export function MessageProfileButton({
navigation.navigate('MessagesConversation', {conversation: convo.id}) navigation.navigate('MessagesConversation', {conversation: convo.id})
}, },
onError: () => { onError: () => {
Toast.show(_(msg`Failed to create conversation`)) Toast.show(l`Failed to create conversation`)
}, },
}) })
@@ -96,7 +95,7 @@ export function MessageProfileButton({
color="secondary" color="secondary"
variant="solid" variant="solid"
shape="round" shape="round"
label={_(msg`Message ${profile.handle}`)} label={l`Message ${profile.handle}`}
style={[a.justify_center]} style={[a.justify_center]}
onPress={wrappedOnPress}> onPress={wrappedOnPress}>
<ButtonIcon icon={Message} size="md" /> <ButtonIcon icon={Message} size="md" />
@@ -1,7 +1,7 @@
import {useCallback, useImperativeHandle, useState} from 'react' import {useCallback, useImperativeHandle, useState} from 'react'
import {Keyboard} from 'react-native' import {Keyboard} from 'react-native'
import DatePicker from 'react-native-date-picker' import DatePicker from 'react-native-date-picker'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react/macro'
import {useTheme} from '#/alf' import {useTheme} from '#/alf'
import {type DateFieldProps} from '#/components/forms/DateField/types' import {type DateFieldProps} from '#/components/forms/DateField/types'
@@ -1,5 +1,5 @@
import {Pressable, View} from 'react-native' import {Pressable, View} from 'react-native'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react/macro'
import {atoms as a, native, useTheme, web} from '#/alf' import {atoms as a, native, useTheme, web} from '#/alf'
import * as TextField from '#/components/forms/TextField' import * as TextField from '#/components/forms/TextField'
+3 -4
View File
@@ -1,8 +1,7 @@
import {useCallback, useImperativeHandle, useState} from 'react' import {useCallback, useImperativeHandle, useState} from 'react'
import {Keyboard, View} from 'react-native' import {Keyboard, View} from 'react-native'
import DatePicker from 'react-native-date-picker' import DatePicker from 'react-native-date-picker'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
@@ -37,7 +36,7 @@ export function DateField({
maximumDate, maximumDate,
minimumDate, minimumDate,
}: DateFieldProps) { }: DateFieldProps) {
const {_, i18n} = useLingui() const {t: l, i18n} = useLingui()
const t = useTheme() const t = useTheme()
const control = Dialog.useDialogControl() const control = Dialog.useDialogControl()
@@ -125,7 +124,7 @@ export function DateField({
/> />
</View> </View>
<Button <Button
label={_(msg`Done`)} label={l`Done`}
onPress={() => { onPress={() => {
/* /*
* Commit the currently shown date even if the user never * Commit the currently shown date even if the user never
+4 -5
View File
@@ -1,7 +1,6 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {Keyboard, View} from 'react-native' import {Keyboard, View} from 'react-native'
import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {toNiceDomain} from '#/lib/strings/url-helpers' import {toNiceDomain} from '#/lib/strings/url-helpers'
@@ -26,7 +25,7 @@ export function HostingProvider({
}) { }) {
const serverInputControl = useDialogControl() const serverInputControl = useDialogControl()
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const onPressSelectService = useCallback(() => { const onPressSelectService = useCallback(() => {
Keyboard.dismiss() Keyboard.dismiss()
@@ -47,7 +46,7 @@ export function HostingProvider({
</Text> </Text>
<Button <Button
label={toNiceDomain(serviceUrl)} label={toNiceDomain(serviceUrl)}
accessibilityHint={_(msg`Changes hosting provider`)} accessibilityHint={l`Changes hosting provider`}
onPress={onPressSelectService} onPress={onPressSelectService}
variant="ghost" variant="ghost"
color="secondary" color="secondary"
@@ -67,7 +66,7 @@ export function HostingProvider({
<Button <Button
testID="selectServiceButton" testID="selectServiceButton"
label={toNiceDomain(serviceUrl)} label={toNiceDomain(serviceUrl)}
accessibilityHint={_(msg`Changes hosting provider`)} accessibilityHint={l`Changes hosting provider`}
variant="solid" variant="solid"
color="secondary" color="secondary"
style={[ style={[

Some files were not shown because too many files have changed in this diff Show More